aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-12-30 21:51:37 +0000
committerFlorian Diebold <[email protected]>2020-01-11 22:33:04 +0000
commitb1325488ec4c1b965e2e9a0b8b6dec1c8342498b (patch)
tree9828eaf61113558eecc05bd0823e2f02752a5d23 /crates/ra_hir_def
parent947eec7b87c4e385176e53acf4577df5fbb566cd (diff)
Use query for importable locations
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r--crates/ra_hir_def/src/db.rs7
-rw-r--r--crates/ra_hir_def/src/find_path.rs94
-rw-r--r--crates/ra_hir_def/src/item_scope.rs8
-rw-r--r--crates/ra_hir_def/src/test_db.rs2
4 files changed, 77 insertions, 34 deletions
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index da273eb11..0c00627b5 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -107,6 +107,13 @@ pub trait DefDatabase: InternDatabase + AstDatabase {
107 // Remove this query completely, in favor of `Attrs::docs` method 107 // Remove this query completely, in favor of `Attrs::docs` method
108 #[salsa::invoke(Documentation::documentation_query)] 108 #[salsa::invoke(Documentation::documentation_query)]
109 fn documentation(&self, def: AttrDefId) -> Option<Documentation>; 109 fn documentation(&self, def: AttrDefId) -> Option<Documentation>;
110
111 #[salsa::invoke(crate::find_path::importable_locations_in_crate_query)]
112 fn importable_locations_in_crate(
113 &self,
114 item: crate::item_scope::ItemInNs,
115 krate: CrateId,
116 ) -> Arc<[(ModuleId, hir_expand::name::Name, crate::visibility::Visibility)]>;
110} 117}
111 118
112fn crate_def_map(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { 119fn crate_def_map(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> {
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs
index be34ee662..09f3bf87d 100644
--- a/crates/ra_hir_def/src/find_path.rs
+++ b/crates/ra_hir_def/src/find_path.rs
@@ -4,12 +4,11 @@ use crate::{
4 db::DefDatabase, 4 db::DefDatabase,
5 item_scope::ItemInNs, 5 item_scope::ItemInNs,
6 path::{ModPath, PathKind}, 6 path::{ModPath, PathKind},
7 ModuleId, ModuleDefId, 7 visibility::Visibility,
8 CrateId, ModuleDefId, ModuleId,
8}; 9};
9use hir_expand::name::Name; 10use hir_expand::name::Name;
10 11
11// TODO performance / memoize
12
13pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { 12pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
14 // Base cases: 13 // Base cases:
15 14
@@ -21,13 +20,23 @@ pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Optio
21 } 20 }
22 21
23 // - if the item is the crate root, return `crate` 22 // - if the item is the crate root, return `crate`
24 if item == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { krate: from.krate, local_id: def_map.root })) { 23 if item
24 == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId {
25 krate: from.krate,
26 local_id: def_map.root,
27 }))
28 {
25 return Some(ModPath::from_simple_segments(PathKind::Crate, Vec::new())); 29 return Some(ModPath::from_simple_segments(PathKind::Crate, Vec::new()));
26 } 30 }
27 31
28 // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) 32 // - 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 { 33 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 })) { 34 if item
35 == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId {
36 krate: from.krate,
37 local_id: parent_id,
38 }))
39 {
31 return Some(ModPath::from_simple_segments(PathKind::Super(1), Vec::new())); 40 return Some(ModPath::from_simple_segments(PathKind::Super(1), Vec::new()));
32 } 41 }
33 } 42 }
@@ -42,7 +51,8 @@ pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Optio
42 // - if the item is in the prelude, return the name from there 51 // - if the item is in the prelude, return the name from there
43 if let Some(prelude_module) = def_map.prelude { 52 if let Some(prelude_module) = def_map.prelude {
44 let prelude_def_map = db.crate_def_map(prelude_module.krate); 53 let prelude_def_map = db.crate_def_map(prelude_module.krate);
45 let prelude_scope: &crate::item_scope::ItemScope = &prelude_def_map.modules[prelude_module.local_id].scope; 54 let prelude_scope: &crate::item_scope::ItemScope =
55 &prelude_def_map.modules[prelude_module.local_id].scope;
46 if let Some((name, vis)) = prelude_scope.reverse_get(item) { 56 if let Some((name, vis)) = prelude_scope.reverse_get(item) {
47 if vis.is_visible_from(db, from) { 57 if vis.is_visible_from(db, from) {
48 return Some(ModPath::from_simple_segments(PathKind::Plain, vec![name.clone()])); 58 return Some(ModPath::from_simple_segments(PathKind::Plain, vec![name.clone()]));
@@ -68,7 +78,8 @@ pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Optio
68 let mut candidate_paths = Vec::new(); 78 let mut candidate_paths = Vec::new();
69 for (module_id, name) in importable_locations { 79 for (module_id, name) in importable_locations {
70 // TODO prevent infinite loops 80 // TODO prevent infinite loops
71 let mut path = match find_path(db, ItemInNs::Types(ModuleDefId::ModuleId(module_id)), from) { 81 let mut path = match find_path(db, ItemInNs::Types(ModuleDefId::ModuleId(module_id)), from)
82 {
72 None => continue, 83 None => continue,
73 Some(path) => path, 84 Some(path) => path,
74 }; 85 };
@@ -78,33 +89,58 @@ pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Optio
78 candidate_paths.into_iter().min_by_key(|path| path.segments.len()) 89 candidate_paths.into_iter().min_by_key(|path| path.segments.len())
79} 90}
80 91
81fn find_importable_locations(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Vec<(ModuleId, Name)> { 92fn find_importable_locations(
93 db: &impl DefDatabase,
94 item: ItemInNs,
95 from: ModuleId,
96) -> Vec<(ModuleId, Name)> {
82 let crate_graph = db.crate_graph(); 97 let crate_graph = db.crate_graph();
83 let mut result = Vec::new(); 98 let mut result = Vec::new();
84 for krate in Some(from.krate).into_iter().chain(crate_graph.dependencies(from.krate).map(|dep| dep.crate_id)) { 99 for krate in Some(from.krate)
85 let def_map = db.crate_def_map(krate); 100 .into_iter()
86 for (local_id, data) in def_map.modules.iter() { 101 .chain(crate_graph.dependencies(from.krate).map(|dep| dep.crate_id))
87 if let Some((name, vis)) = data.scope.reverse_get(item) { 102 {
88 let is_private = if let crate::visibility::Visibility::Module(private_to) = vis { 103 result.extend(
89 private_to.local_id == local_id 104 db.importable_locations_in_crate(item, krate)
90 } else { false }; 105 .iter()
91 let is_original_def = if let Some(module_def_id) = item.as_module_def_id() { 106 .filter(|(_, _, vis)| vis.is_visible_from(db, from))
92 data.scope.declarations().any(|it| it == module_def_id) 107 .map(|(m, n, _)| (*m, n.clone())),
93 } else { false }; 108 );
94 if is_private && !is_original_def { 109 }
95 // Ignore private imports. these could be used if we are 110 result
96 // in a submodule of this module, but that's usually not 111}
97 // what the user wants; and if this module can import 112
98 // the item and we're a submodule of it, so can we. 113pub(crate) fn importable_locations_in_crate_query(
99 continue; 114 db: &impl DefDatabase,
100 } 115 item: ItemInNs,
101 if vis.is_visible_from(db, from) { 116 krate: CrateId,
102 result.push((ModuleId { krate, local_id }, name.clone())); 117) -> std::sync::Arc<[(ModuleId, Name, Visibility)]> {
103 } 118 let def_map = db.crate_def_map(krate);
119 let mut result = Vec::new();
120 for (local_id, data) in def_map.modules.iter() {
121 if let Some((name, vis)) = data.scope.reverse_get(item) {
122 let is_private = if let Visibility::Module(private_to) = vis {
123 private_to.local_id == local_id
124 } else {
125 false
126 };
127 let is_original_def = if let Some(module_def_id) = item.as_module_def_id() {
128 data.scope.declarations().any(|it| it == module_def_id)
129 } else {
130 false
131 };
132 if is_private && !is_original_def {
133 // Ignore private imports. these could be used if we are
134 // in a submodule of this module, but that's usually not
135 // what the user wants; and if this module can import
136 // the item and we're a submodule of it, so can we.
137 // Also this keeps the cached data smaller.
138 continue;
104 } 139 }
140 result.push((ModuleId { krate, local_id }, name.clone(), vis));
105 } 141 }
106 } 142 }
107 result 143 result.into()
108} 144}
109 145
110#[cfg(test)] 146#[cfg(test)]
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index 71afdb235..87c50b34f 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -183,7 +183,7 @@ impl PerNs {
183 } 183 }
184} 184}
185 185
186#[derive(Clone, Copy, PartialEq, Eq)] 186#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
187pub enum ItemInNs { 187pub enum ItemInNs {
188 Types(ModuleDefId), 188 Types(ModuleDefId),
189 Values(ModuleDefId), 189 Values(ModuleDefId),
@@ -195,13 +195,13 @@ impl ItemInNs {
195 match self { 195 match self {
196 ItemInNs::Types(def) => { 196 ItemInNs::Types(def) => {
197 per_ns.types.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis) 197 per_ns.types.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
198 }, 198 }
199 ItemInNs::Values(def) => { 199 ItemInNs::Values(def) => {
200 per_ns.values.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis) 200 per_ns.values.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
201 }, 201 }
202 ItemInNs::Macros(def) => { 202 ItemInNs::Macros(def) => {
203 per_ns.macros.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis) 203 per_ns.macros.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
204 }, 204 }
205 } 205 }
206 } 206 }
207 207
diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs
index a403f183f..1568820e9 100644
--- a/crates/ra_hir_def/src/test_db.rs
+++ b/crates/ra_hir_def/src/test_db.rs
@@ -5,8 +5,8 @@ use std::{
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6}; 6};
7 7
8use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath};
9use crate::db::DefDatabase; 8use crate::db::DefDatabase;
9use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath};
10 10
11#[salsa::database( 11#[salsa::database(
12 ra_db::SourceDatabaseExtStorage, 12 ra_db::SourceDatabaseExtStorage,