aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/nameres')
-rw-r--r--crates/ra_hir/src/nameres/collector.rs60
-rw-r--r--crates/ra_hir/src/nameres/per_ns.rs2
-rw-r--r--crates/ra_hir/src/nameres/raw.rs102
-rw-r--r--crates/ra_hir/src/nameres/tests.rs70
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs105
5 files changed, 293 insertions, 46 deletions
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index ef7dc6ebe..cef2dc9d2 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -1,3 +1,6 @@
1//! FIXME: write short doc here
2
3use ra_cfg::CfgOptions;
1use ra_db::FileId; 4use ra_db::FileId;
2use ra_syntax::{ast, SmolStr}; 5use ra_syntax::{ast, SmolStr};
3use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
@@ -33,6 +36,9 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
33 } 36 }
34 } 37 }
35 38
39 let crate_graph = db.crate_graph();
40 let cfg_options = crate_graph.cfg_options(def_map.krate().crate_id());
41
36 let mut collector = DefCollector { 42 let mut collector = DefCollector {
37 db, 43 db,
38 def_map, 44 def_map,
@@ -40,6 +46,7 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
40 unresolved_imports: Vec::new(), 46 unresolved_imports: Vec::new(),
41 unexpanded_macros: Vec::new(), 47 unexpanded_macros: Vec::new(),
42 macro_stack_monitor: MacroStackMonitor::default(), 48 macro_stack_monitor: MacroStackMonitor::default(),
49 cfg_options,
43 }; 50 };
44 collector.collect(); 51 collector.collect();
45 collector.finish() 52 collector.finish()
@@ -74,8 +81,8 @@ impl MacroStackMonitor {
74} 81}
75 82
76/// Walks the tree of module recursively 83/// Walks the tree of module recursively
77struct DefCollector<DB> { 84struct DefCollector<'a, DB> {
78 db: DB, 85 db: &'a DB,
79 def_map: CrateDefMap, 86 def_map: CrateDefMap,
80 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, 87 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
81 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, 88 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
@@ -84,9 +91,11 @@ struct DefCollector<DB> {
84 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly 91 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly
85 /// To prevent stack overflow, we add a deep counter here for prevent that. 92 /// To prevent stack overflow, we add a deep counter here for prevent that.
86 macro_stack_monitor: MacroStackMonitor, 93 macro_stack_monitor: MacroStackMonitor,
94
95 cfg_options: &'a CfgOptions,
87} 96}
88 97
89impl<'a, DB> DefCollector<&'a DB> 98impl<DB> DefCollector<'_, DB>
90where 99where
91 DB: DefDatabase, 100 DB: DefDatabase,
92{ 101{
@@ -504,7 +513,7 @@ struct ModCollector<'a, D> {
504 parent_module: Option<ParentModule<'a>>, 513 parent_module: Option<ParentModule<'a>>,
505} 514}
506 515
507impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> 516impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>>
508where 517where
509 DB: DefDatabase, 518 DB: DefDatabase,
510{ 519{
@@ -521,24 +530,27 @@ where
521 // `#[macro_use] extern crate` is hoisted to imports macros before collecting 530 // `#[macro_use] extern crate` is hoisted to imports macros before collecting
522 // any other items. 531 // any other items.
523 for item in items { 532 for item in items {
524 if let raw::RawItem::Import(import_id) = *item { 533 if self.is_cfg_enabled(&item.attrs) {
525 let import = self.raw_items[import_id].clone(); 534 if let raw::RawItemKind::Import(import_id) = item.kind {
526 if import.is_extern_crate && import.is_macro_use { 535 let import = self.raw_items[import_id].clone();
527 self.def_collector.import_macros_from_extern_crate(self.module_id, &import); 536 if import.is_extern_crate && import.is_macro_use {
537 self.def_collector.import_macros_from_extern_crate(self.module_id, &import);
538 }
528 } 539 }
529 } 540 }
530 } 541 }
531 542
532 for item in items { 543 for item in items {
533 match *item { 544 if self.is_cfg_enabled(&item.attrs) {
534 raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), 545 match item.kind {
535 raw::RawItem::Import(import_id) => self.def_collector.unresolved_imports.push(( 546 raw::RawItemKind::Module(m) => self.collect_module(&self.raw_items[m]),
536 self.module_id, 547 raw::RawItemKind::Import(import_id) => self
537 import_id, 548 .def_collector
538 self.raw_items[import_id].clone(), 549 .unresolved_imports
539 )), 550 .push((self.module_id, import_id, self.raw_items[import_id].clone())),
540 raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), 551 raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]),
541 raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), 552 raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
553 }
542 } 554 }
543 } 555 }
544 } 556 }
@@ -662,7 +674,10 @@ where
662 // Case 1: macro rules, define a macro in crate-global mutable scope 674 // Case 1: macro rules, define a macro in crate-global mutable scope
663 if is_macro_rules(&mac.path) { 675 if is_macro_rules(&mac.path) {
664 if let Some(name) = &mac.name { 676 if let Some(name) = &mac.name {
665 let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id)); 677 let macro_id = MacroDefId {
678 ast_id: mac.ast_id.with_file_id(self.file_id),
679 krate: self.def_collector.def_map.krate,
680 };
666 let macro_ = MacroDef { id: macro_id }; 681 let macro_ = MacroDef { id: macro_id };
667 self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export); 682 self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export);
668 } 683 }
@@ -698,6 +713,14 @@ where
698 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); 713 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
699 } 714 }
700 } 715 }
716
717 fn is_cfg_enabled(&self, attrs: &raw::Attrs) -> bool {
718 attrs.as_ref().map_or(true, |attrs| {
719 attrs
720 .iter()
721 .all(|attr| attr.is_cfg_enabled(&self.def_collector.cfg_options) != Some(false))
722 })
723 }
701} 724}
702 725
703fn is_macro_rules(path: &Path) -> bool { 726fn is_macro_rules(path: &Path) -> bool {
@@ -725,6 +748,7 @@ mod tests {
725 unresolved_imports: Vec::new(), 748 unresolved_imports: Vec::new(),
726 unexpanded_macros: Vec::new(), 749 unexpanded_macros: Vec::new(),
727 macro_stack_monitor: monitor, 750 macro_stack_monitor: monitor,
751 cfg_options: &CfgOptions::default(),
728 }; 752 };
729 collector.collect(); 753 collector.collect();
730 collector.finish() 754 collector.finish()
diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir/src/nameres/per_ns.rs
index 964da2794..0da6789de 100644
--- a/crates/ra_hir/src/nameres/per_ns.rs
+++ b/crates/ra_hir/src/nameres/per_ns.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use crate::{MacroDef, ModuleDef}; 3use crate::{MacroDef, ModuleDef};
2 4
3#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 5#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
index 29aaddbf1..623b343c4 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -1,3 +1,5 @@
1//! FIXME: write short doc here
2
1use std::{ops::Index, sync::Arc}; 3use std::{ops::Index, sync::Arc};
2 4
3use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 5use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
@@ -8,8 +10,9 @@ use ra_syntax::{
8use test_utils::tested_by; 10use test_utils::tested_by;
9 11
10use crate::{ 12use crate::{
13 attr::Attr,
11 db::{AstDatabase, DefDatabase}, 14 db::{AstDatabase, DefDatabase},
12 AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, 15 AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, Source,
13}; 16};
14 17
15/// `RawItems` is a set of top-level items in a file (except for impls). 18/// `RawItems` is a set of top-level items in a file (except for impls).
@@ -71,6 +74,8 @@ impl RawItems {
71 raw_items: RawItems::default(), 74 raw_items: RawItems::default(),
72 source_ast_id_map: db.ast_id_map(file_id), 75 source_ast_id_map: db.ast_id_map(file_id),
73 source_map: ImportSourceMap::default(), 76 source_map: ImportSourceMap::default(),
77 file_id,
78 db,
74 }; 79 };
75 if let Some(node) = db.parse_or_expand(file_id) { 80 if let Some(node) = db.parse_or_expand(file_id) {
76 if let Some(source_file) = ast::SourceFile::cast(node.clone()) { 81 if let Some(source_file) = ast::SourceFile::cast(node.clone()) {
@@ -115,8 +120,17 @@ impl Index<Macro> for RawItems {
115 } 120 }
116} 121}
117 122
123// Avoid heap allocation on items without attributes.
124pub(super) type Attrs = Option<Arc<[Attr]>>;
125
126#[derive(Debug, PartialEq, Eq, Clone)]
127pub(super) struct RawItem {
128 pub(super) attrs: Attrs,
129 pub(super) kind: RawItemKind,
130}
131
118#[derive(Debug, PartialEq, Eq, Clone, Copy)] 132#[derive(Debug, PartialEq, Eq, Clone, Copy)]
119pub(super) enum RawItem { 133pub(super) enum RawItemKind {
120 Module(Module), 134 Module(Module),
121 Import(ImportId), 135 Import(ImportId),
122 Def(Def), 136 Def(Def),
@@ -192,13 +206,15 @@ pub(super) struct MacroData {
192 pub(super) export: bool, 206 pub(super) export: bool,
193} 207}
194 208
195struct RawItemsCollector { 209struct RawItemsCollector<DB> {
196 raw_items: RawItems, 210 raw_items: RawItems,
197 source_ast_id_map: Arc<AstIdMap>, 211 source_ast_id_map: Arc<AstIdMap>,
198 source_map: ImportSourceMap, 212 source_map: ImportSourceMap,
213 file_id: HirFileId,
214 db: DB,
199} 215}
200 216
201impl RawItemsCollector { 217impl<DB: AstDatabase> RawItemsCollector<&DB> {
202 fn process_module(&mut self, current_module: Option<Module>, body: impl ast::ModuleItemOwner) { 218 fn process_module(&mut self, current_module: Option<Module>, body: impl ast::ModuleItemOwner) {
203 for item_or_macro in body.items_with_macros() { 219 for item_or_macro in body.items_with_macros() {
204 match item_or_macro { 220 match item_or_macro {
@@ -209,6 +225,7 @@ impl RawItemsCollector {
209 } 225 }
210 226
211 fn add_item(&mut self, current_module: Option<Module>, item: ast::ModuleItem) { 227 fn add_item(&mut self, current_module: Option<Module>, item: ast::ModuleItem) {
228 let attrs = self.parse_attrs(&item);
212 let (kind, name) = match item { 229 let (kind, name) = match item {
213 ast::ModuleItem::Module(module) => { 230 ast::ModuleItem::Module(module) => {
214 self.add_module(current_module, module); 231 self.add_module(current_module, module);
@@ -257,7 +274,7 @@ impl RawItemsCollector {
257 if let Some(name) = name { 274 if let Some(name) = name {
258 let name = name.as_name(); 275 let name = name.as_name();
259 let def = self.raw_items.defs.alloc(DefData { name, kind }); 276 let def = self.raw_items.defs.alloc(DefData { name, kind });
260 self.push_item(current_module, RawItem::Def(def)) 277 self.push_item(current_module, attrs, RawItemKind::Def(def));
261 } 278 }
262 } 279 }
263 280
@@ -266,8 +283,10 @@ impl RawItemsCollector {
266 Some(it) => it.as_name(), 283 Some(it) => it.as_name(),
267 None => return, 284 None => return,
268 }; 285 };
286 let attrs = self.parse_attrs(&module);
269 287
270 let ast_id = self.source_ast_id_map.ast_id(&module); 288 let ast_id = self.source_ast_id_map.ast_id(&module);
289 // FIXME: cfg_attr
271 let is_macro_use = module.has_atom_attr("macro_use"); 290 let is_macro_use = module.has_atom_attr("macro_use");
272 if module.has_semi() { 291 if module.has_semi() {
273 let attr_path = extract_mod_path_attribute(&module); 292 let attr_path = extract_mod_path_attribute(&module);
@@ -277,7 +296,7 @@ impl RawItemsCollector {
277 attr_path, 296 attr_path,
278 is_macro_use, 297 is_macro_use,
279 }); 298 });
280 self.push_item(current_module, RawItem::Module(item)); 299 self.push_item(current_module, attrs, RawItemKind::Module(item));
281 return; 300 return;
282 } 301 }
283 302
@@ -291,26 +310,37 @@ impl RawItemsCollector {
291 is_macro_use, 310 is_macro_use,
292 }); 311 });
293 self.process_module(Some(item), item_list); 312 self.process_module(Some(item), item_list);
294 self.push_item(current_module, RawItem::Module(item)); 313 self.push_item(current_module, attrs, RawItemKind::Module(item));
295 return; 314 return;
296 } 315 }
297 tested_by!(name_res_works_for_broken_modules); 316 tested_by!(name_res_works_for_broken_modules);
298 } 317 }
299 318
300 fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) { 319 fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) {
320 // FIXME: cfg_attr
301 let is_prelude = use_item.has_atom_attr("prelude_import"); 321 let is_prelude = use_item.has_atom_attr("prelude_import");
302 322 let attrs = self.parse_attrs(&use_item);
303 Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| { 323
304 let import_data = ImportData { 324 Path::expand_use_item(
305 path, 325 Source { ast: use_item, file_id: self.file_id },
306 alias, 326 self.db,
307 is_glob, 327 |path, use_tree, is_glob, alias| {
308 is_prelude, 328 let import_data = ImportData {
309 is_extern_crate: false, 329 path,
310 is_macro_use: false, 330 alias,
311 }; 331 is_glob,
312 self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); 332 is_prelude,
313 }) 333 is_extern_crate: false,
334 is_macro_use: false,
335 };
336 self.push_import(
337 current_module,
338 attrs.clone(),
339 import_data,
340 Either::A(AstPtr::new(use_tree)),
341 );
342 },
343 )
314 } 344 }
315 345
316 fn add_extern_crate_item( 346 fn add_extern_crate_item(
@@ -321,6 +351,8 @@ impl RawItemsCollector {
321 if let Some(name_ref) = extern_crate.name_ref() { 351 if let Some(name_ref) = extern_crate.name_ref() {
322 let path = Path::from_name_ref(&name_ref); 352 let path = Path::from_name_ref(&name_ref);
323 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); 353 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name());
354 let attrs = self.parse_attrs(&extern_crate);
355 // FIXME: cfg_attr
324 let is_macro_use = extern_crate.has_atom_attr("macro_use"); 356 let is_macro_use = extern_crate.has_atom_attr("macro_use");
325 let import_data = ImportData { 357 let import_data = ImportData {
326 path, 358 path,
@@ -330,37 +362,47 @@ impl RawItemsCollector {
330 is_extern_crate: true, 362 is_extern_crate: true,
331 is_macro_use, 363 is_macro_use,
332 }; 364 };
333 self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate))); 365 self.push_import(
366 current_module,
367 attrs,
368 import_data,
369 Either::B(AstPtr::new(&extern_crate)),
370 );
334 } 371 }
335 } 372 }
336 373
337 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { 374 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) {
338 let path = match m.path().and_then(Path::from_ast) { 375 let attrs = self.parse_attrs(&m);
376 let path = match m
377 .path()
378 .and_then(|path| Path::from_src(Source { ast: path, file_id: self.file_id }, self.db))
379 {
339 Some(it) => it, 380 Some(it) => it,
340 _ => return, 381 _ => return,
341 }; 382 };
342 383
343 let name = m.name().map(|it| it.as_name()); 384 let name = m.name().map(|it| it.as_name());
344 let ast_id = self.source_ast_id_map.ast_id(&m); 385 let ast_id = self.source_ast_id_map.ast_id(&m);
345 let export = m.has_atom_attr("macro_export") 386 // FIXME: cfg_attr
346 || m.attrs().filter_map(|x| x.as_call()).any(|(name, _)| name == "macro_export"); 387 let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export");
347 388
348 let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export }); 389 let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export });
349 self.push_item(current_module, RawItem::Macro(m)); 390 self.push_item(current_module, attrs, RawItemKind::Macro(m));
350 } 391 }
351 392
352 fn push_import( 393 fn push_import(
353 &mut self, 394 &mut self,
354 current_module: Option<Module>, 395 current_module: Option<Module>,
396 attrs: Attrs,
355 data: ImportData, 397 data: ImportData,
356 source: ImportSourcePtr, 398 source: ImportSourcePtr,
357 ) { 399 ) {
358 let import = self.raw_items.imports.alloc(data); 400 let import = self.raw_items.imports.alloc(data);
359 self.source_map.insert(import, source); 401 self.source_map.insert(import, source);
360 self.push_item(current_module, RawItem::Import(import)) 402 self.push_item(current_module, attrs, RawItemKind::Import(import))
361 } 403 }
362 404
363 fn push_item(&mut self, current_module: Option<Module>, item: RawItem) { 405 fn push_item(&mut self, current_module: Option<Module>, attrs: Attrs, kind: RawItemKind) {
364 match current_module { 406 match current_module {
365 Some(module) => match &mut self.raw_items.modules[module] { 407 Some(module) => match &mut self.raw_items.modules[module] {
366 ModuleData::Definition { items, .. } => items, 408 ModuleData::Definition { items, .. } => items,
@@ -368,13 +410,17 @@ impl RawItemsCollector {
368 }, 410 },
369 None => &mut self.raw_items.items, 411 None => &mut self.raw_items.items,
370 } 412 }
371 .push(item) 413 .push(RawItem { attrs, kind })
414 }
415
416 fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs {
417 Attr::from_attrs_owner(self.file_id, item, self.db)
372 } 418 }
373} 419}
374 420
375fn extract_mod_path_attribute(module: &ast::Module) -> Option<SmolStr> { 421fn extract_mod_path_attribute(module: &ast::Module) -> Option<SmolStr> {
376 module.attrs().into_iter().find_map(|attr| { 422 module.attrs().into_iter().find_map(|attr| {
377 attr.as_key_value().and_then(|(name, value)| { 423 attr.as_simple_key_value().and_then(|(name, value)| {
378 let is_path = name == "path"; 424 let is_path = name == "path";
379 if is_path { 425 if is_path {
380 Some(value) 426 Some(value)
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index bc4b47b70..34dd79574 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -7,6 +7,7 @@ mod mod_resolution;
7use std::sync::Arc; 7use std::sync::Arc;
8 8
9use insta::assert_snapshot; 9use insta::assert_snapshot;
10use ra_cfg::CfgOptions;
10use ra_db::SourceDatabase; 11use ra_db::SourceDatabase;
11use test_utils::covers; 12use test_utils::covers;
12 13
@@ -507,3 +508,72 @@ fn values_dont_shadow_extern_crates() {
507 ⋮foo: v 508 ⋮foo: v
508 "###); 509 "###);
509} 510}
511
512#[test]
513fn cfg_not_test() {
514 let map = def_map_with_crate_graph(
515 r#"
516 //- /main.rs
517 use {Foo, Bar, Baz};
518 //- /lib.rs
519 #[prelude_import]
520 pub use self::prelude::*;
521 mod prelude {
522 #[cfg(test)]
523 pub struct Foo;
524 #[cfg(not(test))]
525 pub struct Bar;
526 #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))]
527 pub struct Baz;
528 }
529 "#,
530 crate_graph! {
531 "main": ("/main.rs", ["std"]),
532 "std": ("/lib.rs", []),
533 },
534 );
535
536 assert_snapshot!(map, @r###"
537 ⋮crate
538 ⋮Bar: t v
539 ⋮Baz: _
540 ⋮Foo: _
541 "###);
542}
543
544#[test]
545fn cfg_test() {
546 let map = def_map_with_crate_graph(
547 r#"
548 //- /main.rs
549 use {Foo, Bar, Baz};
550 //- /lib.rs
551 #[prelude_import]
552 pub use self::prelude::*;
553 mod prelude {
554 #[cfg(test)]
555 pub struct Foo;
556 #[cfg(not(test))]
557 pub struct Bar;
558 #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))]
559 pub struct Baz;
560 }
561 "#,
562 crate_graph! {
563 "main": ("/main.rs", ["std"]),
564 "std": ("/lib.rs", [], CfgOptions::default()
565 .atom("test".into())
566 .key_value("feature".into(), "foo".into())
567 .key_value("feature".into(), "bar".into())
568 .key_value("opt".into(), "42".into())
569 ),
570 },
571 );
572
573 assert_snapshot!(map, @r###"
574 ⋮crate
575 ⋮Bar: _
576 ⋮Baz: t v
577 ⋮Foo: t v
578 "###);
579}
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
index bd60f4258..e4b408394 100644
--- a/crates/ra_hir/src/nameres/tests/macros.rs
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -515,3 +515,108 @@ fn path_qualified_macros() {
515 ⋮not_found: _ 515 ⋮not_found: _
516 "###); 516 "###);
517} 517}
518
519#[test]
520fn macro_dollar_crate_is_correct_in_item() {
521 covers!(macro_dollar_crate_self);
522 covers!(macro_dollar_crate_other);
523 let map = def_map_with_crate_graph(
524 "
525 //- /main.rs
526 #[macro_use]
527 extern crate foo;
528
529 #[macro_use]
530 mod m {
531 macro_rules! current {
532 () => {
533 use $crate::Foo as FooSelf;
534 }
535 }
536 }
537
538 struct Foo;
539
540 current!();
541 not_current1!();
542 foo::not_current2!();
543
544 //- /lib.rs
545 mod m {
546 #[macro_export]
547 macro_rules! not_current1 {
548 () => {
549 use $crate::Bar;
550 }
551 }
552 }
553
554 #[macro_export]
555 macro_rules! not_current2 {
556 () => {
557 use $crate::Baz;
558 }
559 }
560
561 struct Bar;
562 struct Baz;
563 ",
564 crate_graph! {
565 "main": ("/main.rs", ["foo"]),
566 "foo": ("/lib.rs", []),
567 },
568 );
569 assert_snapshot!(map, @r###"
570 ⋮crate
571 ⋮Bar: t v
572 ⋮Baz: t v
573 ⋮Foo: t v
574 ⋮FooSelf: t v
575 ⋮foo: t
576 ⋮m: t
577
578 ⋮crate::m
579 "###);
580}
581
582#[test]
583fn macro_dollar_crate_is_correct_in_indirect_deps() {
584 covers!(macro_dollar_crate_other);
585 // From std
586 let map = def_map_with_crate_graph(
587 r#"
588 //- /main.rs
589 foo!();
590
591 //- /std.rs
592 #[prelude_import]
593 use self::prelude::*;
594
595 pub use core::foo;
596
597 mod prelude {}
598
599 #[macro_use]
600 mod std_macros;
601
602 //- /core.rs
603 #[macro_export]
604 macro_rules! foo {
605 () => {
606 use $crate::bar;
607 }
608 }
609
610 pub struct bar;
611 "#,
612 crate_graph! {
613 "main": ("/main.rs", ["std"]),
614 "std": ("/std.rs", ["core"]),
615 "core": ("/core.rs", []),
616 },
617 );
618 assert_snapshot!(map, @r###"
619 ⋮crate
620 ⋮bar: t v
621 "###);
622}