diff options
Diffstat (limited to 'crates/hir_def/src/import_map.rs')
-rw-r--r-- | crates/hir_def/src/import_map.rs | 94 |
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}; | |||
7 | use hir_expand::name::Name; | 7 | use hir_expand::name::Name; |
8 | use indexmap::{map::Entry, IndexMap}; | 8 | use indexmap::{map::Entry, IndexMap}; |
9 | use itertools::Itertools; | 9 | use itertools::Itertools; |
10 | use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; | 10 | use rustc_hash::{FxHashSet, FxHasher}; |
11 | use smallvec::SmallVec; | ||
12 | use syntax::SmolStr; | ||
13 | 11 | ||
14 | use crate::{ | 12 | use 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 | ||
73 | impl ImportMap { | 69 | impl 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 | ||
307 | fn contains_query(query: &Query, input_path: &ImportPath, enforce_lowercase: bool) -> bool { | 316 | fn 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 | ||