From a02a1afc922c7435baa909f81c5ca66e1ae56296 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 29 Sep 2024 09:15:58 +0300 Subject: [PATCH] Allow flyimporting excluded trait items if there is an exact match in the name I.e. with `fn foo()`, don't complete at `x.fo|`, but complete (with imports) for `x.foo|`, since this is less likely to have false positives. I opted to only do that for flyimport, even though for basic imports there can also be snippet completion (completing the params list for a method), since this is less universally applicable and seems not so useful. --- .../src/completions/flyimport.rs | 20 +++++++++-- crates/ide-completion/src/tests/flyimport.rs | 34 ++++++++++++++++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs index 3f74e36101..afa94affb3 100644 --- a/crates/ide-completion/src/completions/flyimport.rs +++ b/crates/ide-completion/src/completions/flyimport.rs @@ -258,6 +258,8 @@ fn import_on_the_fly( let import_cfg = ctx.config.import_path_config(); + let completed_name = ctx.token.to_string(); + import_assets .search_for_imports(&ctx.sema, import_cfg, ctx.config.insert_use.prefix_kind) .filter(ns_filter) @@ -271,7 +273,13 @@ fn import_on_the_fly( if let ModuleDef::Trait(trait_) = import.item_to_import.into_module_def() { let excluded = ctx.exclude_flyimport_traits.contains(&trait_); let trait_itself_imported = import.item_to_import == import.original_item; - !excluded || trait_itself_imported + if !excluded || trait_itself_imported { + return true; + } + + let item = import.original_item.into_module_def(); + // Filter that item out, unless its name matches the name the user wrote exactly - in which case preserve it. + item.name(ctx.db).is_some_and(|name| name.eq_ident(&completed_name)) } else { true } @@ -355,6 +363,8 @@ fn import_on_the_fly_method( let cfg = ctx.config.import_path_config(); + let completed_name = ctx.token.to_string(); + import_assets .search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind) .filter(|import| { @@ -363,7 +373,13 @@ fn import_on_the_fly_method( }) .filter(|import| { if let ModuleDef::Trait(trait_) = import.item_to_import.into_module_def() { - !ctx.exclude_flyimport_traits.contains(&trait_) + if !ctx.exclude_flyimport_traits.contains(&trait_) { + return true; + } + + let item = import.original_item.into_module_def(); + // Filter that method out, unless its name matches the name the user wrote exactly - in which case preserve it. + item.name(ctx.db).is_some_and(|name| name.eq_ident(&completed_name)) } else { true } diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs index 447dbc998b..d413977f7c 100644 --- a/crates/ide-completion/src/tests/flyimport.rs +++ b/crates/ide-completion/src/tests/flyimport.rs @@ -3,10 +3,14 @@ use expect_test::{expect, Expect}; use crate::{ context::{CompletionAnalysis, NameContext, NameKind, NameRefKind}, tests::{check_edit, check_edit_with_config, TEST_CONFIG}, + CompletionConfig, }; fn check(ra_fixture: &str, expect: Expect) { - let config = TEST_CONFIG; + check_with_config(TEST_CONFIG, ra_fixture, expect); +} + +fn check_with_config(config: CompletionConfig<'_>, ra_fixture: &str, expect: Expect) { let (db, position) = crate::tests::position(ra_fixture); let (ctx, analysis) = crate::context::CompletionContext::new(&db, position, &config).unwrap(); @@ -1762,3 +1766,31 @@ fn function() { expect![""], ); } + +#[test] +fn excluded_trait_item_included_when_exact_match() { + check_with_config( + CompletionConfig { + exclude_traits: &["test::module2::ExcludedTrait".to_owned()], + ..TEST_CONFIG + }, + r#" +mod module2 { + pub trait ExcludedTrait { + fn foo(&self) {} + fn bar(&self) {} + fn baz(&self) {} + } + + impl ExcludedTrait for T {} +} + +fn foo() { + true.foo$0 +} + "#, + expect![[r#" + me foo() (use module2::ExcludedTrait) fn(&self) + "#]], + ); +}