aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/nameres.rs1
-rw-r--r--crates/ra_hir/src/nameres/collector.rs190
-rw-r--r--crates/ra_hir/src/nameres/mod_resolution.rs182
3 files changed, 190 insertions, 183 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index f69179bf6..dc2e2172b 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -50,6 +50,7 @@
50mod per_ns; 50mod per_ns;
51mod raw; 51mod raw;
52mod collector; 52mod collector;
53mod mod_resolution;
53#[cfg(test)] 54#[cfg(test)]
54mod tests; 55mod tests;
55 56
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 5d1c42926..d6c7c083d 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -1,9 +1,5 @@
1use std::borrow::Cow; 1use ra_db::FileId;
2use std::sync::Arc; 2use ra_syntax::ast;
3
4use ra_db::{FileId, SourceRoot};
5use ra_syntax::{ast, SmolStr};
6use relative_path::RelativePathBuf;
7use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
8use test_utils::tested_by; 4use test_utils::tested_by;
9 5
@@ -12,8 +8,10 @@ use crate::{
12 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, 8 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind},
13 name::MACRO_RULES, 9 name::MACRO_RULES,
14 nameres::{ 10 nameres::{
15 diagnostics::DefDiagnostic, raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, 11 diagnostics::DefDiagnostic,
16 ModuleDef, PerNs, ReachedFixedPoint, Resolution, ResolveMode, 12 mod_resolution::{resolve_submodule, ParentModule},
13 raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs,
14 ReachedFixedPoint, Resolution, ResolveMode,
17 }, 15 },
18 AstId, Const, DefDatabase, Enum, Function, HirFileId, MacroDef, Module, Name, Path, Static, 16 AstId, Const, DefDatabase, Enum, Function, HirFileId, MacroDef, Module, Name, Path, Static,
19 Struct, Trait, TypeAlias, Union, 17 Struct, Trait, TypeAlias, Union,
@@ -568,7 +566,7 @@ where
568 name, 566 name,
569 is_root, 567 is_root,
570 attr_path.as_ref(), 568 attr_path.as_ref(),
571 self.parent_module.as_ref(), 569 self.parent_module,
572 ) { 570 ) {
573 Ok(file_id) => { 571 Ok(file_id) => {
574 let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); 572 let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id));
@@ -679,180 +677,6 @@ fn is_macro_rules(path: &Path) -> bool {
679 path.as_ident() == Some(&MACRO_RULES) 677 path.as_ident() == Some(&MACRO_RULES)
680} 678}
681 679
682fn resolve_submodule(
683 db: &impl DefDatabase,
684 file_id: HirFileId,
685 name: &Name,
686 is_root: bool,
687 attr_path: Option<&SmolStr>,
688 parent_module: Option<&ParentModule>,
689) -> Result<FileId, RelativePathBuf> {
690 let file_id = file_id.original_file(db);
691 let source_root_id = db.file_source_root(file_id);
692 let path = db.file_relative_path(file_id);
693 let root = RelativePathBuf::default();
694 let dir_path = path.parent().unwrap_or(&root);
695 let mod_name = path.file_stem().unwrap_or("unknown");
696
697 let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) {
698 (Some(file_path), Some(parent_module)) => {
699 let file_path = normalize_attribute_path(file_path);
700 match parent_module.attribute_path() {
701 Some(parent_module_attr_path) => {
702 let path = dir_path
703 .join(format!(
704 "{}/{}",
705 normalize_attribute_path(parent_module_attr_path),
706 file_path
707 ))
708 .normalize();
709 ResolutionMode::InlineModuleWithAttributePath(
710 InsideInlineModuleMode::WithAttributePath(path),
711 )
712 }
713 None => {
714 let path =
715 dir_path.join(format!("{}/{}", parent_module.name, file_path)).normalize();
716 ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath(
717 path,
718 ))
719 }
720 }
721 }
722 (None, Some(parent_module)) => match parent_module.attribute_path() {
723 Some(parent_module_attr_path) => {
724 let path = dir_path.join(format!(
725 "{}/{}.rs",
726 normalize_attribute_path(parent_module_attr_path),
727 name
728 ));
729 ResolutionMode::InlineModuleWithAttributePath(InsideInlineModuleMode::File(path))
730 }
731 None => {
732 let path = dir_path.join(format!("{}/{}.rs", parent_module.name, name));
733 ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path))
734 }
735 },
736 (Some(file_path), None) => {
737 let file_path = normalize_attribute_path(file_path);
738 let path = dir_path.join(file_path.as_ref()).normalize();
739 ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path))
740 }
741 _ => {
742 let is_dir_owner = is_root || mod_name == "mod";
743 if is_dir_owner {
744 let file_mod = dir_path.join(format!("{}.rs", name));
745 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
746 ResolutionMode::OutOfLine(OutOfLineMode::RootOrModRs {
747 file: file_mod,
748 directory: dir_mod,
749 })
750 } else {
751 let path = dir_path.join(format!("{}/{}.rs", mod_name, name));
752 ResolutionMode::OutOfLine(OutOfLineMode::FileInDirectory(path))
753 }
754 }
755 };
756
757 resolve_mode.resolve(db.source_root(source_root_id))
758}
759
760fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> {
761 let current_dir = "./";
762 let windows_path_separator = r#"\"#;
763 let current_dir_normalize = if file_path.starts_with(current_dir) {
764 &file_path[current_dir.len()..]
765 } else {
766 file_path.as_str()
767 };
768 if current_dir_normalize.contains(windows_path_separator) {
769 Cow::Owned(current_dir_normalize.replace(windows_path_separator, "/"))
770 } else {
771 Cow::Borrowed(current_dir_normalize)
772 }
773}
774
775enum OutOfLineMode {
776 RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf },
777 FileInDirectory(RelativePathBuf),
778 WithAttributePath(RelativePathBuf),
779}
780
781impl OutOfLineMode {
782 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
783 match self {
784 OutOfLineMode::RootOrModRs { file, directory } => match source_root.files.get(file) {
785 None => resolve_simple_path(source_root, directory).map_err(|_| file.clone()),
786 file_id => resolve_find_result(file_id, file),
787 },
788 OutOfLineMode::FileInDirectory(path) => resolve_simple_path(source_root, path),
789 OutOfLineMode::WithAttributePath(path) => resolve_simple_path(source_root, path),
790 }
791 }
792}
793
794enum InsideInlineModuleMode {
795 File(RelativePathBuf),
796 WithAttributePath(RelativePathBuf),
797}
798
799impl InsideInlineModuleMode {
800 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
801 match self {
802 InsideInlineModuleMode::File(path) => resolve_simple_path(source_root, path),
803 InsideInlineModuleMode::WithAttributePath(path) => {
804 resolve_simple_path(source_root, path)
805 }
806 }
807 }
808}
809
810enum ResolutionMode {
811 OutOfLine(OutOfLineMode),
812 InsideInlineModule(InsideInlineModuleMode),
813 InlineModuleWithAttributePath(InsideInlineModuleMode),
814}
815
816impl ResolutionMode {
817 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
818 use self::ResolutionMode::*;
819
820 match self {
821 OutOfLine(mode) => mode.resolve(source_root),
822 InsideInlineModule(mode) => mode.resolve(source_root),
823 InlineModuleWithAttributePath(mode) => mode.resolve(source_root),
824 }
825 }
826}
827
828fn resolve_simple_path(
829 source_root: Arc<SourceRoot>,
830 path: &RelativePathBuf,
831) -> Result<FileId, RelativePathBuf> {
832 resolve_find_result(source_root.files.get(path), path)
833}
834
835fn resolve_find_result(
836 file_id: Option<&FileId>,
837 path: &RelativePathBuf,
838) -> Result<FileId, RelativePathBuf> {
839 match file_id {
840 Some(file_id) => Ok(file_id.clone()),
841 None => Err(path.clone()),
842 }
843}
844
845struct ParentModule<'a> {
846 name: &'a Name,
847 attr_path: Option<&'a SmolStr>,
848}
849
850impl<'a> ParentModule<'a> {
851 pub fn attribute_path(&self) -> Option<&SmolStr> {
852 self.attr_path.filter(|p| !p.is_empty())
853 }
854}
855
856#[cfg(test)] 680#[cfg(test)]
857mod tests { 681mod tests {
858 use ra_db::SourceDatabase; 682 use ra_db::SourceDatabase;
diff --git a/crates/ra_hir/src/nameres/mod_resolution.rs b/crates/ra_hir/src/nameres/mod_resolution.rs
new file mode 100644
index 000000000..94c9946ff
--- /dev/null
+++ b/crates/ra_hir/src/nameres/mod_resolution.rs
@@ -0,0 +1,182 @@
1use std::{borrow::Cow, sync::Arc};
2
3use ra_db::{FileId, SourceRoot};
4use ra_syntax::SmolStr;
5use relative_path::RelativePathBuf;
6
7use crate::{DefDatabase, HirFileId, Name};
8
9#[derive(Clone, Copy)]
10pub(super) struct ParentModule<'a> {
11 pub(super) name: &'a Name,
12 pub(super) attr_path: Option<&'a SmolStr>,
13}
14
15impl<'a> ParentModule<'a> {
16 fn attribute_path(&self) -> Option<&SmolStr> {
17 self.attr_path.filter(|p| !p.is_empty())
18 }
19}
20
21pub(super) fn resolve_submodule(
22 db: &impl DefDatabase,
23 file_id: HirFileId,
24 name: &Name,
25 is_root: bool,
26 attr_path: Option<&SmolStr>,
27 parent_module: Option<ParentModule<'_>>,
28) -> Result<FileId, RelativePathBuf> {
29 let file_id = file_id.original_file(db);
30 let source_root_id = db.file_source_root(file_id);
31 let path = db.file_relative_path(file_id);
32 let root = RelativePathBuf::default();
33 let dir_path = path.parent().unwrap_or(&root);
34 let mod_name = path.file_stem().unwrap_or("unknown");
35
36 let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) {
37 (Some(file_path), Some(parent_module)) => {
38 let file_path = normalize_attribute_path(file_path);
39 match parent_module.attribute_path() {
40 Some(parent_module_attr_path) => {
41 let path = dir_path
42 .join(format!(
43 "{}/{}",
44 normalize_attribute_path(parent_module_attr_path),
45 file_path
46 ))
47 .normalize();
48 ResolutionMode::InlineModuleWithAttributePath(
49 InsideInlineModuleMode::WithAttributePath(path),
50 )
51 }
52 None => {
53 let path =
54 dir_path.join(format!("{}/{}", parent_module.name, file_path)).normalize();
55 ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath(
56 path,
57 ))
58 }
59 }
60 }
61 (None, Some(parent_module)) => match parent_module.attribute_path() {
62 Some(parent_module_attr_path) => {
63 let path = dir_path.join(format!(
64 "{}/{}.rs",
65 normalize_attribute_path(parent_module_attr_path),
66 name
67 ));
68 ResolutionMode::InlineModuleWithAttributePath(InsideInlineModuleMode::File(path))
69 }
70 None => {
71 let path = dir_path.join(format!("{}/{}.rs", parent_module.name, name));
72 ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path))
73 }
74 },
75 (Some(file_path), None) => {
76 let file_path = normalize_attribute_path(file_path);
77 let path = dir_path.join(file_path.as_ref()).normalize();
78 ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path))
79 }
80 _ => {
81 let is_dir_owner = is_root || mod_name == "mod";
82 if is_dir_owner {
83 let file_mod = dir_path.join(format!("{}.rs", name));
84 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
85 ResolutionMode::OutOfLine(OutOfLineMode::RootOrModRs {
86 file: file_mod,
87 directory: dir_mod,
88 })
89 } else {
90 let path = dir_path.join(format!("{}/{}.rs", mod_name, name));
91 ResolutionMode::OutOfLine(OutOfLineMode::FileInDirectory(path))
92 }
93 }
94 };
95
96 resolve_mode.resolve(db.source_root(source_root_id))
97}
98
99fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> {
100 let current_dir = "./";
101 let windows_path_separator = r#"\"#;
102 let current_dir_normalize = if file_path.starts_with(current_dir) {
103 &file_path[current_dir.len()..]
104 } else {
105 file_path.as_str()
106 };
107 if current_dir_normalize.contains(windows_path_separator) {
108 Cow::Owned(current_dir_normalize.replace(windows_path_separator, "/"))
109 } else {
110 Cow::Borrowed(current_dir_normalize)
111 }
112}
113
114enum OutOfLineMode {
115 RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf },
116 FileInDirectory(RelativePathBuf),
117 WithAttributePath(RelativePathBuf),
118}
119
120impl OutOfLineMode {
121 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
122 match self {
123 OutOfLineMode::RootOrModRs { file, directory } => match source_root.files.get(file) {
124 None => resolve_simple_path(source_root, directory).map_err(|_| file.clone()),
125 file_id => resolve_find_result(file_id, file),
126 },
127 OutOfLineMode::FileInDirectory(path) => resolve_simple_path(source_root, path),
128 OutOfLineMode::WithAttributePath(path) => resolve_simple_path(source_root, path),
129 }
130 }
131}
132
133enum InsideInlineModuleMode {
134 File(RelativePathBuf),
135 WithAttributePath(RelativePathBuf),
136}
137
138impl InsideInlineModuleMode {
139 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
140 match self {
141 InsideInlineModuleMode::File(path) => resolve_simple_path(source_root, path),
142 InsideInlineModuleMode::WithAttributePath(path) => {
143 resolve_simple_path(source_root, path)
144 }
145 }
146 }
147}
148
149enum ResolutionMode {
150 OutOfLine(OutOfLineMode),
151 InsideInlineModule(InsideInlineModuleMode),
152 InlineModuleWithAttributePath(InsideInlineModuleMode),
153}
154
155impl ResolutionMode {
156 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
157 use self::ResolutionMode::*;
158
159 match self {
160 OutOfLine(mode) => mode.resolve(source_root),
161 InsideInlineModule(mode) => mode.resolve(source_root),
162 InlineModuleWithAttributePath(mode) => mode.resolve(source_root),
163 }
164 }
165}
166
167fn resolve_simple_path(
168 source_root: Arc<SourceRoot>,
169 path: &RelativePathBuf,
170) -> Result<FileId, RelativePathBuf> {
171 resolve_find_result(source_root.files.get(path), path)
172}
173
174fn resolve_find_result(
175 file_id: Option<&FileId>,
176 path: &RelativePathBuf,
177) -> Result<FileId, RelativePathBuf> {
178 match file_id {
179 Some(file_id) => Ok(file_id.clone()),
180 None => Err(path.clone()),
181 }
182}