aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r--crates/ra_hir_def/src/find_path.rs70
-rw-r--r--crates/ra_hir_def/src/item_scope.rs8
2 files changed, 67 insertions, 11 deletions
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs
index 6772330e0..afcf04280 100644
--- a/crates/ra_hir_def/src/find_path.rs
+++ b/crates/ra_hir_def/src/find_path.rs
@@ -8,22 +8,12 @@ use crate::{
8}; 8};
9use hir_expand::name::Name; 9use hir_expand::name::Name;
10 10
11// TODO handle prelude
12// TODO handle enum variants
13// TODO don't import from super imports? or at least deprioritize 11// TODO don't import from super imports? or at least deprioritize
14// TODO use super? 12// TODO use super?
15// TODO use shortest path 13// TODO use shortest path
16// TODO performance / memoize 14// TODO performance / memoize
17 15
18pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { 16pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
19 // 1. Find all locations that the item could be imported from (i.e. that are visible)
20 // - this needs to consider other crates, for reexports from transitive dependencies
21 // - filter by visibility
22 // 2. For each of these, go up the module tree until we find an
23 // item/module/crate that is already in scope (including because it is in
24 // the prelude, and including aliases!)
25 // 3. Then select the one that gives the shortest path
26
27 // Base cases: 17 // Base cases:
28 18
29 // - if the item is already in scope, return the name under which it is 19 // - if the item is already in scope, return the name under which it is
@@ -46,10 +36,28 @@ pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Optio
46 } 36 }
47 37
48 // - if the item is in the prelude, return the name from there 38 // - if the item is in the prelude, return the name from there
49 // TODO check prelude 39 if let Some(prelude_module) = def_map.prelude {
40 let prelude_def_map = db.crate_def_map(prelude_module.krate);
41 let prelude_scope: &crate::item_scope::ItemScope = &prelude_def_map.modules[prelude_module.local_id].scope;
42 if let Some((name, vis)) = prelude_scope.reverse_get(item) {
43 if vis.is_visible_from(db, from) {
44 return Some(ModPath::from_simple_segments(PathKind::Plain, vec![name.clone()]));
45 }
46 }
47 }
50 48
51 // Recursive case: 49 // Recursive case:
52 // - if the item is an enum variant, refer to it via the enum 50 // - if the item is an enum variant, refer to it via the enum
51 if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
52 if let Some(mut path) = find_path(db, ItemInNs::Types(variant.parent.into()), from) {
53 let data = db.enum_data(variant.parent);
54 path.segments.push(data.variants[variant.local_id].name.clone());
55 return Some(path);
56 }
57 // If this doesn't work, it seems we have no way of referring to the
58 // enum; that's very weird, but there might still be a reexport of the
59 // variant somewhere
60 }
53 61
54 // - otherwise, look for modules containing (reexporting) it and import it from one of those 62 // - otherwise, look for modules containing (reexporting) it and import it from one of those
55 let importable_locations = find_importable_locations(db, item, from); 63 let importable_locations = find_importable_locations(db, item, from);
@@ -132,6 +140,16 @@ mod tests {
132 } 140 }
133 141
134 #[test] 142 #[test]
143 fn enum_variant() {
144 let code = r#"
145 //- /main.rs
146 enum E { A }
147 <|>
148 "#;
149 check_found_path(code, "E::A");
150 }
151
152 #[test]
135 fn sub_module() { 153 fn sub_module() {
136 let code = r#" 154 let code = r#"
137 //- /main.rs 155 //- /main.rs
@@ -216,6 +234,19 @@ mod tests {
216 } 234 }
217 235
218 #[test] 236 #[test]
237 fn different_crate_reexport() {
238 let code = r#"
239 //- /main.rs crate:main deps:std
240 <|>
241 //- /std.rs crate:std deps:core
242 pub use core::S;
243 //- /core.rs crate:core
244 pub struct S;
245 "#;
246 check_found_path(code, "std::S");
247 }
248
249 #[test]
219 fn prelude() { 250 fn prelude() {
220 let code = r#" 251 let code = r#"
221 //- /main.rs crate:main deps:std 252 //- /main.rs crate:main deps:std
@@ -227,4 +258,21 @@ mod tests {
227 "#; 258 "#;
228 check_found_path(code, "S"); 259 check_found_path(code, "S");
229 } 260 }
261
262 #[test]
263 fn enum_variant_from_prelude() {
264 let code = r#"
265 //- /main.rs crate:main deps:std
266 <|>
267 //- /std.rs crate:std
268 pub mod prelude {
269 pub enum Option<T> { Some(T), None }
270 pub use Option::*;
271 }
272 #[prelude_import]
273 pub use prelude::*;
274 "#;
275 check_found_path(code, "None");
276 check_found_path(code, "Some");
277 }
230} 278}
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index f88502d78..71afdb235 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -204,4 +204,12 @@ impl ItemInNs {
204 }, 204 },
205 } 205 }
206 } 206 }
207
208 pub fn as_module_def_id(self) -> Option<ModuleDefId> {
209 match self {
210 ItemInNs::Types(t) => Some(t),
211 ItemInNs::Values(v) => Some(v),
212 ItemInNs::Macros(_) => None,
213 }
214 }
207} 215}