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.rs | 187 |
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 { |