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.rs102
-rw-r--r--crates/ra_hir_def/src/item_scope.rs32
2 files changed, 122 insertions, 12 deletions
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs
index 1ddf5fca6..cc686ea6a 100644
--- a/crates/ra_hir_def/src/find_path.rs
+++ b/crates/ra_hir_def/src/find_path.rs
@@ -1,18 +1,35 @@
1//! An algorithm to find a path to refer to a certain item. 1//! An algorithm to find a path to refer to a certain item.
2 2
3use crate::{ModuleDefId, path::ModPath, ModuleId}; 3use crate::{
4 db::DefDatabase,
5 item_scope::ItemInNs,
6 path::{ModPath, PathKind},
7 ModuleId,
8};
4 9
5pub fn find_path(item: ModuleDefId, from: ModuleId) -> ModPath { 10pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> ModPath {
11 // 1. Find all locations that the item could be imported from (i.e. that are visible)
12 // - this needs to consider other crates, for reexports from transitive dependencies
13 // - filter by visibility
14 // 2. For each of these, go up the module tree until we find an
15 // item/module/crate that is already in scope (including because it is in
16 // the prelude, and including aliases!)
17 // 3. Then select the one that gives the shortest path
18 let def_map = db.crate_def_map(from.krate);
19 let from_scope: &crate::item_scope::ItemScope = &def_map.modules[from.local_id].scope;
20 if let Some((name, _)) = from_scope.reverse_get(item) {
21 return ModPath::from_simple_segments(PathKind::Plain, vec![name.clone()]);
22 }
6 todo!() 23 todo!()
7} 24}
8 25
9#[cfg(test)] 26#[cfg(test)]
10mod tests { 27mod tests {
11 use super::*; 28 use super::*;
12 use ra_db::{fixture::WithFixture, SourceDatabase}; 29 use crate::test_db::TestDB;
13 use crate::{db::DefDatabase, test_db::TestDB};
14 use ra_syntax::ast::AstNode;
15 use hir_expand::hygiene::Hygiene; 30 use hir_expand::hygiene::Hygiene;
31 use ra_db::fixture::WithFixture;
32 use ra_syntax::ast::AstNode;
16 33
17 /// `code` needs to contain a cursor marker; checks that `find_path` for the 34 /// `code` needs to contain a cursor marker; checks that `find_path` for the
18 /// item the `path` refers to returns that same path when called from the 35 /// item the `path` refers to returns that same path when called from the
@@ -21,13 +38,26 @@ mod tests {
21 let (db, pos) = TestDB::with_position(code); 38 let (db, pos) = TestDB::with_position(code);
22 let module = db.module_for_file(pos.file_id); 39 let module = db.module_for_file(pos.file_id);
23 let parsed_path_file = ra_syntax::SourceFile::parse(&format!("use {};", path)); 40 let parsed_path_file = ra_syntax::SourceFile::parse(&format!("use {};", path));
24 let ast_path = parsed_path_file.syntax_node().descendants().find_map(ra_syntax::ast::Path::cast).unwrap(); 41 let ast_path = parsed_path_file
42 .syntax_node()
43 .descendants()
44 .find_map(ra_syntax::ast::Path::cast)
45 .unwrap();
25 let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap(); 46 let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap();
26 47
27 let crate_def_map = db.crate_def_map(module.krate); 48 let crate_def_map = db.crate_def_map(module.krate);
28 let resolved = crate_def_map.resolve_path(&db, module.local_id, &mod_path, crate::item_scope::BuiltinShadowMode::Module).0.take_types().unwrap(); 49 let resolved = crate_def_map
50 .resolve_path(
51 &db,
52 module.local_id,
53 &mod_path,
54 crate::item_scope::BuiltinShadowMode::Module,
55 )
56 .0
57 .take_types()
58 .unwrap();
29 59
30 let found_path = find_path(resolved, module); 60 let found_path = find_path(&db, ItemInNs::Types(resolved), module);
31 61
32 assert_eq!(mod_path, found_path); 62 assert_eq!(mod_path, found_path);
33 } 63 }
@@ -35,10 +65,58 @@ mod tests {
35 #[test] 65 #[test]
36 fn same_module() { 66 fn same_module() {
37 let code = r#" 67 let code = r#"
38//- /main.rs 68 //- /main.rs
39struct S; 69 struct S;
40<|> 70 <|>
41"#; 71 "#;
42 check_found_path(code, "S"); 72 check_found_path(code, "S");
43 } 73 }
74
75 #[test]
76 fn sub_module() {
77 let code = r#"
78 //- /main.rs
79 mod foo {
80 pub struct S;
81 }
82 <|>
83 "#;
84 check_found_path(code, "foo::S");
85 }
86
87 #[test]
88 fn same_crate() {
89 let code = r#"
90 //- /main.rs
91 mod foo;
92 struct S;
93 //- /foo.rs
94 <|>
95 "#;
96 check_found_path(code, "crate::S");
97 }
98
99 #[test]
100 fn different_crate() {
101 let code = r#"
102 //- /main.rs crate:main deps:std
103 <|>
104 //- /std.rs crate:std
105 pub struct S;
106 "#;
107 check_found_path(code, "std::S");
108 }
109
110 #[test]
111 fn same_crate_reexport() {
112 let code = r#"
113 //- /main.rs
114 mod bar {
115 mod foo { pub(super) struct S; }
116 pub(crate) use foo::*;
117 }
118 <|>
119 "#;
120 check_found_path(code, "bar::S");
121 }
44} 122}
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index fe7bb9779..f88502d78 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -104,6 +104,15 @@ impl ItemScope {
104 } 104 }
105 } 105 }
106 106
107 pub(crate) fn reverse_get(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
108 for (name, per_ns) in &self.visible {
109 if let Some(vis) = item.match_with(*per_ns) {
110 return Some((name, vis));
111 }
112 }
113 None
114 }
115
107 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { 116 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
108 self.visible.values().filter_map(|def| match def.take_types() { 117 self.visible.values().filter_map(|def| match def.take_types() {
109 Some(ModuleDefId::TraitId(t)) => Some(t), 118 Some(ModuleDefId::TraitId(t)) => Some(t),
@@ -173,3 +182,26 @@ impl PerNs {
173 } 182 }
174 } 183 }
175} 184}
185
186#[derive(Clone, Copy, PartialEq, Eq)]
187pub enum ItemInNs {
188 Types(ModuleDefId),
189 Values(ModuleDefId),
190 Macros(MacroDefId),
191}
192
193impl ItemInNs {
194 fn match_with(self, per_ns: PerNs) -> Option<Visibility> {
195 match self {
196 ItemInNs::Types(def) => {
197 per_ns.types.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
198 },
199 ItemInNs::Values(def) => {
200 per_ns.values.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
201 },
202 ItemInNs::Macros(def) => {
203 per_ns.macros.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
204 },
205 }
206 }
207}