aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authoruHOOCCOOHu <[email protected]>2019-09-06 17:55:58 +0100
committeruHOOCCOOHu <[email protected]>2019-09-08 18:33:28 +0100
commite0f305a6bf710f64f789f909da93a8c362823b67 (patch)
treec34e3c7e8973c5a7137d1e0cd06ce9903f67b710 /crates/ra_hir/src
parent07e3976f426aaab93bfd3056374ec6ed32ffb255 (diff)
Support textual scoped macros
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/nameres.rs5
-rw-r--r--crates/ra_hir/src/nameres/collector.rs84
-rw-r--r--crates/ra_hir/src/nameres/raw.rs12
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs91
4 files changed, 158 insertions, 34 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 7de422128..e6bf0e90c 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -139,6 +139,7 @@ pub(crate) struct ModuleData {
139pub struct ModuleScope { 139pub struct ModuleScope {
140 items: FxHashMap<Name, Resolution>, 140 items: FxHashMap<Name, Resolution>,
141 macros: FxHashMap<Name, MacroDef>, 141 macros: FxHashMap<Name, MacroDef>,
142 textual_macros: FxHashMap<Name, MacroDef>,
142} 143}
143 144
144static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| { 145static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
@@ -164,6 +165,7 @@ impl ModuleScope {
164 _ => None, 165 _ => None,
165 }) 166 })
166 } 167 }
168 /// It resolves in module scope. Textual scoped macros are ignored here.
167 fn get_item_or_macro(&self, name: &Name) -> Option<ItemOrMacro> { 169 fn get_item_or_macro(&self, name: &Name) -> Option<ItemOrMacro> {
168 match (self.get(name), self.macros.get(name)) { 170 match (self.get(name), self.macros.get(name)) {
169 (Some(item), _) if !item.def.is_none() => Some(Either::A(item.def)), 171 (Some(item), _) if !item.def.is_none() => Some(Either::A(item.def)),
@@ -171,6 +173,9 @@ impl ModuleScope {
171 _ => None, 173 _ => None,
172 } 174 }
173 } 175 }
176 fn get_textual_macro(&self, name: &Name) -> Option<MacroDef> {
177 self.textual_macros.get(name).copied()
178 }
174} 179}
175 180
176type ItemOrMacro = Either<PerNs<ModuleDef>, MacroDef>; 181type ItemOrMacro = Either<PerNs<ModuleDef>, MacroDef>;
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 1c0d4369e..f897547e3 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -40,7 +40,6 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
40 glob_imports: FxHashMap::default(), 40 glob_imports: FxHashMap::default(),
41 unresolved_imports: Vec::new(), 41 unresolved_imports: Vec::new(),
42 unexpanded_macros: Vec::new(), 42 unexpanded_macros: Vec::new(),
43 global_macro_scope: FxHashMap::default(),
44 macro_stack_monitor: MacroStackMonitor::default(), 43 macro_stack_monitor: MacroStackMonitor::default(),
45 }; 44 };
46 collector.collect(); 45 collector.collect();
@@ -82,7 +81,6 @@ struct DefCollector<DB> {
82 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, 81 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
83 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, 82 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
84 unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>, 83 unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>,
85 global_macro_scope: FxHashMap<Name, MacroDefId>,
86 84
87 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly 85 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly
88 /// To prevent stack overflow, we add a deep counter here for prevent that. 86 /// To prevent stack overflow, we add a deep counter here for prevent that.
@@ -136,20 +134,6 @@ where
136 macro_id: MacroDefId, 134 macro_id: MacroDefId,
137 export: bool, 135 export: bool,
138 ) { 136 ) {
139 // macro-by-example in Rust have completely weird name resolution logic,
140 // unlike anything else in the language. We'd don't fully implement yet,
141 // just give a somewhat precise approximation.
142 //
143 // Specifically, we store a set of visible macros in each module, just
144 // like how we do with usual items. This is wrong, however, because
145 // macros can be shadowed and their scopes are mostly unrelated to
146 // modules. To paper over the second problem, we also maintain
147 // `global_macro_scope` which works when we construct `CrateDefMap`, but
148 // is completely ignored in expressions.
149 //
150 // What we should do is that, in CrateDefMap, we should maintain a
151 // separate tower of macro scopes, with ids. Then, for each item in the
152 // module, we need to store it's macro scope.
153 let def = Either::B(MacroDef { id: macro_id }); 137 let def = Either::B(MacroDef { id: macro_id });
154 138
155 // In Rust, `#[macro_export]` macros are unconditionally visible at the 139 // In Rust, `#[macro_export]` macros are unconditionally visible at the
@@ -162,13 +146,35 @@ where
162 self.def_map.exported_macros.insert(name.clone(), macro_id); 146 self.def_map.exported_macros.insert(name.clone(), macro_id);
163 } 147 }
164 self.update(module_id, None, &[(name.clone(), def)]); 148 self.update(module_id, None, &[(name.clone(), def)]);
165 self.global_macro_scope.insert(name, macro_id); 149 self.define_textual_macro(module_id, name.clone(), macro_id);
150 }
151
152 /// Define a macro in current textual scope.
153 ///
154 /// We use a map `textual_macros` to store all textual macros visable per module.
155 /// It will clone all macros from parent textual scope, whose definition is prior to
156 /// the definition of current module.
157 /// And also, `macro_use` on a module will import all textual macros visable inside to
158 /// current textual scope, with possible shadowing.
159 ///
160 /// In a single module, the order of definition/usage of textual scoped macros matters.
161 /// But we ignore it here to make it easy to implement.
162 fn define_textual_macro(&mut self, module_id: CrateModuleId, name: Name, macro_id: MacroDefId) {
163 // Always shadowing
164 self.def_map.modules[module_id]
165 .scope
166 .textual_macros
167 .insert(name, MacroDef { id: macro_id });
166 } 168 }
167 169
168 /// Import macros from `#[macro_use] extern crate`. 170 /// Import macros from `#[macro_use] extern crate`.
169 /// 171 ///
170 /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`. 172 /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`.
171 fn import_macros_from_extern_crate(&mut self, import: &raw::ImportData) { 173 fn import_macros_from_extern_crate(
174 &mut self,
175 current_module_id: CrateModuleId,
176 import: &raw::ImportData,
177 ) {
172 log::debug!( 178 log::debug!(
173 "importing macros from extern crate: {:?} ({:?})", 179 "importing macros from extern crate: {:?} ({:?})",
174 import, 180 import,
@@ -184,14 +190,14 @@ where
184 190
185 if let Some(ModuleDef::Module(m)) = res.take_types() { 191 if let Some(ModuleDef::Module(m)) = res.take_types() {
186 tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); 192 tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
187 self.import_all_macros_exported(m); 193 self.import_all_macros_exported(current_module_id, m);
188 } 194 }
189 } 195 }
190 196
191 fn import_all_macros_exported(&mut self, module: Module) { 197 fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, module: Module) {
192 let item_map = self.db.crate_def_map(module.krate); 198 let item_map = self.db.crate_def_map(module.krate);
193 for (name, &macro_id) in &item_map.exported_macros { 199 for (name, &macro_id) in &item_map.exported_macros {
194 self.global_macro_scope.insert(name.clone(), macro_id); 200 self.define_textual_macro(current_module_id, name.clone(), macro_id);
195 } 201 }
196 } 202 }
197 203
@@ -528,7 +534,7 @@ where
528 if let Some(prelude_module) = self.def_collector.def_map.prelude { 534 if let Some(prelude_module) = self.def_collector.def_map.prelude {
529 if prelude_module.krate != self.def_collector.def_map.krate { 535 if prelude_module.krate != self.def_collector.def_map.krate {
530 tested_by!(prelude_is_macro_use); 536 tested_by!(prelude_is_macro_use);
531 self.def_collector.import_all_macros_exported(prelude_module); 537 self.def_collector.import_all_macros_exported(self.module_id, prelude_module);
532 } 538 }
533 } 539 }
534 540
@@ -539,7 +545,7 @@ where
539 if let raw::RawItem::Import(import_id) = *item { 545 if let raw::RawItem::Import(import_id) = *item {
540 let import = self.raw_items[import_id].clone(); 546 let import = self.raw_items[import_id].clone();
541 if import.is_extern_crate && import.is_macro_use { 547 if import.is_extern_crate && import.is_macro_use {
542 self.def_collector.import_macros_from_extern_crate(&import); 548 self.def_collector.import_macros_from_extern_crate(self.module_id, &import);
543 } 549 }
544 } 550 }
545 } 551 }
@@ -561,10 +567,11 @@ where
561 fn collect_module(&mut self, module: &raw::ModuleData) { 567 fn collect_module(&mut self, module: &raw::ModuleData) {
562 match module { 568 match module {
563 // inline module, just recurse 569 // inline module, just recurse
564 raw::ModuleData::Definition { name, items, ast_id, attr_path } => { 570 raw::ModuleData::Definition { name, items, ast_id, attr_path, is_macro_use } => {
565 let module_id = 571 let module_id =
566 self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); 572 self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None);
567 let parent_module = ParentModule { name, attr_path: attr_path.as_ref() }; 573 let parent_module = ParentModule { name, attr_path: attr_path.as_ref() };
574
568 ModCollector { 575 ModCollector {
569 def_collector: &mut *self.def_collector, 576 def_collector: &mut *self.def_collector,
570 module_id, 577 module_id,
@@ -573,9 +580,12 @@ where
573 parent_module: Some(parent_module), 580 parent_module: Some(parent_module),
574 } 581 }
575 .collect(&*items); 582 .collect(&*items);
583 if *is_macro_use {
584 self.import_all_textual_macros(module_id);
585 }
576 } 586 }
577 // out of line module, resolve, parse and recurse 587 // out of line module, resolve, parse and recurse
578 raw::ModuleData::Declaration { name, ast_id, attr_path } => { 588 raw::ModuleData::Declaration { name, ast_id, attr_path, is_macro_use } => {
579 let ast_id = ast_id.with_file_id(self.file_id); 589 let ast_id = ast_id.with_file_id(self.file_id);
580 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); 590 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none();
581 match resolve_submodule( 591 match resolve_submodule(
@@ -596,7 +606,10 @@ where
596 raw_items: &raw_items, 606 raw_items: &raw_items,
597 parent_module: None, 607 parent_module: None,
598 } 608 }
599 .collect(raw_items.items()) 609 .collect(raw_items.items());
610 if *is_macro_use {
611 self.import_all_textual_macros(module_id);
612 }
600 } 613 }
601 Err(candidate) => self.def_collector.def_map.diagnostics.push( 614 Err(candidate) => self.def_collector.def_map.diagnostics.push(
602 DefDiagnostic::UnresolvedModule { 615 DefDiagnostic::UnresolvedModule {
@@ -621,6 +634,7 @@ where
621 modules[res].parent = Some(self.module_id); 634 modules[res].parent = Some(self.module_id);
622 modules[res].declaration = Some(declaration); 635 modules[res].declaration = Some(declaration);
623 modules[res].definition = definition; 636 modules[res].definition = definition;
637 modules[res].scope.textual_macros = modules[self.module_id].scope.textual_macros.clone();
624 modules[self.module_id].children.insert(name.clone(), res); 638 modules[self.module_id].children.insert(name.clone(), res);
625 let resolution = Resolution { 639 let resolution = Resolution {
626 def: PerNs::types( 640 def: PerNs::types(
@@ -674,12 +688,12 @@ where
674 688
675 let ast_id = mac.ast_id.with_file_id(self.file_id); 689 let ast_id = mac.ast_id.with_file_id(self.file_id);
676 690
677 // Case 2: try to expand macro_rules from this crate, triggering 691 // Case 2: try to resolve in textual scope and expand macro_rules, triggering
678 // recursive item collection. 692 // recursive item collection.
679 if let Some(macro_id) = 693 if let Some(macro_def) = mac.path.as_ident().and_then(|name| {
680 mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(&name)) 694 self.def_collector.def_map[self.module_id].scope.get_textual_macro(&name)
681 { 695 }) {
682 let def = *macro_id; 696 let def = macro_def.id;
683 let macro_call_id = MacroCallLoc { def, ast_id }.id(self.def_collector.db); 697 let macro_call_id = MacroCallLoc { def, ast_id }.id(self.def_collector.db);
684 698
685 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def); 699 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def);
@@ -689,6 +703,13 @@ where
689 // Case 3: path to a macro from another crate, expand during name resolution 703 // Case 3: path to a macro from another crate, expand during name resolution
690 self.def_collector.unexpanded_macros.push((self.module_id, ast_id, mac.path.clone())) 704 self.def_collector.unexpanded_macros.push((self.module_id, ast_id, mac.path.clone()))
691 } 705 }
706
707 fn import_all_textual_macros(&mut self, module_id: CrateModuleId) {
708 let macros = self.def_collector.def_map[module_id].scope.textual_macros.clone();
709 for (name, macro_) in macros {
710 self.def_collector.define_textual_macro(self.module_id, name.clone(), macro_.id);
711 }
712 }
692} 713}
693 714
694fn is_macro_rules(path: &Path) -> bool { 715fn is_macro_rules(path: &Path) -> bool {
@@ -715,7 +736,6 @@ mod tests {
715 glob_imports: FxHashMap::default(), 736 glob_imports: FxHashMap::default(),
716 unresolved_imports: Vec::new(), 737 unresolved_imports: Vec::new(),
717 unexpanded_macros: Vec::new(), 738 unexpanded_macros: Vec::new(),
718 global_macro_scope: FxHashMap::default(),
719 macro_stack_monitor: monitor, 739 macro_stack_monitor: monitor,
720 }; 740 };
721 collector.collect(); 741 collector.collect();
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
index 7963736e0..c646d3d00 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -134,12 +134,14 @@ pub(super) enum ModuleData {
134 name: Name, 134 name: Name,
135 ast_id: FileAstId<ast::Module>, 135 ast_id: FileAstId<ast::Module>,
136 attr_path: Option<SmolStr>, 136 attr_path: Option<SmolStr>,
137 is_macro_use: bool,
137 }, 138 },
138 Definition { 139 Definition {
139 name: Name, 140 name: Name,
140 ast_id: FileAstId<ast::Module>, 141 ast_id: FileAstId<ast::Module>,
141 items: Vec<RawItem>, 142 items: Vec<RawItem>,
142 attr_path: Option<SmolStr>, 143 attr_path: Option<SmolStr>,
144 is_macro_use: bool,
143 }, 145 },
144} 146}
145 147
@@ -267,10 +269,15 @@ impl RawItemsCollector {
267 }; 269 };
268 270
269 let ast_id = self.source_ast_id_map.ast_id(&module); 271 let ast_id = self.source_ast_id_map.ast_id(&module);
272 let is_macro_use = module.has_atom_attr("macro_use");
270 if module.has_semi() { 273 if module.has_semi() {
271 let attr_path = extract_mod_path_attribute(&module); 274 let attr_path = extract_mod_path_attribute(&module);
272 let item = 275 let item = self.raw_items.modules.alloc(ModuleData::Declaration {
273 self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id, attr_path }); 276 name,
277 ast_id,
278 attr_path,
279 is_macro_use,
280 });
274 self.push_item(current_module, RawItem::Module(item)); 281 self.push_item(current_module, RawItem::Module(item));
275 return; 282 return;
276 } 283 }
@@ -282,6 +289,7 @@ impl RawItemsCollector {
282 ast_id, 289 ast_id,
283 items: Vec::new(), 290 items: Vec::new(),
284 attr_path, 291 attr_path,
292 is_macro_use,
285 }); 293 });
286 self.process_module(Some(item), item_list); 294 self.process_module(Some(item), item_list);
287 self.push_item(current_module, RawItem::Module(item)); 295 self.push_item(current_module, RawItem::Module(item));
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
index c62152d26..8f0db95f2 100644
--- a/crates/ra_hir/src/nameres/tests/macros.rs
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -277,3 +277,94 @@ fn prelude_cycle() {
277 ⋮crate::foo 277 ⋮crate::foo
278 "###); 278 "###);
279} 279}
280
281#[test]
282fn plain_macros_are_textual_scoped_between_modules() {
283 let map = def_map(
284 r#"
285 //- /main.rs
286 mod m1;
287 bar!(NotFoundNotMacroUse);
288
289 mod m2 {
290 foo!(NotFoundBeforeInside2);
291 }
292
293 macro_rules! foo {
294 ($x:ident) => { struct $x; }
295 }
296 foo!(Ok);
297
298 mod m3;
299 foo!(OkShadowStop);
300 bar!(NotFoundMacroUseStop);
301
302 #[macro_use]
303 mod m5 {
304 #[macro_use]
305 mod m6 {
306 macro_rules! foo {
307 ($x:ident) => { fn $x() {} }
308 }
309 }
310 }
311 foo!(ok_double_macro_use_shadow);
312
313 //- /m1.rs
314 foo!(NotFoundBeforeInside1);
315 macro_rules! bar {
316 ($x:ident) => { struct $x; }
317 }
318
319 //- /m3/mod.rs
320 foo!(OkAfterInside);
321 macro_rules! foo {
322 ($x:ident) => { fn $x() {} }
323 }
324 foo!(ok_shadow);
325
326 #[macro_use]
327 mod m4;
328 bar!(OkMacroUse);
329
330 //- /m3/m4.rs
331 foo!(ok_shadow_deep);
332 macro_rules! bar {
333 ($x:ident) => { struct $x; }
334 }
335 "#,
336 );
337 assert_snapshot!(map, @r###"
338 ⋮crate
339 ⋮Ok: t v
340 ⋮OkShadowStop: t v
341 ⋮foo: m
342 ⋮m1: t
343 ⋮m2: t
344 ⋮m3: t
345 ⋮m5: t
346 ⋮ok_double_macro_use_shadow: v
347
348 ⋮crate::m1
349 ⋮bar: m
350
351 ⋮crate::m5
352 ⋮m6: t
353
354 ⋮crate::m5::m6
355 ⋮foo: m
356
357 ⋮crate::m2
358
359 ⋮crate::m3
360 ⋮OkAfterInside: t v
361 ⋮OkMacroUse: t v
362 ⋮foo: m
363 ⋮m4: t
364 ⋮ok_shadow: v
365
366 ⋮crate::m3::m4
367 ⋮bar: m
368 ⋮ok_shadow_deep: v
369 "###);
370}