diff options
Diffstat (limited to 'crates/ra_hir_def/src')
-rw-r--r-- | crates/ra_hir_def/src/find_path.rs | 50 |
1 files changed, 48 insertions, 2 deletions
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index f7fd0c00a..be34ee662 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs | |||
@@ -8,8 +8,6 @@ use crate::{ | |||
8 | }; | 8 | }; |
9 | use hir_expand::name::Name; | 9 | use hir_expand::name::Name; |
10 | 10 | ||
11 | // TODO don't import from super imports? or at least deprioritize | ||
12 | // TODO use super? | ||
13 | // TODO performance / memoize | 11 | // TODO performance / memoize |
14 | 12 | ||
15 | pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { | 13 | pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { |
@@ -27,6 +25,13 @@ pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Optio | |||
27 | return Some(ModPath::from_simple_segments(PathKind::Crate, Vec::new())); | 25 | return Some(ModPath::from_simple_segments(PathKind::Crate, Vec::new())); |
28 | } | 26 | } |
29 | 27 | ||
28 | // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) | ||
29 | if let Some(parent_id) = def_map.modules[from.local_id].parent { | ||
30 | if item == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { krate: from.krate, local_id: parent_id })) { | ||
31 | return Some(ModPath::from_simple_segments(PathKind::Super(1), Vec::new())); | ||
32 | } | ||
33 | } | ||
34 | |||
30 | // - if the item is the crate root of a dependency crate, return the name from the extern prelude | 35 | // - if the item is the crate root of a dependency crate, return the name from the extern prelude |
31 | for (name, def_id) in &def_map.extern_prelude { | 36 | for (name, def_id) in &def_map.extern_prelude { |
32 | if item == ItemInNs::Types(*def_id) { | 37 | if item == ItemInNs::Types(*def_id) { |
@@ -80,6 +85,19 @@ fn find_importable_locations(db: &impl DefDatabase, item: ItemInNs, from: Module | |||
80 | let def_map = db.crate_def_map(krate); | 85 | let def_map = db.crate_def_map(krate); |
81 | for (local_id, data) in def_map.modules.iter() { | 86 | for (local_id, data) in def_map.modules.iter() { |
82 | if let Some((name, vis)) = data.scope.reverse_get(item) { | 87 | if let Some((name, vis)) = data.scope.reverse_get(item) { |
88 | let is_private = if let crate::visibility::Visibility::Module(private_to) = vis { | ||
89 | private_to.local_id == local_id | ||
90 | } else { false }; | ||
91 | let is_original_def = if let Some(module_def_id) = item.as_module_def_id() { | ||
92 | data.scope.declarations().any(|it| it == module_def_id) | ||
93 | } else { false }; | ||
94 | if is_private && !is_original_def { | ||
95 | // Ignore private imports. these could be used if we are | ||
96 | // in a submodule of this module, but that's usually not | ||
97 | // what the user wants; and if this module can import | ||
98 | // the item and we're a submodule of it, so can we. | ||
99 | continue; | ||
100 | } | ||
83 | if vis.is_visible_from(db, from) { | 101 | if vis.is_visible_from(db, from) { |
84 | result.push((ModuleId { krate, local_id }, name.clone())); | 102 | result.push((ModuleId { krate, local_id }, name.clone())); |
85 | } | 103 | } |
@@ -161,6 +179,20 @@ mod tests { | |||
161 | } | 179 | } |
162 | 180 | ||
163 | #[test] | 181 | #[test] |
182 | fn super_module() { | ||
183 | let code = r#" | ||
184 | //- /main.rs | ||
185 | mod foo; | ||
186 | //- /foo.rs | ||
187 | mod bar; | ||
188 | struct S; | ||
189 | //- /foo/bar.rs | ||
190 | <|> | ||
191 | "#; | ||
192 | check_found_path(code, "super::S"); | ||
193 | } | ||
194 | |||
195 | #[test] | ||
164 | fn crate_root() { | 196 | fn crate_root() { |
165 | let code = r#" | 197 | let code = r#" |
166 | //- /main.rs | 198 | //- /main.rs |
@@ -290,4 +322,18 @@ mod tests { | |||
290 | "#; | 322 | "#; |
291 | check_found_path(code, "baz::S"); | 323 | check_found_path(code, "baz::S"); |
292 | } | 324 | } |
325 | |||
326 | #[test] | ||
327 | fn discount_private_imports() { | ||
328 | let code = r#" | ||
329 | //- /main.rs | ||
330 | mod foo; | ||
331 | pub mod bar { pub struct S; } | ||
332 | use bar::S; | ||
333 | //- /foo.rs | ||
334 | <|> | ||
335 | "#; | ||
336 | // crate::S would be shorter, but using private imports seems wrong | ||
337 | check_found_path(code, "crate::bar::S"); | ||
338 | } | ||
293 | } | 339 | } |