diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index 2e1d35c8cb..fe119b97c5 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs @@ -12,4 +12,5 @@ test_utils::marks!( trait_resolution_on_fn_type infer_while_let macro_rules_from_other_crates_are_visible_with_macro_use + prelude_is_macro_use ); diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index d6c7c083dc..5af26f953a 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -183,11 +183,14 @@ where if let Some(ModuleDef::Module(m)) = res.take_types() { tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); + self.import_all_macros_exported(m); + } + } - let item_map = self.db.crate_def_map(m.krate); - for (name, ¯o_id) in &item_map.exported_macros { - self.global_macro_scope.insert(name.clone(), macro_id); - } + fn import_all_macros_exported(&mut self, module: Module) { + let item_map = self.db.crate_def_map(module.krate); + for (name, ¯o_id) in &item_map.exported_macros { + self.global_macro_scope.insert(name.clone(), macro_id); } } @@ -520,20 +523,32 @@ where DB: DefDatabase, { fn collect(&mut self, items: &[raw::RawItem]) { + // Prelude module is always considered to be `#[macro_use]`. + if let Some(prelude_module) = self.def_collector.def_map.prelude { + tested_by!(prelude_is_macro_use); + self.def_collector.import_all_macros_exported(prelude_module); + } + + // This should be processed eagerly instead of deferred to resolving. + // `#[macro_use] extern crate` is hoisted to imports macros before collecting + // any other items. + for item in items { + if let raw::RawItem::Import(import_id) = *item { + let import = self.raw_items[import_id].clone(); + if import.is_extern_crate && import.is_macro_use { + self.def_collector.import_macros_from_extern_crate(&import); + } + } + } + for item in items { match *item { raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), - raw::RawItem::Import(import_id) => { - let import = self.raw_items[import_id].clone(); - // This should be processed eagerly instead of deferred to resolving. - // Otherwise, since it will only mutate `global_macro_scope` - // without `update` names in `mod`s, unresolved macros cannot be expanded. - if import.is_extern_crate && import.is_macro_use { - self.def_collector.import_macros_from_extern_crate(&import); - } - - self.def_collector.unresolved_imports.push((self.module_id, import_id, import)); - } + raw::RawItem::Import(import_id) => self.def_collector.unresolved_imports.push(( + self.module_id, + import_id, + self.raw_items[import_id].clone(), + )), raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), } diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index ebfefe273f..aece1515b5 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs @@ -144,9 +144,6 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { let map = def_map_with_crate_graph( " //- /main.rs - #[macro_use] - extern crate foo; - structs!(Foo); structs_priv!(Bar); structs_not_exported!(MacroNotResolved1); @@ -154,6 +151,9 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { mod bar; + #[macro_use] + extern crate foo; + //- /bar.rs structs!(Baz); crate::structs!(MacroNotResolved3); @@ -191,3 +191,60 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { ⋮Baz: t v "###); } + +#[test] +fn prelude_is_macro_use() { + covers!(prelude_is_macro_use); + let map = def_map_with_crate_graph( + " + //- /main.rs + structs!(Foo); + structs_priv!(Bar); + structs_outside!(Out); + crate::structs!(MacroNotResolved2); + + mod bar; + + //- /bar.rs + structs!(Baz); + crate::structs!(MacroNotResolved3); + + //- /lib.rs + #[prelude_import] + use self::prelude::*; + + mod prelude { + #[macro_export] + macro_rules! structs { + ($i:ident) => { struct $i; } + } + + mod priv_mod { + #[macro_export] + macro_rules! structs_priv { + ($i:ident) => { struct $i; } + } + } + } + + #[macro_export] + macro_rules! structs_outside { + ($i:ident) => { struct $i; } + } + ", + crate_graph! { + "main": ("/main.rs", ["foo"]), + "foo": ("/lib.rs", []), + }, + ); + assert_snapshot!(map, @r###" + ⋮crate + ⋮Bar: t v + ⋮Foo: t v + ⋮Out: t v + ⋮bar: t + ⋮ + ⋮crate::bar + ⋮Baz: t v + "###); +}