aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres
diff options
context:
space:
mode:
authoruHOOCCOOHu <[email protected]>2019-09-09 13:54:02 +0100
committeruHOOCCOOHu <[email protected]>2019-09-09 13:54:02 +0100
commit40f91341595508833d39eb6d97e4ec2ac7f685cb (patch)
tree3022252410b228efb6501e9e8ff6268c910c87cb /crates/ra_hir/src/nameres
parent734a43e95afc97773c234956a95b78caed88f2a3 (diff)
Make macro scope a real name scope
Fix some details about module scoping
Diffstat (limited to 'crates/ra_hir/src/nameres')
-rw-r--r--crates/ra_hir/src/nameres/collector.rs178
-rw-r--r--crates/ra_hir/src/nameres/per_ns.rs59
-rw-r--r--crates/ra_hir/src/nameres/tests.rs46
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs119
4 files changed, 265 insertions, 137 deletions
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 09cda7656..03fbbd33f 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -5,14 +5,13 @@ use test_utils::tested_by;
5 5
6use crate::{ 6use crate::{
7 db::DefDatabase, 7 db::DefDatabase,
8 either::Either,
9 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, 8 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind},
10 name::MACRO_RULES, 9 name::MACRO_RULES,
11 nameres::{ 10 nameres::{
12 diagnostics::DefDiagnostic, 11 diagnostics::DefDiagnostic,
13 mod_resolution::{resolve_submodule, ParentModule}, 12 mod_resolution::{resolve_submodule, ParentModule},
14 raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs, 13 raw, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef, PerNs, ReachedFixedPoint,
15 ReachedFixedPoint, Resolution, ResolveMode, 14 Resolution, ResolveMode,
16 }, 15 },
17 AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, 16 AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static,
18 Struct, Trait, TypeAlias, Union, 17 Struct, Trait, TypeAlias, Union,
@@ -123,30 +122,51 @@ where
123 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); 122 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
124 // show unresolved imports in completion, etc 123 // show unresolved imports in completion, etc
125 for (module_id, import, import_data) in unresolved_imports { 124 for (module_id, import, import_data) in unresolved_imports {
126 self.record_resolved_import(module_id, Either::A(PerNs::none()), import, &import_data) 125 self.record_resolved_import(module_id, PerNs::none(), import, &import_data)
127 } 126 }
128 } 127 }
129 128
129 /// Define a macro with `macro_rules`.
130 ///
131 /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`,
132 /// then it is also defined in the root module scope.
133 /// You can `use` or invoke it by `crate::macro_name` anywhere, before or after the definition.
134 ///
135 /// It is surprising that the macro will never be in the current module scope.
136 /// These code fails with "unresolved import/macro",
137 /// ```rust,compile_fail
138 /// mod m { macro_rules! foo { () => {} } }
139 /// use m::foo as bar;
140 /// ```
141 ///
142 /// ```rust,compile_fail
143 /// macro_rules! foo { () => {} }
144 /// self::foo!();
145 /// crate::foo!();
146 /// ```
147 ///
148 /// Well, this code compiles, bacause the plain path `foo` in `use` is searched
149 /// in the legacy textual scope only.
150 /// ```rust
151 /// macro_rules! foo { () => {} }
152 /// use foo as bar;
153 /// ```
130 fn define_macro( 154 fn define_macro(
131 &mut self, 155 &mut self,
132 module_id: CrateModuleId, 156 module_id: CrateModuleId,
133 name: Name, 157 name: Name,
134 macro_id: MacroDefId, 158 macro_: MacroDef,
135 export: bool, 159 export: bool,
136 ) { 160 ) {
137 let def = Either::B(MacroDef { id: macro_id }); 161 // Textual scoping
162 self.define_legacy_macro(module_id, name.clone(), macro_);
138 163
164 // Module scoping
139 // In Rust, `#[macro_export]` macros are unconditionally visible at the 165 // In Rust, `#[macro_export]` macros are unconditionally visible at the
140 // crate root, even if the parent modules is **not** visible. 166 // crate root, even if the parent modules is **not** visible.
141 if export { 167 if export {
142 self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); 168 self.update(self.def_map.root, None, &[(name.clone(), Resolution::from_macro(macro_))]);
143
144 // Exported macros are collected in crate level ready for
145 // glob import with `#[macro_use]`.
146 self.def_map.exported_macros.insert(name.clone(), macro_id);
147 } 169 }
148 self.update(module_id, None, &[(name.clone(), def)]);
149 self.define_legacy_macro(module_id, name.clone(), macro_id);
150 } 170 }
151 171
152 /// Define a legacy textual scoped macro in module 172 /// Define a legacy textual scoped macro in module
@@ -156,14 +176,12 @@ where
156 /// the definition of current module. 176 /// the definition of current module.
157 /// And also, `macro_use` on a module will import all legacy macros visable inside to 177 /// And also, `macro_use` on a module will import all legacy macros visable inside to
158 /// current legacy scope, with possible shadowing. 178 /// current legacy scope, with possible shadowing.
159 fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_id: MacroDefId) { 179 fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_: MacroDef) {
160 // Always shadowing 180 // Always shadowing
161 self.def_map.modules[module_id].scope.legacy_macros.insert(name, MacroDef { id: macro_id }); 181 self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_);
162 } 182 }
163 183
164 /// Import macros from `#[macro_use] extern crate`. 184 /// Import macros from `#[macro_use] extern crate`.
165 ///
166 /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`.
167 fn import_macros_from_extern_crate( 185 fn import_macros_from_extern_crate(
168 &mut self, 186 &mut self,
169 current_module_id: CrateModuleId, 187 current_module_id: CrateModuleId,
@@ -184,14 +202,20 @@ where
184 202
185 if let Some(ModuleDef::Module(m)) = res.take_types() { 203 if let Some(ModuleDef::Module(m)) = res.take_types() {
186 tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); 204 tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
187 self.import_all_macros_exported(current_module_id, m); 205 self.import_all_macros_exported(current_module_id, m.krate);
188 } 206 }
189 } 207 }
190 208
191 fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, module: Module) { 209 /// Import all exported macros from another crate
192 let item_map = self.db.crate_def_map(module.krate); 210 ///
193 for (name, &macro_id) in &item_map.exported_macros { 211 /// Exported macros are just all macros in the root module scope.
194 self.define_legacy_macro(current_module_id, name.clone(), macro_id); 212 /// Note that it contains not only all `#[macro_export]` macros, but also all aliases
213 /// created by `use` in the root module, ignoring the visibility of `use`.
214 fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, krate: Crate) {
215 let def_map = self.db.crate_def_map(krate);
216 for (name, def) in def_map[def_map.root].scope.macros() {
217 // `macro_use` only bring things into legacy scope.
218 self.define_legacy_macro(current_module_id, name.clone(), def);
195 } 219 }
196 } 220 }
197 221
@@ -219,7 +243,7 @@ where
219 &self, 243 &self,
220 module_id: CrateModuleId, 244 module_id: CrateModuleId,
221 import: &raw::ImportData, 245 import: &raw::ImportData,
222 ) -> (ItemOrMacro, ReachedFixedPoint) { 246 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) {
223 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 247 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
224 if import.is_extern_crate { 248 if import.is_extern_crate {
225 let res = self.def_map.resolve_name_in_extern_prelude( 249 let res = self.def_map.resolve_name_in_extern_prelude(
@@ -228,7 +252,7 @@ where
228 .as_ident() 252 .as_ident()
229 .expect("extern crate should have been desugared to one-element path"), 253 .expect("extern crate should have been desugared to one-element path"),
230 ); 254 );
231 (Either::A(res), ReachedFixedPoint::Yes) 255 (res, ReachedFixedPoint::Yes)
232 } else { 256 } else {
233 let res = self.def_map.resolve_path_fp_with_macro( 257 let res = self.def_map.resolve_path_fp_with_macro(
234 self.db, 258 self.db,
@@ -244,13 +268,13 @@ where
244 fn record_resolved_import( 268 fn record_resolved_import(
245 &mut self, 269 &mut self,
246 module_id: CrateModuleId, 270 module_id: CrateModuleId,
247 def: ItemOrMacro, 271 def: PerNs<ModuleDef>,
248 import_id: raw::ImportId, 272 import_id: raw::ImportId,
249 import: &raw::ImportData, 273 import: &raw::ImportData,
250 ) { 274 ) {
251 if import.is_glob { 275 if import.is_glob {
252 log::debug!("glob import: {:?}", import); 276 log::debug!("glob import: {:?}", import);
253 match def.a().and_then(|item| item.take_types()) { 277 match def.take_types() {
254 Some(ModuleDef::Module(m)) => { 278 Some(ModuleDef::Module(m)) => {
255 if import.is_prelude { 279 if import.is_prelude {
256 tested_by!(std_prelude); 280 tested_by!(std_prelude);
@@ -260,30 +284,29 @@ where
260 // glob import from other crate => we can just import everything once 284 // glob import from other crate => we can just import everything once
261 let item_map = self.db.crate_def_map(m.krate); 285 let item_map = self.db.crate_def_map(m.krate);
262 let scope = &item_map[m.module_id].scope; 286 let scope = &item_map[m.module_id].scope;
287
288 // Module scoped macros is included
263 let items = scope 289 let items = scope
264 .items 290 .items
265 .iter() 291 .iter()
266 .map(|(name, res)| (name.clone(), Either::A(res.clone()))); 292 .map(|(name, res)| (name.clone(), res.clone()))
267 let macros = 293 .collect::<Vec<_>>();
268 scope.macros.iter().map(|(name, res)| (name.clone(), Either::B(*res)));
269 294
270 let all = items.chain(macros).collect::<Vec<_>>(); 295 self.update(module_id, Some(import_id), &items);
271 self.update(module_id, Some(import_id), &all);
272 } else { 296 } else {
273 // glob import from same crate => we do an initial 297 // glob import from same crate => we do an initial
274 // import, and then need to propagate any further 298 // import, and then need to propagate any further
275 // additions 299 // additions
276 let scope = &self.def_map[m.module_id].scope; 300 let scope = &self.def_map[m.module_id].scope;
301
302 // Module scoped macros is included
277 let items = scope 303 let items = scope
278 .items 304 .items
279 .iter() 305 .iter()
280 .map(|(name, res)| (name.clone(), Either::A(res.clone()))); 306 .map(|(name, res)| (name.clone(), res.clone()))
281 let macros = 307 .collect::<Vec<_>>();
282 scope.macros.iter().map(|(name, res)| (name.clone(), Either::B(*res)));
283 308
284 let all = items.chain(macros).collect::<Vec<_>>(); 309 self.update(module_id, Some(import_id), &items);
285
286 self.update(module_id, Some(import_id), &all);
287 // record the glob import in case we add further items 310 // record the glob import in case we add further items
288 self.glob_imports 311 self.glob_imports
289 .entry(m.module_id) 312 .entry(m.module_id)
@@ -303,7 +326,7 @@ where
303 import: Some(import_id), 326 import: Some(import_id),
304 }; 327 };
305 let name = variant.name(self.db)?; 328 let name = variant.name(self.db)?;
306 Some((name, Either::A(res))) 329 Some((name, res))
307 }) 330 })
308 .collect::<Vec<_>>(); 331 .collect::<Vec<_>>();
309 self.update(module_id, Some(import_id), &resolutions); 332 self.update(module_id, Some(import_id), &resolutions);
@@ -323,18 +346,12 @@ where
323 346
324 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 347 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
325 if import.is_extern_crate && module_id == self.def_map.root { 348 if import.is_extern_crate && module_id == self.def_map.root {
326 if let Some(def) = def.a().and_then(|item| item.take_types()) { 349 if let Some(def) = def.take_types() {
327 self.def_map.extern_prelude.insert(name.clone(), def); 350 self.def_map.extern_prelude.insert(name.clone(), def);
328 } 351 }
329 } 352 }
330 353
331 let resolution = match def { 354 let resolution = Resolution { def, import: Some(import_id) };
332 Either::A(item) => {
333 Either::A(Resolution { def: item, import: Some(import_id) })
334 }
335 Either::B(macro_) => Either::B(macro_),
336 };
337
338 self.update(module_id, Some(import_id), &[(name, resolution)]); 355 self.update(module_id, Some(import_id), &[(name, resolution)]);
339 } 356 }
340 None => tested_by!(bogus_paths), 357 None => tested_by!(bogus_paths),
@@ -346,7 +363,7 @@ where
346 &mut self, 363 &mut self,
347 module_id: CrateModuleId, 364 module_id: CrateModuleId,
348 import: Option<raw::ImportId>, 365 import: Option<raw::ImportId>,
349 resolutions: &[(Name, Either<Resolution, MacroDef>)], 366 resolutions: &[(Name, Resolution)],
350 ) { 367 ) {
351 self.update_recursive(module_id, import, resolutions, 0) 368 self.update_recursive(module_id, import, resolutions, 0)
352 } 369 }
@@ -355,7 +372,7 @@ where
355 &mut self, 372 &mut self,
356 module_id: CrateModuleId, 373 module_id: CrateModuleId,
357 import: Option<raw::ImportId>, 374 import: Option<raw::ImportId>,
358 resolutions: &[(Name, Either<Resolution, MacroDef>)], 375 resolutions: &[(Name, Resolution)],
359 depth: usize, 376 depth: usize,
360 ) { 377 ) {
361 if depth > 100 { 378 if depth > 100 {
@@ -365,35 +382,30 @@ where
365 let module_items = &mut self.def_map.modules[module_id].scope; 382 let module_items = &mut self.def_map.modules[module_id].scope;
366 let mut changed = false; 383 let mut changed = false;
367 for (name, res) in resolutions { 384 for (name, res) in resolutions {
368 match res { 385 let existing = module_items.items.entry(name.clone()).or_default();
369 // item
370 Either::A(res) => {
371 let existing = module_items.items.entry(name.clone()).or_default();
372
373 if existing.def.types.is_none() && res.def.types.is_some() {
374 existing.def.types = res.def.types;
375 existing.import = import.or(res.import);
376 changed = true;
377 }
378 if existing.def.values.is_none() && res.def.values.is_some() {
379 existing.def.values = res.def.values;
380 existing.import = import.or(res.import);
381 changed = true;
382 }
383 386
384 if existing.def.is_none() 387 if existing.def.types.is_none() && res.def.types.is_some() {
385 && res.def.is_none() 388 existing.def.types = res.def.types;
386 && existing.import.is_none() 389 existing.import = import.or(res.import);
387 && res.import.is_some() 390 changed = true;
388 { 391 }
389 existing.import = res.import; 392 if existing.def.values.is_none() && res.def.values.is_some() {
390 } 393 existing.def.values = res.def.values;
391 } 394 existing.import = import.or(res.import);
392 // macro 395 changed = true;
393 Either::B(res) => { 396 }
394 // Always shadowing 397 if existing.def.macros.is_none() && res.def.macros.is_some() {
395 module_items.macros.insert(name.clone(), *res); 398 existing.def.macros = res.def.macros;
396 } 399 existing.import = import.or(res.import);
400 changed = true;
401 }
402
403 if existing.def.is_none()
404 && res.def.is_none()
405 && existing.import.is_none()
406 && res.import.is_some()
407 {
408 existing.import = res.import;
397 } 409 }
398 } 410 }
399 411
@@ -425,7 +437,7 @@ where
425 path, 437 path,
426 ); 438 );
427 439
428 if let Some(def) = resolved_res.resolved_def.b() { 440 if let Some(def) = resolved_res.resolved_def.get_macros() {
429 let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db); 441 let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db);
430 resolved.push((*module_id, call_id, def.id)); 442 resolved.push((*module_id, call_id, def.id));
431 res = ReachedFixedPoint::No; 443 res = ReachedFixedPoint::No;
@@ -528,7 +540,7 @@ where
528 if let Some(prelude_module) = self.def_collector.def_map.prelude { 540 if let Some(prelude_module) = self.def_collector.def_map.prelude {
529 if prelude_module.krate != self.def_collector.def_map.krate { 541 if prelude_module.krate != self.def_collector.def_map.krate {
530 tested_by!(prelude_is_macro_use); 542 tested_by!(prelude_is_macro_use);
531 self.def_collector.import_all_macros_exported(self.module_id, prelude_module); 543 self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
532 } 544 }
533 } 545 }
534 546
@@ -636,7 +648,7 @@ where
636 ), 648 ),
637 import: None, 649 import: None,
638 }; 650 };
639 self.def_collector.update(self.module_id, None, &[(name, Either::A(resolution))]); 651 self.def_collector.update(self.module_id, None, &[(name, resolution)]);
640 res 652 res
641 } 653 }
642 654
@@ -667,7 +679,7 @@ where
667 raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)), 679 raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)),
668 }; 680 };
669 let resolution = Resolution { def, import: None }; 681 let resolution = Resolution { def, import: None };
670 self.def_collector.update(self.module_id, None, &[(name, Either::A(resolution))]) 682 self.def_collector.update(self.module_id, None, &[(name, resolution)])
671 } 683 }
672 684
673 fn collect_macro(&mut self, mac: &raw::MacroData) { 685 fn collect_macro(&mut self, mac: &raw::MacroData) {
@@ -675,7 +687,8 @@ where
675 if is_macro_rules(&mac.path) { 687 if is_macro_rules(&mac.path) {
676 if let Some(name) = &mac.name { 688 if let Some(name) = &mac.name {
677 let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id)); 689 let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id));
678 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export) 690 let macro_ = MacroDef { id: macro_id };
691 self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export);
679 } 692 }
680 return; 693 return;
681 } 694 }
@@ -706,7 +719,7 @@ where
706 fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) { 719 fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) {
707 let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); 720 let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone();
708 for (name, macro_) in macros { 721 for (name, macro_) in macros {
709 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_.id); 722 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
710 } 723 }
711 } 724 }
712} 725}
@@ -758,7 +771,6 @@ mod tests {
758 root, 771 root,
759 modules, 772 modules,
760 poison_macros: FxHashSet::default(), 773 poison_macros: FxHashSet::default(),
761 exported_macros: FxHashMap::default(),
762 diagnostics: Vec::new(), 774 diagnostics: Vec::new(),
763 } 775 }
764 }; 776 };
diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir/src/nameres/per_ns.rs
index c40a3ff9d..6a50e05c1 100644
--- a/crates/ra_hir/src/nameres/per_ns.rs
+++ b/crates/ra_hir/src/nameres/per_ns.rs
@@ -1,78 +1,93 @@
1use crate::MacroDef;
2
1#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 3#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2pub enum Namespace { 4pub enum Namespace {
3 Types, 5 Types,
4 Values, 6 Values,
7 Macro,
5} 8}
6 9
7#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 10#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
8pub struct PerNs<T> { 11pub struct PerNs<T> {
9 pub types: Option<T>, 12 pub types: Option<T>,
10 pub values: Option<T>, 13 pub values: Option<T>,
14 /// Since macros has different type, many methods simply ignore it.
15 /// We can only use special method like `get_macros` to access it.
16 pub macros: Option<MacroDef>,
11} 17}
12 18
13impl<T> Default for PerNs<T> { 19impl<T> Default for PerNs<T> {
14 fn default() -> Self { 20 fn default() -> Self {
15 PerNs { types: None, values: None } 21 PerNs { types: None, values: None, macros: None }
16 } 22 }
17} 23}
18 24
19impl<T> PerNs<T> { 25impl<T> PerNs<T> {
20 pub fn none() -> PerNs<T> { 26 pub fn none() -> PerNs<T> {
21 PerNs { types: None, values: None } 27 PerNs { types: None, values: None, macros: None }
22 } 28 }
23 29
24 pub fn values(t: T) -> PerNs<T> { 30 pub fn values(t: T) -> PerNs<T> {
25 PerNs { types: None, values: Some(t) } 31 PerNs { types: None, values: Some(t), macros: None }
26 } 32 }
27 33
28 pub fn types(t: T) -> PerNs<T> { 34 pub fn types(t: T) -> PerNs<T> {
29 PerNs { types: Some(t), values: None } 35 PerNs { types: Some(t), values: None, macros: None }
30 } 36 }
31 37
32 pub fn both(types: T, values: T) -> PerNs<T> { 38 pub fn both(types: T, values: T) -> PerNs<T> {
33 PerNs { types: Some(types), values: Some(values) } 39 PerNs { types: Some(types), values: Some(values), macros: None }
34 } 40 }
35 41
36 pub fn is_none(&self) -> bool { 42 pub fn macros(macro_: MacroDef) -> PerNs<T> {
37 self.types.is_none() && self.values.is_none() 43 PerNs { types: None, values: None, macros: Some(macro_) }
38 } 44 }
39 45
40 pub fn is_both(&self) -> bool { 46 pub fn is_none(&self) -> bool {
41 self.types.is_some() && self.values.is_some() 47 self.types.is_none() && self.values.is_none() && self.macros.is_none()
42 } 48 }
43 49
44 pub fn take(self, namespace: Namespace) -> Option<T> { 50 pub fn is_all(&self) -> bool {
45 match namespace { 51 self.types.is_some() && self.values.is_some() && self.macros.is_some()
46 Namespace::Types => self.types,
47 Namespace::Values => self.values,
48 }
49 } 52 }
50 53
51 pub fn take_types(self) -> Option<T> { 54 pub fn take_types(self) -> Option<T> {
52 self.take(Namespace::Types) 55 self.types
53 } 56 }
54 57
55 pub fn take_values(self) -> Option<T> { 58 pub fn take_values(self) -> Option<T> {
56 self.take(Namespace::Values) 59 self.values
57 } 60 }
58 61
59 pub fn get(&self, namespace: Namespace) -> Option<&T> { 62 pub fn get_macros(&self) -> Option<MacroDef> {
60 self.as_ref().take(namespace) 63 self.macros
64 }
65
66 pub fn only_macros(&self) -> PerNs<T> {
67 PerNs { types: None, values: None, macros: self.macros }
61 } 68 }
62 69
63 pub fn as_ref(&self) -> PerNs<&T> { 70 pub fn as_ref(&self) -> PerNs<&T> {
64 PerNs { types: self.types.as_ref(), values: self.values.as_ref() } 71 PerNs { types: self.types.as_ref(), values: self.values.as_ref(), macros: self.macros }
65 } 72 }
66 73
67 pub fn or(self, other: PerNs<T>) -> PerNs<T> { 74 pub fn or(self, other: PerNs<T>) -> PerNs<T> {
68 PerNs { types: self.types.or(other.types), values: self.values.or(other.values) } 75 PerNs {
76 types: self.types.or(other.types),
77 values: self.values.or(other.values),
78 macros: self.macros.or(other.macros),
79 }
69 } 80 }
70 81
71 pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> { 82 pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> {
72 PerNs { types: self.types.and_then(&f), values: self.values.and_then(&f) } 83 PerNs {
84 types: self.types.and_then(&f),
85 values: self.values.and_then(&f),
86 macros: self.macros,
87 }
73 } 88 }
74 89
75 pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> { 90 pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> {
76 PerNs { types: self.types.map(&f), values: self.values.map(&f) } 91 PerNs { types: self.types.map(&f), values: self.values.map(&f), macros: self.macros }
77 } 92 }
78} 93}
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 4ff897ca5..bc4b47b70 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -12,8 +12,7 @@ use test_utils::covers;
12 12
13use crate::{ 13use crate::{
14 mock::{CrateGraphFixture, MockDatabase}, 14 mock::{CrateGraphFixture, MockDatabase},
15 nameres::Resolution, 15 Crate,
16 Crate, Either,
17}; 16};
18 17
19use super::*; 18use super::*;
@@ -37,35 +36,38 @@ fn render_crate_def_map(map: &CrateDefMap) -> String {
37 *buf += path; 36 *buf += path;
38 *buf += "\n"; 37 *buf += "\n";
39 38
40 let items = map.modules[module].scope.items.iter().map(|(name, it)| (name, Either::A(it))); 39 let mut entries = map.modules[module]
41 let macros = map.modules[module].scope.macros.iter().map(|(name, m)| (name, Either::B(m))); 40 .scope
42 let mut entries = items.chain(macros).collect::<Vec<_>>(); 41 .items
43 42 .iter()
43 .map(|(name, res)| (name, res.def))
44 .collect::<Vec<_>>();
44 entries.sort_by_key(|(name, _)| *name); 45 entries.sort_by_key(|(name, _)| *name);
46
45 for (name, res) in entries { 47 for (name, res) in entries {
46 match res { 48 *buf += &format!("{}:", name);
47 Either::A(it) => { 49
48 *buf += &format!("{}: {}\n", name, dump_resolution(it)); 50 if res.types.is_some() {
49 } 51 *buf += " t";
50 Either::B(_) => { 52 }
51 *buf += &format!("{}: m\n", name); 53 if res.values.is_some() {
52 } 54 *buf += " v";
55 }
56 if res.macros.is_some() {
57 *buf += " m";
58 }
59 if res.is_none() {
60 *buf += " _";
53 } 61 }
62
63 *buf += "\n";
54 } 64 }
65
55 for (name, child) in map.modules[module].children.iter() { 66 for (name, child) in map.modules[module].children.iter() {
56 let path = path.to_string() + &format!("::{}", name); 67 let path = path.to_string() + &format!("::{}", name);
57 go(buf, map, &path, *child); 68 go(buf, map, &path, *child);
58 } 69 }
59 } 70 }
60
61 fn dump_resolution(resolution: &Resolution) -> &'static str {
62 match (resolution.def.types.is_some(), resolution.def.values.is_some()) {
63 (true, true) => "t v",
64 (true, false) => "t",
65 (false, true) => "v",
66 (false, false) => "_",
67 }
68 }
69} 71}
70 72
71fn def_map(fixtute: &str) -> String { 73fn def_map(fixtute: &str) -> String {
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
index ebc4d6890..20ee63c67 100644
--- a/crates/ra_hir/src/nameres/tests/macros.rs
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -21,7 +21,6 @@ fn macro_rules_are_globally_visible() {
21 ⋮crate 21 ⋮crate
22 ⋮Foo: t v 22 ⋮Foo: t v
23 ⋮nested: t 23 ⋮nested: t
24 ⋮structs: m
25 24
26 ⋮crate::nested 25 ⋮crate::nested
27 ⋮Bar: t v 26 ⋮Bar: t v
@@ -47,7 +46,6 @@ fn macro_rules_can_define_modules() {
47 ); 46 );
48 assert_snapshot!(map, @r###" 47 assert_snapshot!(map, @r###"
49 ⋮crate 48 ⋮crate
50 ⋮m: m
51 ⋮n1: t 49 ⋮n1: t
52 50
53 ⋮crate::n1 51 ⋮crate::n1
@@ -133,7 +131,6 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
133 ⋮crate 131 ⋮crate
134 ⋮Foo: t v 132 ⋮Foo: t v
135 ⋮bar: m 133 ⋮bar: m
136 ⋮baz: m
137 ⋮foo: m 134 ⋮foo: m
138 "###); 135 "###);
139} 136}
@@ -271,7 +268,6 @@ fn prelude_cycle() {
271 ⋮prelude: t 268 ⋮prelude: t
272 269
273 ⋮crate::prelude 270 ⋮crate::prelude
274 ⋮declare_mod: m
275 "###); 271 "###);
276} 272}
277 273
@@ -345,7 +341,6 @@ fn plain_macros_are_legacy_textual_scoped() {
345 ⋮Ok: t v 341 ⋮Ok: t v
346 ⋮OkAfter: t v 342 ⋮OkAfter: t v
347 ⋮OkShadowStop: t v 343 ⋮OkShadowStop: t v
348 ⋮foo: m
349 ⋮m1: t 344 ⋮m1: t
350 ⋮m2: t 345 ⋮m2: t
351 ⋮m3: t 346 ⋮m3: t
@@ -354,28 +349,132 @@ fn plain_macros_are_legacy_textual_scoped() {
354 ⋮ok_double_macro_use_shadow: v 349 ⋮ok_double_macro_use_shadow: v
355 350
356 ⋮crate::m7 351 ⋮crate::m7
357 ⋮baz: m
358 352
359 ⋮crate::m1 353 ⋮crate::m1
360 ⋮bar: m
361 354
362 ⋮crate::m5 355 ⋮crate::m5
363 ⋮m6: t 356 ⋮m6: t
364 357
365 ⋮crate::m5::m6 358 ⋮crate::m5::m6
366 ⋮foo: m
367 359
368 ⋮crate::m2 360 ⋮crate::m2
369 361
370 ⋮crate::m3 362 ⋮crate::m3
371 ⋮OkAfterInside: t v 363 ⋮OkAfterInside: t v
372 ⋮OkMacroUse: t v 364 ⋮OkMacroUse: t v
373 ⋮foo: m
374 ⋮m4: t 365 ⋮m4: t
375 ⋮ok_shadow: v 366 ⋮ok_shadow: v
376 367
377 ⋮crate::m3::m4 368 ⋮crate::m3::m4
378 ⋮bar: m
379 ⋮ok_shadow_deep: v 369 ⋮ok_shadow_deep: v
380 "###); 370 "###);
381} 371}
372
373#[test]
374fn type_value_macro_live_in_different_scopes() {
375 let map = def_map(
376 "
377 //- /main.rs
378 #[macro_export]
379 macro_rules! foo {
380 ($x:ident) => { type $x = (); }
381 }
382
383 foo!(foo);
384 use foo as bar;
385
386 use self::foo as baz;
387 fn baz() {}
388 ",
389 );
390 assert_snapshot!(map, @r###"
391 ⋮crate
392 ⋮bar: t m
393 ⋮baz: t v m
394 ⋮foo: t m
395 "###);
396}
397
398#[test]
399fn macro_use_can_be_aliased() {
400 let map = def_map_with_crate_graph(
401 "
402 //- /main.rs
403 #[macro_use]
404 extern crate foo;
405
406 foo!(Direct);
407 bar!(Alias);
408
409 //- /lib.rs
410 use crate::foo as bar;
411
412 mod m {
413 #[macro_export]
414 macro_rules! foo {
415 ($x:ident) => { struct $x; }
416 }
417 }
418 ",
419 crate_graph! {
420 "main": ("/main.rs", ["foo"]),
421 "foo": ("/lib.rs", []),
422 },
423 );
424 assert_snapshot!(map, @r###"
425 ⋮crate
426 ⋮Alias: t v
427 ⋮Direct: t v
428 ⋮foo: t
429 "###);
430}
431
432#[test]
433fn path_quantified_macros() {
434 let map = def_map(
435 "
436 //- /main.rs
437 macro_rules! foo {
438 ($x:ident) => { struct $x; }
439 }
440
441 crate::foo!(NotResolved);
442
443 crate::bar!(OkCrate);
444 bar!(OkPlain);
445 alias1!(NotHere);
446 m::alias1!(OkAliasPlain);
447 m::alias2!(OkAliasSuper);
448 m::alias3!(OkAliasCrate);
449 not_found!(NotFound);
450
451 mod m {
452 #[macro_export]
453 macro_rules! bar {
454 ($x:ident) => { struct $x; }
455 }
456
457 pub use bar as alias1;
458 pub use super::bar as alias2;
459 pub use crate::bar as alias3;
460 pub use self::bar as not_found;
461 }
462 ",
463 );
464 assert_snapshot!(map, @r###"
465 ⋮crate
466 ⋮OkAliasCrate: t v
467 ⋮OkAliasPlain: t v
468 ⋮OkAliasSuper: t v
469 ⋮OkCrate: t v
470 ⋮OkPlain: t v
471 ⋮bar: m
472 ⋮m: t
473
474 ⋮crate::m
475 ⋮alias1: m
476 ⋮alias2: m
477 ⋮alias3: m
478 ⋮not_found: _
479 "###);
480}