aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres/mod_resolution.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-09-05 18:27:10 +0100
committerAleksey Kladov <[email protected]>2019-09-05 18:27:10 +0100
commit3e5f7299e17c18358904240b08875bf82a9423f2 (patch)
tree472f4d700e94262548b2197e0045c18936c67183 /crates/ra_hir/src/nameres/mod_resolution.rs
parentedc2016f8b49964fa5b179c1ed8e12e4e0a39702 (diff)
move mod resolution to a separate file
Diffstat (limited to 'crates/ra_hir/src/nameres/mod_resolution.rs')
-rw-r--r--crates/ra_hir/src/nameres/mod_resolution.rs182
1 files changed, 182 insertions, 0 deletions
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}