aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/nameres/collector.rs40
-rw-r--r--crates/ra_hir/src/nameres/mod_resolution.rs232
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs29
-rw-r--r--crates/ra_hir/src/nameres/tests/mod_resolution.rs100
4 files changed, 209 insertions, 192 deletions
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index cef2dc9d2..88aee7437 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -2,7 +2,7 @@
2 2
3use ra_cfg::CfgOptions; 3use ra_cfg::CfgOptions;
4use ra_db::FileId; 4use ra_db::FileId;
5use ra_syntax::{ast, SmolStr}; 5use ra_syntax::ast;
6use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
7use test_utils::tested_by; 7use test_utils::tested_by;
8 8
@@ -11,10 +11,8 @@ use crate::{
11 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, 11 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind},
12 name::MACRO_RULES, 12 name::MACRO_RULES,
13 nameres::{ 13 nameres::{
14 diagnostics::DefDiagnostic, 14 diagnostics::DefDiagnostic, mod_resolution::ModDir, raw, Crate, CrateDefMap, CrateModuleId,
15 mod_resolution::{resolve_submodule, ParentModule}, 15 ModuleData, ModuleDef, PerNs, ReachedFixedPoint, Resolution, ResolveMode,
16 raw, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef, PerNs, ReachedFixedPoint,
17 Resolution, ResolveMode,
18 }, 16 },
19 Adt, AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, 17 Adt, AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static,
20 Struct, Trait, TypeAlias, Union, 18 Struct, Trait, TypeAlias, Union,
@@ -45,6 +43,7 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
45 glob_imports: FxHashMap::default(), 43 glob_imports: FxHashMap::default(),
46 unresolved_imports: Vec::new(), 44 unresolved_imports: Vec::new(),
47 unexpanded_macros: Vec::new(), 45 unexpanded_macros: Vec::new(),
46 mod_dirs: FxHashMap::default(),
48 macro_stack_monitor: MacroStackMonitor::default(), 47 macro_stack_monitor: MacroStackMonitor::default(),
49 cfg_options, 48 cfg_options,
50 }; 49 };
@@ -87,6 +86,7 @@ struct DefCollector<'a, DB> {
87 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, 86 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
88 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, 87 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
89 unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>, 88 unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>,
89 mod_dirs: FxHashMap<CrateModuleId, ModDir>,
90 90
91 /// 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
92 /// 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.
@@ -107,11 +107,10 @@ where
107 self.def_map.modules[module_id].definition = Some(file_id); 107 self.def_map.modules[module_id].definition = Some(file_id);
108 ModCollector { 108 ModCollector {
109 def_collector: &mut *self, 109 def_collector: &mut *self,
110 attr_path: None,
111 module_id, 110 module_id,
112 file_id: file_id.into(), 111 file_id: file_id.into(),
113 raw_items: &raw_items, 112 raw_items: &raw_items,
114 parent_module: None, 113 mod_dir: ModDir::root(),
115 } 114 }
116 .collect(raw_items.items()); 115 .collect(raw_items.items());
117 116
@@ -481,13 +480,13 @@ where
481 if !self.macro_stack_monitor.is_poison(macro_def_id) { 480 if !self.macro_stack_monitor.is_poison(macro_def_id) {
482 let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items); 481 let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items);
483 let raw_items = self.db.raw_items(file_id); 482 let raw_items = self.db.raw_items(file_id);
483 let mod_dir = self.mod_dirs[&module_id].clone();
484 ModCollector { 484 ModCollector {
485 def_collector: &mut *self, 485 def_collector: &mut *self,
486 file_id, 486 file_id,
487 attr_path: None,
488 module_id, 487 module_id,
489 raw_items: &raw_items, 488 raw_items: &raw_items,
490 parent_module: None, 489 mod_dir,
491 } 490 }
492 .collect(raw_items.items()); 491 .collect(raw_items.items());
493 } else { 492 } else {
@@ -508,9 +507,8 @@ struct ModCollector<'a, D> {
508 def_collector: D, 507 def_collector: D,
509 module_id: CrateModuleId, 508 module_id: CrateModuleId,
510 file_id: HirFileId, 509 file_id: HirFileId,
511 attr_path: Option<&'a SmolStr>,
512 raw_items: &'a raw::RawItems, 510 raw_items: &'a raw::RawItems,
513 parent_module: Option<ParentModule<'a>>, 511 mod_dir: ModDir,
514} 512}
515 513
516impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>> 514impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>>
@@ -518,6 +516,10 @@ where
518 DB: DefDatabase, 516 DB: DefDatabase,
519{ 517{
520 fn collect(&mut self, items: &[raw::RawItem]) { 518 fn collect(&mut self, items: &[raw::RawItem]) {
519 // Note: don't assert that inserted value is fresh: it's simply not true
520 // for macros.
521 self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
522
521 // Prelude module is always considered to be `#[macro_use]`. 523 // Prelude module is always considered to be `#[macro_use]`.
522 if let Some(prelude_module) = self.def_collector.def_map.prelude { 524 if let Some(prelude_module) = self.def_collector.def_map.prelude {
523 if prelude_module.krate != self.def_collector.def_map.krate { 525 if prelude_module.krate != self.def_collector.def_map.krate {
@@ -561,15 +563,13 @@ where
561 raw::ModuleData::Definition { name, items, ast_id, attr_path, is_macro_use } => { 563 raw::ModuleData::Definition { name, items, ast_id, attr_path, is_macro_use } => {
562 let module_id = 564 let module_id =
563 self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); 565 self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None);
564 let parent_module = ParentModule { name, attr_path: attr_path.as_ref() };
565 566
566 ModCollector { 567 ModCollector {
567 def_collector: &mut *self.def_collector, 568 def_collector: &mut *self.def_collector,
568 module_id, 569 module_id,
569 attr_path: attr_path.as_ref(),
570 file_id: self.file_id, 570 file_id: self.file_id,
571 raw_items: self.raw_items, 571 raw_items: self.raw_items,
572 parent_module: Some(parent_module), 572 mod_dir: self.mod_dir.descend_into_definition(name, attr_path.as_ref()),
573 } 573 }
574 .collect(&*items); 574 .collect(&*items);
575 if *is_macro_use { 575 if *is_macro_use {
@@ -579,26 +579,21 @@ where
579 // out of line module, resolve, parse and recurse 579 // out of line module, resolve, parse and recurse
580 raw::ModuleData::Declaration { name, ast_id, attr_path, is_macro_use } => { 580 raw::ModuleData::Declaration { name, ast_id, attr_path, is_macro_use } => {
581 let ast_id = ast_id.with_file_id(self.file_id); 581 let ast_id = ast_id.with_file_id(self.file_id);
582 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); 582 match self.mod_dir.resolve_submodule(
583 match resolve_submodule(
584 self.def_collector.db, 583 self.def_collector.db,
585 self.file_id, 584 self.file_id,
586 self.attr_path,
587 name, 585 name,
588 is_root,
589 attr_path.as_ref(), 586 attr_path.as_ref(),
590 self.parent_module,
591 ) { 587 ) {
592 Ok(file_id) => { 588 Ok((file_id, mod_dir)) => {
593 let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); 589 let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id));
594 let raw_items = self.def_collector.db.raw_items(file_id.into()); 590 let raw_items = self.def_collector.db.raw_items(file_id.into());
595 ModCollector { 591 ModCollector {
596 def_collector: &mut *self.def_collector, 592 def_collector: &mut *self.def_collector,
597 module_id, 593 module_id,
598 attr_path: attr_path.as_ref(),
599 file_id: file_id.into(), 594 file_id: file_id.into(),
600 raw_items: &raw_items, 595 raw_items: &raw_items,
601 parent_module: None, 596 mod_dir,
602 } 597 }
603 .collect(raw_items.items()); 598 .collect(raw_items.items());
604 if *is_macro_use { 599 if *is_macro_use {
@@ -747,6 +742,7 @@ mod tests {
747 glob_imports: FxHashMap::default(), 742 glob_imports: FxHashMap::default(),
748 unresolved_imports: Vec::new(), 743 unresolved_imports: Vec::new(),
749 unexpanded_macros: Vec::new(), 744 unexpanded_macros: Vec::new(),
745 mod_dirs: FxHashMap::default(),
750 macro_stack_monitor: monitor, 746 macro_stack_monitor: monitor,
751 cfg_options: &CfgOptions::default(), 747 cfg_options: &CfgOptions::default(),
752 }; 748 };
diff --git a/crates/ra_hir/src/nameres/mod_resolution.rs b/crates/ra_hir/src/nameres/mod_resolution.rs
index 3aa32bd66..f50f9abe6 100644
--- a/crates/ra_hir/src/nameres/mod_resolution.rs
+++ b/crates/ra_hir/src/nameres/mod_resolution.rs
@@ -1,111 +1,105 @@
1//! This module resolves `mod foo;` declaration to file. 1//! This module resolves `mod foo;` declaration to file.
2use std::borrow::Cow;
2 3
3use std::{borrow::Cow, sync::Arc}; 4use ra_db::FileId;
4
5use ra_db::{FileId, SourceRoot};
6use ra_syntax::SmolStr; 5use ra_syntax::SmolStr;
7use relative_path::RelativePathBuf; 6use relative_path::{RelativePath, RelativePathBuf};
8 7
9use crate::{db::DefDatabase, HirFileId, Name}; 8use crate::{db::DefDatabase, HirFileId, Name};
10 9
11#[derive(Clone, Copy)] 10#[derive(Clone, Debug)]
12pub(super) struct ParentModule<'a> { 11pub(super) struct ModDir {
13 pub(super) name: &'a Name, 12 /// `.` for `mod.rs`, `lib.rs`
14 pub(super) attr_path: Option<&'a SmolStr>, 13 /// `./foo` for `foo.rs`
14 /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs`
15 path: RelativePathBuf,
16 /// inside `./foo.rs`, mods with `#[path]` should *not* be relative to `./foo/`
17 root_non_dir_owner: bool,
15} 18}
16 19
17impl<'a> ParentModule<'a> { 20impl ModDir {
18 fn attribute_path(&self) -> Option<&SmolStr> { 21 pub(super) fn root() -> ModDir {
19 self.attr_path.filter(|p| !p.is_empty()) 22 ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false }
20 } 23 }
21}
22
23pub(super) fn resolve_submodule(
24 db: &impl DefDatabase,
25 file_id: HirFileId,
26 mod_attr_path: Option<&SmolStr>,
27 name: &Name,
28 is_root: bool,
29 attr_path: Option<&SmolStr>,
30 parent_module: Option<ParentModule<'_>>,
31) -> Result<FileId, RelativePathBuf> {
32 let file_id = file_id.original_file(db);
33 let source_root_id = db.file_source_root(file_id);
34 let path = db.file_relative_path(file_id);
35 let root = RelativePathBuf::default();
36 let dir_path = path.parent().unwrap_or(&root);
37 let mod_name = path.file_stem().unwrap_or("unknown");
38 24
39 let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) { 25 pub(super) fn descend_into_definition(
40 (Some(file_path), Some(parent_module)) => { 26 &self,
41 let file_path = normalize_attribute_path(file_path); 27 name: &Name,
42 match parent_module.attribute_path() { 28 attr_path: Option<&SmolStr>,
43 Some(parent_module_attr_path) => { 29 ) -> ModDir {
44 let path = dir_path 30 let mut path = self.path.clone();
45 .join(format!( 31 match attr_path {
46 "{}/{}", 32 None => path.push(&name.to_string()),
47 normalize_attribute_path(parent_module_attr_path), 33 Some(attr_path) => {
48 file_path 34 if self.root_non_dir_owner {
49 )) 35 path = path
50 .normalize(); 36 .parent()
51 ResolutionMode::InlineModuleWithAttributePath( 37 .map(|it| it.to_relative_path_buf())
52 InsideInlineModuleMode::WithAttributePath(path), 38 .unwrap_or_else(RelativePathBuf::new);
53 )
54 }
55 None => {
56 let path =
57 dir_path.join(format!("{}/{}", parent_module.name, file_path)).normalize();
58 ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath(
59 path,
60 ))
61 } 39 }
40 let attr_path = &*normalize_attribute_path(attr_path);
41 path.push(RelativePath::new(attr_path));
62 } 42 }
63 } 43 }
64 (None, Some(parent_module)) => match parent_module.attribute_path() { 44 ModDir { path, root_non_dir_owner: false }
65 Some(parent_module_attr_path) => { 45 }
66 let path = dir_path.join(format!( 46
67 "{}/{}.rs", 47 pub(super) fn resolve_submodule(
68 normalize_attribute_path(parent_module_attr_path), 48 &self,
69 name 49 db: &impl DefDatabase,
70 )); 50 file_id: HirFileId,
71 ResolutionMode::InlineModuleWithAttributePath(InsideInlineModuleMode::File(path)) 51 name: &Name,
52 attr_path: Option<&SmolStr>,
53 ) -> Result<(FileId, ModDir), RelativePathBuf> {
54 let empty_path = RelativePathBuf::default();
55 let file_id = file_id.original_file(db);
56 let base_dir = {
57 let path = db.file_relative_path(file_id);
58 path.parent().unwrap_or(&empty_path).join(&self.path)
59 };
60
61 let mut candidate_files = Vec::new();
62 match attr_path {
63 Some(attr) => {
64 let base = if self.root_non_dir_owner {
65 base_dir.parent().unwrap_or(&empty_path)
66 } else {
67 &base_dir
68 };
69 candidate_files.push(base.join(&*normalize_attribute_path(attr)))
72 } 70 }
73 None => { 71 None => {
74 let path = dir_path.join(format!("{}/{}.rs", parent_module.name, name)); 72 candidate_files.push(base_dir.join(&format!("{}.rs", name)));
75 ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path)) 73 candidate_files.push(base_dir.join(&format!("{}/mod.rs", name)));
76 } 74 }
77 }, 75 };
78 (Some(file_path), None) => { 76
79 let file_path = normalize_attribute_path(file_path); 77 let source_root_id = db.file_source_root(file_id);
80 let path = dir_path.join(file_path.as_ref()).normalize(); 78 let source_root = db.source_root(source_root_id);
81 ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path)) 79 for candidate in candidate_files.iter() {
82 } 80 let candidate = candidate.normalize();
83 (None, None) => { 81 if let Some(file_id) = source_root.file_by_relative_path(&candidate) {
84 let is_dir_owner = is_root || mod_name == "mod" || mod_attr_path.is_some(); 82 let mut root_non_dir_owner = false;
85 if is_dir_owner { 83 let mut mod_path = RelativePathBuf::new();
86 let file_mod = dir_path.join(format!("{}.rs", name)); 84 if !(candidate.ends_with("mod.rs") || attr_path.is_some()) {
87 let dir_mod = dir_path.join(format!("{}/mod.rs", name)); 85 root_non_dir_owner = true;
88 ResolutionMode::OutOfLine(OutOfLineMode::RootOrModRs { 86 mod_path.push(&name.to_string());
89 file: file_mod, 87 }
90 directory: dir_mod, 88 return Ok((file_id, ModDir { path: mod_path, root_non_dir_owner }));
91 })
92 } else {
93 let path = dir_path.join(format!("{}/{}.rs", mod_name, name));
94 ResolutionMode::OutOfLine(OutOfLineMode::FileInDirectory(path))
95 } 89 }
96 } 90 }
97 }; 91 let suggestion = candidate_files.first().unwrap();
98 92 Err(base_dir.join(suggestion))
99 resolve_mode.resolve(db.source_root(source_root_id)) 93 }
100} 94}
101 95
102fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> { 96fn normalize_attribute_path(file_path: &str) -> Cow<str> {
103 let current_dir = "./"; 97 let current_dir = "./";
104 let windows_path_separator = r#"\"#; 98 let windows_path_separator = r#"\"#;
105 let current_dir_normalize = if file_path.starts_with(current_dir) { 99 let current_dir_normalize = if file_path.starts_with(current_dir) {
106 &file_path[current_dir.len()..] 100 &file_path[current_dir.len()..]
107 } else { 101 } else {
108 file_path.as_str() 102 file_path
109 }; 103 };
110 if current_dir_normalize.contains(windows_path_separator) { 104 if current_dir_normalize.contains(windows_path_separator) {
111 Cow::Owned(current_dir_normalize.replace(windows_path_separator, "/")) 105 Cow::Owned(current_dir_normalize.replace(windows_path_separator, "/"))
@@ -113,75 +107,3 @@ fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> {
113 Cow::Borrowed(current_dir_normalize) 107 Cow::Borrowed(current_dir_normalize)
114 } 108 }
115} 109}
116
117enum OutOfLineMode {
118 RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf },
119 FileInDirectory(RelativePathBuf),
120 WithAttributePath(RelativePathBuf),
121}
122
123impl OutOfLineMode {
124 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
125 match self {
126 OutOfLineMode::RootOrModRs { file, directory } => {
127 match source_root.file_by_relative_path(file) {
128 None => resolve_simple_path(source_root, directory).map_err(|_| file.clone()),
129 file_id => resolve_find_result(file_id, file),
130 }
131 }
132 OutOfLineMode::FileInDirectory(path) => resolve_simple_path(source_root, path),
133 OutOfLineMode::WithAttributePath(path) => resolve_simple_path(source_root, path),
134 }
135 }
136}
137
138enum InsideInlineModuleMode {
139 File(RelativePathBuf),
140 WithAttributePath(RelativePathBuf),
141}
142
143impl InsideInlineModuleMode {
144 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
145 match self {
146 InsideInlineModuleMode::File(path) => resolve_simple_path(source_root, path),
147 InsideInlineModuleMode::WithAttributePath(path) => {
148 resolve_simple_path(source_root, path)
149 }
150 }
151 }
152}
153
154enum ResolutionMode {
155 OutOfLine(OutOfLineMode),
156 InsideInlineModule(InsideInlineModuleMode),
157 InlineModuleWithAttributePath(InsideInlineModuleMode),
158}
159
160impl ResolutionMode {
161 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
162 use self::ResolutionMode::*;
163
164 match self {
165 OutOfLine(mode) => mode.resolve(source_root),
166 InsideInlineModule(mode) => mode.resolve(source_root),
167 InlineModuleWithAttributePath(mode) => mode.resolve(source_root),
168 }
169 }
170}
171
172fn resolve_simple_path(
173 source_root: Arc<SourceRoot>,
174 path: &RelativePathBuf,
175) -> Result<FileId, RelativePathBuf> {
176 resolve_find_result(source_root.file_by_relative_path(path), path)
177}
178
179fn resolve_find_result(
180 file_id: Option<FileId>,
181 path: &RelativePathBuf,
182) -> Result<FileId, RelativePathBuf> {
183 match file_id {
184 Some(file_id) => Ok(file_id.clone()),
185 None => Err(path.clone()),
186 }
187}
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
index e4b408394..4f52ad2c5 100644
--- a/crates/ra_hir/src/nameres/tests/macros.rs
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -38,21 +38,34 @@ fn macro_rules_can_define_modules() {
38 } 38 }
39 m!(n1); 39 m!(n1);
40 40
41 mod m {
42 m!(n3)
43 }
44
41 //- /n1.rs 45 //- /n1.rs
42 m!(n2) 46 m!(n2)
43 //- /n1/n2.rs 47 //- /n1/n2.rs
44 struct X; 48 struct X;
49 //- /m/n3.rs
50 struct Y;
45 ", 51 ",
46 ); 52 );
47 assert_snapshot!(map, @r###" 53 assert_snapshot!(map, @r###"
48 ⋮crate 54 crate
49 ⋮n1: t 55 m: t
50 56 n1: t
51 ⋮crate::n1 57
52 ⋮n2: t 58 crate::m
53 59 n3: t
54 ⋮crate::n1::n2 60
55 ⋮X: t v 61 crate::m::n3
62 Y: t v
63
64 crate::n1
65 n2: t
66
67 crate::n1::n2
68 X: t v
56 "###); 69 "###);
57} 70}
58 71
diff --git a/crates/ra_hir/src/nameres/tests/mod_resolution.rs b/crates/ra_hir/src/nameres/tests/mod_resolution.rs
index e3e6f1e95..755f5723b 100644
--- a/crates/ra_hir/src/nameres/tests/mod_resolution.rs
+++ b/crates/ra_hir/src/nameres/tests/mod_resolution.rs
@@ -26,6 +26,33 @@ fn name_res_works_for_broken_modules() {
26} 26}
27 27
28#[test] 28#[test]
29fn nested_module_resolution() {
30 let map = def_map(
31 "
32 //- /lib.rs
33 mod n1;
34
35 //- /n1.rs
36 mod n2;
37
38 //- /n1/n2.rs
39 struct X;
40 ",
41 );
42
43 assert_snapshot!(map, @r###"
44 ⋮crate
45 ⋮n1: t
46
47 ⋮crate::n1
48 ⋮n2: t
49
50 ⋮crate::n1::n2
51 ⋮X: t v
52 "###);
53}
54
55#[test]
29fn module_resolution_works_for_non_standard_filenames() { 56fn module_resolution_works_for_non_standard_filenames() {
30 let map = def_map_with_crate_graph( 57 let map = def_map_with_crate_graph(
31 " 58 "
@@ -467,7 +494,7 @@ fn module_resolution_decl_inside_inline_module_empty_path() {
467 mod bar; 494 mod bar;
468 } 495 }
469 496
470 //- /foo/users.rs 497 //- /users.rs
471 pub struct Baz; 498 pub struct Baz;
472 "###, 499 "###,
473 crate_graph! { 500 crate_graph! {
@@ -492,7 +519,7 @@ fn module_resolution_decl_empty_path() {
492 let map = def_map_with_crate_graph( 519 let map = def_map_with_crate_graph(
493 r###" 520 r###"
494 //- /main.rs 521 //- /main.rs
495 #[path = ""] 522 #[path = ""] // Should try to read `/` (a directory)
496 mod foo; 523 mod foo;
497 524
498 //- /foo.rs 525 //- /foo.rs
@@ -505,10 +532,6 @@ fn module_resolution_decl_empty_path() {
505 532
506 assert_snapshot!(map, @r###" 533 assert_snapshot!(map, @r###"
507 ⋮crate 534 ⋮crate
508 ⋮foo: t
509
510 ⋮crate::foo
511 ⋮Baz: t v
512 "###); 535 "###);
513} 536}
514 537
@@ -626,7 +649,7 @@ fn module_resolution_decl_inside_inline_module_in_non_crate_root() {
626 } 649 }
627 use self::bar::baz::Baz; 650 use self::bar::baz::Baz;
628 651
629 //- /bar/qwe.rs 652 //- /foo/bar/qwe.rs
630 pub struct Baz; 653 pub struct Baz;
631 "###, 654 "###,
632 crate_graph! { 655 crate_graph! {
@@ -737,3 +760,66 @@ fn module_resolution_decl_inside_module_in_non_crate_root_2() {
737 ⋮Baz: t v 760 ⋮Baz: t v
738 "###); 761 "###);
739} 762}
763
764#[test]
765fn nested_out_of_line_module() {
766 let map = def_map(
767 r###"
768 //- /lib.rs
769 mod a {
770 mod b {
771 mod c;
772 }
773 }
774
775 //- /a/b/c.rs
776 struct X;
777 "###,
778 );
779
780 assert_snapshot!(map, @r###"
781 crate
782 a: t
783
784 crate::a
785 b: t
786
787 crate::a::b
788 c: t
789
790 crate::a::b::c
791 X: t v
792 "###);
793}
794
795#[test]
796fn nested_out_of_line_module_with_path() {
797 let map = def_map(
798 r###"
799 //- /lib.rs
800 mod a {
801 #[path = "d/e"]
802 mod b {
803 mod c;
804 }
805 }
806
807 //- /a/d/e/c.rs
808 struct X;
809 "###,
810 );
811
812 assert_snapshot!(map, @r###"
813 crate
814 a: t
815
816 crate::a
817 b: t
818
819 crate::a::b
820 c: t
821
822 crate::a::b::c
823 X: t v
824 "###);
825}