Repository: racer-rust/racer (language: rust)

Issue:
Racer panics with 'byte index 19610 is out of bounds' on autocompleting RgbImage type alias on image crate
On the image crate, there's this following type alias:

```rust
 type RgbImage = ImageBuffer<Rgb<u8>, Vec<u8>>;
```

Code that triggers the crash:

```rust
extern crate image;

use image::{ImageBuffer, RgbImage, Rgb};

fn main() {        
    let img : ImageBuffer<Rgb<u8>, Vec<u8>> = image::ImageBuffer::new(100,100); // Code completion works
    let img2 : RgbImage = image::ImageBuffer::new(100,100);  // Code completion doesn't work
}
```

When trying to autocomplete the variable `img` which uses the full type name, code completion works perfectly.

But when trying to autocomplete the variable `img2` which uses a type alias, as soon I hit the `.` button, Racer crashes.

Debug log and stacktrace:

```
DEBUG:racer::core: Field: contextstr is |img2|, searchstr is ||
DEBUG:racer::ast: visit_expr expr(4294967295: img2)
DEBUG:racer::ast: expr is a path P[img2]
DEBUG:racer::ast: resolve_ast_path P[img2]
DEBUG:racer::nameres: resolve_path_with_str P[img2]
DEBUG:racer::nameres: resolve_path P[img2] "/home/cmt/Test/src/main.rs" 261 ExactMatch
DEBUG:racer::nameres: resolve_name img2 "/home/cmt/Test/src/main.rs" 261 ExactMatch Both
DEBUG:racer::nameres: search_local_scopes PathSegment { name: "img2", types: [] } "/home/cmt/Test/src/main.rs" 261 ExactMatch Both
DEBUG:racer::nameres: searching scope Both start: 74 point: 261 'img2' "/home/cmt/Test/src/main.rs" ExactMatch local: true, session: Session { .. }
DEBUG:racer::matchers: match_pattern_let point is 167
DEBUG:racer::typeinf: get_type_of match Match ["img2", "/home/cmt/Test/src/main.rs", 167, true, Let, [], [] |let img2 : RgbImage = image::ImageBuffer::new(100,100);|] 
DEBUG:racer::typeinf: get_type_of_let_expr calling parse_let |let img2 : RgbImage = image::ImageBuffer::new(100,100);|
DEBUG:racer::ast: LetTypeVisitor: ty is Some(PathSearch(P[RgbImage], Scope ["/home/cmt/Test/src/main.rs", 167])). pos is 4, src is |let img2 : RgbImage = image::ImageBuffer::new(100,100);|
DEBUG:racer::ast: destructure_pattern_to_ty point 4 ty PathSearch(P[RgbImage], Scope ["/home/cmt/Test/src/main.rs", 167])    ||||||||    pat: pat(4294967295: img2)
DEBUG:racer::ast: destructure_pattern_to_ty matched an ident!
DEBUG:racer::ast: find_type_match P[RgbImage], "/home/cmt/Test/src/main.rs"
DEBUG:racer::nameres: resolve_path_with_str P[RgbImage]
DEBUG:racer::nameres: resolve_path P[RgbImage] "/home/cmt/Test/src/main.rs" 167 ExactMatch
DEBUG:racer::nameres: resolve_name RgbImage "/home/cmt/Test/src/main.rs" 167 ExactMatch Type
DEBUG:racer::nameres: search_local_scopes PathSegment { name: "RgbImage", types: [] } "/home/cmt/Test/src/main.rs" 167 ExactMatch Type
DEBUG:racer::nameres: searching scope Type start: 74 point: 167 'RgbImage' "/home/cmt/Test/src/main.rs" ExactMatch local: true, session: Session { .. }
DEBUG:racer::nameres: search_scope found matches ExactMatch []
DEBUG:racer::nameres: search_scope_headers for |RgbImage| pt: 73
DEBUG:racer::nameres: search_scope_headers preblock is |fn main() |
DEBUG:racer::nameres: search_fn_args: found start of fn!! 63 |impl blah {fn main() {}}| RgbImage
DEBUG:racer::nameres: searching scope Type start: 0 point: 167 'RgbImage' "/home/cmt/Test/src/main.rs" ExactMatch local: true, session: Session { .. }
DEBUG:racer::matchers: found use: RgbImage in |use image::{ImageBuffer, RgbImage, Rgb};|
DEBUG:racer::nameres: resolve_path P[image::RgbImage] "/home/cmt/Test/src/main.rs" 21 ExactMatch
DEBUG:racer::nameres: resolve_path P[image] "/home/cmt/Test/src/main.rs" 21 ExactMatch
DEBUG:racer::nameres: resolve_name image "/home/cmt/Test/src/main.rs" 21 ExactMatch Type
DEBUG:racer::nameres: search_local_scopes PathSegment { name: "image", types: [] } "/home/cmt/Test/src/main.rs" 21 ExactMatch Type
DEBUG:racer::nameres: searching scope Type start: 0 point: 21 'image' "/home/cmt/Test/src/main.rs" ExactMatch local: true, session: Session { .. }
DEBUG:racer::matchers: found an extern crate: |extern crate image;|
DEBUG:racer::matchers: extern crate image
DEBUG:racer::nameres: get_crate_file image, "/home/cmt/Test/src/main.rs"
DEBUG:racer::cargo: get_crate_file: from_path="/home/cmt/Test/src/main.rs"

[...]


DEBUG:racer::cargo: find_src_via_lockfile package_name: image
DEBUG:racer::nameres: get_crate_file  - found the crate file! "/home/cmt/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.16.0/src/lib.rs"
DEBUG:racer::nameres: searching a module 'image' for RgbImage (whole path: P[image::RgbImage])
DEBUG:racer::nameres: searching scope Both start: 0 point: 0 'RgbImage' "/home/cmt/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.16.0/src/lib.rs" ExactMatch local: false, session: Session { .. }
DEBUG:racer::matchers: found use: RgbImage in |pub use buffer::{
    Pixel,
    ConvertBuffer,
    // Image types
    ImageBuffer,
    RgbImage,
    RgbaImage,
    GrayImage,
    GrayAlphaImage
};|
DEBUG:racer::nameres: resolve_path P[buffer::RgbImage] "/home/cmt/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.16.0/src/lib.rs" 1059 ExactMatch
DEBUG:racer::nameres: resolve_path P[buffer] "/home/cmt/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.16.0/src/lib.rs" 1059 ExactMatch
DEBUG:racer::nameres: resolve_name buffer "/home/cmt/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.16.0/src/lib.rs" 1059 ExactMatch Type
DEBUG:racer::nameres: search_local_scopes PathSegment { name: "buffer", types: [] } "/home/cmt/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.16.0/src/lib.rs" 1059 ExactMatch Type
DEBUG:racer::nameres: searching scope Type start: 0 point: 1059 'buffer' "/home/cmt/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.16.0/src/lib.rs" ExactMatch local: true, session: Session { .. }
DEBUG:racer::matchers: found a module declaration: |mod buffer;|
DEBUG:racer::nameres: searching a module 'buffer' for RgbImage (whole path: P[buffer::RgbImage])
DEBUG:racer::nameres: searching scope Both start: 0 point: 0 'RgbImage' "/home/cmt/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.16.0/src/buffer.rs" ExactMatch local: false, session: Session { .. }
DEBUG:racer::matchers: found!! a type RgbImage
DEBUG:racer::nameres: resolve_path returning [Match ["RgbImage", "/home/cmt/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.16.0/src/buffer.rs", 19610, false, Type, [], [] |pub type RgbImage = ImageBuffer<Rgb<u8>, Vec<u8>>;|]]
DEBUG:racer::nameres: resolve_path returning [Match ["RgbImage", "/home/cmt/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.16.0/src/buffer.rs", 19610, false, Type, [], [] |pub type RgbImage = ImageBuffer<Rgb<u8>, Vec<u8>>;|]]
DEBUG:racer::ast: get_type_of_typedef match is Match ["RgbImage", "/home/cmt/.cargo/registry/src/github.com-1ecc6299db9ec823/image-0.16.0/src/buffer.rs", 19610, false, Type, [], [] |pub type RgbImage = ImageBuffer<Rgb<u8>, Vec<u8>>;|]
DEBUG:racer::ast: get_type_of_typedef blob string type RgbImage = ImageBuffer<Rgb<u8>, Vec<u8>>;
DEBUG:racer::ast: type type is P[ImageBuffer<P[Rgb<P[u8]>],P[Vec<P[u8]>]>]
DEBUG:racer::ast: typevisitor type is Some(P[ImageBuffer<P[Rgb<P[u8]>],P[Vec<P[u8]>]>])
DEBUG:racer::ast: get_type_of_typedef parsed type Some(P[ImageBuffer<P[Rgb<P[u8]>],P[Vec<P[u8]>]>])
thread 'main' panicked at 'byte index 19610 is out of bounds of `extern crate image;

use image::{ImageBuffer, RgbImage, Rgb};

fn main() {    
    let img : ImageBuffer<Rgb<u8>, Vec<u8>> = image::ImageBuffer::new(100,100);
    let img2 : RgbImage = image::ImageBuffer::new(100,100);  // Code completion doesn't work
    `[...]', /checkout/src/libcore/str/mod.rs:2226:8
stack backtrace:
   0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace
             at /checkout/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1: std::sys_common::backtrace::_print
             at /checkout/src/libstd/sys_common/backtrace.rs:71
   2: std::panicking::default_hook::{{closure}}
             at /checkout/src/libstd/sys_common/backtrace.rs:60
             at /checkout/src/libstd/panicking.rs:381
   3: std::panicking::default_hook
             at /checkout/src/libstd/panicking.rs:397
   4: std::panicking::rust_panic_with_hook
             at /checkout/src/libstd/panicking.rs:577
   5: std::panicking::begin_panic
             at /checkout/src/libstd/panicking.rs:538
   6: std::panicking::begin_panic_fmt
             at /checkout/src/libstd/panicking.rs:522
   7: rust_begin_unwind
             at /checkout/src/libstd/panicking.rs:498
   8: core::panicking::panic_fmt
             at /checkout/src/libcore/panicking.rs:71
   9: core::str::slice_error_fail
             at /checkout/src/libcore/str/mod.rs:2226
  10: racer::scopes::mask_comments
  11: racer::scopes::scope_start
  12: racer::ast::find_type_match
  13: racer::ast::path_to_match
  14: <racer::ast::LetTypeVisitor<'c, 's> as syntex_syntax::visit::Visitor>::visit_local
  15: racer::ast::get_let_type
  16: racer::typeinf::get_type_of_match
  17: <core::option::Option<T>>::and_then
  18: <racer::ast::ExprTypeVisitor<'c, 's> as syntex_syntax::visit::Visitor>::visit_expr
  19: racer::ast::get_type_of
  20: racer::core::complete_from_file_
  21: racer::core::complete_from_file
  22: std::panicking::try::do_call
  23: __rust_maybe_catch_panic
             at /checkout/src/libpanic_unwind/lib.rs:99
  24: <rls::server::LsService<O>>::dispatch_message
  25: rls::main
  26: __rust_maybe_catch_panic
             at /checkout/src/libpanic_unwind/lib.rs:99
  27: std::rt::lang_start
             at /checkout/src/libstd/panicking.rs:459
             at /checkout/src/libstd/panic.rs:361
             at /checkout/src/libstd/rt.rs:59
  28: __libc_start_main
  29: <unknown>
```

rls-preview 0.122.0-nightly (93b47d1 2017-09-25)
rustc 1.22.0-nightly (185cc5f26 2017-10-02)
cargo 0.23.0-nightly (e447ac7e9 2017-09-27)


Discussion / hints:
Maybe it's just because we set a wrong path to source, but now I'm feeling really difficult to debug this bug!

Fix patch:
diff --git a/src/racer/ast.rs b/src/racer/ast.rs
index e40d92c1..1d68dc30 100644
--- a/src/racer/ast.rs
+++ b/src/racer/ast.rs
@@ -499,7 +499,7 @@ fn find_type_match(path: &core::Path, fpath: &Path, pos: BytePos, session: &Sess
     let res = resolve_path_with_str(path, fpath, pos, core::SearchType::ExactMatch,
                core::Namespace::Type, session).nth(0).and_then(|m| {
                    match m.mtype {
-                       MatchType::Type => get_type_of_typedef(&m, session, fpath),
+                       MatchType::Type => get_type_of_typedef(&m, session),
                        _ => Some(m)
                    }
                });
@@ -518,7 +518,7 @@ fn find_type_match(path: &core::Path, fpath: &Path, pos: BytePos, session: &Sess
     })
 }
 
-fn get_type_of_typedef(m: &Match, session: &Session, fpath: &Path) -> Option<Match> {
+pub(crate) fn get_type_of_typedef(m: &Match, session: &Session) -> Option<Match> {
     debug!("get_type_of_typedef match is {:?}", m);
     let msrc = session.load_file_and_mask_comments(&m.filepath);
     let blobstart = m.point - BytePos(5);  // 5 == "type ".len()
@@ -531,7 +531,7 @@ fn get_type_of_typedef(m: &Match, session: &Session, fpath: &Path) -> Option<Mat
         debug!("get_type_of_typedef parsed type {:?}", res.type_);
         res.type_
     }).and_then(|type_| {
-        let src = session.load_file(fpath);
+        let src = session.load_file(&m.filepath);
         let scope_start = scopes::scope_start(src.as_src(), m.point);
 
         // Type of TypeDef cannot be inside the impl block so look outside
diff --git a/src/racer/core.rs b/src/racer/core.rs
index 6f4186a4..719f1f43 100644
--- a/src/racer/core.rs
+++ b/src/racer/core.rs
@@ -486,13 +486,14 @@ impl fmt::Debug for PathSearch {
     }
 }
 
+#[derive(Clone, Debug)]
 pub struct IndexedSource {
     pub code: String,
     pub idx: Vec<ByteRange>,
     pub lines: RefCell<Vec<ByteRange>>
 }
 
-#[derive(Clone,Copy)]
+#[derive(Clone, Copy, Debug)]
 pub struct Src<'c> {
     pub src: &'c IndexedSource,
     pub range: ByteRange,
diff --git a/src/racer/nameres.rs b/src/racer/nameres.rs
index d20bb100..0b8cf0c8 100644
--- a/src/racer/nameres.rs
+++ b/src/racer/nameres.rs
@@ -7,9 +7,7 @@ use std::path::{Path, PathBuf};
 
 use {core, ast, matchers, scopes, typeinf};
 use core::SearchType::{self, ExactMatch, StartsWith};
-use core::{Match, Src, Session, Coordinate, SessionExt, Ty, BytePos, ByteRange};
-use core::MatchType::{Module, Function, Struct, Enum, EnumVariant, FnArg, Trait, StructField,
-    Impl, TraitImpl, MatchArm, Builtin, TypeParameter};
+use core::{Match, Src, Session, Coordinate, SessionExt, Ty, BytePos, ByteRange, MatchType};
 use core::Namespace;
 use ast::{GenericsArgs, ImplVisitor};
 use fileres::{get_crate_file, get_module_file};
@@ -45,7 +43,7 @@ fn search_struct_fields(searchstr: &str, structmatch: &Match,
                                 point: field_point + struct_start,
                                 coords: None,
                                 local: structmatch.local,
-                                mtype: StructField,
+                                mtype: MatchType::StructField,
                                 contextstr: contextstr,
                                 generic_args: Vec::new(),
                                 generic_types: Vec::new(),
@@ -153,7 +151,7 @@ fn search_scope_for_methods(
                            point: point + blob_range.start + start,
                            coords: None,
                            local: true,
-                           mtype: Function,
+                           mtype: MatchType::Function,
                            contextstr: signature.to_owned(),
                            generic_args: Vec::new(),
                            generic_types: Vec::new(),
@@ -196,7 +194,7 @@ fn search_generic_impl_scope_for_methods(
                            point: point + blob_range.start + start,
                            coords: None,
                            local: true,
-                           mtype: Function,
+                           mtype: MatchType::Function,
                            contextstr: signature.to_owned(),
                            generic_args: contextm.generic_args.clone(),  // Attach impl generic args
                            generic_types: contextm.generic_types.clone(), // Attach impl generic types
@@ -244,7 +242,7 @@ fn search_scope_for_static_trait_fns(
                            point: point + blob_range.start + start,
                            coords: None,
                            local: true,
-                           mtype: Function,
+                           mtype: MatchType::Function,
                            contextstr: signature.to_owned(),
                            generic_args: Vec::new(),
                            generic_types: Vec::new(),
@@ -290,7 +288,7 @@ pub fn search_for_impls(
                     debug!("impl decl {}", decl);
                     let implres = ast::parse_impl(decl);
                     let is_trait_impl = implres.trait_path.is_some();
-                    let mtype = if is_trait_impl { TraitImpl } else { Impl };
+                    let mtype = if is_trait_impl { MatchType::TraitImpl } else { MatchType::Impl };
 
                     if let Some(name_path) = implres.name_path {
                         if let Some(name) = name_path.segments.last() {
@@ -427,7 +425,7 @@ pub fn search_for_generic_impls(
                                 point: start + trait_pos,
                                 coords: None,
                                 local: true,
-                                mtype: TraitImpl,
+                                mtype: MatchType::TraitImpl,
                                 contextstr: "".into(),
                                 generic_args: vec![gen_arg.name().to_owned()],
                                 generic_types: vec![self_pathsearch],
@@ -549,7 +547,7 @@ fn search_scope_headers(
                         point: start,
                         coords: None,
                         local: true,
-                        mtype: MatchArm,
+                        mtype: MatchType::MatchArm,
                         contextstr: lhs.trim().to_owned(),
                         generic_args: Vec::new(),
                         generic_types: Vec::new(),
@@ -643,7 +641,7 @@ fn search_fn_args(
                     point: fnstart + arg_range.start - impl_header_len.into(),
                     coords: None,
                     local: local,
-                    mtype: FnArg,
+                    mtype: MatchType::FnArg,
                     contextstr: s.to_owned(),
                     generic_args: Vec::new(),
                     generic_types: Vec::new(),
@@ -720,7 +718,7 @@ pub fn do_file_search(
                             point: BytePos::ZERO,
                             coords: Some(Coordinate::start()),
                             local: false,
-                            mtype: Module,
+                            mtype: MatchType::Module,
                             contextstr: fname[3..].to_owned(),
                             generic_args: Vec::new(),
                             generic_types: Vec::new(),
@@ -740,7 +738,7 @@ pub fn do_file_search(
                                 point: BytePos::ZERO,
                                 coords: Some(Coordinate::start()),
                                 local: false,
-                                mtype: Module,
+                                mtype: MatchType::Module,
                                 contextstr: filepath.to_str().unwrap().to_owned(),
                                 generic_args: Vec::new(),
                                 generic_types: Vec::new(),
@@ -759,7 +757,7 @@ pub fn do_file_search(
                             point: BytePos::ZERO,
                             coords: Some(Coordinate::start()),
                             local: false,
-                            mtype: Module,
+                            mtype: MatchType::Module,
                             contextstr: fpath_buf.to_str().unwrap().to_owned(),
                             generic_args: Vec::new(),
                             generic_types: Vec::new(),
@@ -993,7 +991,7 @@ pub fn search_scope(
                                   point: BytePos::ZERO,
                                   coords: Some(Coordinate::start()),
                                   local: false,
-                                  mtype: Module,
+                                  mtype: MatchType::Module,
                                   contextstr: context,
                                   generic_args: Vec::new(),
                                   generic_types: Vec::new(),
@@ -1086,7 +1084,7 @@ fn search_closure_args(
                         point: scope_src_pos + pipe_range.start + arg_range.start,
                         coords: None,
                         local: true,
-                        mtype: FnArg,
+                        mtype: MatchType::FnArg,
                         contextstr: pipe_str.to_owned(),
                         generic_args: Vec::new(),
                         generic_types: Vec::new(),
@@ -1285,7 +1283,7 @@ pub fn resolve_path_with_str(
                 point: BytePos::ZERO,
                 coords: Some(Coordinate::start()),
                 local: false,
-                mtype: Builtin,
+                mtype: MatchType::Builtin,
                 contextstr: "str".into(),
                 generic_args: vec![],
                 generic_types: vec![],
@@ -1344,7 +1342,7 @@ pub fn resolve_name(
                         point: BytePos::ZERO,
                         coords: Some(Coordinate::start()),
                         local: false,
-                        mtype: Module,
+                        mtype: MatchType::Module,
                         contextstr: context,
                         generic_args: Vec::new(),
                         generic_types: Vec::new(),
@@ -1425,6 +1423,102 @@ pub fn get_super_scope(filepath: &Path, pos: BytePos, session: &Session,
     }
 }
 
+fn get_impls(
+    search_path: &core::PathSegment,
+    namespace: Namespace,
+    search_type: SearchType,
+    context: &Match,
+    session: &Session,
+    import_info: &ImportInfo,
+) -> Vec<Match> {
+    let mut out = Vec::new();
+    match context.mtype {
+        MatchType::Enum => {
+            let filesrc = session.load_file(&context.filepath);
+            let scopestart = scopes::find_stmt_start(filesrc.as_src(), context.point)
+                .expect("[resolve_path] statement start was not found");
+            let scopesrc = filesrc.get_src_from_start(scopestart);
+            if let Some(blob_range) = scopesrc.iter_stmts().nth(0) {
+                let match_cxt = MatchCxt {
+                    filepath: &context.filepath,
+                    search_str: &search_path.name,
+                    search_type,
+                    range: blob_range.shift(scopestart),
+                    is_local: true,
+                };
+                for mut enum_var in matchers::match_enum_variants(&filesrc, &match_cxt) {
+                    debug!(
+                        "Found enum variant {} with enum type {}",
+                        enum_var.matchstr,
+                        context.matchstr
+                    );
+                    // return Match which has enum simultaneously, for method completion
+                    enum_var.mtype = MatchType::EnumVariant(Some(Box::new(context.clone())));
+                    out.push(enum_var);
+                }
+            }
+        }
+        MatchType::Struct => {}
+        _ => return out,
+    }
+
+    for m_impl in search_for_impls(
+        context.point,
+        &context.matchstr,
+        &context.filepath,
+        context.local,
+        true,
+        session,
+        import_info)
+    {
+        debug!("found impl!! {:?}", m_impl);
+        let src = session.load_file(&m_impl.filepath);
+        // find the opening brace and skip to it.
+        if let Some(n) = src[m_impl.point.0..].find('{') {
+            let point = m_impl.point + BytePos(n + 1);
+            out.extend(search_scope(
+                point,
+                point,
+                src.as_src(),
+                &search_path,
+                &m_impl.filepath,
+                search_type,
+                m_impl.local,
+                namespace,
+                session,
+                import_info,
+            ));
+        }
+        for m_gen in search_for_generic_impls(
+            m_impl.point,
+            &m_impl.matchstr,
+            &context,
+            &m_impl.filepath,
+            session)
+        {
+            debug!("found generic impl!! {:?}", m_gen);
+            let src = session.load_file(&m_gen.filepath);
+            // find the opening brace and skip to it.
+            if let Some(n) = src[m_gen.point.0..].find('{') {
+                let point = m_gen.point + BytePos(n + 1);
+                out.extend(search_scope(
+                    point,
+                    point,
+                    src.as_src(),
+                    search_path,
+                    &m_gen.filepath,
+                    search_type,
+                    m_gen.local,
+                    namespace,
+                    session,
+                    import_info,
+                ));
+            }
+        }
+    };
+    out
+}
+
 pub fn resolve_path(
     path: &core::Path,
     filepath: &Path,
@@ -1470,7 +1564,7 @@ pub fn resolve_path(
         let context = resolve_path(&parent_path, filepath, pos, ExactMatch, Namespace::Type, session, import_info).nth(0);
         context.map(|m| {
             match m.mtype {
-                Module => {
+                MatchType::Module => {
                     let mut searchstr: &str = &path.segments[len-1].name;
                     if let Some(i) = searchstr.rfind(',') {
                         searchstr = searchstr[i+1..].trim();
@@ -1491,120 +1585,27 @@ pub fn resolve_path(
                         import_info,
                     ));
                 }
-                Enum => {
-                    let pathseg = &path.segments[len-1];
-                    debug!("searching an enum '{}' (whole path: {:?}) searchtype: {:?}", m.matchstr, path, search_type);
-                    let filesrc = session.load_file(&m.filepath);
-                    let scopestart = scopes::find_stmt_start(filesrc.as_src(), m.point)
-                        .expect("[resolve_path] statement start was not found");
-                    let scopesrc = filesrc.get_src_from_start(scopestart);
-                    if let Some(blob_range) = scopesrc.iter_stmts().nth(0) {
-                        let match_cxt = MatchCxt {
-                            filepath: &m.filepath,
-                            search_str: &pathseg.name,
+                MatchType::Enum | MatchType::Struct => {
+                    out.extend(get_impls(
+                        &path.segments[len - 1],
+                        namespace,
+                        search_type,
+                        &m,
+                        session,
+                        import_info,
+                    ));
+                }
+                MatchType::Type => {
+                    if let Some(match_) = ast::get_type_of_typedef(&m, session) {
+                        out.extend(get_impls(
+                            &path.segments[len - 1],
+                            namespace,
                             search_type,
-                            range: blob_range.shift(scopestart),
-                            is_local: true,
-                        };
-                        for mut enum_var in matchers::match_enum_variants(&filesrc, &match_cxt) {
-                            debug!("Found enum variant {} with enum type {}", enum_var.matchstr, m.matchstr);
-                            // return Match which has enum simultaneously, for method completion
-                            enum_var.mtype = EnumVariant(Some(Box::new(m.clone())));
-                            out.push(enum_var);
-                        }
+                            &match_,
+                            session,
+                            import_info,
+                        ));
                     }
-
-                    // TODO remove code duplication with the struct branch below. The two implementations are identical.
-
-                    for m_impl in search_for_impls(
-                        m.point,
-                        &m.matchstr, &m.filepath, m.local, true, session, import_info) {
-                        debug!("found impl!! {:?}", m_impl);
-                        let pathseg = &path.segments[len-1];
-                        let src = session.load_file(&m_impl.filepath);
-                        // find the opening brace and skip to it.
-                        if let Some(n) = src[m_impl.point.0..].find('{') {
-                            let point = m_impl.point + BytePos(n + 1);
-                            out.extend(search_scope(
-                                point,
-                                point,
-                                src.as_src(),
-                                pathseg,
-                                &m_impl.filepath,
-                                search_type,
-                                m_impl.local,
-                                namespace,
-                                session,
-                                import_info,
-                            ));
-                        }
-                        for m_gen in search_for_generic_impls(m_impl.point, &m_impl.matchstr, &m, &m_impl.filepath, session) {
-                            debug!("found generic impl!! {:?}", m_gen);
-                            let pathseg = &path.segments[len-1];
-                            let src = session.load_file(&m_gen.filepath);
-                            // find the opening brace and skip to it.
-                            if let Some(n) = src[m_gen.point.0..].find('{') {
-                                let point = m_gen.point + BytePos(n + 1);
-                                out.extend(search_scope(
-                                    point,
-                                    point,
-                                    src.as_src(),
-                                    pathseg,
-                                    &m_gen.filepath,
-                                    search_type,
-                                    m_gen.local,
-                                    namespace,
-                                    session,
-                                    import_info,
-                                ));
-                            }
-                        }
-                    };
-                }
-                Struct => {
-                    debug!("found a struct. Now need to look for impl");
-                    for m_impl in search_for_impls(m.point, &m.matchstr, &m.filepath, m.local, true, session, import_info) {
-                        debug!("found impl!! {:?}", m_impl);
-                        let pathseg = &path.segments[len-1];
-                        let src = session.load_file(&m_impl.filepath);
-                        // find the opening brace and skip to it.
-                        if let Some(n) = src[m_impl.point.0..].find('{') {
-                            let point = m_impl.point + BytePos(n + 1);
-                            out.extend(search_scope(
-                                point,
-                                point,
-                                src.as_src(),
-                                pathseg,
-                                &m_impl.filepath,
-                                search_type,
-                                m_impl.local,
-                                namespace,
-                                session,
-                                import_info,
-                            ));
-                        }
-                        for m_gen in search_for_generic_impls(m_impl.point, &m_impl.matchstr, &m, &m_impl.filepath, session) {
-                            debug!("found generic impl!! {:?}", m_gen);
-                            let pathseg = &path.segments[len-1];
-                            let src = session.load_file(&m_gen.filepath);
-                            // find the opening brace and skip to it.
-                            if let Some(n) = src[m_gen.point.0..].find('{') {
-                                let point = m_gen.point + BytePos(n + 1);
-                                out.extend(search_scope(
-                                    point,
-                                    point,
-                                    src.as_src(),
-                                    pathseg,
-                                    &m_gen.filepath,
-                                    search_type,
-                                    m_gen.local,
-                                    namespace,
-                                    session,
-                                    import_info,
-                                ));
-                            }
-                        }
-                    };
                 }
                 _ => ()
             }
@@ -1653,7 +1654,7 @@ pub fn resolve_method(
                                      Namespace::Both,
                                      session,
                                      import_info)
-                    .filter(|m| m.mtype == Trait)
+                    .filter(|m| m.mtype == MatchType::Trait)
                     .nth(0);
                 if let Some(m) = m {
                     debug!("found trait : match is |{:?}|", m);
@@ -1719,7 +1720,7 @@ pub fn do_external_search(
                            point: BytePos::ZERO,
                            coords: Some(Coordinate::start()),
                            local: false,
-                           mtype: Module,
+                           mtype: MatchType::Module,
                            contextstr: context,
                            generic_args: Vec::new(),
                            generic_types: Vec::new(),
@@ -1732,7 +1733,7 @@ pub fn do_external_search(
         context.map(|m| {
             let import_info = &ImportInfo::default();
             match m.mtype {
-                Module => {
+                MatchType::Module => {
                     debug!("found an external module {}", m.matchstr);
                     // deal with started with "{", so that "foo::{bar" will be same as "foo::bar"
                     let searchstr = match path[path.len()-1].chars().next() {
@@ -1746,7 +1747,7 @@ pub fn do_external_search(
                     }
                 }
 
-                Struct => {
+                MatchType::Struct => {
                     debug!("found a pub struct. Now need to look for impl");
                     for m in search_for_impls(m.point, &m.matchstr, &m.filepath, m.local, false, session, import_info) {
                         debug!("found  impl2!! {}", m.matchstr);
@@ -1837,7 +1838,7 @@ pub fn search_for_field_or_method(context: Match, searchstr: &str, search_type:
         }).flatten()
     };
     match m.mtype {
-        Struct => {
+        MatchType::Struct => {
             debug!("got a struct, looking for fields and impl methods!! {}", m.matchstr);
             for m in search_struct_fields(searchstr, &m, search_type, session) {
                 out.push(m);
@@ -1852,7 +1853,7 @@ pub fn search_for_field_or_method(context: Match, searchstr: &str, search_type:
                 out.push(m);
             }
         },
-        Builtin => {
+        MatchType::Builtin => {
             for m in search_for_impl_methods(&m,
                                     searchstr,
                                     m.point,
@@ -1863,7 +1864,7 @@ pub fn search_for_field_or_method(context: Match, searchstr: &str, search_type:
                 out.push(m);
             }
         },
-        Enum => {
+        MatchType::Enum => {
             debug!("got an enum, looking for impl methods {}", m.matchstr);
             for m in search_for_impl_methods(&m,
                                     searchstr,
@@ -1875,11 +1876,11 @@ pub fn search_for_field_or_method(context: Match, searchstr: &str, search_type:
                 out.push(m);
             }
         },
-        Trait => {
+        MatchType::Trait => {
             debug!("got a trait, looking for methods {}", m.matchstr);
             out.extend(find_inherited_traits(m));
         }
-        TypeParameter(bounds) => {
+        MatchType::TypeParameter(bounds) => {
             debug!("got a trait bound, looking for methods {}", m.matchstr);
             let traits = bounds.get_traits(session);
             traits.into_iter().for_each(|m| {


Test patch:
diff --git a/test_project/test_fixtures/src/lib.rs b/test_project/test_fixtures/src/lib.rs
index 6eaa6b07..207aaa93 100644
--- a/test_project/test_fixtures/src/lib.rs
+++ b/test_project/test_fixtures/src/lib.rs
@@ -23,3 +23,7 @@ pub mod bar;
 pub mod foo;
 
 pub use test_crate2::useless_func;
+
+pub type UsizeVec = Vec<usize>;
+
+
diff --git a/tests/system.rs b/tests/system.rs
index 50085d83..e091b52d 100644
--- a/tests/system.rs
+++ b/tests/system.rs
@@ -4131,3 +4131,33 @@ fn follows_use_crate() {
     assert_eq!(got.matchstr, "myfn");
     assert_eq!(got.contextstr, "pub fn myfn()");
 }
+
+// regression test for #800
+#[test]
+fn completes_typedef_in_external_crate() {
+    let src = "
+    extern crate fixtures;
+
+    use fixtures::Usize~
+    ";
+
+    with_test_project(|dir| {
+        let srcdir = dir.nested_dir("src");
+        let got = get_only_completion(src, Some(srcdir));
+        assert_eq!(got.matchstr, "UsizeVec");
+        assert_eq!(got.contextstr, "pub type UsizeVec = Vec<usize>;");
+    })
+}
+
+#[test]
+fn completes_static_method_for_typedef() {
+    let src = "
+    type UsizeVec = Vec<usize>;
+    fn func() {
+        let u = UsizeVec::with_capacity();
+        u.append_elem~
+    }
+    ";
+    let got = get_only_completion(src, None);
+    assert_eq!(got.matchstr, "append_elements");
+}