From f5bea9051b81f3a490c08afdb336c63c9180aae0 Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Fri, 30 Aug 2019 01:56:00 +0800 Subject: Support resolution of `#[macro_use] extern crate` --- crates/ra_hir/src/nameres/collector.rs | 17 +++++++++++++++++ crates/ra_hir/src/nameres/raw.rs | 13 +++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir/src/nameres') diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 7da2dcdff..26158b5c3 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -295,6 +295,23 @@ where } } + // `#[macro_use] extern crate` glob import macros + if import.is_extern_crate && import.is_macro_use { + if let Some(ModuleDef::Module(m)) = + def.a().and_then(|item| item.take_types()) + { + let item_map = self.db.crate_def_map(m.krate); + let scope = &item_map[m.module_id].scope; + let macros = scope + .macros + .iter() + .map(|(name, res)| (name.clone(), Either::B(*res))) + .collect::>(); + + self.update(module_id, Some(import_id), ¯os); + } + } + let resolution = match def { Either::A(item) => { Either::A(Resolution { def: item, import: Some(import_id) }) diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index 2f973359f..129b047eb 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs @@ -154,6 +154,7 @@ pub struct ImportData { pub(super) is_glob: bool, pub(super) is_prelude: bool, pub(super) is_extern_crate: bool, + pub(super) is_macro_use: bool, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -293,8 +294,14 @@ impl RawItemsCollector { let is_prelude = use_item.has_atom_attr("prelude_import"); Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| { - let import_data = - ImportData { path, alias, is_glob, is_prelude, is_extern_crate: false }; + let import_data = ImportData { + path, + alias, + is_glob, + is_prelude, + is_extern_crate: false, + is_macro_use: false, + }; self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); }) } @@ -307,12 +314,14 @@ impl RawItemsCollector { if let Some(name_ref) = extern_crate.name_ref() { let path = Path::from_name_ref(&name_ref); let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); + let is_macro_use = extern_crate.has_atom_attr("macro_use"); let import_data = ImportData { path, alias, is_glob: false, is_prelude: false, is_extern_crate: true, + is_macro_use, }; self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate))); } -- cgit v1.2.3 From dfa758f6a9146fbcb5109e7294d0a8e561c77913 Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Fri, 30 Aug 2019 02:01:26 +0800 Subject: Add test --- crates/ra_hir/src/nameres/tests/macros.rs | 55 ++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 5 deletions(-) (limited to 'crates/ra_hir/src/nameres') diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index 631df2cef..a8ee0ba28 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs @@ -99,14 +99,14 @@ fn macro_rules_from_other_crates_are_visible() { fn unexpanded_macro_should_expand_by_fixedpoint_loop() { let map = def_map_with_crate_graph( " - //- /main.rs + //- /main.rs macro_rules! baz { () => { - use foo::bar; + use foo::bar; } } - - foo!(); + + foo!(); bar!(); baz!(); @@ -114,7 +114,7 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { #[macro_export] macro_rules! foo { () => { - struct Foo { field: u32 } + struct Foo { field: u32 } } } #[macro_export] @@ -137,3 +137,48 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { ⋮foo: m "###); } + +#[test] +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, Bar) + + mod bar; + + //- /bar.rs + use crate::*; + + //- /lib.rs + #[macro_export] + macro_rules! structs { + ($($i:ident),*) => { + $(struct $i { field: u32 } )* + } + } + ", + crate_graph! { + "main": ("/main.rs", ["foo"]), + "foo": ("/lib.rs", []), + }, + ); + assert_snapshot!(map, @r###" + ⋮crate + ⋮Bar: t v + ⋮Foo: t v + ⋮bar: t + ⋮foo: t + ⋮structs: m + ⋮ + ⋮crate::bar + ⋮Bar: t v + ⋮Foo: t v + ⋮bar: t + ⋮foo: t + ⋮structs: m + "###); +} -- cgit v1.2.3 From a66214b34effe1ad7f4351a1b920cf3a8f98d3c0 Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Mon, 2 Sep 2019 14:36:20 +0800 Subject: Fix import strategy of `macro_use` and its test --- crates/ra_hir/src/nameres/collector.rs | 21 ++++++++++++--------- crates/ra_hir/src/nameres/tests/macros.rs | 10 ++++++++++ 2 files changed, 22 insertions(+), 9 deletions(-) (limited to 'crates/ra_hir/src/nameres') diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 26158b5c3..dbd687236 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -157,6 +157,10 @@ where // crate root, even if the parent modules is **not** visible. if export { self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); + + // Exported macros are collected in crate level ready for + // glob import with `#[macro_use]`. + self.def_map.exported_macros.insert(name.clone(), macro_id); } self.update(module_id, None, &[(name.clone(), def)]); self.global_macro_scope.insert(name, macro_id); @@ -295,20 +299,18 @@ where } } - // `#[macro_use] extern crate` glob import macros + // `#[macro_use] extern crate` glob imports all macros exported, + // ignoring their scopes if import.is_extern_crate && import.is_macro_use { if let Some(ModuleDef::Module(m)) = def.a().and_then(|item| item.take_types()) { + tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); + let item_map = self.db.crate_def_map(m.krate); - let scope = &item_map[m.module_id].scope; - let macros = scope - .macros - .iter() - .map(|(name, res)| (name.clone(), Either::B(*res))) - .collect::>(); - - self.update(module_id, Some(import_id), ¯os); + for (name, ¯o_id) in &item_map.exported_macros { + self.define_macro(module_id, name.clone(), macro_id, false); + } } } @@ -877,6 +879,7 @@ mod tests { root, modules, poison_macros: FxHashSet::default(), + exported_macros: FxHashMap::default(), diagnostics: Vec::new(), } }; diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index a8ee0ba28..cfddf3029 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs @@ -140,6 +140,7 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { #[test] fn macro_rules_from_other_crates_are_visible_with_macro_use() { + covers!(macro_rules_from_other_crates_are_visible_with_macro_use); let map = def_map_with_crate_graph( " //- /main.rs @@ -160,6 +161,13 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { $(struct $i { field: u32 } )* } } + + mod priv_mod { + #[macro_export] + macro_rules! baz { + () => {}; + } + } ", crate_graph! { "main": ("/main.rs", ["foo"]), @@ -171,6 +179,7 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { ⋮Bar: t v ⋮Foo: t v ⋮bar: t + ⋮baz: m ⋮foo: t ⋮structs: m ⋮ @@ -178,6 +187,7 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { ⋮Bar: t v ⋮Foo: t v ⋮bar: t + ⋮baz: m ⋮foo: t ⋮structs: m "###); -- cgit v1.2.3 From 0d23286caf35a7cd8aed6e20fab3a2a3ed91ae8f Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Thu, 5 Sep 2019 11:35:13 +0800 Subject: Let `macro_use` bypass module scope --- crates/ra_hir/src/nameres/collector.rs | 58 ++++++++++++++++++++----------- crates/ra_hir/src/nameres/tests/macros.rs | 29 ++++++++-------- 2 files changed, 52 insertions(+), 35 deletions(-) (limited to 'crates/ra_hir/src/nameres') diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index dbd687236..5d1c42926 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -166,6 +166,33 @@ where self.global_macro_scope.insert(name, macro_id); } + /// Import macros from `#[macro_use] extern crate`. + /// + /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`. + fn import_macros_from_extern_crate(&mut self, import: &raw::ImportData) { + log::debug!( + "importing macros from extern crate: {:?} ({:?})", + import, + self.def_map.edition, + ); + + let res = self.def_map.resolve_name_in_extern_prelude( + &import + .path + .as_ident() + .expect("extern crate should have been desugared to one-element path"), + ); + + if let Some(ModuleDef::Module(m)) = res.take_types() { + tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); + + 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 resolve_imports(&mut self) -> ReachedFixedPoint { let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); let mut resolved = Vec::new(); @@ -299,21 +326,6 @@ where } } - // `#[macro_use] extern crate` glob imports all macros exported, - // ignoring their scopes - if import.is_extern_crate && import.is_macro_use { - if let Some(ModuleDef::Module(m)) = - def.a().and_then(|item| item.take_types()) - { - tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); - - let item_map = self.db.crate_def_map(m.krate); - for (name, ¯o_id) in &item_map.exported_macros { - self.define_macro(module_id, name.clone(), macro_id, false); - } - } - } - let resolution = match def { Either::A(item) => { Either::A(Resolution { def: item, import: Some(import_id) }) @@ -513,11 +525,17 @@ where for item in items { match *item { raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), - raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push(( - self.module_id, - import, - self.raw_items[import].clone(), - )), + 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::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 cfddf3029..ff762ee30 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs @@ -147,25 +147,31 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { #[macro_use] extern crate foo; - structs!(Foo, Bar) + structs!(Foo); + structs_priv!(Bar); + structs_not_exported!(MacroNotResolved1); + crates::structs!(MacroNotResolved2); mod bar; //- /bar.rs - use crate::*; + structs!(Baz); + crates::structs!(MacroNotResolved3); //- /lib.rs #[macro_export] macro_rules! structs { - ($($i:ident),*) => { - $(struct $i { field: u32 } )* - } + ($i:ident) => { struct $i; } + } + + macro_rules! structs_not_exported { + ($i:ident) => { struct $i; } } mod priv_mod { #[macro_export] - macro_rules! baz { - () => {}; + macro_rules! structs_priv { + ($i:ident) => { struct $i; } } } ", @@ -179,16 +185,9 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { ⋮Bar: t v ⋮Foo: t v ⋮bar: t - ⋮baz: m ⋮foo: t - ⋮structs: m ⋮ ⋮crate::bar - ⋮Bar: t v - ⋮Foo: t v - ⋮bar: t - ⋮baz: m - ⋮foo: t - ⋮structs: m + ⋮Baz: t v "###); } -- cgit v1.2.3 From 3ff5d7e73c65393672886de09738adf49cdd4984 Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Thu, 5 Sep 2019 12:03:32 +0800 Subject: Fix typo --- crates/ra_hir/src/nameres/tests/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir/src/nameres') diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index ff762ee30..ebfefe273 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs @@ -150,13 +150,13 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { structs!(Foo); structs_priv!(Bar); structs_not_exported!(MacroNotResolved1); - crates::structs!(MacroNotResolved2); + crate::structs!(MacroNotResolved2); mod bar; //- /bar.rs structs!(Baz); - crates::structs!(MacroNotResolved3); + crate::structs!(MacroNotResolved3); //- /lib.rs #[macro_export] -- cgit v1.2.3