Repository: rust-analyzer/rust-analyzer
Pull request #10960 (2021-12-07 16:36:15)

fix: fix handling of macros in `extern` blocks
- Removes knowledge of what's in an extern block from `ItemTree`.
- Treats extern blocks as `AssocContainerId` and renames the latter to `ItemContainerId`.
- Threads the container through name resolution (which is a bit messy).
- Considers statics to be associated items, since they can be in an extern block. (it might be better to further distinguish potentially-associated-items from potentially-in-an-extern-block-items, but currently I don't expect much of a benefit)
- Adds a test for the incorrect-case diagnostic demonstrating the impact of this change.

Fixes https://github.com/rust-analyzer/rust-analyzer/issues/8913

bors r+


Patch:
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 2f6eed82cb..54e95cf7c3 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -137,6 +137,7 @@ 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 fe8a8018db..3e04ea8da9 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.krate();
+        let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).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 {
-        AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
-        AssocContainerId::ModuleId(_) => None,
+        ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
+        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
     }
 }
 
@@ -1847,9 +1847,11 @@ impl AssocItem {
             AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container,
         };
         match container {
-            AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
-            AssocContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
-            AssocContainerId::ModuleId(_) => panic!("invalid AssocItem"),
+            ItemContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
+            ItemContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
+            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
+                panic!("invalid AssocItem")
+            }
         }
     }
 
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 711062c713..36e46a103c 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -362,6 +362,7 @@ 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));
@@ -443,6 +444,7 @@ 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 f4d0c3af90..ad1c1f2ce5 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,
-    AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
-    Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
+    AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, Intern,
+    ItemContainerId, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -54,6 +54,10 @@ 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
@@ -130,7 +134,7 @@ impl TypeAliasData {
             name: typ.name.clone(),
             type_ref: typ.type_ref.clone(),
             visibility: item_tree[typ.visibility].clone(),
-            is_extern: typ.is_extern,
+            is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
             bounds: typ.bounds.to_vec(),
         })
     }
@@ -162,7 +166,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 = AssocContainerId::TraitId(tr);
+        let container = ItemContainerId::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
@@ -231,7 +235,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 = AssocContainerId::ImplId(id);
+        let container = ItemContainerId::ImplId(id);
         let mut expander = Expander::new(db, impl_loc.id.file_id(), module_id);
 
         let items = collect_items(
@@ -282,16 +286,16 @@ pub struct StaticData {
 
 impl StaticData {
     pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> {
-        let node = konst.lookup(db);
-        let item_tree = node.id.item_tree(db);
-        let statik = &item_tree[node.id.value];
+        let loc = konst.lookup(db);
+        let item_tree = loc.id.item_tree(db);
+        let statik = &item_tree[loc.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: statik.is_extern,
+            is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
         })
     }
 }
@@ -302,7 +306,7 @@ fn collect_items(
     expander: &mut Expander,
     assoc_items: impl Iterator<Item = AssocItem>,
     tree_id: item_tree::TreeId,
-    container: AssocContainerId,
+    container: ItemContainerId,
     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 c977971cd4..7946558311 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, 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, ExternBlockId,
+    ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId,
+    LocalFieldId, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId,
+    TypeAliasLoc, UnionId, UnionLoc, VariantId,
 };
 
 #[salsa::query_group(InternDatabaseStorage)]
@@ -46,6 +46,8 @@ 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 404e3e1539..27a05b87c1 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, AssocContainerId, Lookup};
+    use crate::{test_db::TestDB, ItemContainerId, Lookup};
 
     use super::*;
 
@@ -563,7 +563,7 @@ mod tests {
         };
 
         match container {
-            AssocContainerId::TraitId(it) => Some(ItemInNs::Types(it.into())),
+            ItemContainerId::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 aab3f4b3c8..405cc2d00f 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -660,8 +660,6 @@ 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>,
 }
@@ -695,7 +693,6 @@ 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 32213aac39..e9af991785 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -360,7 +360,6 @@ impl<'a> Ctx<'a> {
             generic_params,
             type_ref,
             ast_id,
-            is_extern: false,
         };
         Some(id(self.data().type_aliases.alloc(res)))
     }
@@ -371,7 +370,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, is_extern: false };
+        let res = Static { name, visibility, mutable, type_ref, ast_id };
         Some(id(self.data().statics.alloc(res)))
     }
 
@@ -525,27 +524,23 @@ 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) => {
-                            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::Static(ast) => self.lower_static(&ast)?.into(),
+                        ast::ExternItem::TypeAlias(ty) => self.lower_type_alias(&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 49dc1eef18..4b46283743 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -328,8 +328,7 @@ impl<'a> Printer<'a> {
                 wln!(self, " = _;");
             }
             ModItem::Static(it) => {
-                let Static { name, visibility, mutable, is_extern, type_ref, ast_id: _ } =
-                    &self.tree[it];
+                let Static { name, visibility, mutable, type_ref, ast_id: _ } = &self.tree[it];
                 self.print_visibility(*visibility);
                 w!(self, "static ");
                 if *mutable {
@@ -338,9 +337,6 @@ 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) => {
@@ -393,15 +389,8 @@ impl<'a> Printer<'a> {
                 wln!(self, "}}");
             }
             ModItem::TypeAlias(it) => {
-                let TypeAlias {
-                    name,
-                    visibility,
-                    bounds,
-                    type_ref,
-                    is_extern,
-                    generic_params,
-                    ast_id: _,
-                } = &self.tree[it];
+                let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id: _ } =
+                    &self.tree[it];
                 self.print_visibility(*visibility);
                 w!(self, "type {}", name);
                 self.print_generic_params(generic_params);
@@ -415,9 +404,6 @@ 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 b68ede4003..c8e60032df 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -65,6 +65,7 @@ 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;
@@ -153,7 +154,7 @@ impl<N: ItemTreeNode> Hash for ItemLoc<N> {
 
 #[derive(Debug)]
 pub struct AssocItemLoc<N: ItemTreeNode> {
-    pub container: AssocContainerId,
+    pub container: ItemContainerId,
     pub id: ItemTreeId<N>,
 }
 
@@ -244,7 +245,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 = ItemLoc<Static>;
+pub type StaticLoc = AssocItemLoc<Static>;
 impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -262,6 +263,11 @@ 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)]
@@ -295,12 +301,13 @@ pub struct ConstParamId {
 pub type LocalConstParamId = Idx<generics::ConstParamData>;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum AssocContainerId {
+pub enum ItemContainerId {
+    ExternBlockId(ExternBlockId),
     ModuleId(ModuleId),
     ImplId(ImplId),
     TraitId(TraitId),
 }
-impl_from!(ModuleId for AssocContainerId);
+impl_from!(ModuleId for ItemContainerId);
 
 /// A Data Type
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
@@ -427,6 +434,7 @@ pub enum AttrDefId {
     MacroDefId(MacroDefId),
     ImplId(ImplId),
     GenericParamId(GenericParamId),
+    ExternBlockId(ExternBlockId),
 }
 
 impl_from!(
@@ -445,12 +453,13 @@ impl_from!(
     for AttrDefId
 );
 
-impl From<AssocContainerId> for AttrDefId {
-    fn from(acid: AssocContainerId) -> Self {
+impl From<ItemContainerId> for AttrDefId {
+    fn from(acid: ItemContainerId) -> Self {
         match acid {
-            AssocContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
-            AssocContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
-            AssocContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
+            ItemContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
+            ItemContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
+            ItemContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
+            ItemContainerId::ExternBlockId(id) => AttrDefId::ExternBlockId(id),
         }
     }
 }
@@ -505,12 +514,13 @@ pub trait HasModule {
     fn module(&self, db: &dyn db::DefDatabase) -> ModuleId;
 }
 
-impl HasModule for AssocContainerId {
+impl HasModule for ItemContainerId {
     fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
         match *self {
-            AssocContainerId::ModuleId(it) => it,
-            AssocContainerId::ImplId(it) => it.lookup(db).container,
-            AssocContainerId::TraitId(it) => it.lookup(db).container,
+            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,
         }
     }
 }
@@ -587,12 +597,6 @@ 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).
     ///
@@ -604,7 +608,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).container,
+            ModuleDefId::StaticId(id) => id.lookup(db).module(db),
             ModuleDefId::TraitId(id) => id.lookup(db).container,
             ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db),
             ModuleDefId::BuiltinType(_) => return None,
@@ -625,6 +629,7 @@ 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 ad4a4aa752..8c0ba3c056 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, FunctionLoc, ImplLoc, Intern,
-    LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
-    UnresolvedMacro,
+    AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionLoc,
+    ImplLoc, Intern, ItemContainerId, LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc,
+    TypeAliasLoc, UnionLoc, UnresolvedMacro,
 };
 
 static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
@@ -213,6 +213,7 @@ struct MacroDirective {
     module_id: LocalModuleId,
     depth: usize,
     kind: MacroDirectiveKind,
+    container: ItemContainerId,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
@@ -306,7 +307,7 @@ impl DefCollector<'_> {
                 item_tree: &item_tree,
                 mod_dir: ModDir::root(),
             }
-            .collect(item_tree.top_level_items());
+            .collect_in_top_module(item_tree.top_level_items());
         }
     }
 
@@ -327,7 +328,7 @@ impl DefCollector<'_> {
                 item_tree: &item_tree,
                 mod_dir: ModDir::root(),
             }
-            .collect(item_tree.top_level_items());
+            .collect_in_top_module(item_tree.top_level_items());
         }
     }
 
@@ -433,7 +434,7 @@ impl DefCollector<'_> {
                     item_tree: &item_tree,
                     mod_dir,
                 }
-                .collect(&[*mod_item]);
+                .collect(&[*mod_item], directive.container);
                 true
             } else {
                 false
@@ -1053,7 +1054,12 @@ impl DefCollector<'_> {
                         &mut |_err| (),
                     );
                     if let Ok(Ok(call_id)) = call_id {
-                        resolved.push((directive.module_id, call_id, directive.depth));
+                        resolved.push((
+                            directive.module_id,
+                            call_id,
+                            directive.depth,
+                            directive.container,
+                        ));
                         res = ReachedFixedPoint::No;
                         return false;
                     }
@@ -1073,7 +1079,12 @@ impl DefCollector<'_> {
                             *derive_attr,
                         );
 
-                        resolved.push((directive.module_id, call_id, directive.depth));
+                        resolved.push((
+                            directive.module_id,
+                            call_id,
+                            directive.depth,
+                            directive.container,
+                        ));
                         res = ReachedFixedPoint::No;
                         return false;
                     }
@@ -1096,7 +1107,7 @@ impl DefCollector<'_> {
                             item_tree: &item_tree,
                             mod_dir,
                         }
-                        .collect(&[*mod_item]);
+                        .collect(&[*mod_item], directive.container);
                         res = ReachedFixedPoint::No;
                         false
                     };
@@ -1144,6 +1155,7 @@ impl DefCollector<'_> {
                                             ast_id,
                                             derive_attr: attr.id,
                                         },
+                                        container: directive.container,
                                     });
                                 }
                             }
@@ -1199,7 +1211,12 @@ impl DefCollector<'_> {
                                 .scope
                                 .add_attr_macro_invoc(ast_id, call_id);
 
-                            resolved.push((directive.module_id, call_id, directive.depth));
+                            resolved.push((
+                                directive.module_id,
+                                call_id,
+                                directive.depth,
+                                directive.container,
+                            ));
                             res = ReachedFixedPoint::No;
                             return false;
                         }
@@ -1213,8 +1230,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) in resolved {
-            self.collect_macro_expansion(module_id, macro_call_id, depth);
+        for (module_id, macro_call_id, depth, container) in resolved {
+            self.collect_macro_expansion(module_id, macro_call_id, depth, container);
         }
 
         res
@@ -1225,6 +1242,7 @@ 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);
@@ -1276,7 +1294,7 @@ impl DefCollector<'_> {
             item_tree: &item_tree,
             mod_dir,
         }
-        .collect(item_tree.top_level_items());
+        .collect(item_tree.top_level_items(), container);
     }
 
     fn finish(mut self) -> DefMap {
@@ -1372,7 +1390,12 @@ struct ModCollector<'a, 'b> {
 }
 
 impl ModCollector<'_, '_> {
-    fn collect(&mut self, items: &[ModItem]) {
+    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) {
         struct DefData<'a> {
             id: ModuleDefId,
             name: &'a Name,
@@ -1423,7 +1446,7 @@ impl ModCollector<'_, '_> {
                 }
             }
 
-            if let Err(()) = self.resolve_attributes(&attrs, item) {
+            if let Err(()) = self.resolve_attributes(&attrs, item, container) {
                 // 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;
@@ -1462,8 +1485,17 @@ impl ModCollector<'_, '_> {
                         status: PartialResolvedImport::Unresolved,
                     })
                 }
-                ModItem::ExternBlock(block) => self.collect(&self.item_tree[block].children),
-                ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]),
+                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::MacroRules(id) => self.collect_macro_rules(id),
                 ModItem::MacroDef(id) => self.collect_macro_def(id),
                 ModItem::Impl(imp) => {
@@ -1480,12 +1512,9 @@ impl ModCollector<'_, '_> {
                     self.collect_proc_macro_def(&func.name, ast_id, &attrs);
 
                     def = Some(DefData {
-                        id: FunctionLoc {
-                            container: module.into(),
-                            id: ItemTreeId::new(self.tree_id, id),
-                        }
-                        .intern(self.def_collector.db)
-                        .into(),
+                        id: FunctionLoc { container, 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,
@@ -1529,11 +1558,8 @@ impl ModCollector<'_, '_> {
                 }
                 ModItem::Const(id) => {
                     let it = &self.item_tree[id];
-                    let const_id = ConstLoc {
-                        container: module.into(),
-                        id: ItemTreeId::new(self.tree_id, id),
-                    }
-                    .intern(self.def_collector.db);
+                    let const_id = ConstLoc { container, id: ItemTreeId::new(self.tree_id, id) }
+                        .intern(self.def_collector.db);
 
                     match &it.name {
                         Some(name) => {
@@ -1556,7 +1582,7 @@ impl ModCollector<'_, '_> {
                     let it = &self.item_tree[id];
 
                     def = Some(DefData {
-                        id: StaticLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
+                        id: StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) }
                             .intern(self.def_collector.db)
                             .into(),
                         name: &it.name,
@@ -1580,12 +1606,9 @@ impl ModCollector<'_, '_> {
                     let it = &self.item_tree[id];
 
                     def = Some(DefData {
-                        id: TypeAliasLoc {
-                            container: module.into(),
-                            id: ItemTreeId::new(self.tree_id, id),
-                        }
-                        .intern(self.def_collector.db)
-                        .into(),
+                        id: TypeAliasLoc { container, 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,
@@ -1633,7 +1656,7 @@ impl ModCollector<'_, '_> {
                         item_tree: self.item_tree,
                         mod_dir,
                     }
-                    .collect(&*items);
+                    .collect_in_top_module(&*items);
                     if is_macro_use {
                         self.import_all_legacy_macros(module_id);
                     }
@@ -1666,7 +1689,7 @@ impl ModCollector<'_, '_> {
                                 item_tree: &item_tree,
                                 mod_dir,
                             }
-                            .collect(item_tree.top_level_items());
+                            .collect_in_top_module(item_tree.top_level_items());
                             let is_macro_use = is_macro_use
                                 || item_tree
                                     .top_level_attrs(db, self.def_collector.def_map.krate)
@@ -1734,7 +1757,12 @@ 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) -> Result<(), ()> {
+    fn resolve_attributes(
+        &mut self,
+        attrs: &Attrs,
+        mod_item: ModItem,
+        container: ItemContainerId,
+    ) -> Result<(), ()> {
         let mut ignore_up_to =
             self.def_collector.skip_attrs.get(&InFile::new(self.file_id(), mod_item)).copied();
         let iter = attrs
@@ -1777,6 +1805,7 @@ impl ModCollector<'_, '_> {
                     mod_item,
                     tree: self.tree_id,
                 },
+                container,
             });
 
             return Err(());
@@ -1951,7 +1980,7 @@ impl ModCollector<'_, '_> {
         );
     }
 
-    fn collect_macro_call(&mut self, mac: &MacroCall) {
+    fn collect_macro_call(&mut self, mac: &MacroCall, container: ItemContainerId) {
         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
@@ -1981,6 +2010,7 @@ impl ModCollector<'_, '_> {
                     self.module_id,
                     macro_call_id,
                     self.macro_depth + 1,
+                    container,
                 );
 
                 if let Some(err) = error {
@@ -2011,6 +2041,7 @@ 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 0cf28acf7f..8b2eea9d58 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, AssocContainerId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId,
-    EnumVariantId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, LifetimeParamId,
+    AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId,
+    FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
     LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
     TypeParamId, VariantId,
 };
@@ -802,6 +802,13 @@ 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 {
@@ -812,12 +819,13 @@ impl HasResolver for DefWithBodyId {
     }
 }
 
-impl HasResolver for AssocContainerId {
+impl HasResolver for ItemContainerId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         match self {
-            AssocContainerId::ModuleId(it) => it.resolver(db),
-            AssocContainerId::TraitId(it) => it.resolver(db),
-            AssocContainerId::ImplId(it) => it.resolver(db),
+            ItemContainerId::ModuleId(it) => it.resolver(db),
+            ItemContainerId::TraitId(it) => it.resolver(db),
+            ItemContainerId::ImplId(it) => it.resolver(db),
+            ItemContainerId::ExternBlockId(it) => it.resolver(db),
         }
     }
 }
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index f58339286f..dc5dcd163c 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},
-    AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, ModuleId, TypeAliasId,
+    AssocItemId, GenericDefId, HasModule, ItemContainerId, 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 {
-        AssocContainerId::TraitId(t) => t,
+        ItemContainerId::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 {
-        AssocContainerId::ImplId(it) => it,
+        ItemContainerId::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 36c56820eb..653c4d5ec8 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,
-    AssocContainerId, FunctionId, GenericDefId, HasModule, Lookup, TraitId,
+    FunctionId, GenericDefId, HasModule, ItemContainerId, 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 {
-                    AssocContainerId::TraitId(trait_id) => Some(trait_id),
+                    ItemContainerId::TraitId(trait_id) => Some(trait_id),
                     _ => None,
                 }
             }
@@ -277,7 +277,7 @@ impl TyExt for Ty {
                     .lookup(db.upcast())
                     .container
                 {
-                    AssocContainerId::TraitId(trait_id) => Some(trait_id),
+                    ItemContainerId::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 {
-            AssocContainerId::TraitId(it) => it,
+            ItemContainerId::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 6a3588dc74..a1e7198bc2 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -178,6 +178,7 @@ 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 e2b4e92575..307323690a 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,
-    AssocContainerId, HasModule, Lookup, ModuleId, TraitId,
+    HasModule, ItemContainerId, 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 {
-                    AssocContainerId::TraitId(it) => it,
+                    ItemContainerId::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 d07a939583..56e554736e 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::AssocContainerId::TraitId(trait_) => trait_,
+                    hir_def::ItemContainerId::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 5fb227c0e4..90c68c9d3f 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,
-    AssocContainerId, FieldId, FunctionId, Lookup,
+    FieldId, FunctionId, ItemContainerId, Lookup,
 };
 use hir_expand::name::{name, Name};
 use stdx::always;
@@ -1167,8 +1167,7 @@ impl<'a> InferenceContext<'a> {
             // add obligation for trait implementation, if this is a trait method
             match def {
                 CallableDefId::FunctionId(f) => {
-                    if let AssocContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container
-                    {
+                    if let ItemContainerId::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 056cdb5d5b..a84501fa54 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, AssocContainerId, AssocItemId, EnumVariantId, Lookup,
+    AdtId, AssocItemId, EnumVariantId, ItemContainerId, Lookup,
 };
 use hir_expand::name::Name;
 
@@ -241,7 +241,7 @@ impl<'a> InferenceContext<'a> {
                     AssocItemId::TypeAliasId(_) => unreachable!(),
                 };
                 let substs = match container {
-                    AssocContainerId::ImplId(impl_id) => {
+                    ItemContainerId::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)
                     }
-                    AssocContainerId::TraitId(trait_) => {
+                    ItemContainerId::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)
                     }
-                    AssocContainerId::ModuleId(_) => None,
+                    ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
                 };
 
                 self.write_assoc_resolution(id, item);
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index af1d5fdb6a..99267e085f 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, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
-    GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
+    AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
+    HasModule, ImplId, ItemContainerId, 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<AssocContainerId> = match def {
+    let container: Option<ItemContainerId> = 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(AssocContainerId::TraitId(trait_id)) = container {
+    if let Some(ItemContainerId::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 8e19928746..6b3f48b194 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, AssocContainerId, AssocItemId, BlockId, FunctionId,
-    GenericDefId, HasModule, ImplId, Lookup, ModuleId, TraitId,
+    lang_item::LangItemTarget, nameres::DefMap, AssocItemId, BlockId, FunctionId, GenericDefId,
+    HasModule, ImplId, ItemContainerId, Lookup, ModuleId, TraitId,
 };
 use hir_expand::name::Name;
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -979,18 +979,19 @@ fn transform_receiver_ty(
     self_ty: &Canonical<Ty>,
 ) -> Option<Ty> {
     let substs = match function_id.lookup(db.upcast()).container {
-        AssocContainerId::TraitId(_) => TyBuilder::subst_for_def(db, function_id)
+        ItemContainerId::TraitId(_) => TyBuilder::subst_for_def(db, function_id)
             .push(self_ty.value.clone())
             .fill_with_unknown()
             .build(),
-        AssocContainerId::ImplId(impl_id) => {
+        ItemContainerId::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()
         }
-        AssocContainerId::ModuleId(_) => unreachable!(),
+        // No receiver
+        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => 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 6a662dcf7b..18a07f2c64 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, AssocContainerId, Lookup, TypeAliasId};
+use hir_def::{AdtId, ItemContainerId, 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 {
-            AssocContainerId::TraitId(t) => t,
+            ItemContainerId::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 {
-            AssocContainerId::TraitId(t) => t,
+            ItemContainerId::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 0037849d1c..a0837377c6 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},
-    AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId,
+    GenericDefId, ItemContainerId, 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 {
-        AssocContainerId::ImplId(it) => Some(it.into()),
-        AssocContainerId::TraitId(it) => Some(it.into()),
-        AssocContainerId::ModuleId(_) => None,
+        ItemContainerId::ImplId(it) => Some(it.into()),
+        ItemContainerId::TraitId(it) => Some(it.into()),
+        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
     }
 }
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs
index e8c6ec3e0e..62f4a81910 100644
--- a/crates/ide_db/src/symbol_index.rs
+++ b/crates/ide_db/src/symbol_index.rs
@@ -36,8 +36,8 @@ use either::Either;
 use fst::{self, Streamer};
 use hir::{
     db::{DefDatabase, HirDatabase},
-    AdtId, AssocContainerId, AssocItemId, AssocItemLoc, DefHasSource, DefWithBodyId, HasSource,
-    HirFileId, ImplId, InFile, ItemLoc, ItemTreeNode, Lookup, MacroDef, Module, ModuleDefId,
+    AdtId, AssocItemId, AssocItemLoc, DefHasSource, DefWithBodyId, HasSource, HirFileId, ImplId,
+    InFile, ItemContainerId, ItemLoc, ItemTreeNode, Lookup, MacroDef, Module, ModuleDefId,
     ModuleId, Semantics, TraitId,
 };
 use rayon::prelude::*;
@@ -508,7 +508,7 @@ impl<'a> SymbolCollector<'a> {
                     self.collect_from_body(id);
                 }
                 ModuleDefId::StaticId(id) => {
-                    self.push_decl(id, FileSymbolKind::Static);
+                    self.push_decl_assoc(id, FileSymbolKind::Static);
                     self.collect_from_body(id);
                 }
                 ModuleDefId::TraitId(id) => {
@@ -610,17 +610,17 @@ impl<'a> SymbolCollector<'a> {
         T: ItemTreeNode,
         <T as ItemTreeNode>::Source: HasName,
     {
-        fn container_name(db: &dyn HirDatabase, container: AssocContainerId) -> Option<SmolStr> {
+        fn container_name(db: &dyn HirDatabase, container: ItemContainerId) -> Option<SmolStr> {
             match container {
-                AssocContainerId::ModuleId(module_id) => {
+                ItemContainerId::ModuleId(module_id) => {
                     let module = Module::from(module_id);
                     module.name(db).and_then(|name| name.as_text())
                 }
-                AssocContainerId::TraitId(trait_id) => {
+                ItemContainerId::TraitId(trait_id) => {
                     let trait_data = db.trait_data(trait_id);
                     trait_data.name.as_text()
                 }
-                AssocContainerId::ImplId(_) => None,
+                ItemContainerId::ImplId(_) | ItemContainerId::ExternBlockId(_) => None,
             }
         }
 
diff --git a/crates/ide_diagnostics/src/handlers/incorrect_case.rs b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
index 6990b19cf3..3206a63a90 100644
--- a/crates/ide_diagnostics/src/handlers/incorrect_case.rs
+++ b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
@@ -397,6 +397,24 @@ 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


Test patch:
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index 7671ccefd1..1969913bf9 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;  // extern
+                pub(self) type ExType;
 
                 #[on_extern_static]  // AttrId { is_doc_comment: false, ast_index: 0 }
-                pub(self) static EX_STATIC: u8 = _;  // extern
+                pub(self) static EX_STATIC: u8 = _;
 
                 #[on_extern_fn]  // AttrId { is_doc_comment: false, ast_index: 0 }
-                // flags = 0x60
+                // flags = 0x20
                 pub(self) fn ex_fn() -> ();
             }
         "##]],