Return more data about located imports

This commit is contained in:
Kirill Bulatov 2021-02-25 01:06:31 +02:00
parent 309421c117
commit 582cee2cdf
9 changed files with 172 additions and 125 deletions

View file

@ -92,14 +92,18 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
let range = ctx.sema.original_range(&syntax_under_caret).range; let range = ctx.sema.original_range(&syntax_under_caret).range;
let group = import_group_message(import_assets.import_candidate()); let group = import_group_message(import_assets.import_candidate());
let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?; let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?;
for (import, _) in proposed_imports { for import in proposed_imports {
acc.add_group( acc.add_group(
&group, &group,
AssistId("auto_import", AssistKind::QuickFix), AssistId("auto_import", AssistKind::QuickFix),
format!("Import `{}`", &import), format!("Import `{}`", import.display_path()),
range, range,
|builder| { |builder| {
let rewriter = insert_use(&scope, mod_path_to_ast(&import), ctx.config.insert_use); let rewriter = insert_use(
&scope,
mod_path_to_ast(import.import_path()),
ctx.config.insert_use,
);
builder.rewrite(rewriter); builder.rewrite(rewriter);
}, },
); );

View file

@ -74,17 +74,17 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
}; };
let group_label = group_label(candidate); let group_label = group_label(candidate);
for (import, item) in proposed_imports { for import in proposed_imports {
acc.add_group( acc.add_group(
&group_label, &group_label,
AssistId("qualify_path", AssistKind::QuickFix), AssistId("qualify_path", AssistKind::QuickFix),
label(candidate, &import), label(candidate, import.display_path()),
range, range,
|builder| { |builder| {
qualify_candidate.qualify( qualify_candidate.qualify(
|replace_with: String| builder.replace(range, replace_with), |replace_with: String| builder.replace(range, replace_with),
import, import.import_path(),
item, import.item_to_import(),
) )
}, },
); );
@ -100,8 +100,13 @@ enum QualifyCandidate<'db> {
} }
impl QualifyCandidate<'_> { impl QualifyCandidate<'_> {
fn qualify(&self, mut replacer: impl FnMut(String), import: hir::ModPath, item: hir::ItemInNs) { fn qualify(
let import = mod_path_to_ast(&import); &self,
mut replacer: impl FnMut(String),
import: &hir::ModPath,
item: hir::ItemInNs,
) {
let import = mod_path_to_ast(import);
match self { match self {
QualifyCandidate::QualifierStart(segment, generics) => { QualifyCandidate::QualifierStart(segment, generics) => {
let generics = generics.as_ref().map_or_else(String::new, ToString::to_string); let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);

View file

@ -96,21 +96,21 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
let mut all_mod_paths = import_assets let mut all_mod_paths = import_assets
.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind) .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
.into_iter() .into_iter()
.map(|(mod_path, item_in_ns)| { .map(|import| {
let scope_item = match item_in_ns { let proposed_def = match import.item_to_import() {
hir::ItemInNs::Types(id) => ScopeDef::ModuleDef(id.into()), hir::ItemInNs::Types(id) => ScopeDef::ModuleDef(id.into()),
hir::ItemInNs::Values(id) => ScopeDef::ModuleDef(id.into()), hir::ItemInNs::Values(id) => ScopeDef::ModuleDef(id.into()),
hir::ItemInNs::Macros(id) => ScopeDef::MacroDef(id.into()), hir::ItemInNs::Macros(id) => ScopeDef::MacroDef(id.into()),
}; };
(mod_path, scope_item) (import, proposed_def)
}) })
.filter(|(_, proposed_def)| !scope_definitions.contains(proposed_def)) .filter(|(_, proposed_def)| !scope_definitions.contains(proposed_def))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
all_mod_paths.sort_by_cached_key(|(mod_path, _)| { all_mod_paths.sort_by_cached_key(|(import, _)| {
compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) compute_fuzzy_completion_order_key(import.display_path(), &user_input_lowercased)
}); });
acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| { acc.add_all(all_mod_paths.into_iter().filter_map(|(import, definition)| {
let import_for_trait_assoc_item = match definition { let import_for_trait_assoc_item = match definition {
ScopeDef::ModuleDef(module_def) => module_def ScopeDef::ModuleDef(module_def) => module_def
.as_assoc_item(ctx.db) .as_assoc_item(ctx.db)
@ -118,11 +118,8 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
.is_some(), .is_some(),
_ => false, _ => false,
}; };
let import_edit = ImportEdit { let import_edit =
import_path, ImportEdit { import, import_scope: import_scope.clone(), import_for_trait_assoc_item };
import_scope: import_scope.clone(),
import_for_trait_assoc_item,
};
render_resolution_with_import(RenderContext::new(ctx), import_edit, &definition) render_resolution_with_import(RenderContext::new(ctx), import_edit, &definition)
})); }));
Some(()) Some(())
@ -186,11 +183,11 @@ fn compute_fuzzy_completion_order_key(
user_input_lowercased: &str, user_input_lowercased: &str,
) -> usize { ) -> usize {
cov_mark::hit!(certain_fuzzy_order_test); cov_mark::hit!(certain_fuzzy_order_test);
let proposed_import_name = match proposed_mod_path.segments().last() { let import_name = match proposed_mod_path.segments().last() {
Some(name) => name.to_string().to_lowercase(), Some(name) => name.to_string().to_lowercase(),
None => return usize::MAX, None => return usize::MAX,
}; };
match proposed_import_name.match_indices(user_input_lowercased).next() { match import_name.match_indices(user_input_lowercased).next() {
Some((first_matching_index, _)) => first_matching_index, Some((first_matching_index, _)) => first_matching_index,
None => usize::MAX, None => usize::MAX,
} }

View file

@ -2,9 +2,10 @@
use std::fmt; use std::fmt;
use hir::{Documentation, ModPath, Mutability}; use hir::{Documentation, Mutability};
use ide_db::{ use ide_db::{
helpers::{ helpers::{
import_assets::LocatedImport,
insert_use::{self, ImportScope, InsertUseConfig}, insert_use::{self, ImportScope, InsertUseConfig},
mod_path_to_ast, SnippetCap, mod_path_to_ast, SnippetCap,
}, },
@ -272,7 +273,7 @@ impl CompletionItem {
/// An extra import to add after the completion is applied. /// An extra import to add after the completion is applied.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ImportEdit { pub struct ImportEdit {
pub import_path: ModPath, pub import: LocatedImport,
pub import_scope: ImportScope, pub import_scope: ImportScope,
pub import_for_trait_assoc_item: bool, pub import_for_trait_assoc_item: bool,
} }
@ -283,8 +284,11 @@ impl ImportEdit {
pub fn to_text_edit(&self, cfg: InsertUseConfig) -> Option<TextEdit> { pub fn to_text_edit(&self, cfg: InsertUseConfig) -> Option<TextEdit> {
let _p = profile::span("ImportEdit::to_text_edit"); let _p = profile::span("ImportEdit::to_text_edit");
let rewriter = let rewriter = insert_use::insert_use(
insert_use::insert_use(&self.import_scope, mod_path_to_ast(&self.import_path), cfg); &self.import_scope,
mod_path_to_ast(self.import.import_path()),
cfg,
);
let old_ast = rewriter.rewrite_root()?; let old_ast = rewriter.rewrite_root()?;
let mut import_insert = TextEdit::builder(); let mut import_insert = TextEdit::builder();
algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert); algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert);
@ -323,19 +327,13 @@ impl Builder {
let mut insert_text = self.insert_text; let mut insert_text = self.insert_text;
if let Some(import_to_add) = self.import_to_add.as_ref() { 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 { if import_to_add.import_for_trait_assoc_item {
lookup = lookup.or_else(|| Some(label.clone())); label = format!("{} ({})", label, display_path);
insert_text = insert_text.or_else(|| Some(label.clone()));
label = format!("{} ({})", label, import_to_add.import_path);
} else { } else {
let mut import_path_without_last_segment = import_to_add.import_path.to_owned(); label = display_path.to_string();
let _ = import_path_without_last_segment.pop_segment();
if !import_path_without_last_segment.segments().is_empty() {
lookup = lookup.or_else(|| Some(label.clone()));
insert_text = insert_text.or_else(|| Some(label.clone()));
label = format!("{}::{}", import_path_without_last_segment, label);
}
} }
} }

View file

@ -13,7 +13,9 @@ mod completions;
use completions::flyimport::position_for_import; use completions::flyimport::position_for_import;
use ide_db::{ use ide_db::{
base_db::FilePosition, helpers::insert_use::ImportScope, imports_locator, RootDatabase, base_db::FilePosition,
helpers::{import_assets::LocatedImport, insert_use::ImportScope},
imports_locator, RootDatabase,
}; };
use text_edit::TextEdit; use text_edit::TextEdit;
@ -148,12 +150,16 @@ pub fn resolve_completion_edits(
let current_module = ctx.sema.scope(position_for_import).module()?; let current_module = ctx.sema.scope(position_for_import).module()?;
let current_crate = current_module.krate(); let current_crate = current_module.krate();
let import_path = imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name) let (import_path, item_to_import) =
.filter_map(|candidate| { imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name)
let item: hir::ItemInNs = candidate.either(Into::into, Into::into); .filter_map(|candidate| {
current_module.find_use_path_prefixed(db, item, config.insert_use.prefix_kind) let item: hir::ItemInNs = candidate.either(Into::into, Into::into);
}) current_module
.find(|mod_path| mod_path.to_string() == full_import_path)?; .find_use_path_prefixed(db, item, config.insert_use.prefix_kind)
.zip(Some(item))
})
.find(|(mod_path, _)| mod_path.to_string() == full_import_path)?;
let import = LocatedImport::new(import_path, item_to_import, None);
ImportEdit { import_path, import_scope, import_for_trait_assoc_item } ImportEdit { import_path, import_scope, import_for_trait_assoc_item }
.to_text_edit(config.insert_use) .to_text_edit(config.insert_use)

View file

@ -56,7 +56,7 @@ pub(crate) fn render_resolution_with_import<'a>(
ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(), 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::Const(c)) => c.name(ctx.completion.db)?.to_string(),
ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(), ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(),
_ => import_edit.import_path.segments().last()?.to_string(), _ => import_edit.import.display_path().segments().last()?.to_string(),
}; };
Render::new(ctx).render_resolution(local_name, Some(import_edit), resolution).map(|mut item| { Render::new(ctx).render_resolution(local_name, Some(import_edit), resolution).map(|mut item| {
item.completion_kind = CompletionKind::Magic; item.completion_kind = CompletionKind::Magic;

View file

@ -117,6 +117,42 @@ impl ImportAssets {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct LocatedImport {
import_path: ModPath,
item_to_import: ItemInNs,
import_display_override: Option<(ModPath, ItemInNs)>,
}
impl LocatedImport {
pub fn new(
import_path: ModPath,
item_to_import: ItemInNs,
import_display_override: Option<(ModPath, ItemInNs)>,
) -> Self {
Self { import_path, item_to_import, import_display_override }
}
pub fn display_path(&self) -> &ModPath {
self.import_display_override
.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.import_display_override.as_ref().map(|&(_, item)| item).unwrap_or(self.item_to_import)
}
pub fn item_to_import(&self) -> ItemInNs {
self.item_to_import
}
}
impl ImportAssets { impl ImportAssets {
pub fn import_candidate(&self) -> &ImportCandidate { pub fn import_candidate(&self) -> &ImportCandidate {
&self.import_candidate &self.import_candidate
@ -134,16 +170,13 @@ impl ImportAssets {
&self, &self,
sema: &Semantics<RootDatabase>, sema: &Semantics<RootDatabase>,
prefix_kind: PrefixKind, prefix_kind: PrefixKind,
) -> Vec<(hir::ModPath, hir::ItemInNs)> { ) -> Vec<LocatedImport> {
let _p = profile::span("import_assets::search_for_imports"); let _p = profile::span("import_assets::search_for_imports");
self.search_for(sema, Some(prefix_kind)) 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. /// This may return non-absolute paths if a part of the returned path is already imported into scope.
pub fn search_for_relative_paths( pub fn search_for_relative_paths(&self, sema: &Semantics<RootDatabase>) -> Vec<LocatedImport> {
&self,
sema: &Semantics<RootDatabase>,
) -> Vec<(hir::ModPath, hir::ItemInNs)> {
let _p = profile::span("import_assets::search_for_relative_paths"); let _p = profile::span("import_assets::search_for_relative_paths");
self.search_for(sema, None) self.search_for(sema, None)
} }
@ -152,7 +185,7 @@ impl ImportAssets {
&self, &self,
sema: &Semantics<RootDatabase>, sema: &Semantics<RootDatabase>,
prefixed: Option<hir::PrefixKind>, prefixed: Option<hir::PrefixKind>,
) -> Vec<(hir::ModPath, hir::ItemInNs)> { ) -> Vec<LocatedImport> {
let current_crate = self.module_with_candidate.krate(); let current_crate = self.module_with_candidate.krate();
let imports_for_candidate_name = match self.name_to_import() { let imports_for_candidate_name = match self.name_to_import() {
@ -181,61 +214,53 @@ impl ImportAssets {
} }
}; };
let mut res = self self.applicable_defs(sema.db, prefixed, imports_for_candidate_name)
.applicable_defs(sema, prefixed, imports_for_candidate_name) .into_iter()
.filter(|(use_path, _)| use_path.len() > 1) .filter(|import| import.import_path().len() > 1)
.collect::<Vec<_>>(); .collect()
res.sort_by_cached_key(|(path, _)| path.clone());
res
} }
fn applicable_defs<'a>( fn applicable_defs(
&'a self, &self,
sema: &'a Semantics<RootDatabase>, db: &RootDatabase,
prefixed: Option<hir::PrefixKind>, prefixed: Option<hir::PrefixKind>,
unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>> + 'a, unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>>,
) -> Box<dyn Iterator<Item = (ModPath, ItemInNs)> + 'a> { ) -> FxHashSet<LocatedImport> {
let current_crate = self.module_with_candidate.krate(); let current_crate = self.module_with_candidate.krate();
let db = sema.db;
let import_path_locator =
|item| get_mod_path(db, item, &self.module_with_candidate, prefixed);
match &self.import_candidate { match &self.import_candidate {
ImportCandidate::Path(path_candidate) => Box::new( ImportCandidate::Path(path_candidate) => {
path_applicable_items( path_applicable_imports(db, path_candidate, import_path_locator, unfiltered_defs)
db, }
path_candidate, ImportCandidate::TraitAssocItem(trait_candidate) => trait_applicable_items(
&self.module_with_candidate, db,
prefixed, current_crate,
unfiltered_defs, trait_candidate,
) true,
.into_iter(), import_path_locator,
unfiltered_defs,
), ),
ImportCandidate::TraitAssocItem(trait_candidate) => Box::new( ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items(
trait_applicable_defs(db, current_crate, trait_candidate, true, unfiltered_defs) db,
.into_iter() current_crate,
.filter_map(move |item_to_search| { trait_candidate,
get_mod_path(db, item_to_search, &self.module_with_candidate, prefixed) false,
.zip(Some(item_to_search)) import_path_locator,
}), unfiltered_defs,
),
ImportCandidate::TraitMethod(trait_candidate) => Box::new(
trait_applicable_defs(db, current_crate, trait_candidate, false, unfiltered_defs)
.into_iter()
.filter_map(move |item_to_search| {
get_mod_path(db, item_to_search, &self.module_with_candidate, prefixed)
.zip(Some(item_to_search))
}),
), ),
} }
} }
} }
fn path_applicable_items<'a>( fn path_applicable_imports(
db: &'a RootDatabase, db: &RootDatabase,
path_candidate: &'a PathImportCandidate, path_candidate: &PathImportCandidate,
module_with_candidate: &hir::Module, import_path_locator: impl Fn(ItemInNs) -> Option<ModPath>,
prefixed: Option<hir::PrefixKind>, unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>>,
unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>> + 'a, ) -> FxHashSet<LocatedImport> {
) -> FxHashSet<(ModPath, ItemInNs)> {
let applicable_items = unfiltered_defs let applicable_items = unfiltered_defs
.filter_map(|def| { .filter_map(|def| {
let (assoc_original, candidate) = match def { let (assoc_original, candidate) = match def {
@ -256,14 +281,15 @@ fn path_applicable_items<'a>(
Some((assoc_original, candidate)) Some((assoc_original, candidate))
}) })
.filter_map(|(assoc_original, candidate)| { .filter_map(|(assoc_original, candidate)| {
get_mod_path(db, candidate, module_with_candidate, prefixed) import_path_locator(candidate).zip(Some((assoc_original, candidate)))
.zip(Some((assoc_original, candidate)))
}); });
let (unresolved_first_segment, unresolved_qualifier) = match &path_candidate.qualifier { let (unresolved_first_segment, unresolved_qualifier) = match &path_candidate.qualifier {
Qualifier::Absent => { Qualifier::Absent => {
return applicable_items return applicable_items
.map(|(candidate_path, (_, candidate))| (candidate_path, candidate)) .map(|(candidate_path, (_, candidate))| {
LocatedImport::new(candidate_path, candidate, None)
})
.collect(); .collect();
} }
Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => (first_segment, qualifier), Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => (first_segment, qualifier),
@ -283,19 +309,22 @@ fn path_applicable_items<'a>(
.filter_map(|(candidate_path, (assoc_original, candidate))| { .filter_map(|(candidate_path, (assoc_original, candidate))| {
if let Some(assoc_original) = assoc_original { if let Some(assoc_original) = assoc_original {
if item_name(db, candidate)?.to_string() == unresolved_first_segment_string { if item_name(db, candidate)?.to_string() == unresolved_first_segment_string {
return Some((candidate_path, ItemInNs::from(assoc_original))); return Some(LocatedImport::new(
candidate_path.clone(),
ItemInNs::from(assoc_original),
Some((candidate_path, candidate)),
));
} }
} }
let matching_module = let matching_module =
module_with_matching_name(db, &unresolved_first_segment_string, candidate)?; module_with_matching_name(db, &unresolved_first_segment_string, candidate)?;
let path = get_mod_path( let item = ItemInNs::from(ModuleDef::from(matching_module));
db, Some(LocatedImport::new(
ItemInNs::from(ModuleDef::from(matching_module)), import_path_locator(item)?,
module_with_candidate, item,
prefixed, Some((candidate_path, candidate)),
)?; ))
Some((path, candidate))
}) })
.collect() .collect()
} }
@ -336,13 +365,14 @@ fn module_with_matching_name(
None None
} }
fn trait_applicable_defs<'a>( fn trait_applicable_items(
db: &'a RootDatabase, db: &RootDatabase,
current_crate: Crate, current_crate: Crate,
trait_candidate: &TraitImportCandidate, trait_candidate: &TraitImportCandidate,
trait_assoc_item: bool, trait_assoc_item: bool,
unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>> + 'a, import_path_locator: impl Fn(ItemInNs) -> Option<ModPath>,
) -> FxHashSet<ItemInNs> { unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>>,
) -> FxHashSet<LocatedImport> {
let mut required_assoc_items = FxHashSet::default(); let mut required_assoc_items = FxHashSet::default();
let trait_candidates = unfiltered_defs let trait_candidates = unfiltered_defs
@ -357,7 +387,7 @@ fn trait_applicable_defs<'a>(
}) })
.collect(); .collect();
let mut applicable_traits = FxHashSet::default(); let mut located_imports = FxHashSet::default();
if trait_assoc_item { if trait_assoc_item {
trait_candidate.receiver_ty.iterate_path_candidates( trait_candidate.receiver_ty.iterate_path_candidates(
@ -372,8 +402,13 @@ fn trait_applicable_defs<'a>(
return None; return None;
} }
} }
applicable_traits
.insert(ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?))); let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?));
located_imports.insert(LocatedImport::new(
import_path_locator(item)?,
item,
None,
));
} }
None::<()> None::<()>
}, },
@ -387,15 +422,19 @@ fn trait_applicable_defs<'a>(
|_, function| { |_, function| {
let assoc = function.as_assoc_item(db)?; let assoc = function.as_assoc_item(db)?;
if required_assoc_items.contains(&assoc) { if required_assoc_items.contains(&assoc) {
applicable_traits let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?));
.insert(ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?))); located_imports.insert(LocatedImport::new(
import_path_locator(item)?,
item,
None,
));
} }
None::<()> None::<()>
}, },
) )
}; };
applicable_traits located_imports
} }
fn get_mod_path( fn get_mod_path(

View file

@ -17,8 +17,8 @@ use rustc_hash::FxHashSet;
pub(crate) const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40; pub(crate) const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40;
pub fn find_exact_imports<'a>( pub fn find_exact_imports(
sema: &Semantics<'a, RootDatabase>, sema: &Semantics<'_, RootDatabase>,
krate: Crate, krate: Crate,
name_to_import: String, name_to_import: String,
) -> Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>>> { ) -> Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>>> {
@ -48,7 +48,7 @@ pub enum AssocItemSearch {
} }
pub fn find_similar_imports<'a>( pub fn find_similar_imports<'a>(
sema: &Semantics<'a, RootDatabase>, sema: &'a Semantics<'a, RootDatabase>,
krate: Crate, krate: Crate,
fuzzy_search_string: String, fuzzy_search_string: String,
assoc_item_search: AssocItemSearch, assoc_item_search: AssocItemSearch,
@ -77,12 +77,11 @@ pub fn find_similar_imports<'a>(
local_query.limit(limit); local_query.limit(limit);
} }
let db = sema.db;
Box::new(find_imports(sema, krate, local_query, external_query).filter( Box::new(find_imports(sema, krate, local_query, external_query).filter(
move |import_candidate| match assoc_item_search { move |import_candidate| match assoc_item_search {
AssocItemSearch::Include => true, AssocItemSearch::Include => true,
AssocItemSearch::Exclude => !is_assoc_item(import_candidate, db), AssocItemSearch::Exclude => !is_assoc_item(import_candidate, sema.db),
AssocItemSearch::AssocItemsOnly => is_assoc_item(import_candidate, db), AssocItemSearch::AssocItemsOnly => is_assoc_item(import_candidate, sema.db),
}, },
)) ))
} }

View file

@ -1534,14 +1534,13 @@ fn fill_resolve_data(
position: &TextDocumentPositionParams, position: &TextDocumentPositionParams,
) -> Option<()> { ) -> Option<()> {
let import_edit = item.import_to_add()?; let import_edit = item.import_to_add()?;
let full_import_path = import_edit.import_path.to_string(); let import_path = import_edit.import.import_path();
let imported_name = import_edit.import_path.segments().last()?.to_string();
*resolve_data = Some( *resolve_data = Some(
to_value(CompletionResolveData { to_value(CompletionResolveData {
position: position.to_owned(), position: position.to_owned(),
full_import_path, full_import_path: import_path.to_string(),
imported_name, imported_name: import_path.segments().last()?.to_string(),
import_for_trait_assoc_item: import_edit.import_for_trait_assoc_item, import_for_trait_assoc_item: import_edit.import_for_trait_assoc_item,
}) })
.unwrap(), .unwrap(),