Skip to content

Commit b132548

Browse files
committed
Use query for importable locations
1 parent 947eec7 commit b132548

File tree

4 files changed

+77
-34
lines changed

4 files changed

+77
-34
lines changed

crates/ra_hir_def/src/db.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ pub trait DefDatabase: InternDatabase + AstDatabase {
107107
// Remove this query completely, in favor of `Attrs::docs` method
108108
#[salsa::invoke(Documentation::documentation_query)]
109109
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)]>;
110117
}
111118

112119
fn crate_def_map(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> {

crates/ra_hir_def/src/find_path.rs

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@ use crate::{
44
db::DefDatabase,
55
item_scope::ItemInNs,
66
path::{ModPath, PathKind},
7-
ModuleId, ModuleDefId,
7+
visibility::Visibility,
8+
CrateId, ModuleDefId, ModuleId,
89
};
910
use hir_expand::name::Name;
1011

11-
// TODO performance / memoize
12-
1312
pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
1413
// Base cases:
1514

@@ -21,13 +20,23 @@ pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Optio
2120
}
2221

2322
// - 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+
{
2529
return Some(ModPath::from_simple_segments(PathKind::Crate, Vec::new()));
2630
}
2731

2832
// - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
2933
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+
{
3140
return Some(ModPath::from_simple_segments(PathKind::Super(1), Vec::new()));
3241
}
3342
}
@@ -42,7 +51,8 @@ pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Optio
4251
// - if the item is in the prelude, return the name from there
4352
if let Some(prelude_module) = def_map.prelude {
4453
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;
4656
if let Some((name, vis)) = prelude_scope.reverse_get(item) {
4757
if vis.is_visible_from(db, from) {
4858
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
6878
let mut candidate_paths = Vec::new();
6979
for (module_id, name) in importable_locations {
7080
// 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+
{
7283
None => continue,
7384
Some(path) => path,
7485
};
@@ -78,33 +89,58 @@ pub fn find_path(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Optio
7889
candidate_paths.into_iter().min_by_key(|path| path.segments.len())
7990
}
8091

81-
fn find_importable_locations(db: &impl DefDatabase, item: ItemInNs, from: ModuleId) -> Vec<(ModuleId, Name)> {
92+
fn find_importable_locations(
93+
db: &impl DefDatabase,
94+
item: ItemInNs,
95+
from: ModuleId,
96+
) -> Vec<(ModuleId, Name)> {
8297
let crate_graph = db.crate_graph();
8398
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)) {
85-
let def_map = db.crate_def_map(krate);
86-
for (local_id, data) in def_map.modules.iter() {
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-
}
101-
if vis.is_visible_from(db, from) {
102-
result.push((ModuleId { krate, local_id }, name.clone()));
103-
}
99+
for krate in Some(from.krate)
100+
.into_iter()
101+
.chain(crate_graph.dependencies(from.krate).map(|dep| dep.crate_id))
102+
{
103+
result.extend(
104+
db.importable_locations_in_crate(item, krate)
105+
.iter()
106+
.filter(|(_, _, vis)| vis.is_visible_from(db, from))
107+
.map(|(m, n, _)| (*m, n.clone())),
108+
);
109+
}
110+
result
111+
}
112+
113+
pub(crate) fn importable_locations_in_crate_query(
114+
db: &impl DefDatabase,
115+
item: ItemInNs,
116+
krate: CrateId,
117+
) -> std::sync::Arc<[(ModuleId, Name, Visibility)]> {
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;
104139
}
140+
result.push((ModuleId { krate, local_id }, name.clone(), vis));
105141
}
106142
}
107-
result
143+
result.into()
108144
}
109145

110146
#[cfg(test)]

crates/ra_hir_def/src/item_scope.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ impl PerNs {
183183
}
184184
}
185185

186-
#[derive(Clone, Copy, PartialEq, Eq)]
186+
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
187187
pub enum ItemInNs {
188188
Types(ModuleDefId),
189189
Values(ModuleDefId),
@@ -195,13 +195,13 @@ impl ItemInNs {
195195
match self {
196196
ItemInNs::Types(def) => {
197197
per_ns.types.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
198-
},
198+
}
199199
ItemInNs::Values(def) => {
200200
per_ns.values.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
201-
},
201+
}
202202
ItemInNs::Macros(def) => {
203203
per_ns.macros.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
204-
},
204+
}
205205
}
206206
}
207207

crates/ra_hir_def/src/test_db.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use std::{
55
sync::{Arc, Mutex},
66
};
77

8-
use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath};
98
use crate::db::DefDatabase;
9+
use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath};
1010

1111
#[salsa::database(
1212
ra_db::SourceDatabaseExtStorage,

0 commit comments

Comments
 (0)