From 33c83e72b9b48177a6171fd06a26676679963a4d Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Wed, 3 Mar 2021 01:26:53 +0200 Subject: [PATCH] Work towards better import labels --- crates/hir_def/src/import_map.rs | 23 +++ crates/ide/src/lib.rs | 2 - .../ide_assists/src/handlers/auto_import.rs | 13 +- .../ide_assists/src/handlers/qualify_path.rs | 22 ++- .../replace_derive_with_manual_impl.rs | 10 +- .../src/completions/flyimport.rs | 101 ++++++------ crates/ide_completion/src/item.rs | 41 ++--- crates/ide_completion/src/lib.rs | 17 +- crates/ide_completion/src/render.rs | 14 +- crates/ide_db/src/helpers/import_assets.rs | 155 +++++++----------- .../{imports_locator.rs => items_locator.rs} | 75 +++++---- crates/ide_db/src/lib.rs | 2 +- crates/rust-analyzer/src/handlers.rs | 5 +- 13 files changed, 242 insertions(+), 238 deletions(-) rename crates/ide_db/src/{imports_locator.rs => items_locator.rs} (62%) diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index 369bc3350b7..07ee7bdfd7e 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs @@ -1094,4 +1094,27 @@ mod tests { expect![[r#""#]], ); } + + #[test] + fn search_with_path() { + check_search( + r#" +//- /main.rs crate:main deps:dep +//- /dep.rs crate:dep +pub mod foo { + pub mod bar { + pub mod baz { + pub trait Display { + fn fmt(); + } + } + } +}"#, + "main", + Query::new("baz::fmt".to_string()).search_mode(SearchMode::Fuzzy), + expect![[r#" + dep::foo::bar::baz::Display::fmt (a) + "#]], + ); + } } diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index b600178ee15..f83ed65d5a6 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -478,7 +478,6 @@ impl Analysis { position: FilePosition, full_import_path: &str, imported_name: String, - import_for_trait_assoc_item: bool, ) -> Cancelable> { Ok(self .with_db(|db| { @@ -488,7 +487,6 @@ impl Analysis { position, full_import_path, imported_name, - import_for_trait_assoc_item, ) })? .unwrap_or_default()) diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs index 18254758932..f3c969eeeca 100644 --- a/crates/ide_assists/src/handlers/auto_import.rs +++ b/crates/ide_assists/src/handlers/auto_import.rs @@ -93,17 +93,18 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> let group = import_group_message(import_assets.import_candidate()); let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?; for import in proposed_imports { + let name = match import.original_item_name(ctx.db()) { + Some(name) => name, + None => continue, + }; acc.add_group( &group, AssistId("auto_import", AssistKind::QuickFix), - format!("Import `{}`", import.display_path()), + format!("Import `{}`", name), range, |builder| { - let rewriter = insert_use( - &scope, - mod_path_to_ast(import.import_path()), - ctx.config.insert_use, - ); + let rewriter = + insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use); builder.rewrite(rewriter); }, ); diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs index 26117844864..407ba47beab 100644 --- a/crates/ide_assists/src/handlers/qualify_path.rs +++ b/crates/ide_assists/src/handlers/qualify_path.rs @@ -2,7 +2,7 @@ use std::iter; use hir::AsAssocItem; use ide_db::helpers::{ - import_assets::{ImportCandidate, Qualifier}, + import_assets::{ImportCandidate, LocatedImport, Qualifier}, mod_path_to_ast, }; use ide_db::RootDatabase; @@ -78,13 +78,13 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> acc.add_group( &group_label, AssistId("qualify_path", AssistKind::QuickFix), - label(candidate, import.display_path()), + label(ctx.db(), candidate, &import), range, |builder| { qualify_candidate.qualify( |replace_with: String| builder.replace(range, replace_with), - import.import_path(), - import.item_to_import(), + &import.import_path, + import.item_to_import, ) }, ); @@ -197,17 +197,21 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel { GroupLabel(format!("Qualify {}", name)) } -fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String { +fn label(db: &RootDatabase, candidate: &ImportCandidate, import: &LocatedImport) -> String { + let display_path = match import.original_item_name(db) { + Some(display_path) => display_path.to_string(), + None => "{unknown}".to_string(), + }; match candidate { ImportCandidate::Path(candidate) => { if !matches!(candidate.qualifier, Qualifier::Absent) { - format!("Qualify with `{}`", &import) + format!("Qualify with `{}`", display_path) } else { - format!("Qualify as `{}`", &import) + format!("Qualify as `{}`", display_path) } } - ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import), - ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import), + ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", display_path), + ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", display_path), } } diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs index c69bc5cacd4..93a03e8b25b 100644 --- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs @@ -1,5 +1,6 @@ +use hir::ModuleDef; use ide_db::helpers::mod_path_to_ast; -use ide_db::imports_locator; +use ide_db::items_locator; use itertools::Itertools; use syntax::{ ast::{self, make, AstNode, NameOwner}, @@ -64,13 +65,14 @@ pub(crate) fn replace_derive_with_manual_impl( let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; let current_crate = current_module.krate(); - let found_traits = imports_locator::find_exact_imports( + let found_traits = items_locator::with_for_exact_name( &ctx.sema, current_crate, trait_token.text().to_string(), ) - .filter_map(|candidate: either::Either| match candidate { - either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_), + .into_iter() + .filter_map(|item| match ModuleDef::from(item.as_module_def_id()?) { + ModuleDef::Trait(trait_) => Some(trait_), _ => None, }) .flat_map(|trait_| { diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index 1ef6f8afbcd..c1e3f091fbf 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs @@ -87,11 +87,12 @@ //! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding //! capability enabled. -use hir::{AsAssocItem, ModPath, ModuleDef, ScopeDef}; +use hir::ModPath; use ide_db::helpers::{ import_assets::{ImportAssets, ImportCandidate}, insert_use::ImportScope, }; +use itertools::Itertools; use syntax::{AstNode, SyntaxNode, T}; use crate::{ @@ -130,27 +131,23 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) &ctx.sema, )?; - let mut all_imports = - import_assets.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind); - all_imports.sort_by_cached_key(|import| { - compute_fuzzy_completion_order_key(import.display_path(), &user_input_lowercased) - }); - - acc.add_all(all_imports.into_iter().filter_map(|import| { - let import_for_trait_assoc_item = import - .item_to_display() - .as_module_def_id() - .and_then(|module_def_id| { - ModuleDef::from(module_def_id).as_assoc_item(ctx.db)?.containing_trait(ctx.db) + acc.add_all( + import_assets + .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind) + .into_iter() + .sorted_by_key(|located_import| { + compute_fuzzy_completion_order_key( + &located_import.import_path, + &user_input_lowercased, + ) }) - .is_some(); - let def_to_display = ScopeDef::from(import.item_to_display()); - render_resolution_with_import( - RenderContext::new(ctx), - ImportEdit { import, import_scope: import_scope.clone(), import_for_trait_assoc_item }, - &def_to_display, - ) - })); + .filter_map(|import| { + render_resolution_with_import( + RenderContext::new(ctx), + ImportEdit { import, import_scope: import_scope.clone() }, + ) + }), + ); Some(()) } @@ -190,6 +187,7 @@ fn import_assets<'a>(ctx: &'a CompletionContext, fuzzy_name: String) -> Option, label: String, insert_text: Option, @@ -322,19 +322,22 @@ impl Builder { pub(crate) fn build(self) -> CompletionItem { let _p = profile::span("item::Builder::build"); - let mut label = self.label; - let mut lookup = self.lookup; - let mut insert_text = self.insert_text; + let label = self.label; + let lookup = self.lookup; + let insert_text = self.insert_text; - if let Some(import_to_add) = self.import_to_add.as_ref() { - lookup = lookup.or_else(|| Some(label.clone())); - insert_text = insert_text.or_else(|| Some(label.clone())); - let display_path = import_to_add.import.display_path(); - if import_to_add.import_for_trait_assoc_item { - label = format!("{} ({})", label, display_path); - } else { - label = display_path.to_string(); - } + if let Some(_import_to_add) = self.import_to_add.as_ref() { + todo!("todo kb") + // let import = &import_to_add.import; + // let item_to_import = import.item_to_import(); + // lookup = lookup.or_else(|| Some(label.clone())); + // insert_text = insert_text.or_else(|| Some(label.clone())); + // let display_path = import_to_add.import.display_path(); + // if import_to_add.import { + // label = format!("{} ({})", label, display_path); + // } else { + // label = display_path.to_string(); + // } } let text_edit = match self.text_edit { @@ -438,8 +441,8 @@ impl Builder { } } -impl<'a> Into for Builder { - fn into(self) -> CompletionItem { - self.build() - } -} +// impl<'a> Into for Builder { +// fn into(self) -> CompletionItem { +// self.build() +// } +// } diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index ca2e5e706a7..d19368de094 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs @@ -15,7 +15,7 @@ use completions::flyimport::position_for_import; use ide_db::{ base_db::FilePosition, helpers::{import_assets::LocatedImport, insert_use::ImportScope}, - imports_locator, RootDatabase, + items_locator, RootDatabase, }; use text_edit::TextEdit; @@ -141,7 +141,6 @@ pub fn resolve_completion_edits( position: FilePosition, full_import_path: &str, imported_name: String, - import_for_trait_assoc_item: bool, ) -> Option> { let ctx = CompletionContext::new(db, position, config)?; let position_for_import = position_for_import(&ctx, None)?; @@ -151,19 +150,17 @@ pub fn resolve_completion_edits( let current_crate = current_module.krate(); let (import_path, item_to_import) = - imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name) + items_locator::with_for_exact_name(&ctx.sema, current_crate, imported_name) + .into_iter() .filter_map(|candidate| { - let item: hir::ItemInNs = candidate.either(Into::into, Into::into); current_module - .find_use_path_prefixed(db, item, config.insert_use.prefix_kind) - .zip(Some(item)) + .find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind) + .zip(Some(candidate)) }) .find(|(mod_path, _)| mod_path.to_string() == full_import_path)?; - let import = LocatedImport::new(import_path, item_to_import, None); + let import = LocatedImport::new(import_path, item_to_import, item_to_import); - ImportEdit { import_path, import_scope, import_for_trait_assoc_item } - .to_text_edit(config.insert_use) - .map(|edit| vec![edit]) + ImportEdit { import, import_scope }.to_text_edit(config.insert_use).map(|edit| vec![edit]) } #[cfg(test)] diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 4bddc3957d6..fae5685e227 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs @@ -53,18 +53,20 @@ pub(crate) fn render_resolution<'a>( pub(crate) fn render_resolution_with_import<'a>( ctx: RenderContext<'a>, import_edit: ImportEdit, - resolution: &ScopeDef, ) -> Option { + let resolution = ScopeDef::from(import_edit.import.original_item); let local_name = match resolution { ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(), ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(), ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(), - _ => item_name(ctx.db(), import_edit.import.item_to_display())?.to_string(), + _ => item_name(ctx.db(), import_edit.import.original_item)?.to_string(), }; - Render::new(ctx).render_resolution(local_name, Some(import_edit), resolution).map(|mut item| { - item.completion_kind = CompletionKind::Magic; - item - }) + Render::new(ctx).render_resolution(local_name, Some(import_edit), &resolution).map( + |mut item| { + item.completion_kind = CompletionKind::Magic; + item + }, + ) } /// Interface for data and methods required for items rendering. diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs index a30a4dd9deb..8d16c011e71 100644 --- a/crates/ide_db/src/helpers/import_assets.rs +++ b/crates/ide_db/src/helpers/import_assets.rs @@ -1,14 +1,13 @@ //! Look up accessible paths for items. -use either::Either; use hir::{ AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, MacroDef, ModPath, Module, - ModuleDef, PathResolution, PrefixKind, ScopeDef, Semantics, SemanticsScope, Type, + ModuleDef, Name, PathResolution, PrefixKind, ScopeDef, Semantics, SemanticsScope, Type, }; use rustc_hash::FxHashSet; use syntax::{ast, AstNode}; use crate::{ - imports_locator::{self, AssocItemSearch, DEFAULT_QUERY_SEARCH_LIMIT}, + items_locator::{self, AssocItemSearch, DEFAULT_QUERY_SEARCH_LIMIT}, RootDatabase, }; @@ -130,34 +129,23 @@ impl<'a> ImportAssets<'a> { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct LocatedImport { - import_path: ModPath, - item_to_import: ItemInNs, - data_to_display: Option<(ModPath, ItemInNs)>, + pub import_path: ModPath, + pub item_to_import: ItemInNs, + pub original_item: ItemInNs, } impl LocatedImport { - pub fn new( - import_path: ModPath, - item_to_import: ItemInNs, - data_to_display: Option<(ModPath, ItemInNs)>, - ) -> Self { - Self { import_path, item_to_import, data_to_display } + pub fn new(import_path: ModPath, item_to_import: ItemInNs, original_item: ItemInNs) -> Self { + Self { import_path, item_to_import, original_item } } - pub fn display_path(&self) -> &ModPath { - self.data_to_display.as_ref().map(|(mod_path, _)| mod_path).unwrap_or(&self.import_path) - } - - pub fn import_path(&self) -> &ModPath { - &self.import_path - } - - pub fn item_to_display(&self) -> ItemInNs { - self.data_to_display.as_ref().map(|&(_, item)| item).unwrap_or(self.item_to_import) - } - - pub fn item_to_import(&self) -> ItemInNs { - self.item_to_import + pub fn original_item_name(&self, db: &RootDatabase) -> Option { + match self.original_item { + ItemInNs::Types(module_def_id) | ItemInNs::Values(module_def_id) => { + ModuleDef::from(module_def_id).name(db) + } + ItemInNs::Macros(macro_def_id) => MacroDef::from(macro_def_id).name(db), + } } } @@ -166,25 +154,20 @@ impl<'a> ImportAssets<'a> { &self.import_candidate } - fn name_to_import(&self) -> &NameToImport { - match &self.import_candidate { - ImportCandidate::Path(candidate) => &candidate.name, - ImportCandidate::TraitAssocItem(candidate) - | ImportCandidate::TraitMethod(candidate) => &candidate.name, - } - } - pub fn search_for_imports( &self, sema: &Semantics, prefix_kind: PrefixKind, - ) -> Vec { + ) -> FxHashSet { let _p = profile::span("import_assets::search_for_imports"); self.search_for(sema, Some(prefix_kind)) } /// This may return non-absolute paths if a part of the returned path is already imported into scope. - pub fn search_for_relative_paths(&self, sema: &Semantics) -> Vec { + pub fn search_for_relative_paths( + &self, + sema: &Semantics, + ) -> FxHashSet { let _p = profile::span("import_assets::search_for_relative_paths"); self.search_for(sema, None) } @@ -193,14 +176,13 @@ impl<'a> ImportAssets<'a> { &self, sema: &Semantics, prefixed: Option, - ) -> Vec { - let current_crate = self.module_with_candidate.krate(); - let scope_definitions = self.scope_definitions(); - - let defs_for_candidate_name = match self.name_to_import() { - NameToImport::Exact(exact_name) => { - imports_locator::find_exact_imports(sema, current_crate, exact_name.clone()) - } + ) -> FxHashSet { + let items_with_candidate_name = match self.name_to_import() { + NameToImport::Exact(exact_name) => items_locator::with_for_exact_name( + sema, + self.module_with_candidate.krate(), + exact_name.clone(), + ), // FIXME: ideally, we should avoid using `fst` for seacrhing trait imports for assoc items: // instead, we need to look up all trait impls for a certain struct and search through them only // see https://github.com/rust-analyzer/rust-analyzer/pull/7293#issuecomment-761585032 @@ -213,9 +195,9 @@ impl<'a> ImportAssets<'a> { (AssocItemSearch::Include, Some(DEFAULT_QUERY_SEARCH_LIMIT)) }; - imports_locator::find_similar_imports( + items_locator::with_similar_name( sema, - current_crate, + self.module_with_candidate.krate(), fuzzy_name.clone(), assoc_item_search, limit, @@ -223,10 +205,11 @@ impl<'a> ImportAssets<'a> { } }; - self.applicable_defs(sema.db, prefixed, defs_for_candidate_name) + let scope_definitions = self.scope_definitions(); + self.applicable_defs(sema.db, prefixed, items_with_candidate_name) .into_iter() - .filter(|import| import.import_path().len() > 1) - .filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import()))) + .filter(|import| import.import_path.len() > 1) + .filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import))) .collect() } @@ -238,11 +221,19 @@ impl<'a> ImportAssets<'a> { scope_definitions } + fn name_to_import(&self) -> &NameToImport { + match &self.import_candidate { + ImportCandidate::Path(candidate) => &candidate.name, + ImportCandidate::TraitAssocItem(candidate) + | ImportCandidate::TraitMethod(candidate) => &candidate.name, + } + } + fn applicable_defs( &self, db: &RootDatabase, prefixed: Option, - defs_for_candidate_name: impl Iterator>, + items_with_candidate_name: FxHashSet, ) -> FxHashSet { let _p = profile::span("import_assets::applicable_defs"); let current_crate = self.module_with_candidate.krate(); @@ -251,7 +242,7 @@ impl<'a> ImportAssets<'a> { match &self.import_candidate { ImportCandidate::Path(path_candidate) => { - path_applicable_imports(db, path_candidate, mod_path, defs_for_candidate_name) + path_applicable_imports(db, path_candidate, mod_path, items_with_candidate_name) } ImportCandidate::TraitAssocItem(trait_candidate) => trait_applicable_items( db, @@ -259,7 +250,7 @@ impl<'a> ImportAssets<'a> { trait_candidate, true, mod_path, - defs_for_candidate_name, + items_with_candidate_name, ), ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items( db, @@ -267,7 +258,7 @@ impl<'a> ImportAssets<'a> { trait_candidate, false, mod_path, - defs_for_candidate_name, + items_with_candidate_name, ), } } @@ -277,17 +268,15 @@ fn path_applicable_imports( db: &RootDatabase, path_candidate: &PathImportCandidate, mod_path: impl Fn(ItemInNs) -> Option + Copy, - defs_for_candidate_name: impl Iterator>, + items_with_candidate_name: FxHashSet, ) -> FxHashSet { let _p = profile::span("import_assets::path_applicable_imports"); - let items_for_candidate_name = - defs_for_candidate_name.map(|def| def.either(ItemInNs::from, ItemInNs::from)); - let (unresolved_first_segment, unresolved_qualifier) = match &path_candidate.qualifier { Qualifier::Absent => { - return items_for_candidate_name - .filter_map(|item| Some(LocatedImport::new(mod_path(item)?, item, None))) + return items_with_candidate_name + .into_iter() + .filter_map(|item| Some(LocatedImport::new(mod_path(item)?, item, item))) .collect(); } Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => { @@ -295,7 +284,8 @@ fn path_applicable_imports( } }; - items_for_candidate_name + items_with_candidate_name + .into_iter() .filter_map(|item| { import_for_item(db, mod_path, &unresolved_first_segment, &unresolved_qualifier, item) }) @@ -336,7 +326,6 @@ fn import_for_item( } let segment_import = find_import_for_segment(db, item_candidate, &unresolved_first_segment)?; - let data_to_display = Some((import_path_candidate.clone(), original_item)); Some(match (segment_import == item_candidate, trait_to_import) { (true, Some(_)) => { // FIXME we should be able to import both the trait and the segment, @@ -345,11 +334,11 @@ fn import_for_item( return None; } (false, Some(trait_to_import)) => { - LocatedImport::new(mod_path(trait_to_import)?, trait_to_import, data_to_display) + LocatedImport::new(mod_path(trait_to_import)?, trait_to_import, original_item) } - (true, None) => LocatedImport::new(import_path_candidate, item_candidate, data_to_display), + (true, None) => LocatedImport::new(import_path_candidate, item_candidate, original_item), (false, None) => { - LocatedImport::new(mod_path(segment_import)?, segment_import, data_to_display) + LocatedImport::new(mod_path(segment_import)?, segment_import, original_item) } }) } @@ -399,16 +388,14 @@ fn trait_applicable_items( trait_candidate: &TraitImportCandidate, trait_assoc_item: bool, mod_path: impl Fn(ItemInNs) -> Option, - defs_for_candidate_name: impl Iterator>, + items_with_candidate_name: FxHashSet, ) -> FxHashSet { let _p = profile::span("import_assets::trait_applicable_items"); let mut required_assoc_items = FxHashSet::default(); - let trait_candidates = defs_for_candidate_name - .filter_map(|input| match input { - Either::Left(module_def) => module_def.as_assoc_item(db), - _ => None, - }) + let trait_candidates = items_with_candidate_name + .into_iter() + .filter_map(|input| ModuleDef::from(input.as_module_def_id()?).as_assoc_item(db)) .filter_map(|assoc| { let assoc_item_trait = assoc.containing_trait(db)?; required_assoc_items.insert(assoc); @@ -433,20 +420,10 @@ fn trait_applicable_items( } let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); - let item_path = mod_path(item)?; - - let assoc_item = assoc_to_item(assoc); - let assoc_item_path = match assoc.container(db) { - AssocItemContainer::Trait(_) => item_path.clone(), - AssocItemContainer::Impl(impl_) => mod_path(ItemInNs::from( - ModuleDef::from(impl_.target_ty(db).as_adt()?), - ))?, - }; - located_imports.insert(LocatedImport::new( - item_path, + mod_path(item)?, item, - Some((assoc_item_path, assoc_item)), + assoc_to_item(assoc), )); } None::<()> @@ -462,20 +439,10 @@ fn trait_applicable_items( let assoc = function.as_assoc_item(db)?; if required_assoc_items.contains(&assoc) { let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); - let item_path = mod_path(item)?; - - let assoc_item = assoc_to_item(assoc); - let assoc_item_path = match assoc.container(db) { - AssocItemContainer::Trait(_) => item_path.clone(), - AssocItemContainer::Impl(impl_) => mod_path(ItemInNs::from( - ModuleDef::from(impl_.target_ty(db).as_adt()?), - ))?, - }; - located_imports.insert(LocatedImport::new( - item_path, + mod_path(item)?, item, - Some((assoc_item_path, assoc_item)), + assoc_to_item(assoc), )); } None::<()> diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/items_locator.rs similarity index 62% rename from crates/ide_db/src/imports_locator.rs rename to crates/ide_db/src/items_locator.rs index fd700e04ff4..b81c14618a3 100644 --- a/crates/ide_db/src/imports_locator.rs +++ b/crates/ide_db/src/items_locator.rs @@ -1,9 +1,10 @@ //! This module contains an import search functionality that is provided to the assists module. //! Later, this should be moved away to a separate crate that is accessible from the assists module. +use either::Either; use hir::{ import_map::{self, ImportKind}, - AsAssocItem, Crate, MacroDef, ModuleDef, Semantics, + AsAssocItem, Crate, ItemInNs, ModuleDef, Semantics, }; use syntax::{ast, AstNode, SyntaxKind::NAME}; @@ -12,32 +13,31 @@ use crate::{ symbol_index::{self, FileSymbol}, RootDatabase, }; -use either::Either; use rustc_hash::FxHashSet; pub(crate) const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40; -pub fn find_exact_imports( +pub fn with_for_exact_name( sema: &Semantics<'_, RootDatabase>, krate: Crate, - name_to_import: String, -) -> Box>> { + exact_name: String, +) -> FxHashSet { let _p = profile::span("find_exact_imports"); - Box::new(find_imports( + find_items( sema, krate, { - let mut local_query = symbol_index::Query::new(name_to_import.clone()); + let mut local_query = symbol_index::Query::new(exact_name.clone()); local_query.exact(); local_query.limit(DEFAULT_QUERY_SEARCH_LIMIT); local_query }, - import_map::Query::new(name_to_import) + import_map::Query::new(exact_name) .limit(DEFAULT_QUERY_SEARCH_LIMIT) .name_only() .search_mode(import_map::SearchMode::Equals) .case_sensitive(), - )) + ) } #[derive(Debug)] @@ -47,13 +47,13 @@ pub enum AssocItemSearch { AssocItemsOnly, } -pub fn find_similar_imports<'a>( - sema: &'a Semantics<'a, RootDatabase>, +pub fn with_similar_name( + sema: &Semantics<'_, RootDatabase>, krate: Crate, fuzzy_search_string: String, assoc_item_search: AssocItemSearch, limit: Option, -) -> Box> + 'a> { +) -> FxHashSet { let _p = profile::span("find_similar_imports"); let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) @@ -77,36 +77,39 @@ pub fn find_similar_imports<'a>( local_query.limit(limit); } - Box::new(find_imports(sema, krate, local_query, external_query).filter( - move |import_candidate| match assoc_item_search { + find_items(sema, krate, local_query, external_query) + .into_iter() + .filter(move |&item| match assoc_item_search { AssocItemSearch::Include => true, - AssocItemSearch::Exclude => !is_assoc_item(import_candidate, sema.db), - AssocItemSearch::AssocItemsOnly => is_assoc_item(import_candidate, sema.db), - }, - )) + AssocItemSearch::Exclude => !is_assoc_item(item, sema.db), + AssocItemSearch::AssocItemsOnly => is_assoc_item(item, sema.db), + }) + .collect() } -fn is_assoc_item(import_candidate: &Either, db: &RootDatabase) -> bool { - match import_candidate { - Either::Left(ModuleDef::Function(function)) => function.as_assoc_item(db).is_some(), - Either::Left(ModuleDef::Const(const_)) => const_.as_assoc_item(db).is_some(), - Either::Left(ModuleDef::TypeAlias(type_alias)) => type_alias.as_assoc_item(db).is_some(), - _ => false, - } +fn is_assoc_item(item: ItemInNs, db: &RootDatabase) -> bool { + item.as_module_def_id() + .and_then(|module_def_id| ModuleDef::from(module_def_id).as_assoc_item(db)) + .is_some() } -fn find_imports<'a>( - sema: &Semantics<'a, RootDatabase>, +fn find_items( + sema: &Semantics<'_, RootDatabase>, krate: Crate, local_query: symbol_index::Query, external_query: import_map::Query, -) -> impl Iterator> { +) -> FxHashSet { let _p = profile::span("find_similar_imports"); let db = sema.db; // Query dependencies first. - let mut candidates: FxHashSet<_> = - krate.query_external_importables(db, external_query).collect(); + let mut candidates = krate + .query_external_importables(db, external_query) + .map(|external_importable| match external_importable { + Either::Left(module_def) => ItemInNs::from(module_def), + Either::Right(macro_def) => ItemInNs::from(macro_def), + }) + .collect::>(); // Query the local crate using the symbol index. let local_results = symbol_index::crate_symbols(db, krate.into(), local_query); @@ -114,19 +117,19 @@ fn find_imports<'a>( candidates.extend( local_results .into_iter() - .filter_map(|import_candidate| get_name_definition(sema, &import_candidate)) + .filter_map(|local_candidate| get_name_definition(sema, &local_candidate)) .filter_map(|name_definition_to_import| match name_definition_to_import { - Definition::ModuleDef(module_def) => Some(Either::Left(module_def)), - Definition::Macro(macro_def) => Some(Either::Right(macro_def)), + Definition::ModuleDef(module_def) => Some(ItemInNs::from(module_def)), + Definition::Macro(macro_def) => Some(ItemInNs::from(macro_def)), _ => None, }), ); - candidates.into_iter() + candidates } -fn get_name_definition<'a>( - sema: &Semantics<'a, RootDatabase>, +fn get_name_definition( + sema: &Semantics<'_, RootDatabase>, import_candidate: &FileSymbol, ) -> Option { let _p = profile::span("get_name_definition"); diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs index 6eb34b06b7c..88ee4a87d51 100644 --- a/crates/ide_db/src/lib.rs +++ b/crates/ide_db/src/lib.rs @@ -8,7 +8,7 @@ pub mod line_index; pub mod symbol_index; pub mod defs; pub mod search; -pub mod imports_locator; +pub mod items_locator; pub mod source_change; pub mod ty_filter; pub mod traits; diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index d479d826fbd..2c4c339cb73 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -697,7 +697,6 @@ pub(crate) fn handle_completion_resolve( FilePosition { file_id, offset }, &resolve_data.full_import_path, resolve_data.imported_name, - resolve_data.import_for_trait_assoc_item, )? .into_iter() .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel))) @@ -1525,7 +1524,6 @@ struct CompletionResolveData { position: lsp_types::TextDocumentPositionParams, full_import_path: String, imported_name: String, - import_for_trait_assoc_item: bool, } fn fill_resolve_data( @@ -1534,14 +1532,13 @@ fn fill_resolve_data( position: &TextDocumentPositionParams, ) -> Option<()> { let import_edit = item.import_to_add()?; - let import_path = import_edit.import.import_path(); + let import_path = &import_edit.import.import_path; *resolve_data = Some( to_value(CompletionResolveData { position: position.to_owned(), full_import_path: import_path.to_string(), imported_name: import_path.segments().last()?.to_string(), - import_for_trait_assoc_item: import_edit.import_for_trait_assoc_item, }) .unwrap(), );