aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_db/src/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_db/src/helpers')
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs110
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.
2use either::Either; 2use either::Either;
3use hir::{ 3use 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};
7use rustc_hash::FxHashSet; 7use rustc_hash::FxHashSet;
8use syntax::{ast, AstNode}; 8use syntax::{ast, AstNode};
@@ -12,6 +12,8 @@ use crate::{
12 RootDatabase, 12 RootDatabase,
13}; 13};
14 14
15use super::item_name;
16
15#[derive(Debug)] 17#[derive(Debug)]
16pub enum ImportCandidate { 18pub 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)]
30pub struct TraitImportCandidate { 32pub 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)]
63pub struct ImportAssets { 65pub 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
68impl ImportAssets { 70impl 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
332fn 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
340fn item_module(db: &RootDatabase, item: ItemInNs) -> Option<Module> { 340fn 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
460fn 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
440fn get_mod_path( 468fn 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,