Repository: rust-analyzer/rust-analyzer
Pull request #11800 (2022-03-23 13:34:34)

fix: fix `#[macro_use]` no longer importing non-`macro_rules!` macros
https://github.com/rust-analyzer/rust-analyzer/pull/11663 introduced a regression tracked in https://github.com/rust-analyzer/rust-analyzer/issues/11781, this fixes it.

Fixes https://github.com/rust-analyzer/rust-analyzer/issues/11781

bors r+


Patch:
diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs
index 858293a345..bdb8c7552d 100644
--- a/crates/hir/src/symbols.rs
+++ b/crates/hir/src/symbols.rs
@@ -3,7 +3,7 @@
 use base_db::FileRange;
 use hir_def::{
     item_tree::ItemTreeNode, src::HasSource, AdtId, AssocItemId, AssocItemLoc, DefWithBodyId,
-    ImplId, ItemContainerId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId,
+    HasModule, ImplId, ItemContainerId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId,
 };
 use hir_expand::{HirFileId, InFile};
 use hir_ty::db::HirDatabase;
@@ -176,9 +176,12 @@ impl<'a> SymbolCollector<'a> {
         }
 
         for (_, id) in scope.legacy_macros() {
-            let loc = id.lookup(self.db.upcast());
-            if loc.container == module_id {
-                self.push_decl(id, FileSymbolKind::Macro);
+            if id.module(self.db.upcast()) == module_id {
+                match id {
+                    MacroId::Macro2Id(id) => self.push_decl(id, FileSymbolKind::Macro),
+                    MacroId::MacroRulesId(id) => self.push_decl(id, FileSymbolKind::Macro),
+                    MacroId::ProcMacroId(id) => self.push_decl(id, FileSymbolKind::Macro),
+                }
             }
         }
     }
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index 6a2212f199..b1337ecc24 100644
--- a/crates/hir_def/src/child_by_source.rs
+++ b/crates/hir_def/src/child_by_source.rs
@@ -103,9 +103,11 @@ impl ChildBySource for ItemScope {
             },
         );
         self.legacy_macros().for_each(|(_, id)| {
-            let loc = id.lookup(db);
-            if loc.id.file_id() == file_id {
-                res[keys::MACRO_RULES].insert(loc.source(db).value, id);
+            if let MacroId::MacroRulesId(id) = id {
+                let loc = id.lookup(db);
+                if loc.id.file_id() == file_id {
+                    res[keys::MACRO_RULES].insert(loc.source(db).value, id);
+                }
             }
         });
         self.derive_macro_invocs().filter(|(id, _)| id.file_id == file_id).for_each(
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index 0096df2288..ddccbbfef9 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -14,8 +14,7 @@ use syntax::ast;
 
 use crate::{
     attr::AttrId, db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType,
-    ConstId, HasModule, ImplId, LocalModuleId, MacroId, MacroRulesId, ModuleDefId, ModuleId,
-    TraitId,
+    ConstId, HasModule, ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId,
 };
 
 #[derive(Copy, Clone)]
@@ -62,7 +61,7 @@ pub struct ItemScope {
     /// Module scoped macros will be inserted into `items` instead of here.
     // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
     // be all resolved to the last one defined if shadowing happens.
-    legacy_macros: FxHashMap<Name, MacroRulesId>,
+    legacy_macros: FxHashMap<Name, MacroId>,
     /// The derive macro invocations in this scope.
     attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
     /// The derive macro invocations in this scope, keyed by the owner item over the actual derive attributes
@@ -135,7 +134,7 @@ impl ItemScope {
     }
 
     /// Iterate over all legacy textual scoped macros visible at the end of the module
-    pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroRulesId)> + 'a {
+    pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroId)> + 'a {
         self.legacy_macros.iter().map(|(name, def)| (name, *def))
     }
 
@@ -181,7 +180,7 @@ impl ItemScope {
         self.declarations.push(def)
     }
 
-    pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroRulesId> {
+    pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroId> {
         self.legacy_macros.get(name).copied()
     }
 
@@ -193,7 +192,7 @@ impl ItemScope {
         self.unnamed_consts.push(konst);
     }
 
-    pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroRulesId) {
+    pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroId) {
         self.legacy_macros.insert(name, mac);
     }
 
@@ -323,7 +322,7 @@ impl ItemScope {
         )
     }
 
-    pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroRulesId> {
+    pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroId> {
         self.legacy_macros.clone()
     }
 
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index ea29f80437..4660ccf500 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -610,7 +610,7 @@ impl DefCollector<'_> {
         export: bool,
     ) {
         // Textual scoping
-        self.define_legacy_macro(module_id, name.clone(), macro_);
+        self.define_legacy_macro(module_id, name.clone(), macro_.into());
 
         // Module scoping
         // In Rust, `#[macro_export]` macros are unconditionally visible at the
@@ -634,7 +634,7 @@ impl DefCollector<'_> {
     /// the definition of current module.
     /// And also, `macro_use` on a module will import all legacy macros visible inside to
     /// current legacy scope, with possible shadowing.
-    fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroRulesId) {
+    fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroId) {
         // Always shadowing
         self.def_map.modules[module_id].scope.define_legacy_macro(name, mac);
     }
@@ -706,10 +706,8 @@ impl DefCollector<'_> {
     fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) {
         let def_map = self.db.crate_def_map(krate);
         for (name, def) in def_map[def_map.root].scope.macros() {
-            if let MacroId::MacroRulesId(def) = def {
-                // `macro_use` only bring things into legacy scope.
-                self.define_legacy_macro(current_module_id, name.clone(), def);
-            }
+            // `#[macro_use]` brings macros into legacy scope. Yes, even non-`macro_rules!` macros.
+            self.define_legacy_macro(current_module_id, name.clone(), def);
         }
     }
 


Test patch:
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs
index 222e524d6c..411840ccbc 100644
--- a/crates/hir_def/src/nameres/tests/macros.rs
+++ b/crates/hir_def/src/nameres/tests/macros.rs
@@ -1143,3 +1143,40 @@ struct A;
         "#]],
     );
 }
+
+#[test]
+fn macro_use_imports_all_macro_types() {
+    let def_map = compute_crate_def_map(
+        r#"
+//- /main.rs crate:main deps:lib
+#[macro_use]
+extern crate lib;
+
+//- /lib.rs crate:lib deps:proc
+pub use proc::*;
+
+#[macro_export]
+macro_rules! legacy { () => () }
+
+pub macro macro20 {}
+
+//- /proc.rs crate:proc
+#![crate_type="proc-macro"]
+
+struct TokenStream;
+
+#[proc_macro_attribute]
+fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
+    "#,
+    );
+
+    let root = &def_map[def_map.root()].scope;
+    let actual = root.legacy_macros().map(|(name, _)| format!("{name}\n")).collect::<String>();
+
+    expect![[r#"
+        macro20
+        legacy
+        proc_attr
+    "#]]
+    .assert_eq(&actual);
+}