Use imports_locator

This commit is contained in:
Kirill Bulatov 2020-11-13 19:16:56 +02:00
parent d1556550f8
commit 4c8edd003a
6 changed files with 116 additions and 83 deletions

View file

@ -62,19 +62,21 @@ pub(crate) fn replace_derive_with_manual_impl(
let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; let current_module = ctx.sema.scope(annotated_name.syntax()).module()?;
let current_crate = current_module.krate(); let current_crate = current_module.krate();
let found_traits = imports_locator::find_imports(&ctx.sema, current_crate, trait_token.text()) let found_traits =
.into_iter() imports_locator::find_exact_imports(&ctx.sema, current_crate, trait_token.text())
.filter_map(|candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate { .filter_map(
either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_), |candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate {
_ => None, either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_),
}) _ => None,
.flat_map(|trait_| { },
current_module )
.find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_)) .flat_map(|trait_| {
.as_ref() current_module
.map(mod_path_to_ast) .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
.zip(Some(trait_)) .as_ref()
}); .map(mod_path_to_ast)
.zip(Some(trait_))
});
let mut no_traits_found = true; let mut no_traits_found = true;
for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {

View file

@ -179,21 +179,25 @@ impl ImportAssets {
} }
}; };
let mut res = imports_locator::find_imports(sema, current_crate, &self.get_search_query()) let mut res =
.into_iter() imports_locator::find_exact_imports(sema, current_crate, &self.get_search_query())
.filter_map(filter) .filter_map(filter)
.filter_map(|candidate| { .filter_map(|candidate| {
let item: hir::ItemInNs = candidate.either(Into::into, Into::into); let item: hir::ItemInNs = candidate.either(Into::into, Into::into);
if let Some(prefix_kind) = prefixed { if let Some(prefix_kind) = prefixed {
self.module_with_name_to_import.find_use_path_prefixed(db, item, prefix_kind) self.module_with_name_to_import.find_use_path_prefixed(
} else { db,
self.module_with_name_to_import.find_use_path(db, item) item,
} prefix_kind,
.map(|path| (path, item)) )
}) } else {
.filter(|(use_path, _)| !use_path.segments.is_empty()) self.module_with_name_to_import.find_use_path(db, item)
.take(20) }
.collect::<Vec<_>>(); .map(|path| (path, item))
})
.filter(|(use_path, _)| !use_path.segments.is_empty())
.take(20)
.collect::<Vec<_>>();
res.sort_by_key(|(path, _)| path.clone()); res.sort_by_key(|(path, _)| path.clone());
res res
} }

View file

@ -2,8 +2,8 @@
use assists::utils::{insert_use, mod_path_to_ast, ImportScope}; use assists::utils::{insert_use, mod_path_to_ast, ImportScope};
use either::Either; use either::Either;
use hir::{db::HirDatabase, MacroDef, ModuleDef, Query}; use hir::{db::HirDatabase, MacroDef, ModuleDef};
use itertools::Itertools; use ide_db::imports_locator;
use syntax::{algo, AstNode}; use syntax::{algo, AstNode};
use text_edit::TextEdit; use text_edit::TextEdit;
@ -22,42 +22,40 @@ pub(crate) fn complete_magic(acc: &mut Completions, ctx: &CompletionContext) ->
let potential_import_name = ctx.token.to_string(); let potential_import_name = ctx.token.to_string();
let possible_imports = ctx let possible_imports =
.krate? imports_locator::find_similar_imports(&ctx.sema, ctx.krate?, &potential_import_name)
// TODO kb use imports_locator instead? .filter_map(|import_candidate| {
.query_external_importables(ctx.db, Query::new(&potential_import_name).limit(40)) let use_path = match import_candidate {
.unique() Either::Left(module_def) => current_module.find_use_path(ctx.db, module_def),
.filter_map(|import_candidate| { Either::Right(macro_def) => current_module.find_use_path(ctx.db, macro_def),
let use_path = match import_candidate { }?;
Either::Left(module_def) => current_module.find_use_path(ctx.db, module_def), Some((use_path, additional_completion(ctx.db, import_candidate)))
Either::Right(macro_def) => current_module.find_use_path(ctx.db, macro_def), })
}?; .filter_map(|(mod_path, additional_completion)| {
Some((use_path, additional_completion(ctx.db, import_candidate))) let mut builder = TextEdit::builder();
})
.filter_map(|(mod_path, additional_completion)| {
let mut builder = TextEdit::builder();
let correct_qualifier = format!( let correct_qualifier = format!(
"{}{}", "{}{}",
mod_path.segments.last()?, mod_path.segments.last()?,
additional_completion.unwrap_or_default() additional_completion.unwrap_or_default()
); );
builder.replace(anchor.syntax().text_range(), correct_qualifier); builder.replace(anchor.syntax().text_range(), correct_qualifier);
let rewriter = insert_use(&import_scope, mod_path_to_ast(&mod_path), ctx.config.merge); let rewriter =
let old_ast = rewriter.rewrite_root()?; insert_use(&import_scope, mod_path_to_ast(&mod_path), ctx.config.merge);
algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut builder); let old_ast = rewriter.rewrite_root()?;
algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut builder);
let completion_item: CompletionItem = CompletionItem::new( let completion_item: CompletionItem = CompletionItem::new(
CompletionKind::Magic, CompletionKind::Magic,
ctx.source_range(), ctx.source_range(),
mod_path.to_string(), mod_path.to_string(),
) )
.kind(CompletionItemKind::Struct) .kind(CompletionItemKind::Struct)
.text_edit(builder.finish()) .text_edit(builder.finish())
.into(); .into();
Some(completion_item) Some(completion_item)
}); });
acc.add_all(possible_imports); acc.add_all(possible_imports);
Some(()) Some(())

View file

@ -118,7 +118,7 @@ pub fn completions(
completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx);
completions::trait_impl::complete_trait_impl(&mut acc, &ctx); completions::trait_impl::complete_trait_impl(&mut acc, &ctx);
completions::mod_::complete_mod(&mut acc, &ctx); completions::mod_::complete_mod(&mut acc, &ctx);
completions::complete_magic::complete_magic(&mut acc, &ctx); completions::magic::complete_magic(&mut acc, &ctx);
Some(acc) Some(acc)
} }

View file

@ -49,7 +49,7 @@ pub use hir_def::{
builtin_type::BuiltinType, builtin_type::BuiltinType,
docs::Documentation, docs::Documentation,
find_path::PrefixKind, find_path::PrefixKind,
import_map::Query, import_map::Query as ExternalImportablesQuery,
item_scope::ItemInNs, item_scope::ItemInNs,
nameres::ModuleSource, nameres::ModuleSource,
path::{ModPath, PathKind}, path::{ModPath, PathKind},

View file

@ -1,40 +1,69 @@
//! This module contains an import search funcionality that is provided to the assists module. //! This module contains an import search funcionality that is provided to the assists module.
//! Later, this should be moved away to a separate crate that is accessible from the assists module. //! Later, this should be moved away to a separate crate that is accessible from the assists module.
use hir::{Crate, MacroDef, ModuleDef, Query as ImportMapQuery, Semantics}; use hir::{Crate, ExternalImportablesQuery, MacroDef, ModuleDef, Semantics};
use syntax::{ast, AstNode, SyntaxKind::NAME}; use syntax::{ast, AstNode, SyntaxKind::NAME};
use crate::{ use crate::{
defs::{Definition, NameClass}, defs::{Definition, NameClass},
symbol_index::{self, FileSymbol, Query as SymbolQuery}, symbol_index::{self, FileSymbol, Query as LocalImportablesQuery},
RootDatabase, RootDatabase,
}; };
use either::Either; use either::Either;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
pub fn find_imports<'a>( pub fn find_exact_imports<'a>(
sema: &Semantics<'a, RootDatabase>, sema: &Semantics<'a, RootDatabase>,
krate: Crate, krate: Crate,
name_to_import: &str, name_to_import: &str,
) -> Vec<Either<ModuleDef, MacroDef>> { ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
let _p = profile::span("search_for_imports"); let _p = profile::span("find_exact_imports");
find_imports(
sema,
krate,
{
let mut local_query = LocalImportablesQuery::new(name_to_import.to_string());
local_query.exact();
local_query.limit(40);
local_query
},
ExternalImportablesQuery::new(name_to_import).anchor_end().case_sensitive().limit(40),
)
}
pub fn find_similar_imports<'a>(
sema: &Semantics<'a, RootDatabase>,
krate: Crate,
name_to_import: &str,
) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
let _p = profile::span("find_similar_imports");
find_imports(
sema,
krate,
{
let mut local_query = LocalImportablesQuery::new(name_to_import.to_string());
local_query.limit(40);
local_query
},
ExternalImportablesQuery::new(name_to_import).limit(40),
)
}
fn find_imports<'a>(
sema: &Semantics<'a, RootDatabase>,
krate: Crate,
local_query: LocalImportablesQuery,
external_query: ExternalImportablesQuery,
) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
let _p = profile::span("find_similar_imports");
let db = sema.db; let db = sema.db;
// Query dependencies first. // Query dependencies first.
let mut candidates: FxHashSet<_> = krate let mut candidates: FxHashSet<_> =
.query_external_importables( krate.query_external_importables(db, external_query).collect();
db,
ImportMapQuery::new(name_to_import).anchor_end().case_sensitive().limit(40),
)
.collect();
// Query the local crate using the symbol index. // Query the local crate using the symbol index.
let local_results = { let local_results = symbol_index::crate_symbols(db, krate.into(), local_query);
let mut query = SymbolQuery::new(name_to_import.to_string());
query.exact();
query.limit(40);
symbol_index::crate_symbols(db, krate.into(), query)
};
candidates.extend( candidates.extend(
local_results local_results
@ -47,7 +76,7 @@ pub fn find_imports<'a>(
}), }),
); );
candidates.into_iter().collect() candidates.into_iter()
} }
fn get_name_definition<'a>( fn get_name_definition<'a>(