aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src')
-rw-r--r--crates/ra_hir_def/src/find_path.rs50
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};
9use hir_expand::name::Name; 9use 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
15pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { 13pub 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}