diff options
author | Aleksey Kladov <[email protected]> | 2019-10-10 12:45:05 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-10-10 12:46:14 +0100 |
commit | ce0d4a3b1deaca318a1ed2ff83cca652ef8e8c82 (patch) | |
tree | c3f495cd98d2a992a2f7b636f2284af2c5c86715 /crates/ra_hir | |
parent | 72b8cfb5aa99d85cd8cc936232cbbf24d1995547 (diff) |
Refactor and fix some more edge cases around name resolution
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 40 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/mod_resolution.rs | 232 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/macros.rs | 29 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/mod_resolution.rs | 100 |
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 | ||
3 | use ra_cfg::CfgOptions; | 3 | use ra_cfg::CfgOptions; |
4 | use ra_db::FileId; | 4 | use ra_db::FileId; |
5 | use ra_syntax::{ast, SmolStr}; | 5 | use ra_syntax::ast; |
6 | use rustc_hash::FxHashMap; | 6 | use rustc_hash::FxHashMap; |
7 | use test_utils::tested_by; | 7 | use 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 | ||
516 | impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>> | 514 | impl<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. |
2 | use std::borrow::Cow; | ||
2 | 3 | ||
3 | use std::{borrow::Cow, sync::Arc}; | 4 | use ra_db::FileId; |
4 | |||
5 | use ra_db::{FileId, SourceRoot}; | ||
6 | use ra_syntax::SmolStr; | 5 | use ra_syntax::SmolStr; |
7 | use relative_path::RelativePathBuf; | 6 | use relative_path::{RelativePath, RelativePathBuf}; |
8 | 7 | ||
9 | use crate::{db::DefDatabase, HirFileId, Name}; | 8 | use crate::{db::DefDatabase, HirFileId, Name}; |
10 | 9 | ||
11 | #[derive(Clone, Copy)] | 10 | #[derive(Clone, Debug)] |
12 | pub(super) struct ParentModule<'a> { | 11 | pub(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 | ||
17 | impl<'a> ParentModule<'a> { | 20 | impl 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 | |||
23 | pub(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 | ||
102 | fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> { | 96 | fn 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 | |||
117 | enum OutOfLineMode { | ||
118 | RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf }, | ||
119 | FileInDirectory(RelativePathBuf), | ||
120 | WithAttributePath(RelativePathBuf), | ||
121 | } | ||
122 | |||
123 | impl 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 | |||
138 | enum InsideInlineModuleMode { | ||
139 | File(RelativePathBuf), | ||
140 | WithAttributePath(RelativePathBuf), | ||
141 | } | ||
142 | |||
143 | impl 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 | |||
154 | enum ResolutionMode { | ||
155 | OutOfLine(OutOfLineMode), | ||
156 | InsideInlineModule(InsideInlineModuleMode), | ||
157 | InlineModuleWithAttributePath(InsideInlineModuleMode), | ||
158 | } | ||
159 | |||
160 | impl 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 | |||
172 | fn 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 | |||
179 | fn 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] |
29 | fn 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] | ||
29 | fn module_resolution_works_for_non_standard_filenames() { | 56 | fn 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] | ||
765 | fn 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] | ||
796 | fn 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 | } | ||