aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/nameres
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/nameres')
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs514
-rw-r--r--crates/ra_hir_def/src/nameres/mod_resolution.rs121
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs482
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs25
-rw-r--r--crates/ra_hir_def/src/nameres/tests/globs.rs137
-rw-r--r--crates/ra_hir_def/src/nameres/tests/incremental.rs38
-rw-r--r--crates/ra_hir_def/src/nameres/tests/macros.rs24
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs28
8 files changed, 614 insertions, 755 deletions
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 353a31ad4..d85a86c0a 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -4,6 +4,7 @@
4//! resolves imports and expands macros. 4//! resolves imports and expands macros.
5 5
6use hir_expand::{ 6use hir_expand::{
7 ast_id_map::FileAstId,
7 builtin_derive::find_builtin_derive, 8 builtin_derive::find_builtin_derive,
8 builtin_macro::find_builtin_macro, 9 builtin_macro::find_builtin_macro,
9 name::{name, AsName, Name}, 10 name::{name, AsName, Name},
@@ -19,25 +20,33 @@ use test_utils::mark;
19use crate::{ 20use crate::{
20 attr::Attrs, 21 attr::Attrs,
21 db::DefDatabase, 22 db::DefDatabase,
23 item_scope::{ImportType, PerNsGlobImports},
24 item_tree::{
25 self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind,
26 },
22 nameres::{ 27 nameres::{
23 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, 28 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
24 raw, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode, 29 BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode,
25 }, 30 },
26 path::{ImportAlias, ModPath, PathKind}, 31 path::{ImportAlias, ModPath, PathKind},
27 per_ns::PerNs, 32 per_ns::PerNs,
28 visibility::Visibility, 33 visibility::{RawVisibility, Visibility},
29 AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId, 34 AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId,
30 FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, 35 FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc,
31 TraitLoc, TypeAliasLoc, UnionLoc, 36 TraitLoc, TypeAliasLoc, UnionLoc,
32}; 37};
33 38
39const GLOB_RECURSION_LIMIT: usize = 100;
40const EXPANSION_DEPTH_LIMIT: usize = 128;
41const FIXED_POINT_LIMIT: usize = 8192;
42
34pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 43pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
35 let crate_graph = db.crate_graph(); 44 let crate_graph = db.crate_graph();
36 45
37 // populate external prelude 46 // populate external prelude
38 for dep in &crate_graph[def_map.krate].dependencies { 47 for dep in &crate_graph[def_map.krate].dependencies {
39 let dep_def_map = db.crate_def_map(dep.crate_id);
40 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); 48 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
49 let dep_def_map = db.crate_def_map(dep.crate_id);
41 def_map.extern_prelude.insert( 50 def_map.extern_prelude.insert(
42 dep.as_name(), 51 dep.as_name(),
43 ModuleId { krate: dep.crate_id, local_id: dep_def_map.root }.into(), 52 ModuleId { krate: dep.crate_id, local_id: dep_def_map.root }.into(),
@@ -76,6 +85,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> Cr
76 mod_dirs: FxHashMap::default(), 85 mod_dirs: FxHashMap::default(),
77 cfg_options, 86 cfg_options,
78 proc_macros, 87 proc_macros,
88 from_glob_import: Default::default(),
79 }; 89 };
80 collector.collect(); 90 collector.collect();
81 collector.finish() 91 collector.finish()
@@ -102,10 +112,50 @@ impl PartialResolvedImport {
102} 112}
103 113
104#[derive(Clone, Debug, Eq, PartialEq)] 114#[derive(Clone, Debug, Eq, PartialEq)]
115struct Import {
116 pub path: ModPath,
117 pub alias: Option<ImportAlias>,
118 pub visibility: RawVisibility,
119 pub is_glob: bool,
120 pub is_prelude: bool,
121 pub is_extern_crate: bool,
122 pub is_macro_use: bool,
123}
124
125impl Import {
126 fn from_use(tree: &ItemTree, id: FileItemTreeId<item_tree::Import>) -> Self {
127 let it = &tree[id];
128 let visibility = &tree[it.visibility];
129 Self {
130 path: it.path.clone(),
131 alias: it.alias.clone(),
132 visibility: visibility.clone(),
133 is_glob: it.is_glob,
134 is_prelude: it.is_prelude,
135 is_extern_crate: false,
136 is_macro_use: false,
137 }
138 }
139
140 fn from_extern_crate(tree: &ItemTree, id: FileItemTreeId<item_tree::ExternCrate>) -> Self {
141 let it = &tree[id];
142 let visibility = &tree[it.visibility];
143 Self {
144 path: it.path.clone(),
145 alias: it.alias.clone(),
146 visibility: visibility.clone(),
147 is_glob: false,
148 is_prelude: false,
149 is_extern_crate: true,
150 is_macro_use: it.is_macro_use,
151 }
152 }
153}
154
155#[derive(Clone, Debug, Eq, PartialEq)]
105struct ImportDirective { 156struct ImportDirective {
106 module_id: LocalModuleId, 157 module_id: LocalModuleId,
107 import_id: raw::Import, 158 import: Import,
108 import: raw::ImportData,
109 status: PartialResolvedImport, 159 status: PartialResolvedImport,
110} 160}
111 161
@@ -123,6 +173,13 @@ struct DeriveDirective {
123 ast_id: AstIdWithPath<ast::ModuleItem>, 173 ast_id: AstIdWithPath<ast::ModuleItem>,
124} 174}
125 175
176struct DefData<'a> {
177 id: ModuleDefId,
178 name: &'a Name,
179 visibility: &'a RawVisibility,
180 has_constructor: bool,
181}
182
126/// Walks the tree of module recursively 183/// Walks the tree of module recursively
127struct DefCollector<'a> { 184struct DefCollector<'a> {
128 db: &'a dyn DefDatabase, 185 db: &'a dyn DefDatabase,
@@ -135,12 +192,13 @@ struct DefCollector<'a> {
135 mod_dirs: FxHashMap<LocalModuleId, ModDir>, 192 mod_dirs: FxHashMap<LocalModuleId, ModDir>,
136 cfg_options: &'a CfgOptions, 193 cfg_options: &'a CfgOptions,
137 proc_macros: Vec<(Name, ProcMacroExpander)>, 194 proc_macros: Vec<(Name, ProcMacroExpander)>,
195 from_glob_import: PerNsGlobImports,
138} 196}
139 197
140impl DefCollector<'_> { 198impl DefCollector<'_> {
141 fn collect(&mut self) { 199 fn collect(&mut self) {
142 let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; 200 let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id;
143 let raw_items = self.db.raw_items(file_id.into()); 201 let item_tree = self.db.item_tree(file_id.into());
144 let module_id = self.def_map.root; 202 let module_id = self.def_map.root;
145 self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; 203 self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id };
146 ModCollector { 204 ModCollector {
@@ -148,10 +206,10 @@ impl DefCollector<'_> {
148 macro_depth: 0, 206 macro_depth: 0,
149 module_id, 207 module_id,
150 file_id: file_id.into(), 208 file_id: file_id.into(),
151 raw_items: &raw_items, 209 item_tree: &item_tree,
152 mod_dir: ModDir::root(), 210 mod_dir: ModDir::root(),
153 } 211 }
154 .collect(raw_items.items()); 212 .collect(item_tree.top_level_items());
155 213
156 // main name resolution fixed-point loop. 214 // main name resolution fixed-point loop.
157 let mut i = 0; 215 let mut i = 0;
@@ -163,7 +221,7 @@ impl DefCollector<'_> {
163 ReachedFixedPoint::Yes => break, 221 ReachedFixedPoint::Yes => break,
164 ReachedFixedPoint::No => i += 1, 222 ReachedFixedPoint::No => i += 1,
165 } 223 }
166 if i == 10000 { 224 if i == FIXED_POINT_LIMIT {
167 log::error!("name resolution is stuck"); 225 log::error!("name resolution is stuck");
168 break; 226 break;
169 } 227 }
@@ -254,6 +312,7 @@ impl DefCollector<'_> {
254 self.def_map.root, 312 self.def_map.root,
255 &[(name, PerNs::macros(macro_, Visibility::Public))], 313 &[(name, PerNs::macros(macro_, Visibility::Public))],
256 Visibility::Public, 314 Visibility::Public,
315 ImportType::Named,
257 ); 316 );
258 } 317 }
259 } 318 }
@@ -279,6 +338,7 @@ impl DefCollector<'_> {
279 self.def_map.root, 338 self.def_map.root,
280 &[(name, PerNs::macros(macro_, Visibility::Public))], 339 &[(name, PerNs::macros(macro_, Visibility::Public))],
281 Visibility::Public, 340 Visibility::Public,
341 ImportType::Named,
282 ); 342 );
283 } 343 }
284 344
@@ -286,7 +346,7 @@ impl DefCollector<'_> {
286 fn import_macros_from_extern_crate( 346 fn import_macros_from_extern_crate(
287 &mut self, 347 &mut self,
288 current_module_id: LocalModuleId, 348 current_module_id: LocalModuleId,
289 import: &raw::ImportData, 349 import: &item_tree::ExternCrate,
290 ) { 350 ) {
291 log::debug!( 351 log::debug!(
292 "importing macros from extern crate: {:?} ({:?})", 352 "importing macros from extern crate: {:?} ({:?})",
@@ -332,7 +392,6 @@ impl DefCollector<'_> {
332 let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); 392 let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
333 for mut directive in imports { 393 for mut directive in imports {
334 directive.status = self.resolve_import(directive.module_id, &directive.import); 394 directive.status = self.resolve_import(directive.module_id, &directive.import);
335
336 match directive.status { 395 match directive.status {
337 PartialResolvedImport::Indeterminate(_) => { 396 PartialResolvedImport::Indeterminate(_) => {
338 self.record_resolved_import(&directive); 397 self.record_resolved_import(&directive);
@@ -352,11 +411,7 @@ impl DefCollector<'_> {
352 } 411 }
353 } 412 }
354 413
355 fn resolve_import( 414 fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport {
356 &self,
357 module_id: LocalModuleId,
358 import: &raw::ImportData,
359 ) -> PartialResolvedImport {
360 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 415 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
361 if import.is_extern_crate { 416 if import.is_extern_crate {
362 let res = self.def_map.resolve_name_in_extern_prelude( 417 let res = self.def_map.resolve_name_in_extern_prelude(
@@ -430,7 +485,7 @@ impl DefCollector<'_> {
430 .filter(|(_, res)| !res.is_none()) 485 .filter(|(_, res)| !res.is_none())
431 .collect::<Vec<_>>(); 486 .collect::<Vec<_>>();
432 487
433 self.update(module_id, &items, vis); 488 self.update(module_id, &items, vis, ImportType::Glob);
434 } else { 489 } else {
435 // glob import from same crate => we do an initial 490 // glob import from same crate => we do an initial
436 // import, and then need to propagate any further 491 // import, and then need to propagate any further
@@ -452,7 +507,7 @@ impl DefCollector<'_> {
452 .filter(|(_, res)| !res.is_none()) 507 .filter(|(_, res)| !res.is_none())
453 .collect::<Vec<_>>(); 508 .collect::<Vec<_>>();
454 509
455 self.update(module_id, &items, vis); 510 self.update(module_id, &items, vis, ImportType::Glob);
456 // record the glob import in case we add further items 511 // record the glob import in case we add further items
457 let glob = self.glob_imports.entry(m.local_id).or_default(); 512 let glob = self.glob_imports.entry(m.local_id).or_default();
458 if !glob.iter().any(|(mid, _)| *mid == module_id) { 513 if !glob.iter().any(|(mid, _)| *mid == module_id) {
@@ -482,7 +537,7 @@ impl DefCollector<'_> {
482 (name, res) 537 (name, res)
483 }) 538 })
484 .collect::<Vec<_>>(); 539 .collect::<Vec<_>>();
485 self.update(module_id, &resolutions, vis); 540 self.update(module_id, &resolutions, vis, ImportType::Glob);
486 } 541 }
487 Some(d) => { 542 Some(d) => {
488 log::debug!("glob import {:?} from non-module/enum {:?}", import, d); 543 log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
@@ -508,15 +563,22 @@ impl DefCollector<'_> {
508 } 563 }
509 } 564 }
510 565
511 self.update(module_id, &[(name, def)], vis); 566 self.update(module_id, &[(name, def)], vis, ImportType::Named);
512 } 567 }
513 None => mark::hit!(bogus_paths), 568 None => mark::hit!(bogus_paths),
514 } 569 }
515 } 570 }
516 } 571 }
517 572
518 fn update(&mut self, module_id: LocalModuleId, resolutions: &[(Name, PerNs)], vis: Visibility) { 573 fn update(
519 self.update_recursive(module_id, resolutions, vis, 0) 574 &mut self,
575 module_id: LocalModuleId,
576 resolutions: &[(Name, PerNs)],
577 vis: Visibility,
578 import_type: ImportType,
579 ) {
580 self.db.check_canceled();
581 self.update_recursive(module_id, resolutions, vis, import_type, 0)
520 } 582 }
521 583
522 fn update_recursive( 584 fn update_recursive(
@@ -526,16 +588,22 @@ impl DefCollector<'_> {
526 // All resolutions are imported with this visibility; the visibilies in 588 // All resolutions are imported with this visibility; the visibilies in
527 // the `PerNs` values are ignored and overwritten 589 // the `PerNs` values are ignored and overwritten
528 vis: Visibility, 590 vis: Visibility,
591 import_type: ImportType,
529 depth: usize, 592 depth: usize,
530 ) { 593 ) {
531 if depth > 100 { 594 if depth > GLOB_RECURSION_LIMIT {
532 // prevent stack overflows (but this shouldn't be possible) 595 // prevent stack overflows (but this shouldn't be possible)
533 panic!("infinite recursion in glob imports!"); 596 panic!("infinite recursion in glob imports!");
534 } 597 }
535 let scope = &mut self.def_map.modules[module_id].scope; 598 let scope = &mut self.def_map.modules[module_id].scope;
536 let mut changed = false; 599 let mut changed = false;
537 for (name, res) in resolutions { 600 for (name, res) in resolutions {
538 changed |= scope.push_res(name.clone(), res.with_visibility(vis)); 601 changed |= scope.push_res_with_import(
602 &mut self.from_glob_import,
603 (module_id, name.clone()),
604 res.with_visibility(vis),
605 import_type,
606 );
539 } 607 }
540 608
541 if !changed { 609 if !changed {
@@ -546,15 +614,22 @@ impl DefCollector<'_> {
546 .get(&module_id) 614 .get(&module_id)
547 .into_iter() 615 .into_iter()
548 .flat_map(|v| v.iter()) 616 .flat_map(|v| v.iter())
617 .filter(|(glob_importing_module, _)| {
618 // we know all resolutions have the same visibility (`vis`), so we
619 // just need to check that once
620 vis.is_visible_from_def_map(&self.def_map, *glob_importing_module)
621 })
549 .cloned() 622 .cloned()
550 .collect::<Vec<_>>(); 623 .collect::<Vec<_>>();
624
551 for (glob_importing_module, glob_import_vis) in glob_imports { 625 for (glob_importing_module, glob_import_vis) in glob_imports {
552 // we know all resolutions have the same visibility (`vis`), so we 626 self.update_recursive(
553 // just need to check that once 627 glob_importing_module,
554 if !vis.is_visible_from_def_map(&self.def_map, glob_importing_module) { 628 resolutions,
555 continue; 629 glob_import_vis,
556 } 630 ImportType::Glob,
557 self.update_recursive(glob_importing_module, resolutions, glob_import_vis, depth + 1); 631 depth + 1,
632 );
558 } 633 }
559 } 634 }
560 635
@@ -571,16 +646,18 @@ impl DefCollector<'_> {
571 return false; 646 return false;
572 } 647 }
573 648
574 if let Some(call_id) = directive.ast_id.as_call_id(self.db, |path| { 649 if let Some(call_id) =
575 let resolved_res = self.def_map.resolve_path_fp_with_macro( 650 directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| {
576 self.db, 651 let resolved_res = self.def_map.resolve_path_fp_with_macro(
577 ResolveMode::Other, 652 self.db,
578 directive.module_id, 653 ResolveMode::Other,
579 &path, 654 directive.module_id,
580 BuiltinShadowMode::Module, 655 &path,
581 ); 656 BuiltinShadowMode::Module,
582 resolved_res.resolved_def.take_macros() 657 );
583 }) { 658 resolved_res.resolved_def.take_macros()
659 })
660 {
584 resolved.push((directive.module_id, call_id, directive.depth)); 661 resolved.push((directive.module_id, call_id, directive.depth));
585 res = ReachedFixedPoint::No; 662 res = ReachedFixedPoint::No;
586 return false; 663 return false;
@@ -589,9 +666,10 @@ impl DefCollector<'_> {
589 true 666 true
590 }); 667 });
591 attribute_macros.retain(|directive| { 668 attribute_macros.retain(|directive| {
592 if let Some(call_id) = directive 669 if let Some(call_id) =
593 .ast_id 670 directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| {
594 .as_call_id(self.db, |path| self.resolve_attribute_macro(&directive, &path)) 671 self.resolve_attribute_macro(&directive, &path)
672 })
595 { 673 {
596 resolved.push((directive.module_id, call_id, 0)); 674 resolved.push((directive.module_id, call_id, 0));
597 res = ReachedFixedPoint::No; 675 res = ReachedFixedPoint::No;
@@ -605,10 +683,6 @@ impl DefCollector<'_> {
605 self.unexpanded_attribute_macros = attribute_macros; 683 self.unexpanded_attribute_macros = attribute_macros;
606 684
607 for (module_id, macro_call_id, depth) in resolved { 685 for (module_id, macro_call_id, depth) in resolved {
608 if depth > 1024 {
609 log::debug!("Max macro expansion depth reached");
610 continue;
611 }
612 self.collect_macro_expansion(module_id, macro_call_id, depth); 686 self.collect_macro_expansion(module_id, macro_call_id, depth);
613 } 687 }
614 688
@@ -645,18 +719,23 @@ impl DefCollector<'_> {
645 macro_call_id: MacroCallId, 719 macro_call_id: MacroCallId,
646 depth: usize, 720 depth: usize,
647 ) { 721 ) {
722 if depth > EXPANSION_DEPTH_LIMIT {
723 mark::hit!(macro_expansion_overflow);
724 log::warn!("macro expansion is too deep");
725 return;
726 }
648 let file_id: HirFileId = macro_call_id.as_file(); 727 let file_id: HirFileId = macro_call_id.as_file();
649 let raw_items = self.db.raw_items(file_id); 728 let item_tree = self.db.item_tree(file_id);
650 let mod_dir = self.mod_dirs[&module_id].clone(); 729 let mod_dir = self.mod_dirs[&module_id].clone();
651 ModCollector { 730 ModCollector {
652 def_collector: &mut *self, 731 def_collector: &mut *self,
653 macro_depth: depth, 732 macro_depth: depth,
654 file_id, 733 file_id,
655 module_id, 734 module_id,
656 raw_items: &raw_items, 735 item_tree: &item_tree,
657 mod_dir, 736 mod_dir,
658 } 737 }
659 .collect(raw_items.items()); 738 .collect(item_tree.top_level_items());
660 } 739 }
661 740
662 fn finish(self) -> CrateDefMap { 741 fn finish(self) -> CrateDefMap {
@@ -670,12 +749,12 @@ struct ModCollector<'a, 'b> {
670 macro_depth: usize, 749 macro_depth: usize,
671 module_id: LocalModuleId, 750 module_id: LocalModuleId,
672 file_id: HirFileId, 751 file_id: HirFileId,
673 raw_items: &'a raw::RawItems, 752 item_tree: &'a ItemTree,
674 mod_dir: ModDir, 753 mod_dir: ModDir,
675} 754}
676 755
677impl ModCollector<'_, '_> { 756impl ModCollector<'_, '_> {
678 fn collect(&mut self, items: &[raw::RawItem]) { 757 fn collect(&mut self, items: &[ModItem]) {
679 // Note: don't assert that inserted value is fresh: it's simply not true 758 // Note: don't assert that inserted value is fresh: it's simply not true
680 // for macros. 759 // for macros.
681 self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone()); 760 self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
@@ -692,64 +771,205 @@ impl ModCollector<'_, '_> {
692 // `#[macro_use] extern crate` is hoisted to imports macros before collecting 771 // `#[macro_use] extern crate` is hoisted to imports macros before collecting
693 // any other items. 772 // any other items.
694 for item in items { 773 for item in items {
695 if self.is_cfg_enabled(&item.attrs) { 774 if self.is_cfg_enabled(self.item_tree.attrs((*item).into())) {
696 if let raw::RawItemKind::Import(import_id) = item.kind { 775 if let ModItem::ExternCrate(id) = item {
697 let import = self.raw_items[import_id].clone(); 776 let import = self.item_tree[*id].clone();
698 if import.is_extern_crate && import.is_macro_use { 777 if import.is_macro_use {
699 self.def_collector.import_macros_from_extern_crate(self.module_id, &import); 778 self.def_collector.import_macros_from_extern_crate(self.module_id, &import);
700 } 779 }
701 } 780 }
702 } 781 }
703 } 782 }
704 783
705 for item in items { 784 for &item in items {
706 if self.is_cfg_enabled(&item.attrs) { 785 let attrs = self.item_tree.attrs(item.into());
707 match item.kind { 786 if self.is_cfg_enabled(attrs) {
708 raw::RawItemKind::Module(m) => { 787 let module =
709 self.collect_module(&self.raw_items[m], &item.attrs) 788 ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
710 } 789 let container = ContainerId::ModuleId(module);
711 raw::RawItemKind::Import(import_id) => { 790
791 let mut def = None;
792 match item {
793 ModItem::Mod(m) => self.collect_module(&self.item_tree[m], attrs),
794 ModItem::Import(import_id) => {
712 self.def_collector.unresolved_imports.push(ImportDirective { 795 self.def_collector.unresolved_imports.push(ImportDirective {
713 module_id: self.module_id, 796 module_id: self.module_id,
714 import_id, 797 import: Import::from_use(&self.item_tree, import_id),
715 import: self.raw_items[import_id].clone(),
716 status: PartialResolvedImport::Unresolved, 798 status: PartialResolvedImport::Unresolved,
717 }) 799 })
718 } 800 }
719 raw::RawItemKind::Def(def) => { 801 ModItem::ExternCrate(import_id) => {
720 self.define_def(&self.raw_items[def], &item.attrs) 802 self.def_collector.unresolved_imports.push(ImportDirective {
803 module_id: self.module_id,
804 import: Import::from_extern_crate(&self.item_tree, import_id),
805 status: PartialResolvedImport::Unresolved,
806 })
721 } 807 }
722 raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), 808 ModItem::MacroCall(mac) => self.collect_macro(&self.item_tree[mac]),
723 raw::RawItemKind::Impl(imp) => { 809 ModItem::Impl(imp) => {
724 let module = ModuleId { 810 let module = ModuleId {
725 krate: self.def_collector.def_map.krate, 811 krate: self.def_collector.def_map.krate,
726 local_id: self.module_id, 812 local_id: self.module_id,
727 }; 813 };
728 let container = ContainerId::ModuleId(module); 814 let container = ContainerId::ModuleId(module);
729 let ast_id = self.raw_items[imp].ast_id; 815 let impl_id = ImplLoc { container, id: ItemTreeId::new(self.file_id, imp) }
730 let impl_id = 816 .intern(self.def_collector.db);
731 ImplLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
732 .intern(self.def_collector.db);
733 self.def_collector.def_map.modules[self.module_id] 817 self.def_collector.def_map.modules[self.module_id]
734 .scope 818 .scope
735 .define_impl(impl_id) 819 .define_impl(impl_id)
736 } 820 }
821 ModItem::Function(id) => {
822 let func = &self.item_tree[id];
823 def = Some(DefData {
824 id: FunctionLoc {
825 container: container.into(),
826 id: ItemTreeId::new(self.file_id, id),
827 }
828 .intern(self.def_collector.db)
829 .into(),
830 name: &func.name,
831 visibility: &self.item_tree[func.visibility],
832 has_constructor: false,
833 });
834 }
835 ModItem::Struct(id) => {
836 let it = &self.item_tree[id];
837
838 // FIXME: check attrs to see if this is an attribute macro invocation;
839 // in which case we don't add the invocation, just a single attribute
840 // macro invocation
841 self.collect_derives(attrs, it.ast_id.upcast());
842
843 def = Some(DefData {
844 id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) }
845 .intern(self.def_collector.db)
846 .into(),
847 name: &it.name,
848 visibility: &self.item_tree[it.visibility],
849 has_constructor: it.kind != StructDefKind::Record,
850 });
851 }
852 ModItem::Union(id) => {
853 let it = &self.item_tree[id];
854
855 // FIXME: check attrs to see if this is an attribute macro invocation;
856 // in which case we don't add the invocation, just a single attribute
857 // macro invocation
858 self.collect_derives(attrs, it.ast_id.upcast());
859
860 def = Some(DefData {
861 id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) }
862 .intern(self.def_collector.db)
863 .into(),
864 name: &it.name,
865 visibility: &self.item_tree[it.visibility],
866 has_constructor: false,
867 });
868 }
869 ModItem::Enum(id) => {
870 let it = &self.item_tree[id];
871
872 // FIXME: check attrs to see if this is an attribute macro invocation;
873 // in which case we don't add the invocation, just a single attribute
874 // macro invocation
875 self.collect_derives(attrs, it.ast_id.upcast());
876
877 def = Some(DefData {
878 id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) }
879 .intern(self.def_collector.db)
880 .into(),
881 name: &it.name,
882 visibility: &self.item_tree[it.visibility],
883 has_constructor: false,
884 });
885 }
886 ModItem::Const(id) => {
887 let it = &self.item_tree[id];
888
889 if let Some(name) = &it.name {
890 def = Some(DefData {
891 id: ConstLoc {
892 container: container.into(),
893 id: ItemTreeId::new(self.file_id, id),
894 }
895 .intern(self.def_collector.db)
896 .into(),
897 name,
898 visibility: &self.item_tree[it.visibility],
899 has_constructor: false,
900 });
901 }
902 }
903 ModItem::Static(id) => {
904 let it = &self.item_tree[id];
905
906 def = Some(DefData {
907 id: StaticLoc { container, id: ItemTreeId::new(self.file_id, id) }
908 .intern(self.def_collector.db)
909 .into(),
910 name: &it.name,
911 visibility: &self.item_tree[it.visibility],
912 has_constructor: false,
913 });
914 }
915 ModItem::Trait(id) => {
916 let it = &self.item_tree[id];
917
918 def = Some(DefData {
919 id: TraitLoc { container, id: ItemTreeId::new(self.file_id, id) }
920 .intern(self.def_collector.db)
921 .into(),
922 name: &it.name,
923 visibility: &self.item_tree[it.visibility],
924 has_constructor: false,
925 });
926 }
927 ModItem::TypeAlias(id) => {
928 let it = &self.item_tree[id];
929
930 def = Some(DefData {
931 id: TypeAliasLoc {
932 container: container.into(),
933 id: ItemTreeId::new(self.file_id, id),
934 }
935 .intern(self.def_collector.db)
936 .into(),
937 name: &it.name,
938 visibility: &self.item_tree[it.visibility],
939 has_constructor: false,
940 });
941 }
942 }
943
944 if let Some(DefData { id, name, visibility, has_constructor }) = def {
945 self.def_collector.def_map.modules[self.module_id].scope.define_def(id);
946 let vis = self
947 .def_collector
948 .def_map
949 .resolve_visibility(self.def_collector.db, self.module_id, visibility)
950 .unwrap_or(Visibility::Public);
951 self.def_collector.update(
952 self.module_id,
953 &[(name.clone(), PerNs::from_def(id, vis, has_constructor))],
954 vis,
955 ImportType::Named,
956 )
737 } 957 }
738 } 958 }
739 } 959 }
740 } 960 }
741 961
742 fn collect_module(&mut self, module: &raw::ModuleData, attrs: &Attrs) { 962 fn collect_module(&mut self, module: &Mod, attrs: &Attrs) {
743 let path_attr = attrs.by_key("path").string_value(); 963 let path_attr = attrs.by_key("path").string_value();
744 let is_macro_use = attrs.by_key("macro_use").exists(); 964 let is_macro_use = attrs.by_key("macro_use").exists();
745 match module { 965 match &module.kind {
746 // inline module, just recurse 966 // inline module, just recurse
747 raw::ModuleData::Definition { name, visibility, items, ast_id } => { 967 ModKind::Inline { items } => {
748 let module_id = self.push_child_module( 968 let module_id = self.push_child_module(
749 name.clone(), 969 module.name.clone(),
750 AstId::new(self.file_id, *ast_id), 970 AstId::new(self.file_id, module.ast_id),
751 None, 971 None,
752 &visibility, 972 &self.item_tree[module.visibility],
753 ); 973 );
754 974
755 ModCollector { 975 ModCollector {
@@ -757,8 +977,8 @@ impl ModCollector<'_, '_> {
757 macro_depth: self.macro_depth, 977 macro_depth: self.macro_depth,
758 module_id, 978 module_id,
759 file_id: self.file_id, 979 file_id: self.file_id,
760 raw_items: self.raw_items, 980 item_tree: self.item_tree,
761 mod_dir: self.mod_dir.descend_into_definition(name, path_attr), 981 mod_dir: self.mod_dir.descend_into_definition(&module.name, path_attr),
762 } 982 }
763 .collect(&*items); 983 .collect(&*items);
764 if is_macro_use { 984 if is_macro_use {
@@ -766,31 +986,31 @@ impl ModCollector<'_, '_> {
766 } 986 }
767 } 987 }
768 // out of line module, resolve, parse and recurse 988 // out of line module, resolve, parse and recurse
769 raw::ModuleData::Declaration { name, visibility, ast_id } => { 989 ModKind::Outline {} => {
770 let ast_id = AstId::new(self.file_id, *ast_id); 990 let ast_id = AstId::new(self.file_id, module.ast_id);
771 match self.mod_dir.resolve_declaration( 991 match self.mod_dir.resolve_declaration(
772 self.def_collector.db, 992 self.def_collector.db,
773 self.file_id, 993 self.file_id,
774 name, 994 &module.name,
775 path_attr, 995 path_attr,
776 ) { 996 ) {
777 Ok((file_id, mod_dir)) => { 997 Ok((file_id, is_mod_rs, mod_dir)) => {
778 let module_id = self.push_child_module( 998 let module_id = self.push_child_module(
779 name.clone(), 999 module.name.clone(),
780 ast_id, 1000 ast_id,
781 Some(file_id), 1001 Some((file_id, is_mod_rs)),
782 &visibility, 1002 &self.item_tree[module.visibility],
783 ); 1003 );
784 let raw_items = self.def_collector.db.raw_items(file_id.into()); 1004 let item_tree = self.def_collector.db.item_tree(file_id.into());
785 ModCollector { 1005 ModCollector {
786 def_collector: &mut *self.def_collector, 1006 def_collector: &mut *self.def_collector,
787 macro_depth: self.macro_depth, 1007 macro_depth: self.macro_depth,
788 module_id, 1008 module_id,
789 file_id: file_id.into(), 1009 file_id: file_id.into(),
790 raw_items: &raw_items, 1010 item_tree: &item_tree,
791 mod_dir, 1011 mod_dir,
792 } 1012 }
793 .collect(raw_items.items()); 1013 .collect(item_tree.top_level_items());
794 if is_macro_use { 1014 if is_macro_use {
795 self.import_all_legacy_macros(module_id); 1015 self.import_all_legacy_macros(module_id);
796 } 1016 }
@@ -811,7 +1031,7 @@ impl ModCollector<'_, '_> {
811 &mut self, 1031 &mut self,
812 name: Name, 1032 name: Name,
813 declaration: AstId<ast::Module>, 1033 declaration: AstId<ast::Module>,
814 definition: Option<FileId>, 1034 definition: Option<(FileId, bool)>,
815 visibility: &crate::visibility::RawVisibility, 1035 visibility: &crate::visibility::RawVisibility,
816 ) -> LocalModuleId { 1036 ) -> LocalModuleId {
817 let vis = self 1037 let vis = self
@@ -822,7 +1042,12 @@ impl ModCollector<'_, '_> {
822 let modules = &mut self.def_collector.def_map.modules; 1042 let modules = &mut self.def_collector.def_map.modules;
823 let res = modules.alloc(ModuleData::default()); 1043 let res = modules.alloc(ModuleData::default());
824 modules[res].parent = Some(self.module_id); 1044 modules[res].parent = Some(self.module_id);
825 modules[res].origin = ModuleOrigin::not_sure_file(definition, declaration); 1045 modules[res].origin = match definition {
1046 None => ModuleOrigin::Inline { definition: declaration },
1047 Some((definition, is_mod_rs)) => {
1048 ModuleOrigin::File { declaration, definition, is_mod_rs }
1049 }
1050 };
826 for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() { 1051 for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() {
827 modules[res].scope.define_legacy_macro(name, mac) 1052 modules[res].scope.define_legacy_macro(name, mac)
828 } 1053 }
@@ -830,81 +1055,16 @@ impl ModCollector<'_, '_> {
830 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res }; 1055 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res };
831 let def: ModuleDefId = module.into(); 1056 let def: ModuleDefId = module.into();
832 self.def_collector.def_map.modules[self.module_id].scope.define_def(def); 1057 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
833 self.def_collector.update(self.module_id, &[(name, PerNs::from_def(def, vis, false))], vis);
834 res
835 }
836
837 fn define_def(&mut self, def: &raw::DefData, attrs: &Attrs) {
838 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
839 // FIXME: check attrs to see if this is an attribute macro invocation;
840 // in which case we don't add the invocation, just a single attribute
841 // macro invocation
842 self.collect_derives(attrs, def);
843
844 let name = def.name.clone();
845 let container = ContainerId::ModuleId(module);
846 let vis = &def.visibility;
847 let mut has_constructor = false;
848
849 let def: ModuleDefId = match def.kind {
850 raw::DefKind::Function(ast_id) => FunctionLoc {
851 container: container.into(),
852 ast_id: AstId::new(self.file_id, ast_id),
853 }
854 .intern(self.def_collector.db)
855 .into(),
856 raw::DefKind::Struct(ast_id, mode) => {
857 has_constructor = mode != raw::StructDefKind::Record;
858 StructLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
859 .intern(self.def_collector.db)
860 .into()
861 }
862 raw::DefKind::Union(ast_id) => {
863 UnionLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
864 .intern(self.def_collector.db)
865 .into()
866 }
867 raw::DefKind::Enum(ast_id) => {
868 EnumLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
869 .intern(self.def_collector.db)
870 .into()
871 }
872 raw::DefKind::Const(ast_id) => {
873 ConstLoc { container: container.into(), ast_id: AstId::new(self.file_id, ast_id) }
874 .intern(self.def_collector.db)
875 .into()
876 }
877 raw::DefKind::Static(ast_id) => {
878 StaticLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
879 .intern(self.def_collector.db)
880 .into()
881 }
882 raw::DefKind::Trait(ast_id) => {
883 TraitLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
884 .intern(self.def_collector.db)
885 .into()
886 }
887 raw::DefKind::TypeAlias(ast_id) => TypeAliasLoc {
888 container: container.into(),
889 ast_id: AstId::new(self.file_id, ast_id),
890 }
891 .intern(self.def_collector.db)
892 .into(),
893 };
894 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
895 let vis = self
896 .def_collector
897 .def_map
898 .resolve_visibility(self.def_collector.db, self.module_id, vis)
899 .unwrap_or(Visibility::Public);
900 self.def_collector.update( 1058 self.def_collector.update(
901 self.module_id, 1059 self.module_id,
902 &[(name, PerNs::from_def(def, vis, has_constructor))], 1060 &[(name, PerNs::from_def(def, vis, false))],
903 vis, 1061 vis,
904 ) 1062 ImportType::Named,
1063 );
1064 res
905 } 1065 }
906 1066
907 fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) { 1067 fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::ModuleItem>) {
908 for derive_subtree in attrs.by_key("derive").tt_values() { 1068 for derive_subtree in attrs.by_key("derive").tt_values() {
909 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree 1069 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree
910 for tt in &derive_subtree.token_trees { 1070 for tt in &derive_subtree.token_trees {
@@ -915,7 +1075,7 @@ impl ModCollector<'_, '_> {
915 }; 1075 };
916 let path = ModPath::from_tt_ident(ident); 1076 let path = ModPath::from_tt_ident(ident);
917 1077
918 let ast_id = AstIdWithPath::new(self.file_id, def.kind.ast_id(), path); 1078 let ast_id = AstIdWithPath::new(self.file_id, ast_id, path);
919 self.def_collector 1079 self.def_collector
920 .unexpanded_attribute_macros 1080 .unexpanded_attribute_macros
921 .push(DeriveDirective { module_id: self.module_id, ast_id }); 1081 .push(DeriveDirective { module_id: self.module_id, ast_id });
@@ -923,11 +1083,11 @@ impl ModCollector<'_, '_> {
923 } 1083 }
924 } 1084 }
925 1085
926 fn collect_macro(&mut self, mac: &raw::MacroData) { 1086 fn collect_macro(&mut self, mac: &MacroCall) {
927 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); 1087 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
928 1088
929 // Case 0: builtin macros 1089 // Case 0: builtin macros
930 if mac.builtin { 1090 if mac.is_builtin {
931 if let Some(name) = &mac.name { 1091 if let Some(name) = &mac.name {
932 let krate = self.def_collector.def_map.krate; 1092 let krate = self.def_collector.def_map.krate;
933 if let Some(macro_id) = find_builtin_macro(name, krate, ast_id.ast_id) { 1093 if let Some(macro_id) = find_builtin_macro(name, krate, ast_id.ast_id) {
@@ -935,7 +1095,7 @@ impl ModCollector<'_, '_> {
935 self.module_id, 1095 self.module_id,
936 name.clone(), 1096 name.clone(),
937 macro_id, 1097 macro_id,
938 mac.export, 1098 mac.is_export,
939 ); 1099 );
940 return; 1100 return;
941 } 1101 }
@@ -949,19 +1109,26 @@ impl ModCollector<'_, '_> {
949 ast_id: Some(ast_id.ast_id), 1109 ast_id: Some(ast_id.ast_id),
950 krate: Some(self.def_collector.def_map.krate), 1110 krate: Some(self.def_collector.def_map.krate),
951 kind: MacroDefKind::Declarative, 1111 kind: MacroDefKind::Declarative,
952 local_inner: mac.local_inner, 1112 local_inner: mac.is_local_inner,
953 }; 1113 };
954 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); 1114 self.def_collector.define_macro(
1115 self.module_id,
1116 name.clone(),
1117 macro_id,
1118 mac.is_export,
1119 );
955 } 1120 }
956 return; 1121 return;
957 } 1122 }
958 1123
959 // Case 2: try to resolve in legacy scope and expand macro_rules 1124 // Case 2: try to resolve in legacy scope and expand macro_rules
960 if let Some(macro_call_id) = ast_id.as_call_id(self.def_collector.db, |path| { 1125 if let Some(macro_call_id) =
961 path.as_ident().and_then(|name| { 1126 ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| {
962 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) 1127 path.as_ident().and_then(|name| {
1128 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
1129 })
963 }) 1130 })
964 }) { 1131 {
965 self.def_collector.unexpanded_macros.push(MacroDirective { 1132 self.def_collector.unexpanded_macros.push(MacroDirective {
966 module_id: self.module_id, 1133 module_id: self.module_id,
967 ast_id, 1134 ast_id,
@@ -1022,6 +1189,7 @@ mod tests {
1022 mod_dirs: FxHashMap::default(), 1189 mod_dirs: FxHashMap::default(),
1023 cfg_options: &CfgOptions::default(), 1190 cfg_options: &CfgOptions::default(),
1024 proc_macros: Default::default(), 1191 proc_macros: Default::default(),
1192 from_glob_import: Default::default(),
1025 }; 1193 };
1026 collector.collect(); 1194 collector.collect();
1027 collector.def_map 1195 collector.def_map
diff --git a/crates/ra_hir_def/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs
index 386c5cade..953961632 100644
--- a/crates/ra_hir_def/src/nameres/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs
@@ -1,23 +1,24 @@
1//! This module resolves `mod foo;` declaration to file. 1//! This module resolves `mod foo;` declaration to file.
2use hir_expand::name::Name; 2use hir_expand::name::Name;
3use ra_db::{FileId, RelativePathBuf}; 3use ra_db::FileId;
4use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
5 5
6use crate::{db::DefDatabase, HirFileId}; 6use crate::{db::DefDatabase, HirFileId};
7 7
8#[derive(Clone, Debug)] 8#[derive(Clone, Debug)]
9pub(super) struct ModDir { 9pub(super) struct ModDir {
10 /// `.` for `mod.rs`, `lib.rs` 10 /// `` for `mod.rs`, `lib.rs`
11 /// `./foo` for `foo.rs` 11 /// `foo/` for `foo.rs`
12 /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs` 12 /// `foo/bar/` for `mod bar { mod x; }` nested in `foo.rs`
13 path: RelativePathBuf, 13 /// Invariant: path.is_empty() || path.ends_with('/')
14 dir_path: DirPath,
14 /// inside `./foo.rs`, mods with `#[path]` should *not* be relative to `./foo/` 15 /// inside `./foo.rs`, mods with `#[path]` should *not* be relative to `./foo/`
15 root_non_dir_owner: bool, 16 root_non_dir_owner: bool,
16} 17}
17 18
18impl ModDir { 19impl ModDir {
19 pub(super) fn root() -> ModDir { 20 pub(super) fn root() -> ModDir {
20 ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false } 21 ModDir { dir_path: DirPath::empty(), root_non_dir_owner: false }
21 } 22 }
22 23
23 pub(super) fn descend_into_definition( 24 pub(super) fn descend_into_definition(
@@ -25,17 +26,21 @@ impl ModDir {
25 name: &Name, 26 name: &Name,
26 attr_path: Option<&SmolStr>, 27 attr_path: Option<&SmolStr>,
27 ) -> ModDir { 28 ) -> ModDir {
28 let mut path = self.path.clone(); 29 let path = match attr_path.map(|it| it.as_str()) {
29 match attr_to_path(attr_path) { 30 None => {
30 None => path.push(&name.to_string()), 31 let mut path = self.dir_path.clone();
32 path.push(&name.to_string());
33 path
34 }
31 Some(attr_path) => { 35 Some(attr_path) => {
32 if self.root_non_dir_owner { 36 let mut path = self.dir_path.join_attr(attr_path, self.root_non_dir_owner);
33 assert!(path.pop()); 37 if !(path.is_empty() || path.ends_with('/')) {
38 path.push('/')
34 } 39 }
35 path.push(attr_path); 40 DirPath::new(path)
36 } 41 }
37 } 42 };
38 ModDir { path, root_non_dir_owner: false } 43 ModDir { dir_path: path, root_non_dir_owner: false }
39 } 44 }
40 45
41 pub(super) fn resolve_declaration( 46 pub(super) fn resolve_declaration(
@@ -44,37 +49,91 @@ impl ModDir {
44 file_id: HirFileId, 49 file_id: HirFileId,
45 name: &Name, 50 name: &Name,
46 attr_path: Option<&SmolStr>, 51 attr_path: Option<&SmolStr>,
47 ) -> Result<(FileId, ModDir), RelativePathBuf> { 52 ) -> Result<(FileId, bool, ModDir), String> {
48 let file_id = file_id.original_file(db.upcast()); 53 let file_id = file_id.original_file(db.upcast());
49 54
50 let mut candidate_files = Vec::new(); 55 let mut candidate_files = Vec::new();
51 match attr_to_path(attr_path) { 56 match attr_path {
52 Some(attr_path) => { 57 Some(attr_path) => {
53 let base = 58 candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner))
54 if self.root_non_dir_owner { self.path.parent().unwrap() } else { &self.path };
55 candidate_files.push(base.join(attr_path))
56 } 59 }
57 None => { 60 None => {
58 candidate_files.push(self.path.join(&format!("{}.rs", name))); 61 candidate_files.push(format!("{}{}.rs", self.dir_path.0, name));
59 candidate_files.push(self.path.join(&format!("{}/mod.rs", name))); 62 candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name));
60 } 63 }
61 }; 64 };
62 65
63 for candidate in candidate_files.iter() { 66 for candidate in candidate_files.iter() {
64 if let Some(file_id) = db.resolve_relative_path(file_id, candidate) { 67 if let Some(file_id) = db.resolve_path(file_id, candidate.as_str()) {
65 let mut root_non_dir_owner = false; 68 let is_mod_rs = candidate.ends_with("mod.rs");
66 let mut mod_path = RelativePathBuf::new(); 69
67 if !(candidate.ends_with("mod.rs") || attr_path.is_some()) { 70 let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() {
68 root_non_dir_owner = true; 71 (DirPath::empty(), false)
69 mod_path.push(&name.to_string()); 72 } else {
70 } 73 (DirPath::new(format!("{}/", name)), true)
71 return Ok((file_id, ModDir { path: mod_path, root_non_dir_owner })); 74 };
75 return Ok((file_id, is_mod_rs, ModDir { dir_path, root_non_dir_owner }));
72 } 76 }
73 } 77 }
74 Err(candidate_files.remove(0)) 78 Err(candidate_files.remove(0))
75 } 79 }
76} 80}
77 81
78fn attr_to_path(attr: Option<&SmolStr>) -> Option<RelativePathBuf> { 82#[derive(Clone, Debug)]
79 attr.and_then(|it| RelativePathBuf::from_path(&it.replace("\\", "/")).ok()) 83struct DirPath(String);
84
85impl DirPath {
86 fn assert_invariant(&self) {
87 assert!(self.0.is_empty() || self.0.ends_with('/'));
88 }
89 fn new(repr: String) -> DirPath {
90 let res = DirPath(repr);
91 res.assert_invariant();
92 res
93 }
94 fn empty() -> DirPath {
95 DirPath::new(String::new())
96 }
97 fn push(&mut self, name: &str) {
98 self.0.push_str(name);
99 self.0.push('/');
100 self.assert_invariant();
101 }
102 fn parent(&self) -> Option<&str> {
103 if self.0.is_empty() {
104 return None;
105 };
106 let idx =
107 self.0[..self.0.len() - '/'.len_utf8()].rfind('/').map_or(0, |it| it + '/'.len_utf8());
108 Some(&self.0[..idx])
109 }
110 /// So this is the case which doesn't really work I think if we try to be
111 /// 100% platform agnostic:
112 ///
113 /// ```
114 /// mod a {
115 /// #[path="C://sad/face"]
116 /// mod b { mod c; }
117 /// }
118 /// ```
119 ///
120 /// Here, we need to join logical dir path to a string path from an
121 /// attribute. Ideally, we should somehow losslessly communicate the whole
122 /// construction to `FileLoader`.
123 fn join_attr(&self, mut attr: &str, relative_to_parent: bool) -> String {
124 let base = if relative_to_parent { self.parent().unwrap() } else { &self.0 };
125
126 if attr.starts_with("./") {
127 attr = &attr["./".len()..];
128 }
129 let tmp;
130 let attr = if attr.contains('\\') {
131 tmp = attr.replace('\\', "/");
132 &tmp
133 } else {
134 attr
135 };
136 let res = format!("{}{}", base, attr);
137 res
138 }
80} 139}
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
deleted file mode 100644
index f44baa579..000000000
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ /dev/null
@@ -1,482 +0,0 @@
1//! Lowers syntax tree of a rust file into a raw representation of containing
2//! items, *without* attaching them to a module structure.
3//!
4//! That is, raw items don't have semantics, just as syntax, but, unlike syntax,
5//! they don't change with trivial source code edits, making them a great tool
6//! for building salsa recomputation firewalls.
7
8use std::{ops::Index, sync::Arc};
9
10use hir_expand::{
11 ast_id_map::AstIdMap,
12 hygiene::Hygiene,
13 name::{AsName, Name},
14};
15use ra_arena::{Arena, Idx};
16use ra_prof::profile;
17use ra_syntax::{
18 ast::{self, AttrsOwner, NameOwner, VisibilityOwner},
19 AstNode,
20};
21use test_utils::mark;
22
23use crate::{
24 attr::Attrs,
25 db::DefDatabase,
26 path::{ImportAlias, ModPath},
27 visibility::RawVisibility,
28 FileAstId, HirFileId, InFile,
29};
30
31/// `RawItems` is a set of top-level items in a file (except for impls).
32///
33/// It is the input to name resolution algorithm. `RawItems` are not invalidated
34/// on most edits.
35#[derive(Debug, Default, PartialEq, Eq)]
36pub struct RawItems {
37 modules: Arena<ModuleData>,
38 imports: Arena<ImportData>,
39 defs: Arena<DefData>,
40 macros: Arena<MacroData>,
41 impls: Arena<ImplData>,
42 /// items for top-level module
43 items: Vec<RawItem>,
44}
45
46impl RawItems {
47 pub(crate) fn raw_items_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<RawItems> {
48 let _p = profile("raw_items_query");
49 let mut collector = RawItemsCollector {
50 raw_items: RawItems::default(),
51 source_ast_id_map: db.ast_id_map(file_id),
52 file_id,
53 hygiene: Hygiene::new(db.upcast(), file_id),
54 };
55 if let Some(node) = db.parse_or_expand(file_id) {
56 if let Some(source_file) = ast::SourceFile::cast(node.clone()) {
57 collector.process_module(None, source_file);
58 } else if let Some(item_list) = ast::MacroItems::cast(node) {
59 collector.process_module(None, item_list);
60 }
61 }
62 let raw_items = collector.raw_items;
63 Arc::new(raw_items)
64 }
65
66 pub(super) fn items(&self) -> &[RawItem] {
67 &self.items
68 }
69}
70
71impl Index<Idx<ModuleData>> for RawItems {
72 type Output = ModuleData;
73 fn index(&self, idx: Idx<ModuleData>) -> &ModuleData {
74 &self.modules[idx]
75 }
76}
77
78impl Index<Import> for RawItems {
79 type Output = ImportData;
80 fn index(&self, idx: Import) -> &ImportData {
81 &self.imports[idx]
82 }
83}
84
85impl Index<Idx<DefData>> for RawItems {
86 type Output = DefData;
87 fn index(&self, idx: Idx<DefData>) -> &DefData {
88 &self.defs[idx]
89 }
90}
91
92impl Index<Idx<MacroData>> for RawItems {
93 type Output = MacroData;
94 fn index(&self, idx: Idx<MacroData>) -> &MacroData {
95 &self.macros[idx]
96 }
97}
98
99impl Index<Idx<ImplData>> for RawItems {
100 type Output = ImplData;
101 fn index(&self, idx: Idx<ImplData>) -> &ImplData {
102 &self.impls[idx]
103 }
104}
105
106#[derive(Debug, PartialEq, Eq, Clone)]
107pub(super) struct RawItem {
108 pub(super) attrs: Attrs,
109 pub(super) kind: RawItemKind,
110}
111
112#[derive(Debug, PartialEq, Eq, Clone, Copy)]
113pub(super) enum RawItemKind {
114 Module(Idx<ModuleData>),
115 Import(Import),
116 Def(Idx<DefData>),
117 Macro(Idx<MacroData>),
118 Impl(Idx<ImplData>),
119}
120
121#[derive(Debug, PartialEq, Eq)]
122pub(super) enum ModuleData {
123 Declaration {
124 name: Name,
125 visibility: RawVisibility,
126 ast_id: FileAstId<ast::Module>,
127 },
128 Definition {
129 name: Name,
130 visibility: RawVisibility,
131 ast_id: FileAstId<ast::Module>,
132 items: Vec<RawItem>,
133 },
134}
135
136pub(crate) type Import = Idx<ImportData>;
137
138#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct ImportData {
140 pub(super) path: ModPath,
141 pub(super) alias: Option<ImportAlias>,
142 pub(super) is_glob: bool,
143 pub(super) is_prelude: bool,
144 pub(super) is_extern_crate: bool,
145 pub(super) is_macro_use: bool,
146 pub(super) visibility: RawVisibility,
147}
148
149// type Def = Idx<DefData>;
150
151#[derive(Debug, PartialEq, Eq)]
152pub(super) struct DefData {
153 pub(super) name: Name,
154 pub(super) kind: DefKind,
155 pub(super) visibility: RawVisibility,
156}
157
158#[derive(Debug, PartialEq, Eq, Clone, Copy)]
159pub(super) enum StructDefKind {
160 Record,
161 Tuple,
162 Unit,
163}
164
165#[derive(Debug, PartialEq, Eq, Clone, Copy)]
166pub(super) enum DefKind {
167 Function(FileAstId<ast::FnDef>),
168 Struct(FileAstId<ast::StructDef>, StructDefKind),
169 Union(FileAstId<ast::UnionDef>),
170 Enum(FileAstId<ast::EnumDef>),
171 Const(FileAstId<ast::ConstDef>),
172 Static(FileAstId<ast::StaticDef>),
173 Trait(FileAstId<ast::TraitDef>),
174 TypeAlias(FileAstId<ast::TypeAliasDef>),
175}
176
177impl DefKind {
178 pub fn ast_id(self) -> FileAstId<ast::ModuleItem> {
179 match self {
180 DefKind::Function(it) => it.upcast(),
181 DefKind::Struct(it, _) => it.upcast(),
182 DefKind::Union(it) => it.upcast(),
183 DefKind::Enum(it) => it.upcast(),
184 DefKind::Const(it) => it.upcast(),
185 DefKind::Static(it) => it.upcast(),
186 DefKind::Trait(it) => it.upcast(),
187 DefKind::TypeAlias(it) => it.upcast(),
188 }
189 }
190}
191
192#[derive(Debug, PartialEq, Eq)]
193pub(super) struct MacroData {
194 pub(super) ast_id: FileAstId<ast::MacroCall>,
195 pub(super) path: ModPath,
196 pub(super) name: Option<Name>,
197 pub(super) export: bool,
198 pub(super) local_inner: bool,
199 pub(super) builtin: bool,
200}
201
202#[derive(Debug, PartialEq, Eq)]
203pub(super) struct ImplData {
204 pub(super) ast_id: FileAstId<ast::ImplDef>,
205}
206
207struct RawItemsCollector {
208 raw_items: RawItems,
209 source_ast_id_map: Arc<AstIdMap>,
210 file_id: HirFileId,
211 hygiene: Hygiene,
212}
213
214impl RawItemsCollector {
215 fn process_module(
216 &mut self,
217 current_module: Option<Idx<ModuleData>>,
218 body: impl ast::ModuleItemOwner,
219 ) {
220 for item in body.items() {
221 self.add_item(current_module, item)
222 }
223 }
224
225 fn add_item(&mut self, current_module: Option<Idx<ModuleData>>, item: ast::ModuleItem) {
226 let attrs = self.parse_attrs(&item);
227 let visibility = RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene);
228 let (kind, name) = match item {
229 ast::ModuleItem::Module(module) => {
230 self.add_module(current_module, module);
231 return;
232 }
233 ast::ModuleItem::UseItem(use_item) => {
234 self.add_use_item(current_module, use_item);
235 return;
236 }
237 ast::ModuleItem::ExternCrateItem(extern_crate) => {
238 self.add_extern_crate_item(current_module, extern_crate);
239 return;
240 }
241 ast::ModuleItem::ImplDef(it) => {
242 self.add_impl(current_module, it);
243 return;
244 }
245 ast::ModuleItem::StructDef(it) => {
246 let kind = match it.kind() {
247 ast::StructKind::Record(_) => StructDefKind::Record,
248 ast::StructKind::Tuple(_) => StructDefKind::Tuple,
249 ast::StructKind::Unit => StructDefKind::Unit,
250 };
251 let id = self.source_ast_id_map.ast_id(&it);
252 let name = it.name();
253 (DefKind::Struct(id, kind), name)
254 }
255 ast::ModuleItem::UnionDef(it) => {
256 let id = self.source_ast_id_map.ast_id(&it);
257 let name = it.name();
258 (DefKind::Union(id), name)
259 }
260 ast::ModuleItem::EnumDef(it) => {
261 (DefKind::Enum(self.source_ast_id_map.ast_id(&it)), it.name())
262 }
263 ast::ModuleItem::FnDef(it) => {
264 (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name())
265 }
266 ast::ModuleItem::TraitDef(it) => {
267 (DefKind::Trait(self.source_ast_id_map.ast_id(&it)), it.name())
268 }
269 ast::ModuleItem::TypeAliasDef(it) => {
270 (DefKind::TypeAlias(self.source_ast_id_map.ast_id(&it)), it.name())
271 }
272 ast::ModuleItem::ConstDef(it) => {
273 (DefKind::Const(self.source_ast_id_map.ast_id(&it)), it.name())
274 }
275 ast::ModuleItem::StaticDef(it) => {
276 (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name())
277 }
278 ast::ModuleItem::MacroCall(it) => {
279 self.add_macro(current_module, it);
280 return;
281 }
282 ast::ModuleItem::ExternBlock(it) => {
283 self.add_extern_block(current_module, it);
284 return;
285 }
286 };
287 if let Some(name) = name {
288 let name = name.as_name();
289 let def = self.raw_items.defs.alloc(DefData { name, kind, visibility });
290 self.push_item(current_module, attrs, RawItemKind::Def(def));
291 }
292 }
293
294 fn add_extern_block(
295 &mut self,
296 current_module: Option<Idx<ModuleData>>,
297 block: ast::ExternBlock,
298 ) {
299 if let Some(items) = block.extern_item_list() {
300 for item in items.extern_items() {
301 let attrs = self.parse_attrs(&item);
302 let visibility =
303 RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene);
304 let (kind, name) = match item {
305 ast::ExternItem::FnDef(it) => {
306 (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name())
307 }
308 ast::ExternItem::StaticDef(it) => {
309 (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name())
310 }
311 };
312
313 if let Some(name) = name {
314 let name = name.as_name();
315 let def = self.raw_items.defs.alloc(DefData { name, kind, visibility });
316 self.push_item(current_module, attrs, RawItemKind::Def(def));
317 }
318 }
319 }
320 }
321
322 fn add_module(&mut self, current_module: Option<Idx<ModuleData>>, module: ast::Module) {
323 let name = match module.name() {
324 Some(it) => it.as_name(),
325 None => return,
326 };
327 let attrs = self.parse_attrs(&module);
328 let visibility = RawVisibility::from_ast_with_hygiene(module.visibility(), &self.hygiene);
329
330 let ast_id = self.source_ast_id_map.ast_id(&module);
331 if module.semicolon_token().is_some() {
332 let item =
333 self.raw_items.modules.alloc(ModuleData::Declaration { name, visibility, ast_id });
334 self.push_item(current_module, attrs, RawItemKind::Module(item));
335 return;
336 }
337
338 if let Some(item_list) = module.item_list() {
339 let item = self.raw_items.modules.alloc(ModuleData::Definition {
340 name,
341 visibility,
342 ast_id,
343 items: Vec::new(),
344 });
345 self.process_module(Some(item), item_list);
346 self.push_item(current_module, attrs, RawItemKind::Module(item));
347 return;
348 }
349 mark::hit!(name_res_works_for_broken_modules);
350 }
351
352 fn add_use_item(&mut self, current_module: Option<Idx<ModuleData>>, use_item: ast::UseItem) {
353 // FIXME: cfg_attr
354 let is_prelude = use_item.has_atom_attr("prelude_import");
355 let attrs = self.parse_attrs(&use_item);
356 let visibility = RawVisibility::from_ast_with_hygiene(use_item.visibility(), &self.hygiene);
357
358 let mut buf = Vec::new();
359 ModPath::expand_use_item(
360 InFile { value: use_item, file_id: self.file_id },
361 &self.hygiene,
362 |path, _use_tree, is_glob, alias| {
363 let import_data = ImportData {
364 path,
365 alias,
366 is_glob,
367 is_prelude,
368 is_extern_crate: false,
369 is_macro_use: false,
370 visibility: visibility.clone(),
371 };
372 buf.push(import_data);
373 },
374 );
375 for import_data in buf {
376 self.push_import(current_module, attrs.clone(), import_data);
377 }
378 }
379
380 fn add_extern_crate_item(
381 &mut self,
382 current_module: Option<Idx<ModuleData>>,
383 extern_crate: ast::ExternCrateItem,
384 ) {
385 if let Some(name_ref) = extern_crate.name_ref() {
386 let path = ModPath::from_name_ref(&name_ref);
387 let visibility =
388 RawVisibility::from_ast_with_hygiene(extern_crate.visibility(), &self.hygiene);
389 let alias = extern_crate.alias().map(|a| {
390 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
391 });
392 let attrs = self.parse_attrs(&extern_crate);
393 // FIXME: cfg_attr
394 let is_macro_use = extern_crate.has_atom_attr("macro_use");
395 let import_data = ImportData {
396 path,
397 alias,
398 is_glob: false,
399 is_prelude: false,
400 is_extern_crate: true,
401 is_macro_use,
402 visibility,
403 };
404 self.push_import(current_module, attrs, import_data);
405 }
406 }
407
408 fn add_macro(&mut self, current_module: Option<Idx<ModuleData>>, m: ast::MacroCall) {
409 let attrs = self.parse_attrs(&m);
410 let path = match m.path().and_then(|path| ModPath::from_src(path, &self.hygiene)) {
411 Some(it) => it,
412 _ => return,
413 };
414
415 let name = m.name().map(|it| it.as_name());
416 let ast_id = self.source_ast_id_map.ast_id(&m);
417
418 // FIXME: cfg_attr
419 let export_attr = attrs.by_key("macro_export");
420
421 let export = export_attr.exists();
422 let local_inner = if export {
423 export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it {
424 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
425 ident.text.contains("local_inner_macros")
426 }
427 _ => false,
428 })
429 } else {
430 false
431 };
432
433 let builtin = attrs.by_key("rustc_builtin_macro").exists();
434
435 let m = self.raw_items.macros.alloc(MacroData {
436 ast_id,
437 path,
438 name,
439 export,
440 local_inner,
441 builtin,
442 });
443 self.push_item(current_module, attrs, RawItemKind::Macro(m));
444 }
445
446 fn add_impl(&mut self, current_module: Option<Idx<ModuleData>>, imp: ast::ImplDef) {
447 let attrs = self.parse_attrs(&imp);
448 let ast_id = self.source_ast_id_map.ast_id(&imp);
449 let imp = self.raw_items.impls.alloc(ImplData { ast_id });
450 self.push_item(current_module, attrs, RawItemKind::Impl(imp))
451 }
452
453 fn push_import(
454 &mut self,
455 current_module: Option<Idx<ModuleData>>,
456 attrs: Attrs,
457 data: ImportData,
458 ) {
459 let import = self.raw_items.imports.alloc(data);
460 self.push_item(current_module, attrs, RawItemKind::Import(import))
461 }
462
463 fn push_item(
464 &mut self,
465 current_module: Option<Idx<ModuleData>>,
466 attrs: Attrs,
467 kind: RawItemKind,
468 ) {
469 match current_module {
470 Some(module) => match &mut self.raw_items.modules[module] {
471 ModuleData::Definition { items, .. } => items,
472 ModuleData::Declaration { .. } => unreachable!(),
473 },
474 None => &mut self.raw_items.items,
475 }
476 .push(RawItem { attrs, kind })
477 }
478
479 fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs {
480 Attrs::new(item, &self.hygiene)
481 }
482}
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 05cd0297d..503099fb7 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -424,31 +424,6 @@ fn extern_crate_rename_2015_edition() {
424} 424}
425 425
426#[test] 426#[test]
427fn import_across_source_roots() {
428 let map = def_map(
429 "
430 //- /main.rs crate:main deps:test_crate
431 use test_crate::a::b::C;
432
433 //- root /test_crate/
434
435 //- /test_crate/lib.rs crate:test_crate
436 pub mod a {
437 pub mod b {
438 pub struct C;
439 }
440 }
441
442 ",
443 );
444
445 assert_snapshot!(map, @r###"
446 ⋮crate
447 ⋮C: t v
448 "###);
449}
450
451#[test]
452fn reexport_across_crates() { 427fn reexport_across_crates() {
453 let map = def_map( 428 let map = def_map(
454 " 429 "
diff --git a/crates/ra_hir_def/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs
index 2b12c0daa..7f3d7509c 100644
--- a/crates/ra_hir_def/src/nameres/tests/globs.rs
+++ b/crates/ra_hir_def/src/nameres/tests/globs.rs
@@ -229,3 +229,140 @@ fn glob_enum_group() {
229 "### 229 "###
230 ); 230 );
231} 231}
232
233#[test]
234fn glob_shadowed_def() {
235 mark::check!(import_shadowed);
236 let map = def_map(
237 r###"
238 //- /lib.rs
239 mod foo;
240 mod bar;
241
242 use foo::*;
243 use bar::baz;
244
245 use baz::Bar;
246
247 //- /foo.rs
248 pub mod baz {
249 pub struct Foo;
250 }
251
252 //- /bar.rs
253 pub mod baz {
254 pub struct Bar;
255 }
256 "###,
257 );
258 assert_snapshot!(map, @r###"
259 ⋮crate
260 ⋮Bar: t v
261 ⋮bar: t
262 ⋮baz: t
263 ⋮foo: t
264
265 ⋮crate::bar
266 ⋮baz: t
267
268 ⋮crate::bar::baz
269 ⋮Bar: t v
270
271 ⋮crate::foo
272 ⋮baz: t
273
274 ⋮crate::foo::baz
275 ⋮Foo: t v
276 "###
277 );
278}
279
280#[test]
281fn glob_shadowed_def_reversed() {
282 let map = def_map(
283 r###"
284 //- /lib.rs
285 mod foo;
286 mod bar;
287
288 use bar::baz;
289 use foo::*;
290
291 use baz::Bar;
292
293 //- /foo.rs
294 pub mod baz {
295 pub struct Foo;
296 }
297
298 //- /bar.rs
299 pub mod baz {
300 pub struct Bar;
301 }
302 "###,
303 );
304 assert_snapshot!(map, @r###"
305 ⋮crate
306 ⋮Bar: t v
307 ⋮bar: t
308 ⋮baz: t
309 ⋮foo: t
310
311 ⋮crate::bar
312 ⋮baz: t
313
314 ⋮crate::bar::baz
315 ⋮Bar: t v
316
317 ⋮crate::foo
318 ⋮baz: t
319
320 ⋮crate::foo::baz
321 ⋮Foo: t v
322 "###
323 );
324}
325
326#[test]
327fn glob_shadowed_def_dependencies() {
328 let map = def_map(
329 r###"
330 //- /lib.rs
331 mod a { pub mod foo { pub struct X; } }
332 mod b { pub use super::a::foo; }
333 mod c { pub mod foo { pub struct Y; } }
334 mod d {
335 use super::c::foo;
336 use super::b::*;
337 use foo::Y;
338 }
339 "###,
340 );
341 assert_snapshot!(map, @r###"
342 ⋮crate
343 ⋮a: t
344 ⋮b: t
345 ⋮c: t
346 ⋮d: t
347
348 ⋮crate::d
349 ⋮Y: t v
350 ⋮foo: t
351
352 ⋮crate::c
353 ⋮foo: t
354
355 ⋮crate::c::foo
356 ⋮Y: t v
357
358 ⋮crate::b
359 ⋮foo: t
360
361 ⋮crate::a
362 ⋮foo: t
363
364 ⋮crate::a::foo
365 ⋮X: t v
366 "###
367 );
368}
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs
index 87165ac33..0c288a108 100644
--- a/crates/ra_hir_def/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs
@@ -58,44 +58,6 @@ fn typing_inside_a_function_should_not_invalidate_def_map() {
58} 58}
59 59
60#[test] 60#[test]
61fn adding_inner_items_should_not_invalidate_def_map() {
62 check_def_map_is_not_recomputed(
63 r"
64 //- /lib.rs
65 struct S { a: i32}
66 enum E { A }
67 trait T {
68 fn a() {}
69 }
70 mod foo;<|>
71 impl S {
72 fn a() {}
73 }
74 use crate::foo::bar::Baz;
75 //- /foo/mod.rs
76 pub mod bar;
77
78 //- /foo/bar.rs
79 pub struct Baz;
80 ",
81 r"
82 struct S { a: i32, b: () }
83 enum E { A, B }
84 trait T {
85 fn a() {}
86 fn b() {}
87 }
88 mod foo;<|>
89 impl S {
90 fn a() {}
91 fn b() {}
92 }
93 use crate::foo::bar::Baz;
94 ",
95 );
96}
97
98#[test]
99fn typing_inside_a_macro_should_not_invalidate_def_map() { 61fn typing_inside_a_macro_should_not_invalidate_def_map() {
100 let (mut db, pos) = TestDB::with_position( 62 let (mut db, pos) = TestDB::with_position(
101 r" 63 r"
diff --git a/crates/ra_hir_def/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs
index 84480d9f6..c52341a07 100644
--- a/crates/ra_hir_def/src/nameres/tests/macros.rs
+++ b/crates/ra_hir_def/src/nameres/tests/macros.rs
@@ -660,3 +660,27 @@ fn expand_multiple_derive() {
660 ); 660 );
661 assert_eq!(map.modules[map.root].scope.impls().len(), 2); 661 assert_eq!(map.modules[map.root].scope.impls().len(), 2);
662} 662}
663
664#[test]
665fn macro_expansion_overflow() {
666 mark::check!(macro_expansion_overflow);
667 compute_crate_def_map(
668 "
669macro_rules! a {
670 ($e:expr; $($t:tt)*) => {
671 b!($($t)*);
672 };
673 () => {};
674}
675
676macro_rules! b {
677 (static = $e:expr; $($t:tt)*) => {
678 a!($e; $($t)*);
679 };
680 () => {};
681}
682
683b! { static = #[] (); }
684",
685 );
686}
diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
index b43b294ca..753684201 100644
--- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
@@ -20,8 +20,11 @@ fn name_res_works_for_broken_modules() {
20 ", 20 ",
21 ); 21 );
22 assert_snapshot!(map, @r###" 22 assert_snapshot!(map, @r###"
23 ⋮crate 23crate
24 ⋮Baz: _ 24Baz: _
25foo: t
26
27crate::foo
25 "###); 28 "###);
26} 29}
27 30
@@ -332,6 +335,22 @@ fn module_resolution_relative_path_2() {
332} 335}
333 336
334#[test] 337#[test]
338fn module_resolution_relative_path_outside_root() {
339 let map = def_map(
340 r###"
341 //- /main.rs
342
343 #[path="../../../../../outside.rs"]
344 mod foo;
345 "###,
346 );
347
348 assert_snapshot!(map, @r###"
349 ⋮crate
350 "###);
351}
352
353#[test]
335fn module_resolution_explicit_path_mod_rs_2() { 354fn module_resolution_explicit_path_mod_rs_2() {
336 let map = def_map( 355 let map = def_map(
337 r###" 356 r###"
@@ -719,10 +738,7 @@ fn unresolved_module_diagnostics() {
719 ), 738 ),
720 ), 739 ),
721 ), 740 ),
722 value: FileAstId { 741 value: FileAstId::<ra_syntax::ast::generated::nodes::Module>(1),
723 raw: Idx::<SyntaxNodePtr>(1),
724 _ty: PhantomData,
725 },
726 }, 742 },
727 candidate: "bar.rs", 743 candidate: "bar.rs",
728 }, 744 },