aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/import_map.rs94
1 files changed, 45 insertions, 49 deletions
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index 810a4a268..6283c1f1a 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -7,9 +7,7 @@ use fst::{self, Streamer};
7use hir_expand::name::Name; 7use hir_expand::name::Name;
8use indexmap::{map::Entry, IndexMap}; 8use indexmap::{map::Entry, IndexMap};
9use itertools::Itertools; 9use itertools::Itertools;
10use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; 10use rustc_hash::{FxHashSet, FxHasher};
11use smallvec::SmallVec;
12use syntax::SmolStr;
13 11
14use crate::{ 12use crate::{
15 db::DefDatabase, item_scope::ItemInNs, visibility::Visibility, AssocItemId, ModuleDefId, 13 db::DefDatabase, item_scope::ItemInNs, visibility::Visibility, AssocItemId, ModuleDefId,
@@ -25,6 +23,8 @@ pub struct ImportInfo {
25 pub path: ImportPath, 23 pub path: ImportPath,
26 /// The module containing this item. 24 /// The module containing this item.
27 pub container: ModuleId, 25 pub container: ModuleId,
26 /// Whether the import is a trait associated item or not.
27 pub is_assoc_item: bool,
28} 28}
29 29
30#[derive(Debug, Clone, Eq, PartialEq)] 30#[derive(Debug, Clone, Eq, PartialEq)]
@@ -64,10 +64,6 @@ pub struct ImportMap {
64 /// the index of the first one. 64 /// the index of the first one.
65 importables: Vec<ItemInNs>, 65 importables: Vec<ItemInNs>,
66 fst: fst::Map<Vec<u8>>, 66 fst: fst::Map<Vec<u8>>,
67
68 /// Maps names of associated items to the item's ID. Only includes items whose defining trait is
69 /// exported.
70 assoc_map: FxHashMap<SmolStr, SmallVec<[AssocItemId; 1]>>,
71} 67}
72 68
73impl ImportMap { 69impl ImportMap {
@@ -108,14 +104,22 @@ impl ImportMap {
108 104
109 for item in per_ns.iter_items() { 105 for item in per_ns.iter_items() {
110 let path = mk_path(); 106 let path = mk_path();
107 let path_len = path.len();
108 let import_info = ImportInfo { path, container: module, is_assoc_item: false };
109
110 // If we've added a path to a trait, add the trait's associated items to the assoc map.
111 if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
112 import_map.collect_trait_assoc_items(db, tr, &import_info);
113 }
114
111 match import_map.map.entry(item) { 115 match import_map.map.entry(item) {
112 Entry::Vacant(entry) => { 116 Entry::Vacant(entry) => {
113 entry.insert(ImportInfo { path, container: module }); 117 entry.insert(import_info);
114 } 118 }
115 Entry::Occupied(mut entry) => { 119 Entry::Occupied(mut entry) => {
116 // If the new path is shorter, prefer that one. 120 // If the new path is shorter, prefer that one.
117 if path.len() < entry.get().path.len() { 121 if path_len < entry.get().path.len() {
118 *entry.get_mut() = ImportInfo { path, container: module }; 122 *entry.get_mut() = import_info;
119 } else { 123 } else {
120 continue; 124 continue;
121 } 125 }
@@ -128,11 +132,6 @@ impl ImportMap {
128 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { 132 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
129 worklist.push((mod_id, mk_path())); 133 worklist.push((mod_id, mk_path()));
130 } 134 }
131
132 // If we've added a path to a trait, add the trait's methods to the method map.
133 if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
134 import_map.collect_trait_methods(db, tr);
135 }
136 } 135 }
137 } 136 }
138 } 137 }
@@ -153,12 +152,10 @@ impl ImportMap {
153 } 152 }
154 } 153 }
155 154
156 let start = last_batch_start; 155 let key = fst_path(&importables[last_batch_start].1.path);
157 last_batch_start = idx + 1; 156 builder.insert(key, last_batch_start as u64).unwrap();
158 157
159 let key = fst_path(&importables[start].1.path); 158 last_batch_start = idx + 1;
160
161 builder.insert(key, start as u64).unwrap();
162 } 159 }
163 160
164 import_map.fst = fst::Map::new(builder.into_inner().unwrap()).unwrap(); 161 import_map.fst = fst::Map::new(builder.into_inner().unwrap()).unwrap();
@@ -176,10 +173,22 @@ impl ImportMap {
176 self.map.get(&item) 173 self.map.get(&item)
177 } 174 }
178 175
179 fn collect_trait_methods(&mut self, db: &dyn DefDatabase, tr: TraitId) { 176 fn collect_trait_assoc_items(
180 let data = db.trait_data(tr); 177 &mut self,
181 for (name, item) in data.items.iter() { 178 db: &dyn DefDatabase,
182 self.assoc_map.entry(name.to_string().into()).or_default().push(*item); 179 tr: TraitId,
180 import_info: &ImportInfo,
181 ) {
182 for (assoc_item_name, item) in db.trait_data(tr).items.iter() {
183 let assoc_item = ItemInNs::Types(match item.clone() {
184 AssocItemId::FunctionId(f) => f.into(),
185 AssocItemId::ConstId(c) => c.into(),
186 AssocItemId::TypeAliasId(t) => t.into(),
187 });
188 let mut assoc_item_info = import_info.to_owned();
189 assoc_item_info.path.segments.push(assoc_item_name.to_owned());
190 assoc_item_info.is_assoc_item = true;
191 self.map.insert(assoc_item, assoc_item_info);
183 } 192 }
184 } 193 }
185} 194}
@@ -304,11 +313,11 @@ impl Query {
304 } 313 }
305} 314}
306 315
307fn contains_query(query: &Query, input_path: &ImportPath, enforce_lowercase: bool) -> bool { 316fn import_matches_query(import: &ImportInfo, query: &Query, enforce_lowercase: bool) -> bool {
308 let mut input = if query.name_only { 317 let mut input = if import.is_assoc_item || query.name_only {
309 input_path.segments.last().unwrap().to_string() 318 import.path.segments.last().unwrap().to_string()
310 } else { 319 } else {
311 input_path.to_string() 320 import.path.to_string()
312 }; 321 };
313 if enforce_lowercase || !query.case_sensitive { 322 if enforce_lowercase || !query.case_sensitive {
314 input.make_ascii_lowercase(); 323 input.make_ascii_lowercase();
@@ -366,13 +375,13 @@ pub fn search_dependencies<'a>(
366 let import_map = &import_maps[indexed_value.index]; 375 let import_map = &import_maps[indexed_value.index];
367 let importables = &import_map.importables[indexed_value.value as usize..]; 376 let importables = &import_map.importables[indexed_value.value as usize..];
368 377
369 // Path shared by the importable items in this group. 378 let common_importable_data = &import_map.map[&importables[0]];
370 let common_importables_path = &import_map.map[&importables[0]].path; 379 if !import_matches_query(common_importable_data, &query, true) {
371 if !contains_query(&query, common_importables_path, true) {
372 continue; 380 continue;
373 } 381 }
374 382
375 let common_importables_path_fst = fst_path(common_importables_path); 383 // Path shared by the importable items in this group.
384 let common_importables_path_fst = fst_path(&common_importable_data.path);
376 // Add the items from this `ModPath` group. Those are all subsequent items in 385 // Add the items from this `ModPath` group. Those are all subsequent items in
377 // `importables` whose paths match `path`. 386 // `importables` whose paths match `path`.
378 let iter = importables 387 let iter = importables
@@ -387,7 +396,7 @@ pub fn search_dependencies<'a>(
387 }) 396 })
388 .filter(|item| { 397 .filter(|item| {
389 !query.case_sensitive // we've already checked the common importables path case-insensitively 398 !query.case_sensitive // we've already checked the common importables path case-insensitively
390 || contains_query(&query, &import_map.map[item].path, false) 399 || import_matches_query(&import_map.map[item], &query, false)
391 }); 400 });
392 res.extend(iter); 401 res.extend(iter);
393 402
@@ -398,19 +407,6 @@ pub fn search_dependencies<'a>(
398 } 407 }
399 } 408 }
400 409
401 // Add all exported associated items whose names match the query (exactly).
402 for map in &import_maps {
403 if let Some(v) = map.assoc_map.get(&*query.query) {
404 res.extend(v.iter().map(|&assoc| {
405 ItemInNs::Types(match assoc {
406 AssocItemId::FunctionId(it) => it.into(),
407 AssocItemId::ConstId(it) => it.into(),
408 AssocItemId::TypeAliasId(it) => it.into(),
409 })
410 }));
411 }
412 }
413
414 res 410 res
415} 411}
416 412
@@ -755,7 +751,7 @@ mod tests {
755 //- /dep.rs crate:dep 751 //- /dep.rs crate:dep
756 pub mod fmt { 752 pub mod fmt {
757 pub trait Display { 753 pub trait Display {
758 fn fmttt(); 754 fn format();
759 } 755 }
760 } 756 }
761 "#; 757 "#;
@@ -767,7 +763,7 @@ mod tests {
767 expect![[r#" 763 expect![[r#"
768 dep::fmt (t) 764 dep::fmt (t)
769 dep::fmt::Display (t) 765 dep::fmt::Display (t)
770 dep::fmt::Display::fmttt (f) 766 dep::fmt::Display::format (f)
771 "#]], 767 "#]],
772 ); 768 );
773 } 769 }
@@ -808,8 +804,8 @@ mod tests {
808 dep::Fmt (v) 804 dep::Fmt (v)
809 dep::Fmt (m) 805 dep::Fmt (m)
810 dep::fmt::Display (t) 806 dep::fmt::Display (t)
811 dep::format (f)
812 dep::fmt::Display::fmt (f) 807 dep::fmt::Display::fmt (f)
808 dep::format (f)
813 "#]], 809 "#]],
814 ); 810 );
815 811