Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/completions/flyimport.rs')
-rw-r--r--crates/ide-completion/src/completions/flyimport.rs187
1 files changed, 120 insertions, 67 deletions
diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs
index 33ae365cff..15e431f9c5 100644
--- a/crates/ide-completion/src/completions/flyimport.rs
+++ b/crates/ide-completion/src/completions/flyimport.rs
@@ -1,16 +1,16 @@
//! See [`import_on_the_fly`].
use hir::{ItemInNs, ModuleDef};
use ide_db::imports::{
- import_assets::{ImportAssets, ImportCandidate, LocatedImport},
+ import_assets::{ImportAssets, LocatedImport},
insert_use::ImportScope,
};
use itertools::Itertools;
-use syntax::{AstNode, SyntaxNode, T};
+use syntax::{ast, AstNode, SyntaxNode, T};
use crate::{
context::{
- CompletionContext, NameRefContext, NameRefKind, PathCompletionCtx, PathKind,
- PatternContext, TypeLocation,
+ CompletionContext, DotAccess, PathCompletionCtx, PathKind, PatternContext, Qualified,
+ TypeLocation,
},
render::{render_resolution_with_import, RenderContext},
};
@@ -108,45 +108,108 @@ use super::Completions;
// The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.autoimport.enable` flag.
// Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corresponding
// capability enabled.
-pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
+pub(crate) fn import_on_the_fly_path(
+ acc: &mut Completions,
+ ctx: &CompletionContext,
+ path_ctx: &PathCompletionCtx,
+) -> Option<()> {
if !ctx.config.enable_imports_on_the_fly {
return None;
}
- let path_kind = match ctx.nameref_ctx() {
- Some(NameRefContext {
+ let (kind, qualified) = match path_ctx {
+ PathCompletionCtx {
kind:
- Some(NameRefKind::Path(PathCompletionCtx {
- kind:
- kind @ (PathKind::Expr { .. }
- | PathKind::Type { .. }
- | PathKind::Attr { .. }
- | PathKind::Derive { .. }
- | PathKind::Pat),
- ..
- })),
+ kind @ (PathKind::Expr { .. }
+ | PathKind::Type { .. }
+ | PathKind::Attr { .. }
+ | PathKind::Derive { .. }
+ | PathKind::Pat),
+ qualified,
..
- }) => Some(kind),
- Some(NameRefContext { kind: Some(NameRefKind::DotAccess(_)), .. }) => None,
- None if matches!(ctx.pattern_ctx, Some(PatternContext { record_pat: None, .. })) => {
- Some(&PathKind::Pat)
- }
+ } => (Some(kind), qualified),
_ => return None,
};
+ let potential_import_name = import_name(ctx);
+ let qualifier = match qualified {
+ Qualified::With { path, .. } => Some(path.clone()),
+ _ => None,
+ };
+ let import_assets = import_assets_for_path(ctx, &potential_import_name, qualifier.clone())?;
- let potential_import_name = {
- let token_kind = ctx.token.kind();
- if matches!(token_kind, T![.] | T![::]) {
- String::new()
- } else {
- ctx.token.to_string()
- }
+ import_on_the_fly(
+ acc,
+ ctx,
+ kind,
+ import_assets,
+ qualifier.map(|it| it.syntax().clone()).or_else(|| ctx.original_token.parent())?,
+ potential_import_name,
+ )
+}
+
+pub(crate) fn import_on_the_fly_dot(
+ acc: &mut Completions,
+ ctx: &CompletionContext,
+ dot_access: &DotAccess,
+) -> Option<()> {
+ if !ctx.config.enable_imports_on_the_fly {
+ return None;
+ }
+ let receiver = dot_access.receiver.as_ref()?;
+ let ty = dot_access.receiver_ty.as_ref()?;
+ let potential_import_name = import_name(ctx);
+ let import_assets = ImportAssets::for_fuzzy_method_call(
+ ctx.module,
+ ty.original.clone(),
+ potential_import_name.clone(),
+ receiver.syntax().clone(),
+ )?;
+
+ import_on_the_fly(
+ acc,
+ ctx,
+ None,
+ import_assets,
+ receiver.syntax().clone(),
+ potential_import_name,
+ )
+}
+
+pub(crate) fn import_on_the_fly_pat(
+ acc: &mut Completions,
+ ctx: &CompletionContext,
+ pat_ctx: &PatternContext,
+) -> Option<()> {
+ if !ctx.config.enable_imports_on_the_fly {
+ return None;
+ }
+ let kind = match pat_ctx {
+ PatternContext { record_pat: None, .. } => PathKind::Pat,
+ _ => return None,
};
+ let potential_import_name = import_name(ctx);
+ let import_assets = import_assets_for_path(ctx, &potential_import_name, None)?;
+
+ import_on_the_fly(
+ acc,
+ ctx,
+ Some(&kind),
+ import_assets,
+ ctx.original_token.parent()?,
+ potential_import_name,
+ )
+}
+
+fn import_on_the_fly(
+ acc: &mut Completions,
+ ctx: &CompletionContext,
+ path_kind: Option<&PathKind>,
+ import_assets: ImportAssets,
+ position: SyntaxNode,
+ potential_import_name: String,
+) -> Option<()> {
let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.clone());
- let user_input_lowercased = potential_import_name.to_lowercase();
- let import_assets = import_assets(ctx, potential_import_name)?;
- let position = position_for_import(ctx, Some(import_assets.import_candidate()))?;
if ImportScope::find_insert_use_container(&position, &ctx.sema).is_none() {
return None;
}
@@ -194,6 +257,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
(PathKind::Derive { .. }, _) => false,
}
};
+ let user_input_lowercased = potential_import_name.to_lowercase();
acc.add_all(
import_assets
@@ -216,47 +280,36 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
Some(())
}
-pub(crate) fn position_for_import(
- ctx: &CompletionContext,
- import_candidate: Option<&ImportCandidate>,
-) -> Option<SyntaxNode> {
- Some(
- match import_candidate {
- Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual()?.syntax(),
- Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(),
- Some(ImportCandidate::Path(_)) | None => return ctx.original_token.parent(),
- }
- .clone(),
- )
+fn import_name(ctx: &CompletionContext) -> String {
+ let token_kind = ctx.token.kind();
+ if matches!(token_kind, T![.] | T![::]) {
+ String::new()
+ } else {
+ ctx.token.to_string()
+ }
}
-fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> {
- let current_module = ctx.module;
- if let Some(dot_receiver) = ctx.dot_receiver() {
- ImportAssets::for_fuzzy_method_call(
- current_module,
- ctx.sema.type_of_expr(dot_receiver)?.original,
- fuzzy_name,
- dot_receiver.syntax().clone(),
- )
- } else {
- let fuzzy_name_length = fuzzy_name.len();
- let mut assets_for_path = ImportAssets::for_fuzzy_path(
- current_module,
- ctx.path_qual().cloned(),
- fuzzy_name,
- &ctx.sema,
- ctx.token.parent()?,
- )?;
- if fuzzy_name_length < 3 {
- cov_mark::hit!(flyimport_exact_on_short_path);
- assets_for_path.path_fuzzy_name_to_exact(false);
- }
- Some(assets_for_path)
+fn import_assets_for_path(
+ ctx: &CompletionContext,
+ potential_import_name: &str,
+ qualifier: Option<ast::Path>,
+) -> Option<ImportAssets> {
+ let fuzzy_name_length = potential_import_name.len();
+ let mut assets_for_path = ImportAssets::for_fuzzy_path(
+ ctx.module,
+ qualifier,
+ potential_import_name.to_owned(),
+ &ctx.sema,
+ ctx.token.parent()?,
+ )?;
+ if fuzzy_name_length < 3 {
+ cov_mark::hit!(flyimport_exact_on_short_path);
+ assets_for_path.path_fuzzy_name_to_exact(false);
}
+ Some(assets_for_path)
}
-pub(crate) fn compute_fuzzy_completion_order_key(
+fn compute_fuzzy_completion_order_key(
proposed_mod_path: &hir::ModPath,
user_input_lowercased: &str,
) -> usize {