diff options
-rw-r--r-- | crates/ra_hir/src/marks.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 48 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/raw.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/macros.rs | 64 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 1 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 1 |
7 files changed, 119 insertions, 12 deletions
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index 5b15eee90..2e1d35c8c 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs | |||
@@ -11,4 +11,5 @@ test_utils::marks!( | |||
11 | match_ergonomics_ref | 11 | match_ergonomics_ref |
12 | trait_resolution_on_fn_type | 12 | trait_resolution_on_fn_type |
13 | infer_while_let | 13 | infer_while_let |
14 | macro_rules_from_other_crates_are_visible_with_macro_use | ||
14 | ); | 15 | ); |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index bbdc606cd..f69179bf6 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -101,6 +101,8 @@ pub struct CrateDefMap { | |||
101 | /// However, do we want to put it as a global variable? | 101 | /// However, do we want to put it as a global variable? |
102 | poison_macros: FxHashSet<MacroDefId>, | 102 | poison_macros: FxHashSet<MacroDefId>, |
103 | 103 | ||
104 | exported_macros: FxHashMap<Name, MacroDefId>, | ||
105 | |||
104 | diagnostics: Vec<DefDiagnostic>, | 106 | diagnostics: Vec<DefDiagnostic>, |
105 | } | 107 | } |
106 | 108 | ||
@@ -245,6 +247,7 @@ impl CrateDefMap { | |||
245 | root, | 247 | root, |
246 | modules, | 248 | modules, |
247 | poison_macros: FxHashSet::default(), | 249 | poison_macros: FxHashSet::default(), |
250 | exported_macros: FxHashMap::default(), | ||
248 | diagnostics: Vec::new(), | 251 | diagnostics: Vec::new(), |
249 | } | 252 | } |
250 | }; | 253 | }; |
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 7da2dcdff..5d1c42926 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -157,11 +157,42 @@ where | |||
157 | // crate root, even if the parent modules is **not** visible. | 157 | // crate root, even if the parent modules is **not** visible. |
158 | if export { | 158 | if export { |
159 | self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); | 159 | self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); |
160 | |||
161 | // Exported macros are collected in crate level ready for | ||
162 | // glob import with `#[macro_use]`. | ||
163 | self.def_map.exported_macros.insert(name.clone(), macro_id); | ||
160 | } | 164 | } |
161 | self.update(module_id, None, &[(name.clone(), def)]); | 165 | self.update(module_id, None, &[(name.clone(), def)]); |
162 | self.global_macro_scope.insert(name, macro_id); | 166 | self.global_macro_scope.insert(name, macro_id); |
163 | } | 167 | } |
164 | 168 | ||
169 | /// Import macros from `#[macro_use] extern crate`. | ||
170 | /// | ||
171 | /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`. | ||
172 | fn import_macros_from_extern_crate(&mut self, import: &raw::ImportData) { | ||
173 | log::debug!( | ||
174 | "importing macros from extern crate: {:?} ({:?})", | ||
175 | import, | ||
176 | self.def_map.edition, | ||
177 | ); | ||
178 | |||
179 | let res = self.def_map.resolve_name_in_extern_prelude( | ||
180 | &import | ||
181 | .path | ||
182 | .as_ident() | ||
183 | .expect("extern crate should have been desugared to one-element path"), | ||
184 | ); | ||
185 | |||
186 | if let Some(ModuleDef::Module(m)) = res.take_types() { | ||
187 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); | ||
188 | |||
189 | let item_map = self.db.crate_def_map(m.krate); | ||
190 | for (name, ¯o_id) in &item_map.exported_macros { | ||
191 | self.global_macro_scope.insert(name.clone(), macro_id); | ||
192 | } | ||
193 | } | ||
194 | } | ||
195 | |||
165 | fn resolve_imports(&mut self) -> ReachedFixedPoint { | 196 | fn resolve_imports(&mut self) -> ReachedFixedPoint { |
166 | let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | 197 | let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); |
167 | let mut resolved = Vec::new(); | 198 | let mut resolved = Vec::new(); |
@@ -494,11 +525,17 @@ where | |||
494 | for item in items { | 525 | for item in items { |
495 | match *item { | 526 | match *item { |
496 | raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), | 527 | raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), |
497 | raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push(( | 528 | raw::RawItem::Import(import_id) => { |
498 | self.module_id, | 529 | let import = self.raw_items[import_id].clone(); |
499 | import, | 530 | // This should be processed eagerly instead of deferred to resolving. |
500 | self.raw_items[import].clone(), | 531 | // Otherwise, since it will only mutate `global_macro_scope` |
501 | )), | 532 | // without `update` names in `mod`s, unresolved macros cannot be expanded. |
533 | if import.is_extern_crate && import.is_macro_use { | ||
534 | self.def_collector.import_macros_from_extern_crate(&import); | ||
535 | } | ||
536 | |||
537 | self.def_collector.unresolved_imports.push((self.module_id, import_id, import)); | ||
538 | } | ||
502 | raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), | 539 | raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), |
503 | raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), | 540 | raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), |
504 | } | 541 | } |
@@ -860,6 +897,7 @@ mod tests { | |||
860 | root, | 897 | root, |
861 | modules, | 898 | modules, |
862 | poison_macros: FxHashSet::default(), | 899 | poison_macros: FxHashSet::default(), |
900 | exported_macros: FxHashMap::default(), | ||
863 | diagnostics: Vec::new(), | 901 | diagnostics: Vec::new(), |
864 | } | 902 | } |
865 | }; | 903 | }; |
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 { | |||
154 | pub(super) is_glob: bool, | 154 | pub(super) is_glob: bool, |
155 | pub(super) is_prelude: bool, | 155 | pub(super) is_prelude: bool, |
156 | pub(super) is_extern_crate: bool, | 156 | pub(super) is_extern_crate: bool, |
157 | pub(super) is_macro_use: bool, | ||
157 | } | 158 | } |
158 | 159 | ||
159 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 160 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -293,8 +294,14 @@ impl RawItemsCollector { | |||
293 | let is_prelude = use_item.has_atom_attr("prelude_import"); | 294 | let is_prelude = use_item.has_atom_attr("prelude_import"); |
294 | 295 | ||
295 | Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| { | 296 | Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| { |
296 | let import_data = | 297 | let import_data = ImportData { |
297 | ImportData { path, alias, is_glob, is_prelude, is_extern_crate: false }; | 298 | path, |
299 | alias, | ||
300 | is_glob, | ||
301 | is_prelude, | ||
302 | is_extern_crate: false, | ||
303 | is_macro_use: false, | ||
304 | }; | ||
298 | self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); | 305 | self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); |
299 | }) | 306 | }) |
300 | } | 307 | } |
@@ -307,12 +314,14 @@ impl RawItemsCollector { | |||
307 | if let Some(name_ref) = extern_crate.name_ref() { | 314 | if let Some(name_ref) = extern_crate.name_ref() { |
308 | let path = Path::from_name_ref(&name_ref); | 315 | let path = Path::from_name_ref(&name_ref); |
309 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); | 316 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); |
317 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); | ||
310 | let import_data = ImportData { | 318 | let import_data = ImportData { |
311 | path, | 319 | path, |
312 | alias, | 320 | alias, |
313 | is_glob: false, | 321 | is_glob: false, |
314 | is_prelude: false, | 322 | is_prelude: false, |
315 | is_extern_crate: true, | 323 | is_extern_crate: true, |
324 | is_macro_use, | ||
316 | }; | 325 | }; |
317 | self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate))); | 326 | self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate))); |
318 | } | 327 | } |
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index 631df2cef..ebfefe273 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() { | |||
99 | fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | 99 | fn unexpanded_macro_should_expand_by_fixedpoint_loop() { |
100 | let map = def_map_with_crate_graph( | 100 | let map = def_map_with_crate_graph( |
101 | " | 101 | " |
102 | //- /main.rs | 102 | //- /main.rs |
103 | macro_rules! baz { | 103 | macro_rules! baz { |
104 | () => { | 104 | () => { |
105 | use foo::bar; | 105 | use foo::bar; |
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | foo!(); | 109 | foo!(); |
110 | bar!(); | 110 | bar!(); |
111 | baz!(); | 111 | baz!(); |
112 | 112 | ||
@@ -114,7 +114,7 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | |||
114 | #[macro_export] | 114 | #[macro_export] |
115 | macro_rules! foo { | 115 | macro_rules! foo { |
116 | () => { | 116 | () => { |
117 | struct Foo { field: u32 } | 117 | struct Foo { field: u32 } |
118 | } | 118 | } |
119 | } | 119 | } |
120 | #[macro_export] | 120 | #[macro_export] |
@@ -137,3 +137,57 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | |||
137 | ⋮foo: m | 137 | ⋮foo: m |
138 | "###); | 138 | "###); |
139 | } | 139 | } |
140 | |||
141 | #[test] | ||
142 | fn macro_rules_from_other_crates_are_visible_with_macro_use() { | ||
143 | covers!(macro_rules_from_other_crates_are_visible_with_macro_use); | ||
144 | let map = def_map_with_crate_graph( | ||
145 | " | ||
146 | //- /main.rs | ||
147 | #[macro_use] | ||
148 | extern crate foo; | ||
149 | |||
150 | structs!(Foo); | ||
151 | structs_priv!(Bar); | ||
152 | structs_not_exported!(MacroNotResolved1); | ||
153 | crate::structs!(MacroNotResolved2); | ||
154 | |||
155 | mod bar; | ||
156 | |||
157 | //- /bar.rs | ||
158 | structs!(Baz); | ||
159 | crate::structs!(MacroNotResolved3); | ||
160 | |||
161 | //- /lib.rs | ||
162 | #[macro_export] | ||
163 | macro_rules! structs { | ||
164 | ($i:ident) => { struct $i; } | ||
165 | } | ||
166 | |||
167 | macro_rules! structs_not_exported { | ||
168 | ($i:ident) => { struct $i; } | ||
169 | } | ||
170 | |||
171 | mod priv_mod { | ||
172 | #[macro_export] | ||
173 | macro_rules! structs_priv { | ||
174 | ($i:ident) => { struct $i; } | ||
175 | } | ||
176 | } | ||
177 | ", | ||
178 | crate_graph! { | ||
179 | "main": ("/main.rs", ["foo"]), | ||
180 | "foo": ("/lib.rs", []), | ||
181 | }, | ||
182 | ); | ||
183 | assert_snapshot!(map, @r###" | ||
184 | ⋮crate | ||
185 | ⋮Bar: t v | ||
186 | ⋮Foo: t v | ||
187 | ⋮bar: t | ||
188 | ⋮foo: t | ||
189 | ⋮ | ||
190 | ⋮crate::bar | ||
191 | ⋮Baz: t v | ||
192 | "###); | ||
193 | } | ||
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index e2a92ae60..bcf753f78 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -934,6 +934,7 @@ impl AstNode for ExternCrateItem { | |||
934 | &self.syntax | 934 | &self.syntax |
935 | } | 935 | } |
936 | } | 936 | } |
937 | impl ast::AttrsOwner for ExternCrateItem {} | ||
937 | impl ExternCrateItem { | 938 | impl ExternCrateItem { |
938 | pub fn name_ref(&self) -> Option<NameRef> { | 939 | pub fn name_ref(&self) -> Option<NameRef> { |
939 | AstChildren::new(&self.syntax).next() | 940 | AstChildren::new(&self.syntax).next() |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index c14ee0e85..3e6c2d3f3 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -669,6 +669,7 @@ Grammar( | |||
669 | collections: [("use_trees", "UseTree")] | 669 | collections: [("use_trees", "UseTree")] |
670 | ), | 670 | ), |
671 | "ExternCrateItem": ( | 671 | "ExternCrateItem": ( |
672 | traits: ["AttrsOwner"], | ||
672 | options: ["NameRef", "Alias"], | 673 | options: ["NameRef", "Alias"], |
673 | ), | 674 | ), |
674 | "ArgList": ( | 675 | "ArgList": ( |