diff options
author | Kirill Bulatov <[email protected]> | 2021-03-02 23:26:53 +0000 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2021-03-08 21:59:20 +0000 |
commit | 33c83e72b9b48177a6171fd06a26676679963a4d (patch) | |
tree | b787206319b2cf0050e4ce7c89ad4365b9a43c11 /crates/ide_db/src/helpers | |
parent | 4d4ac1d4fa0aba107a27d3fd2d209304dfe69b9f (diff) |
Work towards better import labels
Diffstat (limited to 'crates/ide_db/src/helpers')
-rw-r--r-- | crates/ide_db/src/helpers/import_assets.rs | 155 |
1 files changed, 61 insertions, 94 deletions
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs index a30a4dd9d..8d16c011e 100644 --- a/crates/ide_db/src/helpers/import_assets.rs +++ b/crates/ide_db/src/helpers/import_assets.rs | |||
@@ -1,14 +1,13 @@ | |||
1 | //! Look up accessible paths for items. | 1 | //! Look up accessible paths for items. |
2 | use either::Either; | ||
3 | use hir::{ | 2 | use hir::{ |
4 | AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, MacroDef, ModPath, Module, | 3 | AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, MacroDef, ModPath, Module, |
5 | ModuleDef, PathResolution, PrefixKind, ScopeDef, Semantics, SemanticsScope, Type, | 4 | ModuleDef, Name, PathResolution, PrefixKind, ScopeDef, Semantics, SemanticsScope, Type, |
6 | }; | 5 | }; |
7 | use rustc_hash::FxHashSet; | 6 | use rustc_hash::FxHashSet; |
8 | use syntax::{ast, AstNode}; | 7 | use syntax::{ast, AstNode}; |
9 | 8 | ||
10 | use crate::{ | 9 | use crate::{ |
11 | imports_locator::{self, AssocItemSearch, DEFAULT_QUERY_SEARCH_LIMIT}, | 10 | items_locator::{self, AssocItemSearch, DEFAULT_QUERY_SEARCH_LIMIT}, |
12 | RootDatabase, | 11 | RootDatabase, |
13 | }; | 12 | }; |
14 | 13 | ||
@@ -130,34 +129,23 @@ impl<'a> ImportAssets<'a> { | |||
130 | 129 | ||
131 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 130 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
132 | pub struct LocatedImport { | 131 | pub struct LocatedImport { |
133 | import_path: ModPath, | 132 | pub import_path: ModPath, |
134 | item_to_import: ItemInNs, | 133 | pub item_to_import: ItemInNs, |
135 | data_to_display: Option<(ModPath, ItemInNs)>, | 134 | pub original_item: ItemInNs, |
136 | } | 135 | } |
137 | 136 | ||
138 | impl LocatedImport { | 137 | impl LocatedImport { |
139 | pub fn new( | 138 | pub fn new(import_path: ModPath, item_to_import: ItemInNs, original_item: ItemInNs) -> Self { |
140 | import_path: ModPath, | 139 | Self { import_path, item_to_import, original_item } |
141 | item_to_import: ItemInNs, | ||
142 | data_to_display: Option<(ModPath, ItemInNs)>, | ||
143 | ) -> Self { | ||
144 | Self { import_path, item_to_import, data_to_display } | ||
145 | } | 140 | } |
146 | 141 | ||
147 | pub fn display_path(&self) -> &ModPath { | 142 | pub fn original_item_name(&self, db: &RootDatabase) -> Option<Name> { |
148 | self.data_to_display.as_ref().map(|(mod_path, _)| mod_path).unwrap_or(&self.import_path) | 143 | match self.original_item { |
149 | } | 144 | ItemInNs::Types(module_def_id) | ItemInNs::Values(module_def_id) => { |
150 | 145 | ModuleDef::from(module_def_id).name(db) | |
151 | pub fn import_path(&self) -> &ModPath { | 146 | } |
152 | &self.import_path | 147 | ItemInNs::Macros(macro_def_id) => MacroDef::from(macro_def_id).name(db), |
153 | } | 148 | } |
154 | |||
155 | pub fn item_to_display(&self) -> ItemInNs { | ||
156 | self.data_to_display.as_ref().map(|&(_, item)| item).unwrap_or(self.item_to_import) | ||
157 | } | ||
158 | |||
159 | pub fn item_to_import(&self) -> ItemInNs { | ||
160 | self.item_to_import | ||
161 | } | 149 | } |
162 | } | 150 | } |
163 | 151 | ||
@@ -166,25 +154,20 @@ impl<'a> ImportAssets<'a> { | |||
166 | &self.import_candidate | 154 | &self.import_candidate |
167 | } | 155 | } |
168 | 156 | ||
169 | fn name_to_import(&self) -> &NameToImport { | ||
170 | match &self.import_candidate { | ||
171 | ImportCandidate::Path(candidate) => &candidate.name, | ||
172 | ImportCandidate::TraitAssocItem(candidate) | ||
173 | | ImportCandidate::TraitMethod(candidate) => &candidate.name, | ||
174 | } | ||
175 | } | ||
176 | |||
177 | pub fn search_for_imports( | 157 | pub fn search_for_imports( |
178 | &self, | 158 | &self, |
179 | sema: &Semantics<RootDatabase>, | 159 | sema: &Semantics<RootDatabase>, |
180 | prefix_kind: PrefixKind, | 160 | prefix_kind: PrefixKind, |
181 | ) -> Vec<LocatedImport> { | 161 | ) -> FxHashSet<LocatedImport> { |
182 | let _p = profile::span("import_assets::search_for_imports"); | 162 | let _p = profile::span("import_assets::search_for_imports"); |
183 | self.search_for(sema, Some(prefix_kind)) | 163 | self.search_for(sema, Some(prefix_kind)) |
184 | } | 164 | } |
185 | 165 | ||
186 | /// This may return non-absolute paths if a part of the returned path is already imported into scope. | 166 | /// This may return non-absolute paths if a part of the returned path is already imported into scope. |
187 | pub fn search_for_relative_paths(&self, sema: &Semantics<RootDatabase>) -> Vec<LocatedImport> { | 167 | pub fn search_for_relative_paths( |
168 | &self, | ||
169 | sema: &Semantics<RootDatabase>, | ||
170 | ) -> FxHashSet<LocatedImport> { | ||
188 | let _p = profile::span("import_assets::search_for_relative_paths"); | 171 | let _p = profile::span("import_assets::search_for_relative_paths"); |
189 | self.search_for(sema, None) | 172 | self.search_for(sema, None) |
190 | } | 173 | } |
@@ -193,14 +176,13 @@ impl<'a> ImportAssets<'a> { | |||
193 | &self, | 176 | &self, |
194 | sema: &Semantics<RootDatabase>, | 177 | sema: &Semantics<RootDatabase>, |
195 | prefixed: Option<PrefixKind>, | 178 | prefixed: Option<PrefixKind>, |
196 | ) -> Vec<LocatedImport> { | 179 | ) -> FxHashSet<LocatedImport> { |
197 | let current_crate = self.module_with_candidate.krate(); | 180 | let items_with_candidate_name = match self.name_to_import() { |
198 | let scope_definitions = self.scope_definitions(); | 181 | NameToImport::Exact(exact_name) => items_locator::with_for_exact_name( |
199 | 182 | sema, | |
200 | let defs_for_candidate_name = match self.name_to_import() { | 183 | self.module_with_candidate.krate(), |
201 | NameToImport::Exact(exact_name) => { | 184 | exact_name.clone(), |
202 | imports_locator::find_exact_imports(sema, current_crate, exact_name.clone()) | 185 | ), |
203 | } | ||
204 | // FIXME: ideally, we should avoid using `fst` for seacrhing trait imports for assoc items: | 186 | // FIXME: ideally, we should avoid using `fst` for seacrhing trait imports for assoc items: |
205 | // instead, we need to look up all trait impls for a certain struct and search through them only | 187 | // instead, we need to look up all trait impls for a certain struct and search through them only |
206 | // see https://github.com/rust-analyzer/rust-analyzer/pull/7293#issuecomment-761585032 | 188 | // see https://github.com/rust-analyzer/rust-analyzer/pull/7293#issuecomment-761585032 |
@@ -213,9 +195,9 @@ impl<'a> ImportAssets<'a> { | |||
213 | (AssocItemSearch::Include, Some(DEFAULT_QUERY_SEARCH_LIMIT)) | 195 | (AssocItemSearch::Include, Some(DEFAULT_QUERY_SEARCH_LIMIT)) |
214 | }; | 196 | }; |
215 | 197 | ||
216 | imports_locator::find_similar_imports( | 198 | items_locator::with_similar_name( |
217 | sema, | 199 | sema, |
218 | current_crate, | 200 | self.module_with_candidate.krate(), |
219 | fuzzy_name.clone(), | 201 | fuzzy_name.clone(), |
220 | assoc_item_search, | 202 | assoc_item_search, |
221 | limit, | 203 | limit, |
@@ -223,10 +205,11 @@ impl<'a> ImportAssets<'a> { | |||
223 | } | 205 | } |
224 | }; | 206 | }; |
225 | 207 | ||
226 | self.applicable_defs(sema.db, prefixed, defs_for_candidate_name) | 208 | let scope_definitions = self.scope_definitions(); |
209 | self.applicable_defs(sema.db, prefixed, items_with_candidate_name) | ||
227 | .into_iter() | 210 | .into_iter() |
228 | .filter(|import| import.import_path().len() > 1) | 211 | .filter(|import| import.import_path.len() > 1) |
229 | .filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import()))) | 212 | .filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import))) |
230 | .collect() | 213 | .collect() |
231 | } | 214 | } |
232 | 215 | ||
@@ -238,11 +221,19 @@ impl<'a> ImportAssets<'a> { | |||
238 | scope_definitions | 221 | scope_definitions |
239 | } | 222 | } |
240 | 223 | ||
224 | fn name_to_import(&self) -> &NameToImport { | ||
225 | match &self.import_candidate { | ||
226 | ImportCandidate::Path(candidate) => &candidate.name, | ||
227 | ImportCandidate::TraitAssocItem(candidate) | ||
228 | | ImportCandidate::TraitMethod(candidate) => &candidate.name, | ||
229 | } | ||
230 | } | ||
231 | |||
241 | fn applicable_defs( | 232 | fn applicable_defs( |
242 | &self, | 233 | &self, |
243 | db: &RootDatabase, | 234 | db: &RootDatabase, |
244 | prefixed: Option<PrefixKind>, | 235 | prefixed: Option<PrefixKind>, |
245 | defs_for_candidate_name: impl Iterator<Item = Either<ModuleDef, MacroDef>>, | 236 | items_with_candidate_name: FxHashSet<ItemInNs>, |
246 | ) -> FxHashSet<LocatedImport> { | 237 | ) -> FxHashSet<LocatedImport> { |
247 | let _p = profile::span("import_assets::applicable_defs"); | 238 | let _p = profile::span("import_assets::applicable_defs"); |
248 | let current_crate = self.module_with_candidate.krate(); | 239 | let current_crate = self.module_with_candidate.krate(); |
@@ -251,7 +242,7 @@ impl<'a> ImportAssets<'a> { | |||
251 | 242 | ||
252 | match &self.import_candidate { | 243 | match &self.import_candidate { |
253 | ImportCandidate::Path(path_candidate) => { | 244 | ImportCandidate::Path(path_candidate) => { |
254 | path_applicable_imports(db, path_candidate, mod_path, defs_for_candidate_name) | 245 | path_applicable_imports(db, path_candidate, mod_path, items_with_candidate_name) |
255 | } | 246 | } |
256 | ImportCandidate::TraitAssocItem(trait_candidate) => trait_applicable_items( | 247 | ImportCandidate::TraitAssocItem(trait_candidate) => trait_applicable_items( |
257 | db, | 248 | db, |
@@ -259,7 +250,7 @@ impl<'a> ImportAssets<'a> { | |||
259 | trait_candidate, | 250 | trait_candidate, |
260 | true, | 251 | true, |
261 | mod_path, | 252 | mod_path, |
262 | defs_for_candidate_name, | 253 | items_with_candidate_name, |
263 | ), | 254 | ), |
264 | ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items( | 255 | ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items( |
265 | db, | 256 | db, |
@@ -267,7 +258,7 @@ impl<'a> ImportAssets<'a> { | |||
267 | trait_candidate, | 258 | trait_candidate, |
268 | false, | 259 | false, |
269 | mod_path, | 260 | mod_path, |
270 | defs_for_candidate_name, | 261 | items_with_candidate_name, |
271 | ), | 262 | ), |
272 | } | 263 | } |
273 | } | 264 | } |
@@ -277,17 +268,15 @@ fn path_applicable_imports( | |||
277 | db: &RootDatabase, | 268 | db: &RootDatabase, |
278 | path_candidate: &PathImportCandidate, | 269 | path_candidate: &PathImportCandidate, |
279 | mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy, | 270 | mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy, |
280 | defs_for_candidate_name: impl Iterator<Item = Either<ModuleDef, MacroDef>>, | 271 | items_with_candidate_name: FxHashSet<ItemInNs>, |
281 | ) -> FxHashSet<LocatedImport> { | 272 | ) -> FxHashSet<LocatedImport> { |
282 | let _p = profile::span("import_assets::path_applicable_imports"); | 273 | let _p = profile::span("import_assets::path_applicable_imports"); |
283 | 274 | ||
284 | let items_for_candidate_name = | ||
285 | defs_for_candidate_name.map(|def| def.either(ItemInNs::from, ItemInNs::from)); | ||
286 | |||
287 | let (unresolved_first_segment, unresolved_qualifier) = match &path_candidate.qualifier { | 275 | let (unresolved_first_segment, unresolved_qualifier) = match &path_candidate.qualifier { |
288 | Qualifier::Absent => { | 276 | Qualifier::Absent => { |
289 | return items_for_candidate_name | 277 | return items_with_candidate_name |
290 | .filter_map(|item| Some(LocatedImport::new(mod_path(item)?, item, None))) | 278 | .into_iter() |
279 | .filter_map(|item| Some(LocatedImport::new(mod_path(item)?, item, item))) | ||
291 | .collect(); | 280 | .collect(); |
292 | } | 281 | } |
293 | Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => { | 282 | Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => { |
@@ -295,7 +284,8 @@ fn path_applicable_imports( | |||
295 | } | 284 | } |
296 | }; | 285 | }; |
297 | 286 | ||
298 | items_for_candidate_name | 287 | items_with_candidate_name |
288 | .into_iter() | ||
299 | .filter_map(|item| { | 289 | .filter_map(|item| { |
300 | import_for_item(db, mod_path, &unresolved_first_segment, &unresolved_qualifier, item) | 290 | import_for_item(db, mod_path, &unresolved_first_segment, &unresolved_qualifier, item) |
301 | }) | 291 | }) |
@@ -336,7 +326,6 @@ fn import_for_item( | |||
336 | } | 326 | } |
337 | 327 | ||
338 | let segment_import = find_import_for_segment(db, item_candidate, &unresolved_first_segment)?; | 328 | let segment_import = find_import_for_segment(db, item_candidate, &unresolved_first_segment)?; |
339 | let data_to_display = Some((import_path_candidate.clone(), original_item)); | ||
340 | Some(match (segment_import == item_candidate, trait_to_import) { | 329 | Some(match (segment_import == item_candidate, trait_to_import) { |
341 | (true, Some(_)) => { | 330 | (true, Some(_)) => { |
342 | // FIXME we should be able to import both the trait and the segment, | 331 | // FIXME we should be able to import both the trait and the segment, |
@@ -345,11 +334,11 @@ fn import_for_item( | |||
345 | return None; | 334 | return None; |
346 | } | 335 | } |
347 | (false, Some(trait_to_import)) => { | 336 | (false, Some(trait_to_import)) => { |
348 | LocatedImport::new(mod_path(trait_to_import)?, trait_to_import, data_to_display) | 337 | LocatedImport::new(mod_path(trait_to_import)?, trait_to_import, original_item) |
349 | } | 338 | } |
350 | (true, None) => LocatedImport::new(import_path_candidate, item_candidate, data_to_display), | 339 | (true, None) => LocatedImport::new(import_path_candidate, item_candidate, original_item), |
351 | (false, None) => { | 340 | (false, None) => { |
352 | LocatedImport::new(mod_path(segment_import)?, segment_import, data_to_display) | 341 | LocatedImport::new(mod_path(segment_import)?, segment_import, original_item) |
353 | } | 342 | } |
354 | }) | 343 | }) |
355 | } | 344 | } |
@@ -399,16 +388,14 @@ fn trait_applicable_items( | |||
399 | trait_candidate: &TraitImportCandidate, | 388 | trait_candidate: &TraitImportCandidate, |
400 | trait_assoc_item: bool, | 389 | trait_assoc_item: bool, |
401 | mod_path: impl Fn(ItemInNs) -> Option<ModPath>, | 390 | mod_path: impl Fn(ItemInNs) -> Option<ModPath>, |
402 | defs_for_candidate_name: impl Iterator<Item = Either<ModuleDef, MacroDef>>, | 391 | items_with_candidate_name: FxHashSet<ItemInNs>, |
403 | ) -> FxHashSet<LocatedImport> { | 392 | ) -> FxHashSet<LocatedImport> { |
404 | let _p = profile::span("import_assets::trait_applicable_items"); | 393 | let _p = profile::span("import_assets::trait_applicable_items"); |
405 | let mut required_assoc_items = FxHashSet::default(); | 394 | let mut required_assoc_items = FxHashSet::default(); |
406 | 395 | ||
407 | let trait_candidates = defs_for_candidate_name | 396 | let trait_candidates = items_with_candidate_name |
408 | .filter_map(|input| match input { | 397 | .into_iter() |
409 | Either::Left(module_def) => module_def.as_assoc_item(db), | 398 | .filter_map(|input| ModuleDef::from(input.as_module_def_id()?).as_assoc_item(db)) |
410 | _ => None, | ||
411 | }) | ||
412 | .filter_map(|assoc| { | 399 | .filter_map(|assoc| { |
413 | let assoc_item_trait = assoc.containing_trait(db)?; | 400 | let assoc_item_trait = assoc.containing_trait(db)?; |
414 | required_assoc_items.insert(assoc); | 401 | required_assoc_items.insert(assoc); |
@@ -433,20 +420,10 @@ fn trait_applicable_items( | |||
433 | } | 420 | } |
434 | 421 | ||
435 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); | 422 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); |
436 | let item_path = mod_path(item)?; | ||
437 | |||
438 | let assoc_item = assoc_to_item(assoc); | ||
439 | let assoc_item_path = match assoc.container(db) { | ||
440 | AssocItemContainer::Trait(_) => item_path.clone(), | ||
441 | AssocItemContainer::Impl(impl_) => mod_path(ItemInNs::from( | ||
442 | ModuleDef::from(impl_.target_ty(db).as_adt()?), | ||
443 | ))?, | ||
444 | }; | ||
445 | |||
446 | located_imports.insert(LocatedImport::new( | 423 | located_imports.insert(LocatedImport::new( |
447 | item_path, | 424 | mod_path(item)?, |
448 | item, | 425 | item, |
449 | Some((assoc_item_path, assoc_item)), | 426 | assoc_to_item(assoc), |
450 | )); | 427 | )); |
451 | } | 428 | } |
452 | None::<()> | 429 | None::<()> |
@@ -462,20 +439,10 @@ fn trait_applicable_items( | |||
462 | let assoc = function.as_assoc_item(db)?; | 439 | let assoc = function.as_assoc_item(db)?; |
463 | if required_assoc_items.contains(&assoc) { | 440 | if required_assoc_items.contains(&assoc) { |
464 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); | 441 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); |
465 | let item_path = mod_path(item)?; | ||
466 | |||
467 | let assoc_item = assoc_to_item(assoc); | ||
468 | let assoc_item_path = match assoc.container(db) { | ||
469 | AssocItemContainer::Trait(_) => item_path.clone(), | ||
470 | AssocItemContainer::Impl(impl_) => mod_path(ItemInNs::from( | ||
471 | ModuleDef::from(impl_.target_ty(db).as_adt()?), | ||
472 | ))?, | ||
473 | }; | ||
474 | |||
475 | located_imports.insert(LocatedImport::new( | 442 | located_imports.insert(LocatedImport::new( |
476 | item_path, | 443 | mod_path(item)?, |
477 | item, | 444 | item, |
478 | Some((assoc_item_path, assoc_item)), | 445 | assoc_to_item(assoc), |
479 | )); | 446 | )); |
480 | } | 447 | } |
481 | None::<()> | 448 | None::<()> |