Repository: rust-analyzer/rust-analyzer (rust)

Issue:
extern crate syntax not resolving
`extern crate` is still used in the 2018 edition for accessing `core`, `alloc` and `proc_macro`. Currently, the crate name after `extern crate` is not resolved, and go to def does not work on these spans.

Pull request:
Add support for extern crate
This adds syntax highlighting, hover and goto def functionality for extern crate.

Fixes #5690 

Patch:
diff --git a/crates/ra_assists/src/handlers/add_turbo_fish.rs b/crates/ra_assists/src/handlers/add_turbo_fish.rs
index 0c565e89af..537322a72c 100644
--- a/crates/ra_assists/src/handlers/add_turbo_fish.rs
+++ b/crates/ra_assists/src/handlers/add_turbo_fish.rs
@@ -41,7 +41,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
     let name_ref = ast::NameRef::cast(ident.parent())?;
     let def = match classify_name_ref(&ctx.sema, &name_ref)? {
         NameRefClass::Definition(def) => def,
-        NameRefClass::FieldShorthand { .. } => return None,
+        NameRefClass::ExternCrate(_) | NameRefClass::FieldShorthand { .. } => return None,
     };
     let fun = match def {
         Definition::ModuleDef(hir::ModuleDef::Function(it)) => it,
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs
index 54d5678d14..0de6fdf3fb 100644
--- a/crates/ra_assists/src/utils.rs
+++ b/crates/ra_assists/src/utils.rs
@@ -257,7 +257,7 @@ pub use prelude::*;
             .find(|dep| &dep.name.to_string() == std_crate)?
             .krate;
 
-        let mut module = std_crate.root_module(db)?;
+        let mut module = std_crate.root_module(db);
         for segment in path {
             module = module.children(db).find_map(|child| {
                 let name = child.name(db)?;
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 27cdabea03..44456e49e2 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -83,9 +83,9 @@ impl Crate {
             .collect()
     }
 
-    pub fn root_module(self, db: &dyn HirDatabase) -> Option<Module> {
+    pub fn root_module(self, db: &dyn HirDatabase) -> Module {
         let module_id = db.crate_def_map(self.id).root;
-        Some(Module::new(self, module_id))
+        Module::new(self, module_id)
     }
 
     pub fn root_file(self, db: &dyn HirDatabase) -> FileId {
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 307b336f20..e392130ab6 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -8,7 +8,7 @@ use hir_def::{
     resolver::{self, HasResolver, Resolver},
     AsMacroCall, FunctionId, TraitId, VariantId,
 };
-use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo};
+use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, name::AsName, ExpansionInfo};
 use hir_ty::associated_type_shorthand_candidates;
 use itertools::Itertools;
 use ra_db::{FileId, FileRange};
@@ -24,8 +24,8 @@ use crate::{
     diagnostics::Diagnostic,
     semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
     source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer},
-    AssocItem, Callable, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module,
-    ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef,
+    AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef,
+    Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef,
 };
 use resolver::TypeNs;
 
@@ -228,6 +228,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.resolve_path(path)
     }
 
+    pub fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
+        self.imp.resolve_extern_crate(extern_crate)
+    }
+
     pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> {
         self.imp.resolve_variant(record_lit).map(VariantDef::from)
     }
@@ -443,6 +447,17 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(path.syntax()).resolve_path(self.db, path)
     }
 
+    fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
+        let krate = self.scope(extern_crate.syntax()).krate()?;
+        krate.dependencies(self.db).into_iter().find_map(|dep| {
+            if dep.name == extern_crate.name_ref()?.as_name() {
+                Some(dep.krate)
+            } else {
+                None
+            }
+        })
+    }
+
     fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
         self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit)
     }
@@ -612,6 +627,10 @@ impl<'a> SemanticsScope<'a> {
         Some(Module { id: self.resolver.module()? })
     }
 
+    pub fn krate(&self) -> Option<Crate> {
+        Some(Crate { id: self.resolver.krate()? })
+    }
+
     /// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type
     // FIXME: rename to visible_traits to not repeat scope?
     pub fn traits_in_scope(&self) -> FxHashSet<TraitId> {
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 3d12039a6d..28f32a0a4d 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -440,12 +440,6 @@ impl<'a> InferenceContext<'a> {
                 let ty = self.insert_type_vars(ty.subst(&substs));
                 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
             }
-            TypeNs::AdtId(AdtId::UnionId(u)) => {
-                let substs = Ty::substs_from_path(&ctx, path, u.into(), true);
-                let ty = self.db.ty(u.into());
-                let ty = self.insert_type_vars(ty.subst(&substs));
-                forbid_unresolved_segments((ty, Some(u.into())), unresolved)
-            }
             TypeNs::EnumVariantId(var) => {
                 let substs = Ty::substs_from_path(&ctx, path, var.into(), true);
                 let ty = self.db.ty(var.parent.into());
@@ -496,7 +490,10 @@ impl<'a> InferenceContext<'a> {
                 // FIXME potentially resolve assoc type
                 (Ty::Unknown, None)
             }
-            TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) => {
+            TypeNs::AdtId(AdtId::EnumId(_))
+            | TypeNs::AdtId(AdtId::UnionId(_))
+            | TypeNs::BuiltinType(_)
+            | TypeNs::TraitId(_) => {
                 // FIXME diagnostic
                 (Ty::Unknown, None)
             }
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 7638f167b5..1eacc6f95e 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -518,7 +518,6 @@ impl Ty {
         let (segment, generic_def) = match resolved {
             ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
             ValueTyDefId::StructId(it) => (last, Some(it.into())),
-            ValueTyDefId::UnionId(it) => (last, Some(it.into())),
             ValueTyDefId::ConstId(it) => (last, Some(it.into())),
             ValueTyDefId::StaticId(_) => (last, None),
             ValueTyDefId::EnumVariantId(var) => {
@@ -1149,12 +1148,11 @@ impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefI
 pub enum ValueTyDefId {
     FunctionId(FunctionId),
     StructId(StructId),
-    UnionId(UnionId),
     EnumVariantId(EnumVariantId),
     ConstId(ConstId),
     StaticId(StaticId),
 }
-impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
+impl_from!(FunctionId, StructId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
 
 /// Build the declared type of an item. This depends on the namespace; e.g. for
 /// `struct Foo(usize)`, we have two types: The type of the struct itself, and
@@ -1181,7 +1179,6 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders
     match def {
         ValueTyDefId::FunctionId(it) => type_for_fn(db, it),
         ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
-        ValueTyDefId::UnionId(it) => type_for_adt(db, it.into()),
         ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
         ValueTyDefId::ConstId(it) => type_for_const(db, it),
         ValueTyDefId::StaticId(it) => type_for_static(db, it),
diff --git a/crates/ra_ide/src/display/short_label.rs b/crates/ra_ide/src/display/short_label.rs
index 0fdf8e9a58..b5ff9fa2de 100644
--- a/crates/ra_ide/src/display/short_label.rs
+++ b/crates/ra_ide/src/display/short_label.rs
@@ -47,6 +47,12 @@ impl ShortLabel for ast::Module {
     }
 }
 
+impl ShortLabel for ast::SourceFile {
+    fn short_label(&self) -> Option<String> {
+        None
+    }
+}
+
 impl ShortLabel for ast::TypeAlias {
     fn short_label(&self) -> Option<String> {
         short_label_from_node(self, "type ")
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index 4e3f428fae..45389fd23f 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -1,6 +1,6 @@
 use hir::Semantics;
 use ra_ide_db::{
-    defs::{classify_name, classify_name_ref, NameClass},
+    defs::{classify_name, classify_name_ref},
     symbol_index, RootDatabase,
 };
 use ra_syntax::{
@@ -40,10 +40,7 @@ pub(crate) fn goto_definition(
                 reference_definition(&sema, &name_ref).to_vec()
             },
             ast::Name(name) => {
-                let def = match classify_name(&sema, &name)? {
-                    NameClass::Definition(def) | NameClass::ConstReference(def) => def,
-                    NameClass::FieldShorthand { local: _, field } => field,
-                };
+                let def = classify_name(&sema, &name)?.definition(sema.db);
                 let nav = def.try_to_nav(sema.db)?;
                 vec![nav]
             },
@@ -86,8 +83,7 @@ pub(crate) fn reference_definition(
 ) -> ReferenceResult {
     let name_kind = classify_name_ref(sema, name_ref);
     if let Some(def) = name_kind {
-        let def = def.definition();
-
+        let def = def.definition(sema.db);
         return match def.try_to_nav(sema.db) {
             Some(nav) => ReferenceResult::Exact(nav),
             None => ReferenceResult::Approximate(Vec::new()),
@@ -133,6 +129,32 @@ mod tests {
         assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() });
     }
 
+    #[test]
+    fn goto_def_for_extern_crate() {
+        check(
+            r#"
+            //- /main.rs
+            extern crate std<|>;
+            //- /std/lib.rs
+            // empty
+            //^ file
+            "#,
+        )
+    }
+
+    #[test]
+    fn goto_def_for_renamed_extern_crate() {
+        check(
+            r#"
+            //- /main.rs
+            extern crate std as abc<|>;
+            //- /std/lib.rs
+            // empty
+            //^ file
+            "#,
+        )
+    }
+
     #[test]
     fn goto_def_in_items() {
         check(
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index aa48cb412f..f6e493817b 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -85,8 +85,8 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
     let node = token.parent();
     let definition = match_ast! {
         match node {
-            ast::NameRef(name_ref) => classify_name_ref(&sema, &name_ref).map(|d| d.definition()),
-            ast::Name(name) => classify_name(&sema, &name).map(|d| d.definition()),
+            ast::NameRef(name_ref) => classify_name_ref(&sema, &name_ref).map(|d| d.definition(sema.db)),
+            ast::Name(name) => classify_name(&sema, &name).map(|d| d.definition(sema.db)),
             _ => None,
         }
     };
@@ -304,7 +304,10 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
                     let docs = Documentation::from_ast(&it).map(Into::into);
                     hover_markup(docs, it.short_label(), mod_path)
                 }
-                _ => None,
+                ModuleSource::SourceFile(it) => {
+                    let docs = Documentation::from_ast(&it).map(Into::into);
+                    hover_markup(docs, it.short_label(), mod_path)
+                }
             },
             ModuleDef::Function(it) => from_def_source(db, it, mod_path),
             ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path),
@@ -1106,6 +1109,46 @@ fn bar() { fo<|>o(); }
         );
     }
 
+    #[test]
+    fn test_hover_extern_crate() {
+        check(
+            r#"
+//- /main.rs
+extern crate st<|>d;
+//- /std/lib.rs
+//! Standard library for this test
+//!
+//! Printed?
+//! abc123
+            "#,
+            expect![[r#"
+            *std*
+            Standard library for this test
+
+            Printed?
+            abc123
+            "#]],
+        );
+        check(
+            r#"
+//- /main.rs
+extern crate std as ab<|>c;
+//- /std/lib.rs
+//! Standard library for this test
+//!
+//! Printed?
+//! abc123
+            "#,
+            expect![[r#"
+            *abc*
+            Standard library for this test
+
+            Printed?
+            abc123
+            "#]],
+        );
+    }
+
     #[test]
     fn test_hover_mod_with_same_name_as_function() {
         check(
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index cf456630a5..453985de3e 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -130,13 +130,13 @@ fn find_name(
     opt_name: Option<ast::Name>,
 ) -> Option<RangeInfo<Definition>> {
     if let Some(name) = opt_name {
-        let def = classify_name(sema, &name)?.definition();
+        let def = classify_name(sema, &name)?.definition(sema.db);
         let range = name.syntax().text_range();
         return Some(RangeInfo::new(range, def));
     }
     let name_ref =
         sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?;
-    let def = classify_name_ref(sema, &name_ref)?.definition();
+    let def = classify_name_ref(sema, &name_ref)?.definition(sema.db);
     let range = name_ref.syntax().text_range();
     Some(RangeInfo::new(range, def))
 }
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index f71b804fe9..ec442bcd83 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -4,7 +4,7 @@ mod injection;
 #[cfg(test)]
 mod tests;
 
-use hir::{Name, Semantics, VariantDef};
+use hir::{Name, Semantics};
 use ra_ide_db::{
     defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass},
     RootDatabase,
@@ -455,18 +455,6 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> {
     Some(TextRange::new(range_start, range_end))
 }
 
-fn is_possibly_unsafe(name_ref: &ast::NameRef) -> bool {
-    name_ref
-        .syntax()
-        .parent()
-        .and_then(|parent| {
-            ast::FieldExpr::cast(parent.clone())
-                .map(|_| true)
-                .or_else(|| ast::RecordPatField::cast(parent).map(|_| true))
-        })
-        .unwrap_or(false)
-}
-
 fn highlight_element(
     sema: &Semantics<RootDatabase>,
     bindings_shadow_count: &mut FxHashMap<Name, u32>,
@@ -495,20 +483,12 @@ fn highlight_element(
             };
 
             match name_kind {
+                Some(NameClass::ExternCrate(_)) => HighlightTag::Module.into(),
                 Some(NameClass::Definition(def)) => {
-                    highlight_name(db, def, false) | HighlightModifier::Definition
-                }
-                Some(NameClass::ConstReference(def)) => highlight_name(db, def, false),
-                Some(NameClass::FieldShorthand { field, .. }) => {
-                    let mut h = HighlightTag::Field.into();
-                    if let Definition::Field(field) = field {
-                        if let VariantDef::Union(_) = field.parent_def(db) {
-                            h |= HighlightModifier::Unsafe;
-                        }
-                    }
-
-                    h
+                    highlight_name(db, def) | HighlightModifier::Definition
                 }
+                Some(NameClass::ConstReference(def)) => highlight_name(db, def),
+                Some(NameClass::FieldShorthand { .. }) => HighlightTag::Field.into(),
                 None => highlight_name_by_syntax(name) | HighlightModifier::Definition,
             }
         }
@@ -519,9 +499,9 @@ fn highlight_element(
         }
         NAME_REF => {
             let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
-            let possibly_unsafe = is_possibly_unsafe(&name_ref);
             match classify_name_ref(sema, &name_ref) {
                 Some(name_kind) => match name_kind {
+                    NameRefClass::ExternCrate(_) => HighlightTag::Module.into(),
                     NameRefClass::Definition(def) => {
                         if let Definition::Local(local) = &def {
                             if let Some(name) = local.name(db) {
@@ -530,13 +510,11 @@ fn highlight_element(
                                 binding_hash = Some(calc_binding_hash(&name, *shadow_count))
                             }
                         };
-                        highlight_name(db, def, possibly_unsafe)
+                        highlight_name(db, def)
                     }
                     NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(),
                 },
-                None if syntactic_name_ref_highlighting => {
-                    highlight_name_ref_by_syntax(name_ref, sema)
-                }
+                None if syntactic_name_ref_highlighting => highlight_name_ref_by_syntax(name_ref),
                 None => HighlightTag::UnresolvedReference.into(),
             }
         }
@@ -676,19 +654,10 @@ fn is_child_of_impl(element: &SyntaxElement) -> bool {
     }
 }
 
-fn highlight_name(db: &RootDatabase, def: Definition, possibly_unsafe: bool) -> Highlight {
+fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight {
     match def {
         Definition::Macro(_) => HighlightTag::Macro,
-        Definition::Field(field) => {
-            let mut h = HighlightTag::Field.into();
-            if possibly_unsafe {
-                if let VariantDef::Union(_) = field.parent_def(db) {
-                    h |= HighlightModifier::Unsafe;
-                }
-            }
-
-            return h;
-        }
+        Definition::Field(_) => HighlightTag::Field,
         Definition::ModuleDef(def) => match def {
             hir::ModuleDef::Module(_) => HighlightTag::Module,
             hir::ModuleDef::Function(func) => {
@@ -758,7 +727,7 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
     tag.into()
 }
 
-fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight {
+fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight {
     let default = HighlightTag::UnresolvedReference;
 
     let parent = match name.syntax().parent() {
@@ -768,20 +737,7 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas
 
     let tag = match parent.kind() {
         METHOD_CALL_EXPR => HighlightTag::Function,
-        FIELD_EXPR => {
-            let h = HighlightTag::Field;
-            let is_union = ast::FieldExpr::cast(parent)
-                .and_then(|field_expr| {
-                    let field = sema.resolve_field(&field_expr)?;
-                    Some(if let VariantDef::Union(_) = field.parent_def(sema.db) {
-                        true
-                    } else {
-                        false
-                    })
-                })
-                .unwrap_or(false);
-            return if is_union { h | HighlightModifier::Unsafe } else { h.into() };
-        }
+        FIELD_EXPR => HighlightTag::Field,
         PATH_SEGMENT => {
             let path = match parent.parent().and_then(ast::Path::cast) {
                 Some(it) => it,
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs
index b51000b03f..9bb95277d0 100644
--- a/crates/ra_ide_db/src/defs.rs
+++ b/crates/ra_ide_db/src/defs.rs
@@ -6,8 +6,8 @@
 // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
 
 use hir::{
-    Field, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, Name, PathResolution,
-    Semantics, TypeParam, Visibility,
+    db::HirDatabase, Crate, Field, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef,
+    Name, PathResolution, Semantics, TypeParam, Visibility,
 };
 use ra_prof::profile;
 use ra_syntax::{
@@ -80,6 +80,7 @@ impl Definition {
 
 #[derive(Debug)]
 pub enum NameClass {
+    ExternCrate(Crate),
     Definition(Definition),
     /// `None` in `if let None = Some(82) {}`
     ConstReference(Definition),
@@ -90,16 +91,18 @@ pub enum NameClass {
 }
 
 impl NameClass {
-    pub fn into_definition(self) -> Option<Definition> {
-        match self {
-            NameClass::Definition(it) => Some(it),
-            NameClass::ConstReference(_) => None,
-            NameClass::FieldShorthand { local, field: _ } => Some(Definition::Local(local)),
-        }
+    pub fn into_definition(self, db: &dyn HirDatabase) -> Option<Definition> {
+        Some(match self {
+            NameClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()),
+            NameClass::Definition(it) => it,
+            NameClass::ConstReference(_) => return None,
+            NameClass::FieldShorthand { local, field: _ } => Definition::Local(local),
+        })
     }
 
-    pub fn definition(self) -> Definition {
+    pub fn definition(self, db: &dyn HirDatabase) -> Definition {
         match self {
+            NameClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()),
             NameClass::Definition(it) | NameClass::ConstReference(it) => it,
             NameClass::FieldShorthand { local: _, field } => field,
         }
@@ -120,32 +123,37 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option
     match_ast! {
         match parent {
             ast::Rename(it) => {
-                let use_tree = it.syntax().parent().and_then(ast::UseTree::cast)?;
-                let path = use_tree.path()?;
-                let path_segment = path.segment()?;
-                let name_ref_class = path_segment
-                    .name_ref()
-                    // The rename might be from a `self` token, so fallback to the name higher
-                    // in the use tree.
-                    .or_else(||{
-                        if path_segment.self_token().is_none() {
-                            return None;
-                        }
+                if let Some(use_tree) = it.syntax().parent().and_then(ast::UseTree::cast) {
+                    let path = use_tree.path()?;
+                    let path_segment = path.segment()?;
+                    let name_ref_class = path_segment
+                        .name_ref()
+                        // The rename might be from a `self` token, so fallback to the name higher
+                        // in the use tree.
+                        .or_else(||{
+                            if path_segment.self_token().is_none() {
+                                return None;
+                            }
 
-                        let use_tree = use_tree
-                            .syntax()
-                            .parent()
-                            .as_ref()
-                            // Skip over UseTreeList
-                            .and_then(SyntaxNode::parent)
-                            .and_then(ast::UseTree::cast)?;
-                        let path = use_tree.path()?;
-                        let path_segment = path.segment()?;
-                        path_segment.name_ref()
-                    })
-                    .and_then(|name_ref| classify_name_ref(sema, &name_ref))?;
+                            let use_tree = use_tree
+                                .syntax()
+                                .parent()
+                                .as_ref()
+                                // Skip over UseTreeList
+                                .and_then(SyntaxNode::parent)
+                                .and_then(ast::UseTree::cast)?;
+                            let path = use_tree.path()?;
+                            let path_segment = path.segment()?;
+                            path_segment.name_ref()
+                        })
+                        .and_then(|name_ref| classify_name_ref(sema, &name_ref))?;
 
-                Some(NameClass::Definition(name_ref_class.definition()))
+                    Some(NameClass::Definition(name_ref_class.definition(sema.db)))
+                } else {
+                    let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?;
+                    let resolved = sema.resolve_extern_crate(&extern_crate)?;
+                    Some(NameClass::ExternCrate(resolved))
+                }
             },
             ast::IdentPat(it) => {
                 let local = sema.to_def(&it)?;
@@ -220,13 +228,15 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option
 
 #[derive(Debug)]
 pub enum NameRefClass {
+    ExternCrate(Crate),
     Definition(Definition),
     FieldShorthand { local: Local, field: Definition },
 }
 
 impl NameRefClass {
-    pub fn definition(self) -> Definition {
+    pub fn definition(self, db: &dyn HirDatabase) -> Definition {
         match self {
+            NameRefClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()),
             NameRefClass::Definition(def) => def,
             NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local),
         }
@@ -307,9 +317,15 @@ pub fn classify_name_ref(
         }
     }
 
-    let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
-    let resolved = sema.resolve_path(&path)?;
-    Some(NameRefClass::Definition(resolved.into()))
+    if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) {
+        if let Some(resolved) = sema.resolve_path(&path) {
+            return Some(NameRefClass::Definition(resolved.into()));
+        }
+    }
+
+    let extern_crate = ast::ExternCrate::cast(parent)?;
+    let resolved = sema.resolve_extern_crate(&extern_crate)?;
+    Some(NameRefClass::ExternCrate(resolved))
 }
 
 impl From<PathResolution> for Definition {
diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs
index 1fba71ff85..9e040973b3 100644
--- a/crates/ra_ide_db/src/imports_locator.rs
+++ b/crates/ra_ide_db/src/imports_locator.rs
@@ -61,5 +61,5 @@ fn get_name_definition<'a>(
         candidate_node
     };
     let name = ast::Name::cast(candidate_name_node)?;
-    classify_name(sema, &name)?.into_definition()
+    classify_name(sema, &name)?.into_definition(sema.db)
 }
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 721d41a58f..0d386841e5 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -72,7 +72,7 @@ impl AnalysisStatsCmd {
             shuffle(&mut rng, &mut krates);
         }
         for krate in krates {
-            let module = krate.root_module(db).expect("crate without root module");
+            let module = krate.root_module(db);
             let file_id = module.definition_source(db).file_id;
             let file_id = file_id.original_file(db);
             let source_root = db.file_source_root(file_id);
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs
index 4ac8c8772e..f17fc5dfe9 100644
--- a/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -28,7 +28,7 @@ pub fn diagnostics(
     let mut work = Vec::new();
     let krates = Crate::all(db);
     for krate in krates {
-        let module = krate.root_module(db).expect("crate without root module");
+        let module = krate.root_module(db);
         let file_id = module.definition_source(db).file_id;
         let file_id = file_id.original_file(db);
         let source_root = db.file_source_root(file_id);
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 438e965e08..ceddb2b056 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -47,7 +47,7 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
         SetThreadPriority(thread, thread_priority_above_normal);
     }
 
-    GlobalState::new(connection.sender, config).run(connection.receiver)
+    GlobalState::new(connection.sender.clone(), config).run(connection.receiver)
 }
 
 enum Event {


Test patch:
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index 5a7cf9455b..3fd7d5cd4f 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -334,44 +334,16 @@ fn infer_union() {
             bar: f32,
         }
 
-        fn test() {
-            let u = MyUnion { foo: 0 };
-            unsafe { baz(u); }
-            let u = MyUnion { bar: 0.0 };
-            unsafe { baz(u); }
-        }
-
         unsafe fn baz(u: MyUnion) {
             let inner = u.foo;
-            let inner = u.bar;
         }
         "#,
         expect![[r#"
-            57..172 '{     ...); } }': ()
-            67..68 'u': MyUnion
-            71..89 'MyUnio...o: 0 }': MyUnion
-            86..87 '0': u32
-            95..113 'unsafe...(u); }': ()
-            102..113 '{ baz(u); }': ()
-            104..107 'baz': fn baz(MyUnion)
-            104..110 'baz(u)': ()
-            108..109 'u': MyUnion
-            122..123 'u': MyUnion
-            126..146 'MyUnio... 0.0 }': MyUnion
-            141..144 '0.0': f32
-            152..170 'unsafe...(u); }': ()
-            159..170 '{ baz(u); }': ()
-            161..164 'baz': fn baz(MyUnion)
-            161..167 'baz(u)': ()
-            165..166 'u': MyUnion
-            188..189 'u': MyUnion
-            200..249 '{     ...bar; }': ()
-            210..215 'inner': u32
-            218..219 'u': MyUnion
-            218..223 'u.foo': u32
-            233..238 'inner': f32
-            241..242 'u': MyUnion
-            241..246 'u.bar': f32
+            61..62 'u': MyUnion
+            73..99 '{     ...foo; }': ()
+            83..88 'inner': u32
+            91..92 'u': MyUnion
+            91..96 'u.foo': u32
         "#]],
     );
 }
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs
index 730efff0de..b8d60bdc63 100644
--- a/crates/ra_ide/src/syntax_highlighting/tests.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tests.rs
@@ -275,11 +275,6 @@ fn test_unsafe_highlighting() {
         r#"
 unsafe fn unsafe_fn() {}
 
-union Union {
-    a: u32,
-    b: f32,
-}
-
 struct HasUnsafeFn;
 
 impl HasUnsafeFn {
@@ -294,14 +289,8 @@ static mut global_mut: TypeForStaticMut = TypeForStaticMut { a: 0 };
 
 fn main() {
     let x = &5 as *const usize;
-    let u = Union { b: 0 };
     unsafe {
         unsafe_fn();
-        let b = u.b;
-        match u {
-            Union { b: 0 } => (),
-            Union { a } => (),
-        }
         HasUnsafeFn.unsafe_method();
         let y = *(x);
         let z = -x;
@@ -391,6 +380,23 @@ macro_rules! noop {
     );
 }
 
+#[test]
+fn test_extern_crate() {
+    check_highlighting(
+        r#"
+        //- /main.rs
+        extern crate std;
+        extern crate alloc as abc;
+        //- /std/lib.rs
+        pub struct S;
+        //- /alloc/lib.rs
+        pub struct A
+        "#,
+        expect_file!["crates/ra_ide/test_data/highlight_extern_crate.html"],
+        false,
+    );
+}
+
 /// Highlights the code given by the `ra_fixture` argument, renders the
 /// result as HTML, and compares it with the HTML file given as `snapshot`.
 /// Note that the `snapshot` file is overwritten by the rendered HTML.
diff --git a/crates/ra_ide/test_data/highlight_extern_crate.html b/crates/ra_ide/test_data/highlight_extern_crate.html
new file mode 100644
index 0000000000..800d894c76
--- /dev/null
+++ b/crates/ra_ide/test_data/highlight_extern_crate.html
@@ -0,0 +1,40 @@
+
+<style>
+body                { margin: 0; }
+pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime           { color: #DFAF8F; font-style: italic; }
+.comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.injected           { opacity: 0.65 ; }
+.struct, .enum      { color: #7CB8BB; }
+.enum_variant       { color: #BDE0F3; }
+.string_literal     { color: #CC9393; }
+.field              { color: #94BFF3; }
+.function           { color: #93E0E3; }
+.function.unsafe    { color: #BC8383; }
+.operator.unsafe    { color: #BC8383; }
+.parameter          { color: #94BFF3; }
+.text               { color: #DCDCCC; }
+.type               { color: #7CB8BB; }
+.builtin_type       { color: #8CD0D3; }
+.type_param         { color: #DFAF8F; }
+.attribute          { color: #94BFF3; }
+.numeric_literal    { color: #BFEBBF; }
+.bool_literal       { color: #BFE6EB; }
+.macro              { color: #94BFF3; }
+.module             { color: #AFD8AF; }
+.value_param        { color: #DCDCCC; }
+.variable           { color: #DCDCCC; }
+.format_specifier   { color: #CC696B; }
+.mutable            { text-decoration: underline; }
+.escape_sequence    { color: #94BFF3; }
+.keyword            { color: #F0DFAF; font-weight: bold; }
+.keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.control            { font-style: italic; }
+
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">std</span><span class="punctuation">;</span>
+<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">alloc</span> <span class="keyword">as</span> <span class="module">abc</span><span class="punctuation">;</span>
+</code></pre>
\ No newline at end of file
diff --git a/crates/ra_ide/test_data/highlight_unsafe.html b/crates/ra_ide/test_data/highlight_unsafe.html
index 79409fe816..87d8c15568 100644
--- a/crates/ra_ide/test_data/highlight_unsafe.html
+++ b/crates/ra_ide/test_data/highlight_unsafe.html
@@ -37,11 +37,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 </style>
 <pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span>
 
-<span class="keyword">union</span> <span class="union declaration">Union</span> <span class="punctuation">{</span>
-    <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u32</span><span class="punctuation">,</span>
-    <span class="field declaration">b</span><span class="punctuation">:</span> <span class="builtin_type">f32</span><span class="punctuation">,</span>
-<span class="punctuation">}</span>
-
 <span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span>
 
 <span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span>
@@ -56,14 +51,8 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 <span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
     <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="punctuation">;</span>
-    <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="punctuation">{</span> <span class="field">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span>
     <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span>
         <span class="function unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
-        <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="punctuation">.</span><span class="field unsafe">b</span><span class="punctuation">;</span>
-        <span class="keyword control">match</span> <span class="variable">u</span> <span class="punctuation">{</span>
-            <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span> <span class="operator">=&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span>
-            <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">a</span> <span class="punctuation">}</span> <span class="operator">=&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span>
-        <span class="punctuation">}</span>
         <span class="struct">HasUnsafeFn</span><span class="punctuation">.</span><span class="function unsafe">unsafe_method</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
         <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="punctuation">(</span><span class="variable">x</span><span class="punctuation">)</span><span class="punctuation">;</span>
         <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="variable">x</span><span class="punctuation">;</span>