Repository: rust-analyzer/rust-analyzer
Pull request #10950 (2021-12-06 15:01:55)

internal: completion: split out more PathKinds from ImmediateLocation
bors r+


Patch:
diff --git a/.gitignore b/.gitignore
index 68c87a6b1e..f3e3cab1d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,3 @@ generated_diagnostic.adoc
 .DS_Store
 /out/
 /dump.lsif
-.envrc
diff --git a/Cargo.lock b/Cargo.lock
index 92f98b536c..3ad8244466 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -881,9 +881,9 @@ dependencies = [
 
 [[package]]
 name = "matchers"
-version = "0.1.0"
+version = "0.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
+checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
 dependencies = [
  "regex-automata",
 ]
@@ -1731,9 +1731,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-subscriber"
-version = "0.3.3"
+version = "0.2.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "245da694cc7fc4729f3f418b304cb57789f1bed2a78c575407ab8a23f53cb4d3"
+checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71"
 dependencies = [
  "lazy_static",
  "matchers",
@@ -1747,9 +1747,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-tree"
-version = "0.2.0"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ce989c9962c7f61fe084dd4a230eec784649dfc2392467c790007c3a6e134e7"
+checksum = "a2a408a91fbd4850982080e643a261aef2a2ef72c8263ce353b61d25acfc2c49"
 dependencies = [
  "ansi_term",
  "atty",
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 54e95cf7c3..2f6eed82cb 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -137,7 +137,6 @@ fn resolve_doc_path(
         AttrDefId::TraitId(it) => it.resolver(db.upcast()),
         AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()),
         AttrDefId::ImplId(it) => it.resolver(db.upcast()),
-        AttrDefId::ExternBlockId(it) => it.resolver(db.upcast()),
         AttrDefId::GenericParamId(it) => match it {
             GenericParamId::TypeParamId(it) => it.parent,
             GenericParamId::LifetimeParamId(it) => it.parent,
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 3e04ea8da9..fe8a8018db 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -114,11 +114,11 @@ pub use {
         type_ref::{Mutability, TypeRef},
         visibility::Visibility,
         AdtId,
+        AssocContainerId,
         AssocItemId,
         AssocItemLoc,
         DefWithBodyId,
         ImplId,
-        ItemContainerId,
         ItemLoc,
         Lookup,
         ModuleDefId,
@@ -1550,7 +1550,7 @@ impl Static {
     pub fn ty(self, db: &dyn HirDatabase) -> Type {
         let data = db.static_data(self.id);
         let resolver = self.id.resolver(db.upcast());
-        let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate();
+        let krate = self.id.lookup(db.upcast()).container.krate();
         let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
         let ty = ctx.lower_ty(&data.type_ref);
         Type::new_with_resolver_inner(db, krate, &resolver, ty)
@@ -1820,8 +1820,8 @@ where
     AST: ItemTreeNode,
 {
     match id.lookup(db.upcast()).container {
-        ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
-        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
+        AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
+        AssocContainerId::ModuleId(_) => None,
     }
 }
 
@@ -1847,11 +1847,9 @@ impl AssocItem {
             AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container,
         };
         match container {
-            ItemContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
-            ItemContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
-            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
-                panic!("invalid AssocItem")
-            }
+            AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
+            AssocContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
+            AssocContainerId::ModuleId(_) => panic!("invalid AssocItem"),
         }
     }
 
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 36e46a103c..711062c713 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -362,7 +362,6 @@ impl AttrsWithOwner {
                     RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
                 }
             },
-            AttrDefId::ExternBlockId(it) => attrs_from_item_tree(it.lookup(db).id, db),
         };
 
         let attrs = raw_attrs.filter(db, def.krate(db));
@@ -444,7 +443,6 @@ impl AttrsWithOwner {
                     .child_source(db)
                     .map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())),
             },
-            AttrDefId::ExternBlockId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
         };
 
         AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn HasAttrs))
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index ad1c1f2ce5..f4d0c3af90 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -13,8 +13,8 @@ use crate::{
     item_tree::{self, AssocItem, FnFlags, ItemTreeId, ModItem, Param},
     type_ref::{TraitRef, TypeBound, TypeRef},
     visibility::RawVisibility,
-    AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, Intern,
-    ItemContainerId, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
+    AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
+    Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -54,10 +54,6 @@ impl FunctionData {
             flags.bits |= FnFlags::IS_VARARGS;
         }
 
-        if matches!(loc.container, ItemContainerId::ExternBlockId(_)) {
-            flags.bits |= FnFlags::IS_IN_EXTERN_BLOCK;
-        }
-
         Arc::new(FunctionData {
             name: func.name.clone(),
             params: enabled_params
@@ -134,7 +130,7 @@ impl TypeAliasData {
             name: typ.name.clone(),
             type_ref: typ.type_ref.clone(),
             visibility: item_tree[typ.visibility].clone(),
-            is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
+            is_extern: typ.is_extern,
             bounds: typ.bounds.to_vec(),
         })
     }
@@ -166,7 +162,7 @@ impl TraitData {
         let is_auto = tr_def.is_auto;
         let is_unsafe = tr_def.is_unsafe;
         let module_id = tr_loc.container;
-        let container = ItemContainerId::TraitId(tr);
+        let container = AssocContainerId::TraitId(tr);
         let visibility = item_tree[tr_def.visibility].clone();
         let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id);
         let skip_array_during_method_dispatch = item_tree
@@ -235,7 +231,7 @@ impl ImplData {
         let self_ty = impl_def.self_ty.clone();
         let is_negative = impl_def.is_negative;
         let module_id = impl_loc.container;
-        let container = ItemContainerId::ImplId(id);
+        let container = AssocContainerId::ImplId(id);
         let mut expander = Expander::new(db, impl_loc.id.file_id(), module_id);
 
         let items = collect_items(
@@ -286,16 +282,16 @@ pub struct StaticData {
 
 impl StaticData {
     pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> {
-        let loc = konst.lookup(db);
-        let item_tree = loc.id.item_tree(db);
-        let statik = &item_tree[loc.id.value];
+        let node = konst.lookup(db);
+        let item_tree = node.id.item_tree(db);
+        let statik = &item_tree[node.id.value];
 
         Arc::new(StaticData {
             name: statik.name.clone(),
             type_ref: statik.type_ref.clone(),
             visibility: item_tree[statik.visibility].clone(),
             mutable: statik.mutable,
-            is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
+            is_extern: statik.is_extern,
         })
     }
 }
@@ -306,7 +302,7 @@ fn collect_items(
     expander: &mut Expander,
     assoc_items: impl Iterator<Item = AssocItem>,
     tree_id: item_tree::TreeId,
-    container: ItemContainerId,
+    container: AssocContainerId,
     limit: usize,
 ) -> Vec<(Name, AssocItemId)> {
     if limit == 0 {
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs
index 7946558311..c977971cd4 100644
--- a/crates/hir_def/src/db.rs
+++ b/crates/hir_def/src/db.rs
@@ -19,10 +19,10 @@ use crate::{
     lang_item::{LangItemTarget, LangItems},
     nameres::DefMap,
     visibility::{self, Visibility},
-    AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId,
-    ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId,
-    LocalFieldId, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId,
-    TypeAliasLoc, UnionId, UnionLoc, VariantId,
+    AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId,
+    FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId,
+    StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId,
+    UnionLoc, VariantId,
 };
 
 #[salsa::query_group(InternDatabaseStorage)]
@@ -46,8 +46,6 @@ pub trait InternDatabase: SourceDatabase {
     #[salsa::interned]
     fn intern_impl(&self, loc: ImplLoc) -> ImplId;
     #[salsa::interned]
-    fn intern_extern_block(&self, loc: ExternBlockLoc) -> ExternBlockId;
-    #[salsa::interned]
     fn intern_block(&self, loc: BlockLoc) -> BlockId;
 }
 
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index 27a05b87c1..404e3e1539 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -468,7 +468,7 @@ mod tests {
     use base_db::{fixture::WithFixture, SourceDatabase, Upcast};
     use expect_test::{expect, Expect};
 
-    use crate::{test_db::TestDB, ItemContainerId, Lookup};
+    use crate::{test_db::TestDB, AssocContainerId, Lookup};
 
     use super::*;
 
@@ -563,7 +563,7 @@ mod tests {
         };
 
         match container {
-            ItemContainerId::TraitId(it) => Some(ItemInNs::Types(it.into())),
+            AssocContainerId::TraitId(it) => Some(ItemInNs::Types(it.into())),
             _ => None,
         }
     }
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 405cc2d00f..aab3f4b3c8 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -660,6 +660,8 @@ pub struct Static {
     pub name: Name,
     pub visibility: RawVisibilityId,
     pub mutable: bool,
+    /// Whether the static is in an `extern` block.
+    pub is_extern: bool,
     pub type_ref: Interned<TypeRef>,
     pub ast_id: FileAstId<ast::Static>,
 }
@@ -693,6 +695,7 @@ pub struct TypeAlias {
     pub bounds: Box<[Interned<TypeBound>]>,
     pub generic_params: Interned<GenericParams>,
     pub type_ref: Option<Interned<TypeRef>>,
+    pub is_extern: bool,
     pub ast_id: FileAstId<ast::TypeAlias>,
 }
 
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index e9af991785..32213aac39 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -360,6 +360,7 @@ impl<'a> Ctx<'a> {
             generic_params,
             type_ref,
             ast_id,
+            is_extern: false,
         };
         Some(id(self.data().type_aliases.alloc(res)))
     }
@@ -370,7 +371,7 @@ impl<'a> Ctx<'a> {
         let visibility = self.lower_visibility(static_);
         let mutable = static_.mut_token().is_some();
         let ast_id = self.source_ast_id_map.ast_id(static_);
-        let res = Static { name, visibility, mutable, type_ref, ast_id };
+        let res = Static { name, visibility, mutable, type_ref, ast_id, is_extern: false };
         Some(id(self.data().statics.alloc(res)))
     }
 
@@ -524,23 +525,27 @@ impl<'a> Ctx<'a> {
         let children: Box<[_]> = block.extern_item_list().map_or(Box::new([]), |list| {
             list.extern_items()
                 .filter_map(|item| {
-                    // Note: All items in an `extern` block need to be lowered as if they're outside of one
-                    // (in other words, the knowledge that they're in an extern block must not be used).
-                    // This is because an extern block can contain macros whose ItemTree's top-level items
-                    // should be considered to be in an extern block too.
                     let attrs = RawAttrs::new(self.db, &item, &self.hygiene);
                     let id: ModItem = match item {
                         ast::ExternItem::Fn(ast) => {
                             let func_id = self.lower_function(&ast)?;
                             let func = &mut self.data().functions[func_id.index];
                             if is_intrinsic_fn_unsafe(&func.name) {
-                                // FIXME: this breaks in macros
                                 func.flags.bits |= FnFlags::IS_UNSAFE;
                             }
+                            func.flags.bits |= FnFlags::IS_IN_EXTERN_BLOCK;
                             func_id.into()
                         }
-                        ast::ExternItem::Static(ast) => self.lower_static(&ast)?.into(),
-                        ast::ExternItem::TypeAlias(ty) => self.lower_type_alias(&ty)?.into(),
+                        ast::ExternItem::Static(ast) => {
+                            let statik = self.lower_static(&ast)?;
+                            self.data().statics[statik.index].is_extern = true;
+                            statik.into()
+                        }
+                        ast::ExternItem::TypeAlias(ty) => {
+                            let foreign_ty = self.lower_type_alias(&ty)?;
+                            self.data().type_aliases[foreign_ty.index].is_extern = true;
+                            foreign_ty.into()
+                        }
                         ast::ExternItem::MacroCall(call) => {
                             // FIXME: we need some way of tracking that the macro call is in an
                             // extern block
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index 4b46283743..49dc1eef18 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -328,7 +328,8 @@ impl<'a> Printer<'a> {
                 wln!(self, " = _;");
             }
             ModItem::Static(it) => {
-                let Static { name, visibility, mutable, type_ref, ast_id: _ } = &self.tree[it];
+                let Static { name, visibility, mutable, is_extern, type_ref, ast_id: _ } =
+                    &self.tree[it];
                 self.print_visibility(*visibility);
                 w!(self, "static ");
                 if *mutable {
@@ -337,6 +338,9 @@ impl<'a> Printer<'a> {
                 w!(self, "{}: ", name);
                 self.print_type_ref(type_ref);
                 w!(self, " = _;");
+                if *is_extern {
+                    w!(self, "  // extern");
+                }
                 wln!(self);
             }
             ModItem::Trait(it) => {
@@ -389,8 +393,15 @@ impl<'a> Printer<'a> {
                 wln!(self, "}}");
             }
             ModItem::TypeAlias(it) => {
-                let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id: _ } =
-                    &self.tree[it];
+                let TypeAlias {
+                    name,
+                    visibility,
+                    bounds,
+                    type_ref,
+                    is_extern,
+                    generic_params,
+                    ast_id: _,
+                } = &self.tree[it];
                 self.print_visibility(*visibility);
                 w!(self, "type {}", name);
                 self.print_generic_params(generic_params);
@@ -404,6 +415,9 @@ impl<'a> Printer<'a> {
                 }
                 self.print_where_clause(generic_params);
                 w!(self, ";");
+                if *is_extern {
+                    w!(self, "  // extern");
+                }
                 wln!(self);
             }
             ModItem::Mod(it) => {
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index c8e60032df..b68ede4003 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -65,7 +65,6 @@ use hir_expand::{
     hygiene::Hygiene,
     AstId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
 };
-use item_tree::ExternBlock;
 use la_arena::Idx;
 use nameres::DefMap;
 use path::ModPath;
@@ -154,7 +153,7 @@ impl<N: ItemTreeNode> Hash for ItemLoc<N> {
 
 #[derive(Debug)]
 pub struct AssocItemLoc<N: ItemTreeNode> {
-    pub container: ItemContainerId,
+    pub container: AssocContainerId,
     pub id: ItemTreeId<N>,
 }
 
@@ -245,7 +244,7 @@ impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct StaticId(salsa::InternId);
-pub type StaticLoc = AssocItemLoc<Static>;
+pub type StaticLoc = ItemLoc<Static>;
 impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -263,11 +262,6 @@ pub struct ImplId(salsa::InternId);
 type ImplLoc = ItemLoc<Impl>;
 impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
-pub struct ExternBlockId(salsa::InternId);
-type ExternBlockLoc = ItemLoc<ExternBlock>;
-impl_intern!(ExternBlockId, ExternBlockLoc, intern_extern_block, lookup_intern_extern_block);
-
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct BlockId(salsa::InternId);
 #[derive(Debug, Hash, PartialEq, Eq, Clone)]
@@ -301,13 +295,12 @@ pub struct ConstParamId {
 pub type LocalConstParamId = Idx<generics::ConstParamData>;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum ItemContainerId {
-    ExternBlockId(ExternBlockId),
+pub enum AssocContainerId {
     ModuleId(ModuleId),
     ImplId(ImplId),
     TraitId(TraitId),
 }
-impl_from!(ModuleId for ItemContainerId);
+impl_from!(ModuleId for AssocContainerId);
 
 /// A Data Type
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
@@ -434,7 +427,6 @@ pub enum AttrDefId {
     MacroDefId(MacroDefId),
     ImplId(ImplId),
     GenericParamId(GenericParamId),
-    ExternBlockId(ExternBlockId),
 }
 
 impl_from!(
@@ -453,13 +445,12 @@ impl_from!(
     for AttrDefId
 );
 
-impl From<ItemContainerId> for AttrDefId {
-    fn from(acid: ItemContainerId) -> Self {
+impl From<AssocContainerId> for AttrDefId {
+    fn from(acid: AssocContainerId) -> Self {
         match acid {
-            ItemContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
-            ItemContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
-            ItemContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
-            ItemContainerId::ExternBlockId(id) => AttrDefId::ExternBlockId(id),
+            AssocContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
+            AssocContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
+            AssocContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
         }
     }
 }
@@ -514,13 +505,12 @@ pub trait HasModule {
     fn module(&self, db: &dyn db::DefDatabase) -> ModuleId;
 }
 
-impl HasModule for ItemContainerId {
+impl HasModule for AssocContainerId {
     fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
         match *self {
-            ItemContainerId::ModuleId(it) => it,
-            ItemContainerId::ImplId(it) => it.lookup(db).container,
-            ItemContainerId::TraitId(it) => it.lookup(db).container,
-            ItemContainerId::ExternBlockId(it) => it.lookup(db).container,
+            AssocContainerId::ModuleId(it) => it,
+            AssocContainerId::ImplId(it) => it.lookup(db).container,
+            AssocContainerId::TraitId(it) => it.lookup(db).container,
         }
     }
 }
@@ -597,6 +587,12 @@ impl HasModule for TraitId {
     }
 }
 
+impl HasModule for StaticLoc {
+    fn module(&self, _db: &dyn db::DefDatabase) -> ModuleId {
+        self.container
+    }
+}
+
 impl ModuleDefId {
     /// Returns the module containing `self` (or `self`, if `self` is itself a module).
     ///
@@ -608,7 +604,7 @@ impl ModuleDefId {
             ModuleDefId::AdtId(id) => id.module(db),
             ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container,
             ModuleDefId::ConstId(id) => id.lookup(db).container.module(db),
-            ModuleDefId::StaticId(id) => id.lookup(db).module(db),
+            ModuleDefId::StaticId(id) => id.lookup(db).container,
             ModuleDefId::TraitId(id) => id.lookup(db).container,
             ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db),
             ModuleDefId::BuiltinType(_) => return None,
@@ -629,7 +625,6 @@ impl AttrDefId {
             AttrDefId::TraitId(it) => it.lookup(db).container.krate,
             AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate,
             AttrDefId::ImplId(it) => it.lookup(db).container.krate,
-            AttrDefId::ExternBlockId(it) => it.lookup(db).container.krate,
             AttrDefId::GenericParamId(it) => {
                 match it {
                     GenericParamId::TypeParamId(it) => it.parent,
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 8c0ba3c056..ad4a4aa752 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -44,9 +44,9 @@ use crate::{
     path::{ImportAlias, ModPath, PathKind},
     per_ns::PerNs,
     visibility::{RawVisibility, Visibility},
-    AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionLoc,
-    ImplLoc, Intern, ItemContainerId, LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc,
-    TypeAliasLoc, UnionLoc, UnresolvedMacro,
+    AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern,
+    LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
+    UnresolvedMacro,
 };
 
 static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
@@ -213,7 +213,6 @@ struct MacroDirective {
     module_id: LocalModuleId,
     depth: usize,
     kind: MacroDirectiveKind,
-    container: ItemContainerId,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
@@ -307,7 +306,7 @@ impl DefCollector<'_> {
                 item_tree: &item_tree,
                 mod_dir: ModDir::root(),
             }
-            .collect_in_top_module(item_tree.top_level_items());
+            .collect(item_tree.top_level_items());
         }
     }
 
@@ -328,7 +327,7 @@ impl DefCollector<'_> {
                 item_tree: &item_tree,
                 mod_dir: ModDir::root(),
             }
-            .collect_in_top_module(item_tree.top_level_items());
+            .collect(item_tree.top_level_items());
         }
     }
 
@@ -434,7 +433,7 @@ impl DefCollector<'_> {
                     item_tree: &item_tree,
                     mod_dir,
                 }
-                .collect(&[*mod_item], directive.container);
+                .collect(&[*mod_item]);
                 true
             } else {
                 false
@@ -1054,12 +1053,7 @@ impl DefCollector<'_> {
                         &mut |_err| (),
                     );
                     if let Ok(Ok(call_id)) = call_id {
-                        resolved.push((
-                            directive.module_id,
-                            call_id,
-                            directive.depth,
-                            directive.container,
-                        ));
+                        resolved.push((directive.module_id, call_id, directive.depth));
                         res = ReachedFixedPoint::No;
                         return false;
                     }
@@ -1079,12 +1073,7 @@ impl DefCollector<'_> {
                             *derive_attr,
                         );
 
-                        resolved.push((
-                            directive.module_id,
-                            call_id,
-                            directive.depth,
-                            directive.container,
-                        ));
+                        resolved.push((directive.module_id, call_id, directive.depth));
                         res = ReachedFixedPoint::No;
                         return false;
                     }
@@ -1107,7 +1096,7 @@ impl DefCollector<'_> {
                             item_tree: &item_tree,
                             mod_dir,
                         }
-                        .collect(&[*mod_item], directive.container);
+                        .collect(&[*mod_item]);
                         res = ReachedFixedPoint::No;
                         false
                     };
@@ -1155,7 +1144,6 @@ impl DefCollector<'_> {
                                             ast_id,
                                             derive_attr: attr.id,
                                         },
-                                        container: directive.container,
                                     });
                                 }
                             }
@@ -1211,12 +1199,7 @@ impl DefCollector<'_> {
                                 .scope
                                 .add_attr_macro_invoc(ast_id, call_id);
 
-                            resolved.push((
-                                directive.module_id,
-                                call_id,
-                                directive.depth,
-                                directive.container,
-                            ));
+                            resolved.push((directive.module_id, call_id, directive.depth));
                             res = ReachedFixedPoint::No;
                             return false;
                         }
@@ -1230,8 +1213,8 @@ impl DefCollector<'_> {
         // Attribute resolution can add unresolved macro invocations, so concatenate the lists.
         self.unresolved_macros.extend(macros);
 
-        for (module_id, macro_call_id, depth, container) in resolved {
-            self.collect_macro_expansion(module_id, macro_call_id, depth, container);
+        for (module_id, macro_call_id, depth) in resolved {
+            self.collect_macro_expansion(module_id, macro_call_id, depth);
         }
 
         res
@@ -1242,7 +1225,6 @@ impl DefCollector<'_> {
         module_id: LocalModuleId,
         macro_call_id: MacroCallId,
         depth: usize,
-        container: ItemContainerId,
     ) {
         if EXPANSION_DEPTH_LIMIT.check(depth).is_err() {
             cov_mark::hit!(macro_expansion_overflow);
@@ -1294,7 +1276,7 @@ impl DefCollector<'_> {
             item_tree: &item_tree,
             mod_dir,
         }
-        .collect(item_tree.top_level_items(), container);
+        .collect(item_tree.top_level_items());
     }
 
     fn finish(mut self) -> DefMap {
@@ -1390,12 +1372,7 @@ struct ModCollector<'a, 'b> {
 }
 
 impl ModCollector<'_, '_> {
-    fn collect_in_top_module(&mut self, items: &[ModItem]) {
-        let module = self.def_collector.def_map.module_id(self.module_id);
-        self.collect(items, module.into())
-    }
-
-    fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
+    fn collect(&mut self, items: &[ModItem]) {
         struct DefData<'a> {
             id: ModuleDefId,
             name: &'a Name,
@@ -1446,7 +1423,7 @@ impl ModCollector<'_, '_> {
                 }
             }
 
-            if let Err(()) = self.resolve_attributes(&attrs, item, container) {
+            if let Err(()) = self.resolve_attributes(&attrs, item) {
                 // Do not process the item. It has at least one non-builtin attribute, so the
                 // fixed-point algorithm is required to resolve the rest of them.
                 continue;
@@ -1485,17 +1462,8 @@ impl ModCollector<'_, '_> {
                         status: PartialResolvedImport::Unresolved,
                     })
                 }
-                ModItem::ExternBlock(block) => self.collect(
-                    &self.item_tree[block].children,
-                    ItemContainerId::ExternBlockId(
-                        ExternBlockLoc {
-                            container: module,
-                            id: ItemTreeId::new(self.tree_id, block),
-                        }
-                        .intern(self.def_collector.db),
-                    ),
-                ),
-                ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac], container),
+                ModItem::ExternBlock(block) => self.collect(&self.item_tree[block].children),
+                ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]),
                 ModItem::MacroRules(id) => self.collect_macro_rules(id),
                 ModItem::MacroDef(id) => self.collect_macro_def(id),
                 ModItem::Impl(imp) => {
@@ -1512,9 +1480,12 @@ impl ModCollector<'_, '_> {
                     self.collect_proc_macro_def(&func.name, ast_id, &attrs);
 
                     def = Some(DefData {
-                        id: FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }
-                            .intern(self.def_collector.db)
-                            .into(),
+                        id: FunctionLoc {
+                            container: module.into(),
+                            id: ItemTreeId::new(self.tree_id, id),
+                        }
+                        .intern(self.def_collector.db)
+                        .into(),
                         name: &func.name,
                         visibility: &self.item_tree[func.visibility],
                         has_constructor: false,
@@ -1558,8 +1529,11 @@ impl ModCollector<'_, '_> {
                 }
                 ModItem::Const(id) => {
                     let it = &self.item_tree[id];
-                    let const_id = ConstLoc { container, id: ItemTreeId::new(self.tree_id, id) }
-                        .intern(self.def_collector.db);
+                    let const_id = ConstLoc {
+                        container: module.into(),
+                        id: ItemTreeId::new(self.tree_id, id),
+                    }
+                    .intern(self.def_collector.db);
 
                     match &it.name {
                         Some(name) => {
@@ -1582,7 +1556,7 @@ impl ModCollector<'_, '_> {
                     let it = &self.item_tree[id];
 
                     def = Some(DefData {
-                        id: StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) }
+                        id: StaticLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
                             .intern(self.def_collector.db)
                             .into(),
                         name: &it.name,
@@ -1606,9 +1580,12 @@ impl ModCollector<'_, '_> {
                     let it = &self.item_tree[id];
 
                     def = Some(DefData {
-                        id: TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) }
-                            .intern(self.def_collector.db)
-                            .into(),
+                        id: TypeAliasLoc {
+                            container: module.into(),
+                            id: ItemTreeId::new(self.tree_id, id),
+                        }
+                        .intern(self.def_collector.db)
+                        .into(),
                         name: &it.name,
                         visibility: &self.item_tree[it.visibility],
                         has_constructor: false,
@@ -1656,7 +1633,7 @@ impl ModCollector<'_, '_> {
                         item_tree: self.item_tree,
                         mod_dir,
                     }
-                    .collect_in_top_module(&*items);
+                    .collect(&*items);
                     if is_macro_use {
                         self.import_all_legacy_macros(module_id);
                     }
@@ -1689,7 +1666,7 @@ impl ModCollector<'_, '_> {
                                 item_tree: &item_tree,
                                 mod_dir,
                             }
-                            .collect_in_top_module(item_tree.top_level_items());
+                            .collect(item_tree.top_level_items());
                             let is_macro_use = is_macro_use
                                 || item_tree
                                     .top_level_attrs(db, self.def_collector.def_map.krate)
@@ -1757,12 +1734,7 @@ impl ModCollector<'_, '_> {
     ///
     /// If `ignore_up_to` is `Some`, attributes preceding and including that attribute will be
     /// assumed to be resolved already.
-    fn resolve_attributes(
-        &mut self,
-        attrs: &Attrs,
-        mod_item: ModItem,
-        container: ItemContainerId,
-    ) -> Result<(), ()> {
+    fn resolve_attributes(&mut self, attrs: &Attrs, mod_item: ModItem) -> Result<(), ()> {
         let mut ignore_up_to =
             self.def_collector.skip_attrs.get(&InFile::new(self.file_id(), mod_item)).copied();
         let iter = attrs
@@ -1805,7 +1777,6 @@ impl ModCollector<'_, '_> {
                     mod_item,
                     tree: self.tree_id,
                 },
-                container,
             });
 
             return Err(());
@@ -1980,7 +1951,7 @@ impl ModCollector<'_, '_> {
         );
     }
 
-    fn collect_macro_call(&mut self, mac: &MacroCall, container: ItemContainerId) {
+    fn collect_macro_call(&mut self, mac: &MacroCall) {
         let ast_id = AstIdWithPath::new(self.file_id(), mac.ast_id, ModPath::clone(&mac.path));
 
         // Case 1: try to resolve in legacy scope and expand macro_rules
@@ -2010,7 +1981,6 @@ impl ModCollector<'_, '_> {
                     self.module_id,
                     macro_call_id,
                     self.macro_depth + 1,
-                    container,
                 );
 
                 if let Some(err) = error {
@@ -2041,7 +2011,6 @@ impl ModCollector<'_, '_> {
             module_id: self.module_id,
             depth: self.macro_depth + 1,
             kind: MacroDirectiveKind::FnLike { ast_id, expand_to: mac.expand_to },
-            container,
         });
     }
 
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index 8b2eea9d58..0cf28acf7f 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -22,8 +22,8 @@ use crate::{
     path::{ModPath, PathKind},
     per_ns::PerNs,
     visibility::{RawVisibility, Visibility},
-    AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId,
-    FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
+    AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId,
+    EnumVariantId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, LifetimeParamId,
     LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
     TypeParamId, VariantId,
 };
@@ -802,13 +802,6 @@ impl HasResolver for ImplId {
     }
 }
 
-impl HasResolver for ExternBlockId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
-        // Same as parent's
-        self.lookup(db).container.resolver(db)
-    }
-}
-
 impl HasResolver for DefWithBodyId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         match self {
@@ -819,13 +812,12 @@ impl HasResolver for DefWithBodyId {
     }
 }
 
-impl HasResolver for ItemContainerId {
+impl HasResolver for AssocContainerId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         match self {
-            ItemContainerId::ModuleId(it) => it.resolver(db),
-            ItemContainerId::TraitId(it) => it.resolver(db),
-            ItemContainerId::ImplId(it) => it.resolver(db),
-            ItemContainerId::ExternBlockId(it) => it.resolver(db),
+            AssocContainerId::ModuleId(it) => it.resolver(db),
+            AssocContainerId::TraitId(it) => it.resolver(db),
+            AssocContainerId::ImplId(it) => it.resolver(db),
         }
     }
 }
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 5c6525c0f4..4ec8749f87 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -36,8 +36,8 @@ limit = { path = "../limit", version = "0.0.0" }
 test_utils = { path = "../test_utils" }
 expect-test = "1.2.0-pre.1"
 tracing = "0.1"
-tracing-subscriber = { version = "0.3", default-features = false, features = [
+tracing-subscriber = { version = "0.2", default-features = false, features = [
     "env-filter",
     "registry",
 ] }
-tracing-tree = "0.2"
+tracing-tree = { version = "0.1.10" }
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index dc5dcd163c..f58339286f 100644
--- a/crates/hir_ty/src/chalk_db.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -11,7 +11,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
 use base_db::CrateId;
 use hir_def::{
     lang_item::{lang_attr, LangItemTarget},
-    AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
+    AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, ModuleId, TypeAliasId,
 };
 use hir_expand::name::name;
 
@@ -396,7 +396,7 @@ pub(crate) fn associated_ty_data_query(
     debug!("associated_ty_data {:?}", id);
     let type_alias: TypeAliasId = from_assoc_type_id(id);
     let trait_ = match type_alias.lookup(db.upcast()).container {
-        ItemContainerId::TraitId(t) => t,
+        AssocContainerId::TraitId(t) => t,
         _ => panic!("associated type not in trait"),
     };
 
@@ -634,7 +634,7 @@ fn type_alias_associated_ty_value(
 ) -> Arc<AssociatedTyValue> {
     let type_alias_data = db.type_alias_data(type_alias);
     let impl_id = match type_alias.lookup(db.upcast()).container {
-        ItemContainerId::ImplId(it) => it,
+        AssocContainerId::ImplId(it) => it,
         _ => panic!("assoc ty value should be in impl"),
     };
 
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs
index 653c4d5ec8..36c56820eb 100644
--- a/crates/hir_ty/src/chalk_ext.rs
+++ b/crates/hir_ty/src/chalk_ext.rs
@@ -4,7 +4,7 @@ use chalk_ir::{FloatTy, IntTy, Mutability, Scalar, UintTy};
 use hir_def::{
     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint},
     type_ref::Rawness,
-    FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId,
+    AssocContainerId, FunctionId, GenericDefId, HasModule, Lookup, TraitId,
 };
 
 use crate::{
@@ -268,7 +268,7 @@ impl TyExt for Ty {
         match self.kind(&Interner) {
             TyKind::AssociatedType(id, ..) => {
                 match from_assoc_type_id(*id).lookup(db.upcast()).container {
-                    ItemContainerId::TraitId(trait_id) => Some(trait_id),
+                    AssocContainerId::TraitId(trait_id) => Some(trait_id),
                     _ => None,
                 }
             }
@@ -277,7 +277,7 @@ impl TyExt for Ty {
                     .lookup(db.upcast())
                     .container
                 {
-                    ItemContainerId::TraitId(trait_id) => Some(trait_id),
+                    AssocContainerId::TraitId(trait_id) => Some(trait_id),
                     _ => None,
                 }
             }
@@ -331,7 +331,7 @@ impl ProjectionTyExt for ProjectionTy {
 
     fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
         match from_assoc_type_id(self.associated_ty_id).lookup(db.upcast()).container {
-            ItemContainerId::TraitId(it) => it,
+            AssocContainerId::TraitId(it) => it,
             _ => panic!("projection ty without parent trait"),
         }
     }
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index a1e7198bc2..6a3588dc74 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -178,7 +178,6 @@ impl<'a> DeclValidator<'a> {
                 AttrDefId::ConstId(cid) => Some(cid.lookup(self.db.upcast()).container.into()),
                 AttrDefId::TraitId(tid) => Some(tid.lookup(self.db.upcast()).container.into()),
                 AttrDefId::ImplId(iid) => Some(iid.lookup(self.db.upcast()).container.into()),
-                AttrDefId::ExternBlockId(id) => Some(id.lookup(self.db.upcast()).container.into()),
                 // These warnings should not explore macro definitions at all
                 AttrDefId::MacroDefId(_) => None,
                 // Will never occur under an enum/struct/union/type alias
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 307323690a..e2b4e92575 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -16,7 +16,7 @@ use hir_def::{
     path::{Path, PathKind},
     type_ref::{TraitBoundModifier, TypeBound, TypeRef},
     visibility::Visibility,
-    HasModule, ItemContainerId, Lookup, ModuleId, TraitId,
+    AssocContainerId, HasModule, Lookup, ModuleId, TraitId,
 };
 use hir_expand::{hygiene::Hygiene, name::Name};
 use itertools::Itertools;
@@ -576,7 +576,7 @@ impl HirDisplay for Ty {
             TyKind::AssociatedType(assoc_type_id, parameters) => {
                 let type_alias = from_assoc_type_id(*assoc_type_id);
                 let trait_ = match type_alias.lookup(f.db.upcast()).container {
-                    ItemContainerId::TraitId(it) => it,
+                    AssocContainerId::TraitId(it) => it,
                     _ => panic!("not an associated type"),
                 };
                 let trait_ = f.db.trait_data(trait_);
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 56e554736e..d07a939583 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -521,7 +521,7 @@ impl<'a> InferenceContext<'a> {
         match assoc_ty {
             Some(res_assoc_ty) => {
                 let trait_ = match res_assoc_ty.lookup(self.db.upcast()).container {
-                    hir_def::ItemContainerId::TraitId(trait_) => trait_,
+                    hir_def::AssocContainerId::TraitId(trait_) => trait_,
                     _ => panic!("resolve_associated_type called with non-associated type"),
                 };
                 let ty = self.table.new_type_var();
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 90c68c9d3f..5fb227c0e4 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -14,7 +14,7 @@ use hir_def::{
     },
     path::{GenericArg, GenericArgs},
     resolver::resolver_for_expr,
-    FieldId, FunctionId, ItemContainerId, Lookup,
+    AssocContainerId, FieldId, FunctionId, Lookup,
 };
 use hir_expand::name::{name, Name};
 use stdx::always;
@@ -1167,7 +1167,8 @@ impl<'a> InferenceContext<'a> {
             // add obligation for trait implementation, if this is a trait method
             match def {
                 CallableDefId::FunctionId(f) => {
-                    if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
+                    if let AssocContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container
+                    {
                         // construct a TraitRef
                         let substs = crate::subst_prefix(
                             &*parameters,
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index a84501fa54..056cdb5d5b 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -6,7 +6,7 @@ use chalk_ir::cast::Cast;
 use hir_def::{
     path::{Path, PathSegment},
     resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs},
-    AdtId, AssocItemId, EnumVariantId, ItemContainerId, Lookup,
+    AdtId, AssocContainerId, AssocItemId, EnumVariantId, Lookup,
 };
 use hir_expand::name::Name;
 
@@ -241,7 +241,7 @@ impl<'a> InferenceContext<'a> {
                     AssocItemId::TypeAliasId(_) => unreachable!(),
                 };
                 let substs = match container {
-                    ItemContainerId::ImplId(impl_id) => {
+                    AssocContainerId::ImplId(impl_id) => {
                         let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
                             .fill(iter::repeat_with(|| self.table.new_type_var()))
                             .build();
@@ -250,7 +250,7 @@ impl<'a> InferenceContext<'a> {
                         self.unify(&impl_self_ty, &ty);
                         Some(impl_substs)
                     }
-                    ItemContainerId::TraitId(trait_) => {
+                    AssocContainerId::TraitId(trait_) => {
                         // we're picking this method
                         let trait_ref = TyBuilder::trait_ref(self.db, trait_)
                             .push(ty.clone())
@@ -259,7 +259,7 @@ impl<'a> InferenceContext<'a> {
                         self.push_obligation(trait_ref.clone().cast(&Interner));
                         Some(trait_ref.substitution)
                     }
-                    ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
+                    AssocContainerId::ModuleId(_) => None,
                 };
 
                 self.write_assoc_resolution(id, item);
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 99267e085f..af1d5fdb6a 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -19,8 +19,8 @@ use hir_def::{
     path::{GenericArg, Path, PathSegment, PathSegments},
     resolver::{HasResolver, Resolver, TypeNs},
     type_ref::{TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
-    AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
-    HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
+    AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
+    GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
     TypeAliasId, TypeParamId, UnionId, VariantId,
 };
 use hir_expand::{name::Name, ExpandResult};
@@ -1125,7 +1125,7 @@ pub(crate) fn trait_environment_query(
         }
     }
 
-    let container: Option<ItemContainerId> = match def {
+    let container: Option<AssocContainerId> = match def {
         // FIXME: is there a function for this?
         GenericDefId::FunctionId(f) => Some(f.lookup(db.upcast()).container),
         GenericDefId::AdtId(_) => None,
@@ -1135,7 +1135,7 @@ pub(crate) fn trait_environment_query(
         GenericDefId::EnumVariantId(_) => None,
         GenericDefId::ConstId(c) => Some(c.lookup(db.upcast()).container),
     };
-    if let Some(ItemContainerId::TraitId(trait_id)) = container {
+    if let Some(AssocContainerId::TraitId(trait_id)) = container {
         // add `Self: Trait<T1, T2, ...>` to the environment in trait
         // function default implementations (and speculative code
         // inside consts or type aliases)
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 6b3f48b194..8e19928746 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -8,8 +8,8 @@ use arrayvec::ArrayVec;
 use base_db::{CrateId, Edition};
 use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
 use hir_def::{
-    lang_item::LangItemTarget, nameres::DefMap, AssocItemId, BlockId, FunctionId, GenericDefId,
-    HasModule, ImplId, ItemContainerId, Lookup, ModuleId, TraitId,
+    lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, BlockId, FunctionId,
+    GenericDefId, HasModule, ImplId, Lookup, ModuleId, TraitId,
 };
 use hir_expand::name::Name;
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -979,19 +979,18 @@ fn transform_receiver_ty(
     self_ty: &Canonical<Ty>,
 ) -> Option<Ty> {
     let substs = match function_id.lookup(db.upcast()).container {
-        ItemContainerId::TraitId(_) => TyBuilder::subst_for_def(db, function_id)
+        AssocContainerId::TraitId(_) => TyBuilder::subst_for_def(db, function_id)
             .push(self_ty.value.clone())
             .fill_with_unknown()
             .build(),
-        ItemContainerId::ImplId(impl_id) => {
+        AssocContainerId::ImplId(impl_id) => {
             let impl_substs = inherent_impl_substs(db, env, impl_id, self_ty)?;
             TyBuilder::subst_for_def(db, function_id)
                 .use_parent_substs(&impl_substs)
                 .fill_with_unknown()
                 .build()
         }
-        // No receiver
-        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => unreachable!(),
+        AssocContainerId::ModuleId(_) => unreachable!(),
     };
     let sig = db.callable_item_signature(function_id.into());
     Some(sig.map(|s| s.params()[0].clone()).substitute(&Interner, &substs))
diff --git a/crates/hir_ty/src/tls.rs b/crates/hir_ty/src/tls.rs
index 18a07f2c64..6a662dcf7b 100644
--- a/crates/hir_ty/src/tls.rs
+++ b/crates/hir_ty/src/tls.rs
@@ -7,7 +7,7 @@ use crate::{
     chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk,
     CallableDefId, Interner,
 };
-use hir_def::{AdtId, ItemContainerId, Lookup, TypeAliasId};
+use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId};
 
 pub(crate) use unsafe_tls::{set_current_program, with_current_program};
 
@@ -45,7 +45,7 @@ impl DebugContext<'_> {
         let type_alias: TypeAliasId = from_assoc_type_id(id);
         let type_alias_data = self.0.type_alias_data(type_alias);
         let trait_ = match type_alias.lookup(self.0.upcast()).container {
-            ItemContainerId::TraitId(t) => t,
+            AssocContainerId::TraitId(t) => t,
             _ => panic!("associated type not in trait"),
         };
         let trait_data = self.0.trait_data(trait_);
@@ -60,7 +60,7 @@ impl DebugContext<'_> {
         let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
         let type_alias_data = self.0.type_alias_data(type_alias);
         let trait_ = match type_alias.lookup(self.0.upcast()).container {
-            ItemContainerId::TraitId(t) => t,
+            AssocContainerId::TraitId(t) => t,
             _ => panic!("associated type not in trait"),
         };
         let trait_data = self.0.trait_data(trait_);
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index a0837377c6..0037849d1c 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -14,7 +14,7 @@ use hir_def::{
     path::Path,
     resolver::{HasResolver, TypeNs},
     type_ref::{TraitBoundModifier, TypeRef},
-    GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, TypeParamId,
+    AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId,
 };
 use hir_expand::name::{name, Name};
 use rustc_hash::FxHashSet;
@@ -296,8 +296,8 @@ fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<Generic
     };
 
     match container {
-        ItemContainerId::ImplId(it) => Some(it.into()),
-        ItemContainerId::TraitId(it) => Some(it.into()),
-        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
+        AssocContainerId::ImplId(it) => Some(it.into()),
+        AssocContainerId::TraitId(it) => Some(it.into()),
+        AssocContainerId::ModuleId(_) => None,
     }
 }
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 5bd9f054dd..e7feb042b2 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -56,7 +56,6 @@ mod typing;
 mod view_crate_graph;
 mod view_hir;
 mod view_item_tree;
-mod shuffle_crate_graph;
 
 use std::sync::Arc;
 
@@ -178,10 +177,6 @@ impl AnalysisHost {
     pub fn raw_database_mut(&mut self) -> &mut RootDatabase {
         &mut self.db
     }
-
-    pub fn shuffle_crate_graph(&mut self) {
-        shuffle_crate_graph::shuffle_crate_graph(&mut self.db);
-    }
 }
 
 impl Default for AnalysisHost {
diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs
index 52e099513a..d97e52200d 100644
--- a/crates/ide/src/navigation_target.rs
+++ b/crates/ide/src/navigation_target.rs
@@ -9,6 +9,7 @@ use hir::{
 };
 use ide_db::{
     base_db::{FileId, FileRange},
+    symbol_index::FileSymbolKind,
     SymbolKind,
 };
 use ide_db::{defs::Definition, RootDatabase};
@@ -90,17 +91,18 @@ impl NavigationTarget {
 
     pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
         let name = module.name(db).map(|it| it.to_smol_str()).unwrap_or_default();
-        if let Some(src @ InFile { value, .. }) = &module.declaration_source(db) {
-            let FileRange { file_id, range: full_range } = src.syntax().original_file_range(db);
-            let focus_range = value
+        if let Some(src) = module.declaration_source(db) {
+            let node = src.syntax();
+            let full_range = node.original_file_range(db);
+            let focus_range = src
+                .value
                 .name()
-                .and_then(|name| src.with_value(name.syntax()).original_file_range_opt(db))
-                .map(|it| it.range);
+                .map(|name| src.with_value(name.syntax()).original_file_range(db).range);
             let mut res = NavigationTarget::from_syntax(
-                file_id,
+                full_range.file_id,
                 name,
                 focus_range,
-                full_range,
+                full_range.range,
                 SymbolKind::Module,
             );
             res.docs = module.attrs(db).docs();
@@ -140,9 +142,9 @@ impl NavigationTarget {
             .name()
             .and_then(|it| node.with_value(it.syntax()).original_file_range_opt(db))
             .map(|it| it.range);
-        let FileRange { file_id, range } = node.map(|it| it.syntax()).original_file_range(db);
+        let frange = node.map(|it| it.syntax()).original_file_range(db);
 
-        NavigationTarget::from_syntax(file_id, name, focus_range, range, kind)
+        NavigationTarget::from_syntax(frange.file_id, name, focus_range, frange.range, kind)
     }
 
     fn from_syntax(
@@ -173,7 +175,18 @@ impl TryToNav for FileSymbol {
         Some(NavigationTarget {
             file_id: full_range.file_id,
             name: self.name.clone(),
-            kind: Some(self.kind.into()),
+            kind: Some(match self.kind {
+                FileSymbolKind::Function => SymbolKind::Function,
+                FileSymbolKind::Struct => SymbolKind::Struct,
+                FileSymbolKind::Enum => SymbolKind::Enum,
+                FileSymbolKind::Trait => SymbolKind::Trait,
+                FileSymbolKind::Module => SymbolKind::Module,
+                FileSymbolKind::TypeAlias => SymbolKind::TypeAlias,
+                FileSymbolKind::Const => SymbolKind::Const,
+                FileSymbolKind::Static => SymbolKind::Static,
+                FileSymbolKind::Macro => SymbolKind::Macro,
+                FileSymbolKind::Union => SymbolKind::Union,
+            }),
             full_range: full_range.range,
             focus_range: Some(name_range.range),
             container_name: self.container_name.clone(),
@@ -274,49 +287,39 @@ where
 
 impl ToNav for hir::Module {
     fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let InFile { file_id, value } = self.definition_source(db);
-
+        let src = self.definition_source(db);
         let name = self.name(db).map(|it| it.to_smol_str()).unwrap_or_default();
-        let (syntax, focus) = match &value {
+        let (syntax, focus) = match &src.value {
             ModuleSource::SourceFile(node) => (node.syntax(), None),
-            ModuleSource::Module(node) => (
-                node.syntax(),
-                node.name()
-                    .and_then(|it| InFile::new(file_id, it.syntax()).original_file_range_opt(db))
-                    .map(|it| it.range),
-            ),
+            ModuleSource::Module(node) => {
+                (node.syntax(), node.name().map(|it| it.syntax().text_range()))
+            }
             ModuleSource::BlockExpr(node) => (node.syntax(), None),
         };
-        let FileRange { file_id, range: full_range } =
-            InFile::new(file_id, syntax).original_file_range(db);
-        NavigationTarget::from_syntax(file_id, name, focus, full_range, SymbolKind::Module)
+        let frange = src.with_value(syntax).original_file_range(db);
+        NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, SymbolKind::Module)
     }
 }
 
 impl TryToNav for hir::Impl {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
-        let InFile { file_id, value } = self.source(db)?;
+        let src = self.source(db)?;
         let derive_attr = self.is_builtin_derive(db);
-
+        let frange = match &derive_attr {
+            Some(item) => item.syntax().original_file_range(db),
+            None => src.syntax().original_file_range(db),
+        };
         let focus_range = if derive_attr.is_some() {
             None
         } else {
-            value
-                .self_ty()
-                .and_then(|ty| InFile::new(file_id, ty.syntax()).original_file_range_opt(db))
-                .map(|it| it.range)
-        };
-
-        let FileRange { file_id, range: full_range } = match &derive_attr {
-            Some(attr) => attr.syntax().original_file_range(db),
-            None => InFile::new(file_id, value.syntax()).original_file_range(db),
+            src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range)
         };
 
         Some(NavigationTarget::from_syntax(
-            file_id,
+            frange.file_id,
             "impl".into(),
             focus_range,
-            full_range,
+            frange.range,
             SymbolKind::Impl,
         ))
     }
@@ -335,9 +338,14 @@ impl TryToNav for hir::Field {
                 res
             }
             FieldSource::Pos(it) => {
-                let FileRange { file_id, range } =
-                    src.with_value(it.syntax()).original_file_range(db);
-                NavigationTarget::from_syntax(file_id, "".into(), None, range, SymbolKind::Field)
+                let frange = src.with_value(it.syntax()).original_file_range(db);
+                NavigationTarget::from_syntax(
+                    frange.file_id,
+                    "".into(),
+                    None,
+                    frange.range,
+                    SymbolKind::Field,
+                )
             }
         };
         Some(field_source)
@@ -355,7 +363,13 @@ impl TryToNav for hir::MacroDef {
         let mut res = NavigationTarget::from_named(
             db,
             src.as_ref().with_value(name_owner),
-            self.kind().into(),
+            match self.kind() {
+                hir::MacroKind::Declarative
+                | hir::MacroKind::BuiltIn
+                | hir::MacroKind::ProcMacro => SymbolKind::Macro,
+                hir::MacroKind::Derive => SymbolKind::Derive,
+                hir::MacroKind::Attr => SymbolKind::Attribute,
+            },
         );
         res.docs = self.docs(db);
         Some(res)
@@ -394,17 +408,15 @@ impl TryToNav for hir::GenericParam {
 
 impl ToNav for hir::Local {
     fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let InFile { file_id, value } = self.source(db);
-        let (node, name) = match &value {
-            Either::Left(bind_pat) => (bind_pat.syntax(), bind_pat.name()),
-            Either::Right(it) => (it.syntax(), it.name()),
+        let src = self.source(db);
+        let (node, name) = match &src.value {
+            Either::Left(bind_pat) => (bind_pat.syntax().clone(), bind_pat.name()),
+            Either::Right(it) => (it.syntax().clone(), it.name()),
         };
-        let focus_range = name
-            .and_then(|it| InFile::new(file_id, it.syntax()).original_file_range_opt(db))
-            .map(|it| it.range);
-        let FileRange { file_id, range: full_range } =
-            InFile::new(file_id, node).original_file_range(db);
+        let focus_range =
+            name.map(|it| src.with_value(&it.syntax().clone()).original_file_range(db).range);
 
+        let full_range = src.with_value(&node).original_file_range(db);
         let name = match self.name(db) {
             Some(it) => it.to_smol_str(),
             None => "".into(),
@@ -417,10 +429,10 @@ impl ToNav for hir::Local {
             SymbolKind::Local
         };
         NavigationTarget {
-            file_id,
+            file_id: full_range.file_id,
             name,
             kind: Some(kind),
-            full_range,
+            full_range: full_range.range,
             focus_range,
             container_name: None,
             description: None,
@@ -431,18 +443,17 @@ impl ToNav for hir::Local {
 
 impl ToNav for hir::Label {
     fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        let InFile { file_id, value } = self.source(db);
+        let src = self.source(db);
+        let node = src.value.syntax();
+        let FileRange { file_id, range } = src.with_value(node).original_file_range(db);
+        let focus_range =
+            src.value.lifetime().and_then(|lt| lt.lifetime_ident_token()).map(|lt| lt.text_range());
         let name = self.name(db).to_smol_str();
-
-        let range = |syntax: &_| InFile::new(file_id, syntax).original_file_range(db);
-        let FileRange { file_id, range: full_range } = range(value.syntax());
-        let focus_range = value.lifetime().map(|lt| range(lt.syntax()).range);
-
         NavigationTarget {
             file_id,
             name,
             kind: Some(SymbolKind::Label),
-            full_range,
+            full_range: range,
             focus_range,
             container_name: None,
             description: None,
@@ -453,25 +464,21 @@ impl ToNav for hir::Label {
 
 impl TryToNav for hir::TypeParam {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
-        let InFile { file_id, value } = self.source(db)?;
-        let name = self.name(db).to_smol_str();
-
-        let range = |syntax: &_| InFile::new(file_id, syntax).original_file_range(db);
-        let focus_range = |syntax: &_| InFile::new(file_id, syntax).original_file_range_opt(db);
-        let FileRange { file_id, range: full_range } = match &value {
-            Either::Left(type_param) => range(type_param.syntax()),
+        let src = self.source(db)?;
+        let full_range = match &src.value {
+            Either::Left(type_param) => type_param.syntax().text_range(),
             Either::Right(trait_) => trait_
                 .name()
-                .and_then(|name| focus_range(name.syntax()))
-                .unwrap_or_else(|| range(trait_.syntax())),
+                .map_or_else(|| trait_.syntax().text_range(), |name| name.syntax().text_range()),
         };
-        let focus_range = value
-            .either(|it| it.name(), |it| it.name())
-            .and_then(|it| focus_range(it.syntax()))
-            .map(|it| it.range);
+        let focus_range = match &src.value {
+            Either::Left(it) => it.name(),
+            Either::Right(it) => it.name(),
+        }
+        .map(|it| it.syntax().text_range());
         Some(NavigationTarget {
-            file_id,
-            name,
+            file_id: src.file_id.original_file(db),
+            name: self.name(db).to_smol_str(),
             kind: Some(SymbolKind::TypeParam),
             full_range,
             focus_range,
@@ -484,14 +491,11 @@ impl TryToNav for hir::TypeParam {
 
 impl TryToNav for hir::LifetimeParam {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
-        let InFile { file_id, value } = self.source(db)?;
-        let name = self.name(db).to_smol_str();
-
-        let FileRange { file_id, range: full_range } =
-            InFile::new(file_id, value.syntax()).original_file_range(db);
+        let src = self.source(db)?;
+        let full_range = src.value.syntax().text_range();
         Some(NavigationTarget {
-            file_id,
-            name,
+            file_id: src.file_id.original_file(db),
+            name: self.name(db).to_smol_str(),
             kind: Some(SymbolKind::LifetimeParam),
             full_range,
             focus_range: Some(full_range),
@@ -504,21 +508,14 @@ impl TryToNav for hir::LifetimeParam {
 
 impl TryToNav for hir::ConstParam {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
-        let InFile { file_id, value } = self.source(db)?;
-        let name = self.name(db).to_smol_str();
-
-        let focus_range = value
-            .name()
-            .and_then(|it| InFile::new(file_id, it.syntax()).original_file_range_opt(db))
-            .map(|it| it.range);
-        let FileRange { file_id, range: full_range } =
-            InFile::new(file_id, value.syntax()).original_file_range(db);
+        let src = self.source(db)?;
+        let full_range = src.value.syntax().text_range();
         Some(NavigationTarget {
-            file_id,
-            name,
+            file_id: src.file_id.original_file(db),
+            name: self.name(db).to_smol_str(),
             kind: Some(SymbolKind::ConstParam),
             full_range,
-            focus_range,
+            focus_range: src.value.name().map(|n| n.syntax().text_range()),
             container_name: None,
             description: None,
             docs: None,
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 67062654d6..3078789d12 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -1437,6 +1437,7 @@ gen2!();
                                 0,
                             ),
                             full_range: 228..236,
+                            focus_range: 228..236,
                             name: "tests2",
                             kind: Module,
                             description: "mod tests2",
@@ -1521,6 +1522,7 @@ foo!();
                                 0,
                             ),
                             full_range: 210..217,
+                            focus_range: 210..217,
                             name: "foo_tests",
                             kind: Module,
                             description: "mod foo_tests",
diff --git a/crates/ide/src/shuffle_crate_graph.rs b/crates/ide/src/shuffle_crate_graph.rs
deleted file mode 100644
index 9c3cce5dfe..0000000000
--- a/crates/ide/src/shuffle_crate_graph.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use std::sync::Arc;
-
-use ide_db::base_db::salsa::Durability;
-use ide_db::base_db::{CrateGraph, SourceDatabase};
-use ide_db::RootDatabase;
-use rustc_hash::FxHashMap;
-
-// Feature: Shuffle Crate Graph
-//
-// Randomizes all crate IDs in the crate graph, for debugging.
-//
-// |===
-// | Editor  | Action Name
-//
-// | VS Code | **Rust Analyzer: Shuffle Crate Graph**
-// |===
-pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) {
-    let crate_graph = db.crate_graph();
-
-    let mut shuffled_ids = crate_graph.iter().collect::<Vec<_>>();
-    shuffle(&mut shuffled_ids);
-
-    let mut new_graph = CrateGraph::default();
-
-    let mut map = FxHashMap::default();
-    for old_id in shuffled_ids.iter().copied() {
-        let data = &crate_graph[old_id];
-        let new_id = new_graph.add_crate_root(
-            data.root_file_id,
-            data.edition,
-            data.display_name.clone(),
-            data.version.clone(),
-            data.cfg_options.clone(),
-            data.potential_cfg_options.clone(),
-            data.env.clone(),
-            data.proc_macro.clone(),
-            data.origin.clone(),
-        );
-        map.insert(old_id, new_id);
-    }
-
-    for old_id in shuffled_ids.iter().copied() {
-        let data = &crate_graph[old_id];
-        for dep in &data.dependencies {
-            let mut new_dep = dep.clone();
-            new_dep.crate_id = map[&dep.crate_id];
-            new_graph.add_dep(map[&old_id], new_dep).unwrap();
-        }
-    }
-
-    db.set_crate_graph_with_durability(Arc::new(new_graph), Durability::HIGH);
-}
-
-fn shuffle<T>(slice: &mut [T]) {
-    let mut rng = oorandom::Rand32::new(seed());
-
-    let mut remaining = slice.len() - 1;
-    while remaining > 0 {
-        let index = rng.rand_range(0..remaining as u32);
-        slice.swap(remaining, index as usize);
-        remaining -= 1;
-    }
-}
-
-fn seed() -> u64 {
-    use std::collections::hash_map::RandomState;
-    use std::hash::{BuildHasher, Hasher};
-
-    RandomState::new().build_hasher().finish()
-}
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 05d2732251..a52b2247c5 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -375,7 +375,13 @@ fn highlight_def(
 ) -> Highlight {
     let db = sema.db;
     let mut h = match def {
-        Definition::Macro(m) => Highlight::new(HlTag::Symbol(m.kind().into())),
+        Definition::Macro(m) => Highlight::new(HlTag::Symbol(match m.kind() {
+            hir::MacroKind::Declarative | hir::MacroKind::BuiltIn | hir::MacroKind::ProcMacro => {
+                SymbolKind::Macro
+            }
+            hir::MacroKind::Derive => SymbolKind::Derive,
+            hir::MacroKind::Attr => SymbolKind::Attribute,
+        })),
         Definition::Field(_) => Highlight::new(HlTag::Symbol(SymbolKind::Field)),
         Definition::Module(module) => {
             let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Module));
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 446a808de8..3a9c1b3beb 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -110,7 +110,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
     if !ctx.config.enable_imports_on_the_fly {
         return None;
     }
-    if ctx.in_use_tree()
+    if matches!(ctx.path_kind(), Some(PathKind::Vis { .. } | PathKind::Use))
         || ctx.is_path_disallowed()
         || ctx.expects_item()
         || ctx.expects_assoc_item()
@@ -118,6 +118,11 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
     {
         return None;
     }
+    // FIXME: This should be encoded in a different way
+    if ctx.pattern_ctx.is_none() && ctx.path_context.is_none() && !ctx.has_dot_receiver() {
+        // completion inside `ast::Name` of a item declaration
+        return None;
+    }
     let potential_import_name = {
         let token_kind = ctx.token.kind();
         if matches!(token_kind, T![.] | T![::]) {
@@ -147,14 +152,25 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
             }
         };
         match (kind, import.original_item) {
+            // Aren't handled in flyimport
+            (PathKind::Vis { .. } | PathKind::Use, _) => false,
+            // modules are always fair game
+            (_, ItemInNs::Types(hir::ModuleDef::Module(_))) => true,
+            // and so are macros(except for attributes)
+            (
+                PathKind::Expr | PathKind::Type | PathKind::Mac | PathKind::Pat,
+                ItemInNs::Macros(mac),
+            ) => mac.is_fn_like(),
+            (PathKind::Mac, _) => true,
+
             (PathKind::Expr, ItemInNs::Types(_) | ItemInNs::Values(_)) => true,
 
+            (PathKind::Pat, ItemInNs::Types(_)) => true,
+            (PathKind::Pat, ItemInNs::Values(def)) => matches!(def, hir::ModuleDef::Const(_)),
+
             (PathKind::Type, ItemInNs::Types(_)) => true,
             (PathKind::Type, ItemInNs::Values(_)) => false,
 
-            (PathKind::Expr | PathKind::Type, ItemInNs::Macros(mac)) => mac.is_fn_like(),
-
-            (PathKind::Attr, ItemInNs::Types(hir::ModuleDef::Module(_))) => true,
             (PathKind::Attr, ItemInNs::Macros(mac)) => mac.is_attr(),
             (PathKind::Attr, _) => false,
         }
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index 36d25d5d02..1c686dc0a6 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -5,8 +5,9 @@
 use syntax::{SyntaxKind, T};
 
 use crate::{
-    context::PathCompletionContext, patterns::ImmediateLocation, CompletionContext, CompletionItem,
-    CompletionItemKind, Completions,
+    context::{PathCompletionContext, PathKind},
+    patterns::ImmediateLocation,
+    CompletionContext, CompletionItem, CompletionItemKind, Completions,
 };
 
 pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
@@ -33,8 +34,8 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
     let has_block_expr_parent = ctx.has_block_expr_parent();
     let expects_item = ctx.expects_item();
 
-    if let Some(ImmediateLocation::Visibility(vis)) = &ctx.completion_location {
-        if vis.in_token().is_none() {
+    if let Some(PathKind::Vis { has_in_token }) = ctx.path_kind() {
+        if !has_in_token {
             cov_mark::hit!(kw_completion_in);
             add_keyword("in", "in");
         }
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index c63c274151..0476590142 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -1,15 +1,17 @@
-//! Completes constants and paths in patterns.
+//! Completes constants and paths in unqualified patterns.
 
 use crate::{
     context::{PatternContext, PatternRefutability},
     CompletionContext, Completions,
 };
 
-/// Completes constants and paths in patterns.
+/// Completes constants and paths in unqualified patterns.
 pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
     let refutable = match ctx.pattern_ctx {
-        Some(PatternContext { refutability, .. }) => refutability == PatternRefutability::Refutable,
-        None => return,
+        Some(PatternContext { refutability, .. }) if ctx.path_context.is_none() => {
+            refutability == PatternRefutability::Refutable
+        }
+        _ => return,
     };
 
     if refutable {
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index 4abf7374b3..b5c3d83c16 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -7,17 +7,23 @@ use rustc_hash::FxHashSet;
 use syntax::{ast, AstNode};
 
 use crate::{
-    context::PathCompletionContext, patterns::ImmediateLocation, CompletionContext, Completions,
+    context::{PathCompletionContext, PathKind},
+    patterns::ImmediateLocation,
+    CompletionContext, Completions,
 };
 
 pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
     if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() {
         return;
     }
-    let (path, use_tree_parent) = match &ctx.path_context {
-        Some(PathCompletionContext { qualifier: Some(qualifier), use_tree_parent, .. }) => {
-            (qualifier, *use_tree_parent)
-        }
+    let (path, use_tree_parent, kind) = match ctx.path_context {
+        // let ... else, syntax would come in really handy here right now
+        Some(PathCompletionContext {
+            qualifier: Some(ref qualifier),
+            use_tree_parent,
+            kind,
+            ..
+        }) => (qualifier, use_tree_parent, kind),
         _ => return,
     };
 
@@ -44,7 +50,11 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
             }
             return;
         }
-        Some(ImmediateLocation::Visibility(_)) => {
+        _ => (),
+    }
+
+    match kind {
+        Some(PathKind::Vis { .. }) => {
             if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
                 if let Some(current_module) = ctx.scope.module() {
                     if let Some(next) = current_module
@@ -61,7 +71,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
             }
             return;
         }
-        Some(ImmediateLocation::Attribute(_)) => {
+        Some(PathKind::Attr) => {
             if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
                 for (name, def) in module.scope(ctx.db, context_module) {
                     let add_resolution = match def {
@@ -76,37 +86,38 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
             }
             return;
         }
+        Some(PathKind::Use) => {
+            if iter::successors(Some(path.clone()), |p| p.qualifier())
+                .all(|p| p.segment().and_then(|s| s.super_token()).is_some())
+            {
+                acc.add_keyword(ctx, "super::");
+            }
+            // only show `self` in a new use-tree when the qualifier doesn't end in self
+            if use_tree_parent
+                && !matches!(
+                    path.segment().and_then(|it| it.kind()),
+                    Some(ast::PathSegmentKind::SelfKw)
+                )
+            {
+                acc.add_keyword(ctx, "self");
+            }
+        }
         _ => (),
     }
 
-    if ctx.in_use_tree() {
-        if iter::successors(Some(path.clone()), |p| p.qualifier())
-            .all(|p| p.segment().and_then(|s| s.super_token()).is_some())
-        {
-            acc.add_keyword(ctx, "super::");
-        }
-        // only show `self` in a new use-tree when the qualifier doesn't end in self
-        if use_tree_parent
-            && !matches!(
-                path.segment().and_then(|it| it.kind()),
-                Some(ast::PathSegmentKind::SelfKw)
-            )
-        {
-            acc.add_keyword(ctx, "self");
-        }
+    if !matches!(kind, Some(PathKind::Pat)) {
+        // Add associated types on type parameters and `Self`.
+        resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| {
+            acc.add_type_alias(ctx, alias);
+            None::<()>
+        });
     }
 
-    // Add associated types on type parameters and `Self`.
-    resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| {
-        acc.add_type_alias(ctx, alias);
-        None::<()>
-    });
-
     match resolution {
         hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
             let module_scope = module.scope(ctx.db, context_module);
             for (name, def) in module_scope {
-                if ctx.in_use_tree() {
+                if let Some(PathKind::Use) = kind {
                     if let ScopeDef::Unknown = def {
                         if let Some(ast::NameLike::NameRef(name_ref)) = ctx.name_syntax.as_ref() {
                             if name_ref.syntax().text() == name.to_smol_str().as_str() {
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index 414c1d961b..ac1ba2da7c 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -3,15 +3,23 @@
 use hir::ScopeDef;
 use syntax::{ast, AstNode};
 
-use crate::{patterns::ImmediateLocation, CompletionContext, Completions};
+use crate::{
+    context::{PathCompletionContext, PathKind},
+    patterns::ImmediateLocation,
+    CompletionContext, Completions,
+};
 
 pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
     let _p = profile::span("complete_unqualified_path");
-    if ctx.is_path_disallowed() || !ctx.is_trivial_path() || ctx.has_impl_or_trait_prev_sibling() {
+    if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() {
         return;
     }
+    let kind = match ctx.path_context {
+        Some(PathCompletionContext { is_trivial_path: true, kind, .. }) => kind,
+        _ => return,
+    };
 
-    if ctx.in_use_tree() {
+    if let Some(PathKind::Use) = kind {
         // only show modules in a fresh UseTree
         cov_mark::hit!(unqualified_path_only_modules_in_import);
         ctx.process_all_names(&mut |name, res| {
@@ -25,8 +33,25 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
     }
     ["self", "super", "crate"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
 
+    match kind {
+        Some(PathKind::Vis { .. }) => return,
+        Some(PathKind::Attr) => {
+            ctx.process_all_names(&mut |name, res| {
+                let add_resolution = match res {
+                    ScopeDef::MacroDef(mac) => mac.is_attr(),
+                    ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
+                    _ => false,
+                };
+                if add_resolution {
+                    acc.add_resolution(ctx, name, &res);
+                }
+            });
+            return;
+        }
+        _ => (),
+    }
+
     match &ctx.completion_location {
-        Some(ImmediateLocation::Visibility(_)) => return,
         Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
             // only show macros in {Assoc}ItemList
             ctx.process_all_names(&mut |name, res| {
@@ -56,19 +81,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
             });
             return;
         }
-        Some(ImmediateLocation::Attribute(_)) => {
-            ctx.process_all_names(&mut |name, res| {
-                let add_resolution = match res {
-                    ScopeDef::MacroDef(mac) => mac.is_attr(),
-                    ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
-                    _ => false,
-                };
-                if add_resolution {
-                    acc.add_resolution(ctx, name, &res);
-                }
-            });
-            return;
-        }
         _ => (),
     }
 
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index b3ce1f8e9c..e8566b80b6 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -35,16 +35,23 @@ pub(super) enum PathKind {
     Expr,
     Type,
     Attr,
+    Mac,
+    Pat,
+    Vis { has_in_token: bool },
+    Use,
 }
 
 #[derive(Debug)]
 pub(crate) struct PathCompletionContext {
     /// If this is a call with () already there
-    call_kind: Option<CallKind>,
+    has_call_parens: bool,
     /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
     pub(super) is_trivial_path: bool,
     /// If not a trivial path, the prefix (qualifier).
     pub(super) qualifier: Option<ast::Path>,
+    #[allow(dead_code)]
+    /// If not a trivial path, the suffix (parent).
+    pub(super) parent: Option<ast::Path>,
     /// Whether the qualifier comes from a use tree parent or not
     pub(super) use_tree_parent: bool,
     pub(super) kind: Option<PathKind>,
@@ -70,13 +77,6 @@ pub(super) enum LifetimeContext {
     LabelDef,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub(crate) enum CallKind {
-    Pat,
-    Mac,
-    Expr,
-}
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub(crate) enum ParamKind {
     Function,
@@ -206,13 +206,6 @@ impl<'a> CompletionContext<'a> {
         )
     }
 
-    pub(crate) fn in_use_tree(&self) -> bool {
-        matches!(
-            self.completion_location,
-            Some(ImmediateLocation::Use | ImmediateLocation::UseTree)
-        )
-    }
-
     pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool {
         matches!(
             self.prev_sibling,
@@ -257,8 +250,8 @@ impl<'a> CompletionContext<'a> {
         matches!(self.path_context, Some(PathCompletionContext { kind: Some(PathKind::Type), .. }))
     }
 
-    pub(crate) fn path_call_kind(&self) -> Option<CallKind> {
-        self.path_context.as_ref().and_then(|it| it.call_kind)
+    pub(crate) fn path_is_call(&self) -> bool {
+        self.path_context.as_ref().map_or(false, |it| it.has_call_parens)
     }
 
     pub(crate) fn is_trivial_path(&self) -> bool {
@@ -673,7 +666,12 @@ impl<'a> CompletionContext<'a> {
                     Self::classify_lifetime(&self.sema, original_file, lifetime, offset);
             }
             ast::NameLike::NameRef(name_ref) => {
-                self.path_context = Self::classify_name_ref(&self.sema, original_file, name_ref);
+                if let Some((path_ctx, pat_ctx)) =
+                    Self::classify_name_ref(&self.sema, original_file, name_ref)
+                {
+                    self.path_context = Some(path_ctx);
+                    self.pattern_ctx = pat_ctx;
+                }
             }
             ast::NameLike::Name(name) => {
                 self.pattern_ctx = Self::classify_name(&self.sema, name);
@@ -716,83 +714,61 @@ impl<'a> CompletionContext<'a> {
         if !bind_pat.is_simple_ident() {
             return None;
         }
-        let mut is_param = None;
-        let (refutability, has_type_ascription) = bind_pat
-            .syntax()
-            .ancestors()
-            .skip_while(|it| ast::Pat::can_cast(it.kind()))
-            .next()
-            .map_or((PatternRefutability::Irrefutable, false), |node| {
-                let refutability = match_ast! {
-                    match node {
-                        ast::LetStmt(let_) => return (PatternRefutability::Irrefutable, let_.ty().is_some()),
-                        ast::Param(param) => {
-                            let is_closure_param = param
-                                .syntax()
-                                .ancestors()
-                                .nth(2)
-                                .and_then(ast::ClosureExpr::cast)
-                                .is_some();
-                            is_param = Some(if is_closure_param {
-                                ParamKind::Closure
-                            } else {
-                                ParamKind::Function
-                            });
-                            return (PatternRefutability::Irrefutable, param.ty().is_some())
-                        },
-                        ast::MatchArm(__) => PatternRefutability::Refutable,
-                        ast::Condition(__) => PatternRefutability::Refutable,
-                        ast::ForExpr(__) => PatternRefutability::Irrefutable,
-                        _ => PatternRefutability::Irrefutable,
-                    }
-                };
-                (refutability, false)
-            });
-        Some(PatternContext { refutability, is_param, has_type_ascription })
+        Some(pattern_context_for(bind_pat.into()))
     }
 
     fn classify_name_ref(
         _sema: &Semantics<RootDatabase>,
         original_file: &SyntaxNode,
         name_ref: ast::NameRef,
-    ) -> Option<PathCompletionContext> {
+    ) -> Option<(PathCompletionContext, Option<PatternContext>)> {
         let parent = name_ref.syntax().parent()?;
         let segment = ast::PathSegment::cast(parent)?;
+        let path = segment.parent_path();
 
         let mut path_ctx = PathCompletionContext {
-            call_kind: None,
+            has_call_parens: false,
             is_trivial_path: false,
             qualifier: None,
+            parent: None,
             has_type_args: false,
             can_be_stmt: false,
             in_loop_body: false,
             use_tree_parent: false,
             kind: None,
         };
+        let mut pat_ctx = None;
         path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax());
-        let path = segment.parent_path();
-
-        if let Some(p) = path.syntax().parent() {
-            path_ctx.call_kind = match_ast! {
-                match p {
-                    ast::PathExpr(it) => it.syntax().parent().and_then(ast::CallExpr::cast).map(|_| CallKind::Expr),
-                    ast::MacroCall(it) => it.excl_token().and(Some(CallKind::Mac)),
-                    ast::TupleStructPat(_it) => Some(CallKind::Pat),
-                    _ => None
-                }
-            };
-        }
 
-        if let Some(parent) = path.syntax().parent() {
-            path_ctx.kind = match_ast! {
-                match parent {
+        path_ctx.kind  = path.syntax().ancestors().find_map(|it| {
+            match_ast! {
+                match it {
                     ast::PathType(_it) => Some(PathKind::Type),
-                    ast::PathExpr(_it) => Some(PathKind::Expr),
+                    ast::PathExpr(it) => {
+                        path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
+                        Some(PathKind::Expr)
+                    },
+                    ast::TupleStructPat(it) => {
+                        path_ctx.has_call_parens = true;
+                        pat_ctx = Some(pattern_context_for(it.into()));
+                        Some(PathKind::Pat)
+                    },
+                    ast::RecordPat(it) => {
+                        pat_ctx = Some(pattern_context_for(it.into()));
+                        Some(PathKind::Pat)
+                    },
+                    ast::PathPat(it) => {
+                        pat_ctx = Some(pattern_context_for(it.into()));
+                        Some(PathKind::Pat)
+                    },
+                    ast::MacroCall(it) => it.excl_token().and(Some(PathKind::Mac)),
                     ast::Meta(_it) => Some(PathKind::Attr),
+                    ast::Visibility(it) => Some(PathKind::Vis { has_in_token: it.in_token().is_some() }),
+                    ast::UseTree(_it) => Some(PathKind::Use),
                     _ => None,
                 }
-            };
-        }
+            }
+        });
         path_ctx.has_type_args = segment.generic_arg_list().is_some();
 
         if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
@@ -806,12 +782,12 @@ impl<'a> CompletionContext<'a> {
                     )
                 })
                 .map(|it| it.parent_path());
-            return Some(path_ctx);
+            return Some((path_ctx, pat_ctx));
         }
 
         if let Some(segment) = path.segment() {
             if segment.coloncolon_token().is_some() {
-                return Some(path_ctx);
+                return Some((path_ctx, pat_ctx));
             }
         }
 
@@ -835,10 +811,46 @@ impl<'a> CompletionContext<'a> {
                 None
             })
             .unwrap_or(false);
-        Some(path_ctx)
+        Some((path_ctx, pat_ctx))
     }
 }
 
+fn pattern_context_for(pat: ast::Pat) -> PatternContext {
+    let mut is_param = None;
+    let (refutability, has_type_ascription) =
+    pat
+        .syntax()
+        .ancestors()
+        .skip_while(|it| ast::Pat::can_cast(it.kind()))
+        .next()
+        .map_or((PatternRefutability::Irrefutable, false), |node| {
+            let refutability = match_ast! {
+                match node {
+                    ast::LetStmt(let_) => return (PatternRefutability::Irrefutable, let_.ty().is_some()),
+                    ast::Param(param) => {
+                        let is_closure_param = param
+                            .syntax()
+                            .ancestors()
+                            .nth(2)
+                            .and_then(ast::ClosureExpr::cast)
+                            .is_some();
+                        is_param = Some(if is_closure_param {
+                            ParamKind::Closure
+                        } else {
+                            ParamKind::Function
+                        });
+                        return (PatternRefutability::Irrefutable, param.ty().is_some())
+                    },
+                    ast::MatchArm(__) => PatternRefutability::Refutable,
+                    ast::Condition(__) => PatternRefutability::Refutable,
+                    ast::ForExpr(__) => PatternRefutability::Irrefutable,
+                    _ => PatternRefutability::Irrefutable,
+                }
+            };
+            (refutability, false)
+        });
+    PatternContext { refutability, is_param, has_type_ascription }
+}
 fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> {
     syntax.covering_element(range).ancestors().find_map(N::cast)
 }
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index 13c739325c..b50f76b911 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -33,8 +33,6 @@ pub(crate) enum ImmediatePrevSibling {
 /// from which file the nodes are.
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub(crate) enum ImmediateLocation {
-    Use,
-    UseTree,
     Rename,
     Impl,
     Trait,
@@ -47,10 +45,7 @@ pub(crate) enum ImmediateLocation {
     TypeBound,
     Variant,
     /// Fake file ast node
-    Attribute(ast::Attr),
-    /// Fake file ast node
     ModDeclaration(ast::Module),
-    Visibility(ast::Visibility),
     /// Original file ast node
     MethodCall {
         receiver: Option<ast::Expr>,
@@ -206,9 +201,6 @@ pub(crate) fn determine_location(
     let res = match_ast! {
         match parent {
             ast::IdentPat(_it) => ImmediateLocation::IdentPat,
-            ast::Use(_it) => ImmediateLocation::Use,
-            ast::UseTree(_it) => ImmediateLocation::UseTree,
-            ast::UseTreeList(_it) => ImmediateLocation::UseTree,
             ast::Rename(_it) => ImmediateLocation::Rename,
             ast::StmtList(_it) => ImmediateLocation::StmtList,
             ast::SourceFile(_it) => ImmediateLocation::ItemList,
@@ -242,7 +234,6 @@ pub(crate) fn determine_location(
                     return None;
                 }
             },
-            ast::Attr(it) => ImmediateLocation::Attribute(it),
             ast::FieldExpr(it) => {
                 let receiver = it
                     .expr()
@@ -268,8 +259,6 @@ pub(crate) fn determine_location(
                     .and_then(|r| find_node_with_range(original_file, r)),
                 has_parens: it.arg_list().map_or(false, |it| it.l_paren_token().is_some())
             },
-            ast::Visibility(it) => it.pub_token()
-                .and_then(|t| (t.text_range().end() < offset).then(|| ImmediateLocation::Visibility(it)))?,
             _ => return None,
         }
     };
@@ -417,14 +406,6 @@ mod tests {
         check_location(r"impl A { fn f$0 }", None);
     }
 
-    #[test]
-    fn test_use_loc() {
-        check_location(r"use f$0", ImmediateLocation::Use);
-        check_location(r"use f$0;", ImmediateLocation::Use);
-        check_location(r"use f::{f$0}", ImmediateLocation::UseTree);
-        check_location(r"use {f$0}", ImmediateLocation::UseTree);
-    }
-
     #[test]
     fn test_record_field_loc() {
         check_location(r"struct Foo { f$0 }", ImmediateLocation::RecordField);
diff --git a/crates/ide_completion/src/render/builder_ext.rs b/crates/ide_completion/src/render/builder_ext.rs
index ea8222f76a..4d04054445 100644
--- a/crates/ide_completion/src/render/builder_ext.rs
+++ b/crates/ide_completion/src/render/builder_ext.rs
@@ -4,7 +4,7 @@ use either::Either;
 use itertools::Itertools;
 use syntax::ast::{self, HasName};
 
-use crate::{context::CallKind, item::Builder, patterns::ImmediateLocation, CompletionContext};
+use crate::{context::PathKind, item::Builder, patterns::ImmediateLocation, CompletionContext};
 
 #[derive(Debug)]
 pub(super) enum Params {
@@ -30,11 +30,11 @@ impl Builder {
         if !ctx.config.add_call_parenthesis {
             return false;
         }
-        if ctx.in_use_tree() {
+        if let Some(PathKind::Use) = ctx.path_kind() {
             cov_mark::hit!(no_parens_in_use_item);
             return false;
         }
-        if matches!(ctx.path_call_kind(), Some(CallKind::Expr | CallKind::Pat))
+        if matches!(ctx.path_kind(), Some(PathKind::Expr | PathKind::Pat) if ctx.path_is_call())
             | matches!(
                 ctx.completion_location,
                 Some(ImmediateLocation::MethodCall { has_parens: true, .. })
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index 4b505b3f5a..6eb982a43e 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -9,7 +9,7 @@ use syntax::{
 };
 
 use crate::{
-    context::CallKind,
+    context::PathKind,
     item::{CompletionItem, ImportEdit},
     render::RenderContext,
 };
@@ -52,8 +52,14 @@ impl<'a> MacroRender<'a> {
         } else {
             Some(self.ctx.source_range())
         }?;
-        let mut item =
-            CompletionItem::new(SymbolKind::from(self.macro_.kind()), source_range, self.label());
+        let kind = match self.macro_.kind() {
+            hir::MacroKind::Derive => SymbolKind::Derive,
+            hir::MacroKind::Attr => SymbolKind::Attribute,
+            hir::MacroKind::BuiltIn | hir::MacroKind::Declarative | hir::MacroKind::ProcMacro => {
+                SymbolKind::Macro
+            }
+        };
+        let mut item = CompletionItem::new(kind, source_range, self.label());
         item.set_deprecated(self.ctx.is_deprecated(self.macro_)).set_detail(self.detail());
 
         if let Some(import_to_add) = import_to_add {
@@ -61,9 +67,8 @@ impl<'a> MacroRender<'a> {
         }
 
         let needs_bang = self.macro_.is_fn_like()
-            && !(self.ctx.completion.in_use_tree()
-                || matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac)));
-        let has_parens = self.ctx.completion.path_call_kind().is_some();
+            && !matches!(self.ctx.completion.path_kind(), Some(PathKind::Mac | PathKind::Use));
+        let has_parens = self.ctx.completion.path_is_call();
 
         match self.ctx.snippet_cap() {
             Some(cap) if needs_bang && !has_parens => {
@@ -86,8 +91,7 @@ impl<'a> MacroRender<'a> {
     }
 
     fn needs_bang(&self) -> bool {
-        !self.ctx.completion.in_use_tree()
-            && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac))
+        !matches!(self.ctx.completion.path_kind(), Some(PathKind::Mac | PathKind::Use))
     }
 
     fn label(&self) -> SmolStr {
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs
index bcbb09e31b..0d14c176b5 100644
--- a/crates/ide_db/src/lib.rs
+++ b/crates/ide_db/src/lib.rs
@@ -171,18 +171,6 @@ pub enum SymbolKind {
     Variant,
 }
 
-impl From<hir::MacroKind> for SymbolKind {
-    fn from(it: hir::MacroKind) -> Self {
-        match it {
-            hir::MacroKind::Declarative | hir::MacroKind::BuiltIn | hir::MacroKind::ProcMacro => {
-                SymbolKind::Macro
-            }
-            hir::MacroKind::Derive => SymbolKind::Derive,
-            hir::MacroKind::Attr => SymbolKind::Attribute,
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     mod sourcegen_lints;
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs
index 62f4a81910..cc2b2bbb7b 100644
--- a/crates/ide_db/src/symbol_index.rs
+++ b/crates/ide_db/src/symbol_index.rs
@@ -36,15 +36,15 @@ use either::Either;
 use fst::{self, Streamer};
 use hir::{
     db::{DefDatabase, HirDatabase},
-    AdtId, AssocItemId, AssocItemLoc, DefHasSource, DefWithBodyId, HasSource, HirFileId, ImplId,
-    InFile, ItemContainerId, ItemLoc, ItemTreeNode, Lookup, MacroDef, Module, ModuleDefId,
+    AdtId, AssocContainerId, AssocItemId, AssocItemLoc, DefHasSource, DefWithBodyId, HasSource,
+    HirFileId, ImplId, InFile, ItemLoc, ItemTreeNode, Lookup, MacroDef, Module, ModuleDefId,
     ModuleId, Semantics, TraitId,
 };
 use rayon::prelude::*;
 use rustc_hash::FxHashSet;
 use syntax::{ast::HasName, AstNode, SmolStr, SyntaxNode, SyntaxNodePtr};
 
-use crate::{RootDatabase, SymbolKind};
+use crate::RootDatabase;
 
 #[derive(Debug)]
 pub struct Query {
@@ -430,23 +430,6 @@ impl FileSymbolKind {
     }
 }
 
-impl From<FileSymbolKind> for SymbolKind {
-    fn from(it: FileSymbolKind) -> Self {
-        match it {
-            FileSymbolKind::Const => SymbolKind::Const,
-            FileSymbolKind::Enum => SymbolKind::Enum,
-            FileSymbolKind::Function => SymbolKind::Function,
-            FileSymbolKind::Macro => SymbolKind::Macro,
-            FileSymbolKind::Module => SymbolKind::Module,
-            FileSymbolKind::Static => SymbolKind::Static,
-            FileSymbolKind::Struct => SymbolKind::Struct,
-            FileSymbolKind::Trait => SymbolKind::Trait,
-            FileSymbolKind::TypeAlias => SymbolKind::TypeAlias,
-            FileSymbolKind::Union => SymbolKind::Union,
-        }
-    }
-}
-
 /// Represents an outstanding module that the symbol collector must collect symbols from.
 struct SymbolCollectorWork {
     module_id: ModuleId,
@@ -508,7 +491,7 @@ impl<'a> SymbolCollector<'a> {
                     self.collect_from_body(id);
                 }
                 ModuleDefId::StaticId(id) => {
-                    self.push_decl_assoc(id, FileSymbolKind::Static);
+                    self.push_decl(id, FileSymbolKind::Static);
                     self.collect_from_body(id);
                 }
                 ModuleDefId::TraitId(id) => {
@@ -610,17 +593,17 @@ impl<'a> SymbolCollector<'a> {
         T: ItemTreeNode,
         <T as ItemTreeNode>::Source: HasName,
     {
-        fn container_name(db: &dyn HirDatabase, container: ItemContainerId) -> Option<SmolStr> {
+        fn container_name(db: &dyn HirDatabase, container: AssocContainerId) -> Option<SmolStr> {
             match container {
-                ItemContainerId::ModuleId(module_id) => {
+                AssocContainerId::ModuleId(module_id) => {
                     let module = Module::from(module_id);
                     module.name(db).and_then(|name| name.as_text())
                 }
-                ItemContainerId::TraitId(trait_id) => {
+                AssocContainerId::TraitId(trait_id) => {
                     let trait_data = db.trait_data(trait_id);
                     trait_data.name.as_text()
                 }
-                ItemContainerId::ImplId(_) | ItemContainerId::ExternBlockId(_) => None,
+                AssocContainerId::ImplId(_) => None,
             }
         }
 
diff --git a/crates/ide_diagnostics/src/handlers/incorrect_case.rs b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
index 3206a63a90..6990b19cf3 100644
--- a/crates/ide_diagnostics/src/handlers/incorrect_case.rs
+++ b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
@@ -397,24 +397,6 @@ extern {
         );
     }
 
-    #[test]
-    fn ignores_extern_items_from_macro() {
-        check_diagnostics(
-            r#"
-macro_rules! m {
-    () => {
-        fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
-        pub static SomeStatic: u8 = 10;
-    }
-}
-
-extern {
-    m!();
-}
-            "#,
-        );
-    }
-
     #[test]
     fn bug_traits_arent_checked() {
         // FIXME: Traits and functions in traits aren't currently checked by
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 6d2f042ccb..0863c40716 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -34,14 +34,14 @@ rayon = "1.5"
 mimalloc = { version = "0.1.19", default-features = false, optional = true }
 lsp-server = "0.5.1"
 tracing = "0.1"
-tracing-subscriber = { version = "0.3", default-features = false, features = [
+tracing-subscriber = { version = "0.2", default-features = false, features = [
     "env-filter",
     "registry",
     "fmt",
     "tracing-log",
 ] }
 tracing-log = "0.1.2"
-tracing-tree = "0.2"
+tracing-tree = { version = "0.1.10" }
 always-assert = "0.1"
 
 stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/rust-analyzer/src/bin/logger.rs b/crates/rust-analyzer/src/bin/logger.rs
index db00029da2..083ab69587 100644
--- a/crates/rust-analyzer/src/bin/logger.rs
+++ b/crates/rust-analyzer/src/bin/logger.rs
@@ -2,9 +2,9 @@
 //! filter syntax and `tracing_appender` for non blocking output.
 
 use std::{
-    fmt,
+    fmt::{self, Write},
     fs::File,
-    io::{self, Stderr},
+    io,
     sync::Arc,
 };
 
@@ -12,10 +12,7 @@ use rust_analyzer::Result;
 use tracing::{level_filters::LevelFilter, Event, Subscriber};
 use tracing_log::NormalizeEvent;
 use tracing_subscriber::{
-    fmt::{
-        format::Writer, writer::BoxMakeWriter, FmtContext, FormatEvent, FormatFields,
-        FormattedFields, MakeWriter,
-    },
+    fmt::{writer::BoxMakeWriter, FmtContext, FormatEvent, FormatFields, FormattedFields},
     layer::SubscriberExt,
     registry::LookupSpan,
     util::SubscriberInitExt,
@@ -28,16 +25,6 @@ pub(crate) struct Logger {
     file: Option<File>,
 }
 
-struct MakeWriterStderr;
-
-impl<'a> MakeWriter<'a> for MakeWriterStderr {
-    type Writer = Stderr;
-
-    fn make_writer(&'a self) -> Self::Writer {
-        io::stderr()
-    }
-}
-
 impl Logger {
     pub(crate) fn new(file: Option<File>, filter: Option<&str>) -> Logger {
         let filter = filter.map_or(EnvFilter::default(), EnvFilter::new);
@@ -67,7 +54,7 @@ impl Logger {
             .with_indent_lines(true)
             .with_ansi(false)
             .with_indent_amount(2)
-            .with_writer(io::stderr);
+            .with_writer(std::io::stderr);
 
         let writer = match self.file {
             Some(file) => BoxMakeWriter::new(Arc::new(file)),
@@ -109,7 +96,7 @@ where
     fn format_event(
         &self,
         ctx: &FmtContext<'_, S, N>,
-        mut writer: Writer,
+        writer: &mut dyn Write,
         event: &Event<'_>,
     ) -> fmt::Result {
         // Write level and target
@@ -148,7 +135,7 @@ where
         })?;
 
         // Write fields on the event
-        ctx.field_format().format_fields(writer.by_ref(), event)?;
+        ctx.field_format().format_fields(writer, event)?;
 
         writeln!(writer)
     }
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index ab3c9e8227..bf153012d9 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -97,11 +97,6 @@ pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result<Stri
     Ok(out)
 }
 
-pub(crate) fn handle_shuffle_crate_graph(state: &mut GlobalState, _: ()) -> Result<()> {
-    state.analysis_host.shuffle_crate_graph();
-    Ok(())
-}
-
 pub(crate) fn handle_syntax_tree(
     snap: GlobalStateSnapshot,
     params: lsp_ext::SyntaxTreeParams,
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 0e23094199..19137b942e 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -31,14 +31,6 @@ impl Request for MemoryUsage {
     const METHOD: &'static str = "rust-analyzer/memoryUsage";
 }
 
-pub enum ShuffleCrateGraph {}
-
-impl Request for ShuffleCrateGraph {
-    type Params = ();
-    type Result = ();
-    const METHOD: &'static str = "rust-analyzer/shuffleCrateGraph";
-}
-
 pub enum ReloadWorkspace {}
 
 impl Request for ReloadWorkspace {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 65f9c87367..2d83cbee66 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -567,7 +567,6 @@ impl GlobalState {
                 Ok(())
             })?
             .on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage)?
-            .on_sync_mut::<lsp_ext::ShuffleCrateGraph>(handlers::handle_shuffle_crate_graph)?
             .on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)?
             .on_sync::<lsp_ext::OnEnter>(handlers::handle_on_enter)?
             .on_sync::<lsp_types::request::SelectionRangeRequest>(handlers::handle_selection_range)?
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index c92395553c..b925f146a7 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
 <!---
-lsp_ext.rs hash: 49ffd619919ed74
+lsp_ext.rs hash: c6568e4035333f3a
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue:
@@ -526,14 +526,6 @@ Renders rust-analyzer's crate graph as an SVG image.
 
 If `full` is `true`, the graph includes non-workspace crates (crates.io dependencies as well as sysroot crates).
 
-## Shuffle Crate Graph
-
-**Method:** `rust-analyzer/shuffleCrateGraph`
-
-**Request:** `null`
-
-Shuffles the crate IDs in the crate graph, for debugging purposes.
-
 ## Expand Macro
 
 **Method:** `rust-analyzer/expandMacro`
diff --git a/editors/code/package.json b/editors/code/package.json
index 4b6e5ef333..da4fa15b02 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -171,11 +171,6 @@
                 "title": "Memory Usage (Clears Database)",
                 "category": "Rust Analyzer"
             },
-            {
-                "command": "rust-analyzer.shuffleCrateGraph",
-                "title": "Shuffle Crate Graph",
-                "category": "Rust Analyzer"
-            },
             {
                 "command": "rust-analyzer.reloadWorkspace",
                 "title": "Reload workspace",
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index fe006a63e2..c9385361f8 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -85,15 +85,6 @@ export function memoryUsage(ctx: Ctx): Cmd {
     };
 }
 
-export function shuffleCrateGraph(ctx: Ctx): Cmd {
-    return async () => {
-        const client = ctx.client;
-        if (!client) return;
-
-        await client.sendRequest(ra.shuffleCrateGraph);
-    };
-}
-
 export function matchingBrace(ctx: Ctx): Cmd {
     return async () => {
         const editor = ctx.activeRustEditor;
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index a21a742a57..90796e611e 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -9,7 +9,6 @@ export interface AnalyzerStatusParams {
 }
 export const analyzerStatus = new lc.RequestType<AnalyzerStatusParams, string, void>("rust-analyzer/analyzerStatus");
 export const memoryUsage = new lc.RequestType0<string, void>("rust-analyzer/memoryUsage");
-export const shuffleCrateGraph = new lc.RequestType0<null, void>("rust-analyzer/shuffleCrateGraph");
 
 export interface ServerStatusParams {
     health: "ok" | "warning" | "error";
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index a06fc09fc8..734f224503 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -117,7 +117,6 @@ async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) {
 
     ctx.registerCommand('analyzerStatus', commands.analyzerStatus);
     ctx.registerCommand('memoryUsage', commands.memoryUsage);
-    ctx.registerCommand('shuffleCrateGraph', commands.shuffleCrateGraph);
     ctx.registerCommand('reloadWorkspace', commands.reloadWorkspace);
     ctx.registerCommand('matchingBrace', commands.matchingBrace);
     ctx.registerCommand('joinLines', commands.joinLines);


Test patch:
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index 1969913bf9..7671ccefd1 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -70,13 +70,13 @@ extern "C" {
             #[on_extern_block]  // AttrId { is_doc_comment: false, ast_index: 0 }
             extern "C" {
                 #[on_extern_type]  // AttrId { is_doc_comment: false, ast_index: 0 }
-                pub(self) type ExType;
+                pub(self) type ExType;  // extern
 
                 #[on_extern_static]  // AttrId { is_doc_comment: false, ast_index: 0 }
-                pub(self) static EX_STATIC: u8 = _;
+                pub(self) static EX_STATIC: u8 = _;  // extern
 
                 #[on_extern_fn]  // AttrId { is_doc_comment: false, ast_index: 0 }
-                // flags = 0x20
+                // flags = 0x60
                 pub(self) fn ex_fn() -> ();
             }
         "##]],
diff --git a/crates/ide_completion/src/tests/flyimport.rs b/crates/ide_completion/src/tests/flyimport.rs
index ff46dda5e2..23e5da463c 100644
--- a/crates/ide_completion/src/tests/flyimport.rs
+++ b/crates/ide_completion/src/tests/flyimport.rs
@@ -1000,6 +1000,19 @@ fn function() {
     );
 }
 
+#[test]
+fn flyimport_item_name() {
+    check(
+        r#"
+mod module {
+    pub struct Struct;
+}
+struct Str$0
+    "#,
+        expect![[r#""#]],
+    );
+}
+
 #[test]
 fn flyimport_rename() {
     check(