diff options
Diffstat (limited to 'crates/ide_db/src/helpers')
-rw-r--r-- | crates/ide_db/src/helpers/import_assets.rs | 110 |
1 files changed, 69 insertions, 41 deletions
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs index d8bf61aaa..3d79f9771 100644 --- a/crates/ide_db/src/helpers/import_assets.rs +++ b/crates/ide_db/src/helpers/import_assets.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | //! Look up accessible paths for items. | 1 | //! Look up accessible paths for items. |
2 | use either::Either; | 2 | use either::Either; |
3 | use hir::{ | 3 | use hir::{ |
4 | AsAssocItem, AssocItem, Crate, ItemInNs, MacroDef, ModPath, Module, ModuleDef, Name, | 4 | AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, MacroDef, ModPath, Module, |
5 | PrefixKind, Semantics, | 5 | ModuleDef, PathResolution, PrefixKind, Semantics, Type, |
6 | }; | 6 | }; |
7 | use rustc_hash::FxHashSet; | 7 | use rustc_hash::FxHashSet; |
8 | use syntax::{ast, AstNode}; | 8 | use syntax::{ast, AstNode}; |
@@ -12,6 +12,8 @@ use crate::{ | |||
12 | RootDatabase, | 12 | RootDatabase, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | use super::item_name; | ||
16 | |||
15 | #[derive(Debug)] | 17 | #[derive(Debug)] |
16 | pub enum ImportCandidate { | 18 | pub enum ImportCandidate { |
17 | // A path, qualified (`std::collections::HashMap`) or not (`HashMap`). | 19 | // A path, qualified (`std::collections::HashMap`) or not (`HashMap`). |
@@ -28,7 +30,7 @@ pub enum ImportCandidate { | |||
28 | 30 | ||
29 | #[derive(Debug)] | 31 | #[derive(Debug)] |
30 | pub struct TraitImportCandidate { | 32 | pub struct TraitImportCandidate { |
31 | pub receiver_ty: hir::Type, | 33 | pub receiver_ty: Type, |
32 | pub name: NameToImport, | 34 | pub name: NameToImport, |
33 | } | 35 | } |
34 | 36 | ||
@@ -62,7 +64,7 @@ impl NameToImport { | |||
62 | #[derive(Debug)] | 64 | #[derive(Debug)] |
63 | pub struct ImportAssets { | 65 | pub struct ImportAssets { |
64 | import_candidate: ImportCandidate, | 66 | import_candidate: ImportCandidate, |
65 | module_with_candidate: hir::Module, | 67 | module_with_candidate: Module, |
66 | } | 68 | } |
67 | 69 | ||
68 | impl ImportAssets { | 70 | impl ImportAssets { |
@@ -104,7 +106,7 @@ impl ImportAssets { | |||
104 | 106 | ||
105 | pub fn for_fuzzy_method_call( | 107 | pub fn for_fuzzy_method_call( |
106 | module_with_method_call: Module, | 108 | module_with_method_call: Module, |
107 | receiver_ty: hir::Type, | 109 | receiver_ty: Type, |
108 | fuzzy_method_name: String, | 110 | fuzzy_method_name: String, |
109 | ) -> Option<Self> { | 111 | ) -> Option<Self> { |
110 | Some(Self { | 112 | Some(Self { |
@@ -184,7 +186,7 @@ impl ImportAssets { | |||
184 | fn search_for( | 186 | fn search_for( |
185 | &self, | 187 | &self, |
186 | sema: &Semantics<RootDatabase>, | 188 | sema: &Semantics<RootDatabase>, |
187 | prefixed: Option<hir::PrefixKind>, | 189 | prefixed: Option<PrefixKind>, |
188 | ) -> Vec<LocatedImport> { | 190 | ) -> Vec<LocatedImport> { |
189 | let current_crate = self.module_with_candidate.krate(); | 191 | let current_crate = self.module_with_candidate.krate(); |
190 | 192 | ||
@@ -223,7 +225,7 @@ impl ImportAssets { | |||
223 | fn applicable_defs( | 225 | fn applicable_defs( |
224 | &self, | 226 | &self, |
225 | db: &RootDatabase, | 227 | db: &RootDatabase, |
226 | prefixed: Option<hir::PrefixKind>, | 228 | prefixed: Option<PrefixKind>, |
227 | unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>>, | 229 | unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>>, |
228 | ) -> FxHashSet<LocatedImport> { | 230 | ) -> FxHashSet<LocatedImport> { |
229 | let current_crate = self.module_with_candidate.krate(); | 231 | let current_crate = self.module_with_candidate.krate(); |
@@ -266,10 +268,10 @@ fn path_applicable_imports( | |||
266 | let (assoc_original, candidate) = match def { | 268 | let (assoc_original, candidate) = match def { |
267 | Either::Left(module_def) => match module_def.as_assoc_item(db) { | 269 | Either::Left(module_def) => match module_def.as_assoc_item(db) { |
268 | Some(assoc_item) => match assoc_item.container(db) { | 270 | Some(assoc_item) => match assoc_item.container(db) { |
269 | hir::AssocItemContainer::Trait(trait_) => { | 271 | AssocItemContainer::Trait(trait_) => { |
270 | (Some(module_def), ItemInNs::from(ModuleDef::from(trait_))) | 272 | (Some(module_def), ItemInNs::from(ModuleDef::from(trait_))) |
271 | } | 273 | } |
272 | hir::AssocItemContainer::Impl(impl_) => ( | 274 | AssocItemContainer::Impl(impl_) => ( |
273 | Some(module_def), | 275 | Some(module_def), |
274 | ItemInNs::from(ModuleDef::from(impl_.target_ty(db).as_adt()?)), | 276 | ItemInNs::from(ModuleDef::from(impl_.target_ty(db).as_adt()?)), |
275 | ), | 277 | ), |
@@ -296,6 +298,7 @@ fn path_applicable_imports( | |||
296 | }; | 298 | }; |
297 | 299 | ||
298 | // TODO kb need to remove turbofish from the qualifier, maybe use the segments instead? | 300 | // TODO kb need to remove turbofish from the qualifier, maybe use the segments instead? |
301 | // TODO kb sorting is changed now, return back? | ||
299 | let unresolved_qualifier_string = unresolved_qualifier.to_string(); | 302 | let unresolved_qualifier_string = unresolved_qualifier.to_string(); |
300 | let unresolved_first_segment_string = unresolved_first_segment.to_string(); | 303 | let unresolved_first_segment_string = unresolved_first_segment.to_string(); |
301 | 304 | ||
@@ -305,38 +308,35 @@ fn path_applicable_imports( | |||
305 | candidate_path_string.contains(&unresolved_qualifier_string) | 308 | candidate_path_string.contains(&unresolved_qualifier_string) |
306 | && candidate_path_string.contains(&unresolved_first_segment_string) | 309 | && candidate_path_string.contains(&unresolved_first_segment_string) |
307 | }) | 310 | }) |
308 | // TODO kb need to adjust the return type: I get the results rendered rather badly | ||
309 | .filter_map(|(candidate_path, (assoc_original, candidate))| { | 311 | .filter_map(|(candidate_path, (assoc_original, candidate))| { |
310 | if let Some(assoc_original) = assoc_original { | 312 | let found_segment_resolution = item_name(db, candidate) |
311 | if item_name(db, candidate)?.to_string() == unresolved_first_segment_string { | 313 | .map(|name| name.to_string() == unresolved_first_segment_string) |
312 | return Some(LocatedImport::new( | 314 | .unwrap_or(false); |
313 | candidate_path.clone(), | 315 | let (import_path, item_to_import) = if found_segment_resolution { |
314 | ItemInNs::from(assoc_original), | 316 | (candidate_path.clone(), candidate) |
315 | Some((candidate_path, candidate)), | 317 | } else { |
316 | )); | 318 | let matching_module = |
317 | } | 319 | module_with_matching_name(db, &unresolved_first_segment_string, candidate)?; |
318 | } | 320 | let module_item = ItemInNs::from(ModuleDef::from(matching_module)); |
321 | (import_path_locator(module_item)?, module_item) | ||
322 | }; | ||
319 | 323 | ||
320 | let matching_module = | 324 | Some(match assoc_original { |
321 | module_with_matching_name(db, &unresolved_first_segment_string, candidate)?; | 325 | Some(assoc_original) => LocatedImport::new( |
322 | let item = ItemInNs::from(ModuleDef::from(matching_module)); | 326 | import_path.clone(), |
323 | Some(LocatedImport::new( | 327 | item_to_import, |
324 | import_path_locator(item)?, | 328 | Some((import_path, ItemInNs::from(assoc_original))), |
325 | item, | 329 | ), |
326 | Some((candidate_path, candidate)), | 330 | None => LocatedImport::new( |
327 | )) | 331 | import_path, |
332 | item_to_import, | ||
333 | if found_segment_resolution { None } else { Some((candidate_path, candidate)) }, | ||
334 | ), | ||
335 | }) | ||
328 | }) | 336 | }) |
329 | .collect() | 337 | .collect() |
330 | } | 338 | } |
331 | 339 | ||
332 | fn item_name(db: &RootDatabase, item: ItemInNs) -> Option<Name> { | ||
333 | match item { | ||
334 | ItemInNs::Types(module_def_id) => ModuleDef::from(module_def_id).name(db), | ||
335 | ItemInNs::Values(module_def_id) => ModuleDef::from(module_def_id).name(db), | ||
336 | ItemInNs::Macros(macro_def_id) => MacroDef::from(macro_def_id).name(db), | ||
337 | } | ||
338 | } | ||
339 | |||
340 | fn item_module(db: &RootDatabase, item: ItemInNs) -> Option<Module> { | 340 | fn item_module(db: &RootDatabase, item: ItemInNs) -> Option<Module> { |
341 | match item { | 341 | match item { |
342 | ItemInNs::Types(module_def_id) => ModuleDef::from(module_def_id).module(db), | 342 | ItemInNs::Types(module_def_id) => ModuleDef::from(module_def_id).module(db), |
@@ -404,10 +404,20 @@ fn trait_applicable_items( | |||
404 | } | 404 | } |
405 | 405 | ||
406 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); | 406 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); |
407 | let item_path = import_path_locator(item)?; | ||
408 | |||
409 | let assoc_item = assoc_to_item(assoc); | ||
410 | let assoc_item_path = match assoc.container(db) { | ||
411 | AssocItemContainer::Trait(_) => item_path.clone(), | ||
412 | AssocItemContainer::Impl(impl_) => import_path_locator(ItemInNs::from( | ||
413 | ModuleDef::from(impl_.target_ty(db).as_adt()?), | ||
414 | ))?, | ||
415 | }; | ||
416 | |||
407 | located_imports.insert(LocatedImport::new( | 417 | located_imports.insert(LocatedImport::new( |
408 | import_path_locator(item)?, | 418 | item_path, |
409 | item, | 419 | item, |
410 | None, | 420 | Some((assoc_item_path, assoc_item)), |
411 | )); | 421 | )); |
412 | } | 422 | } |
413 | None::<()> | 423 | None::<()> |
@@ -423,10 +433,20 @@ fn trait_applicable_items( | |||
423 | let assoc = function.as_assoc_item(db)?; | 433 | let assoc = function.as_assoc_item(db)?; |
424 | if required_assoc_items.contains(&assoc) { | 434 | if required_assoc_items.contains(&assoc) { |
425 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); | 435 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); |
436 | let item_path = import_path_locator(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_) => import_path_locator(ItemInNs::from( | ||
442 | ModuleDef::from(impl_.target_ty(db).as_adt()?), | ||
443 | ))?, | ||
444 | }; | ||
445 | |||
426 | located_imports.insert(LocatedImport::new( | 446 | located_imports.insert(LocatedImport::new( |
427 | import_path_locator(item)?, | 447 | item_path, |
428 | item, | 448 | item, |
429 | None, | 449 | Some((assoc_item_path, assoc_item)), |
430 | )); | 450 | )); |
431 | } | 451 | } |
432 | None::<()> | 452 | None::<()> |
@@ -437,11 +457,19 @@ fn trait_applicable_items( | |||
437 | located_imports | 457 | located_imports |
438 | } | 458 | } |
439 | 459 | ||
460 | fn assoc_to_item(assoc: AssocItem) -> ItemInNs { | ||
461 | match assoc { | ||
462 | AssocItem::Function(f) => ItemInNs::from(ModuleDef::from(f)), | ||
463 | AssocItem::Const(c) => ItemInNs::from(ModuleDef::from(c)), | ||
464 | AssocItem::TypeAlias(t) => ItemInNs::from(ModuleDef::from(t)), | ||
465 | } | ||
466 | } | ||
467 | |||
440 | fn get_mod_path( | 468 | fn get_mod_path( |
441 | db: &RootDatabase, | 469 | db: &RootDatabase, |
442 | item_to_search: ItemInNs, | 470 | item_to_search: ItemInNs, |
443 | module_with_candidate: &Module, | 471 | module_with_candidate: &Module, |
444 | prefixed: Option<hir::PrefixKind>, | 472 | prefixed: Option<PrefixKind>, |
445 | ) -> Option<ModPath> { | 473 | ) -> Option<ModPath> { |
446 | if let Some(prefix_kind) = prefixed { | 474 | if let Some(prefix_kind) = prefixed { |
447 | module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind) | 475 | module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind) |
@@ -509,7 +537,7 @@ fn path_import_candidate( | |||
509 | return None; | 537 | return None; |
510 | } | 538 | } |
511 | } | 539 | } |
512 | Some(hir::PathResolution::Def(hir::ModuleDef::Adt(assoc_item_path))) => { | 540 | Some(PathResolution::Def(ModuleDef::Adt(assoc_item_path))) => { |
513 | ImportCandidate::TraitAssocItem(TraitImportCandidate { | 541 | ImportCandidate::TraitAssocItem(TraitImportCandidate { |
514 | receiver_ty: assoc_item_path.ty(sema.db), | 542 | receiver_ty: assoc_item_path.ty(sema.db), |
515 | name, | 543 | name, |