From bd6ea14002949c2b2fdf9ec51cce3634b7a15147 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 24 Sep 2024 19:24:15 +0300 Subject: Allow excluding specific traits from completion To be accurate, only their methods are excluded, the trait themselves are still available. I also excluded a bunch of std traits by default. Some less opinionated, like `AsRef`, which should never be used directly except in generic scenarios (and won't be excluded there), some more opinionated, like the ops traits, which I know some users sometimes want to use directly. Either way it's configurable. It should be pretty easy to extend support to excluding only specific methods, but I didn't do that currently. Traits configured to be excluded are resolved in each completion request from scratch. If this proves too expensive, it is easy enough to cache them in the DB. --- src/tools/rust-analyzer/editors/code/package.json | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'src/tools/rust-analyzer/editors/code') diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index b9249e9ac8b..a6e92838a06 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -1139,6 +1139,49 @@ } } }, + { + "title": "completion", + "properties": { + "rust-analyzer.completion.autoimport.excludeTraits": { + "markdownDescription": "A list of full paths to traits to exclude from flyimport.\n\nTraits in this list won't be suggested to be imported by flyimport for their methods. Methods from them won't be available in flyimport completion. They will still be available if in scope.\n\nNote that the trait themselves can still be suggested by flyimport.\n\nThis setting also inherits `#rust-analyzer.completion.excludeTraits#`.\n\nThis setting defaults to:\n\n - [`core::borrow::Borrow`](https://doc.rust-lang.org/nightly/core/borrow/trait.Borrow.html)\n - [`core::borrow::BorrowMut`](https://doc.rust-lang.org/nightly/core/borrow/trait.BorrowMut.html)\n - [`core::cmp::PartialEq`](https://doc.rust-lang.org/nightly/core/cmp/trait.PartialEq.html)\n - All operator traits (in [`core::ops`](https://doc.rust-lang.org/nightly/core/ops))\n\nNote that if you override this setting, those traits won't be automatically inserted, so you may want to insert them manually.", + "default": [ + "core::borrow::Borrow", + "core::borrow::BorrowMut", + "core::cmp::PartialEq", + "core::ops::Add", + "core::ops::AddAssign", + "core::ops::BitAnd", + "core::ops::BitAndAssign", + "core::ops::BitOr", + "core::ops::BitOrAssign", + "core::ops::BitXor", + "core::ops::BitXorAssign", + "core::ops::Div", + "core::ops::DivAssign", + "core::ops::Mul", + "core::ops::MulAssign", + "core::ops::Rem", + "core::ops::RemAssign", + "core::ops::Shl", + "core::ops::ShlAssign", + "core::ops::Shr", + "core::ops::ShrAssign", + "core::ops::Sub", + "core::ops::SubAssign", + "core::ops::Neg", + "core::ops::Not", + "core::ops::Index", + "core::ops::IndexMut", + "core::ops::Deref", + "core::ops::DerefMut" + ], + "type": "array", + "items": { + "type": "string" + } + } + } + }, { "title": "completion", "properties": { @@ -1169,6 +1212,19 @@ } } }, + { + "title": "completion", + "properties": { + "rust-analyzer.completion.excludeTraits": { + "markdownDescription": "A list of full paths to traits to exclude from completion.\n\nMethods from these traits won't be completed, even if the trait is in scope. However, they will still be suggested on expressions whose type is `dyn Trait`, `impl Trait` or `T where T: Trait`.\n\nNote that the trait themselves can still be completed.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } + }, { "title": "completion", "properties": { -- cgit 1.4.1-3-g733a5 From 13af22df98c790875d0a31f49c19cfd84e14d424 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 1 Jan 2025 14:09:05 +0100 Subject: Reduce the default autoimport exclusion list --- .../rust-analyzer/crates/hir-def/src/item_scope.rs | 7 - .../crates/ide-completion/src/tests/expression.rs | 154 +++++++++++---------- .../crates/rust-analyzer/src/config.rs | 41 +----- .../rust-analyzer/docs/user/generated_config.adoc | 43 +----- src/tools/rust-analyzer/editors/code/package.json | 31 +---- 5 files changed, 90 insertions(+), 186 deletions(-) (limited to 'src/tools/rust-analyzer/editors/code') diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index f600efea9f2..2c3eb5c8e5e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -354,13 +354,6 @@ impl ItemScope { .chain(self.unnamed_trait_imports.keys().copied()) } - pub fn trait_by_name(&self, name: &Name) -> Option { - self.types.get(name).and_then(|def| match def.def { - ModuleDefId::TraitId(it) => Some(it), - _ => None, - }) - } - pub(crate) fn resolutions(&self) -> impl Iterator, PerNs)> + '_ { self.entries().map(|(name, res)| (Some(name.clone()), res)).chain( self.unnamed_trait_imports.iter().map(|(tr, trait_)| { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index 6c95980507c..d1bbf1e8d0b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -1430,19 +1430,22 @@ fn foo() { } "#, expect![[r#" - me inherent() fn(&self) - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn deref *expr - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr - sn return return expr - sn unsafe unsafe {} + me bar() (as ExcludedTrait) fn(&self) + me baz() (as ExcludedTrait) fn(&self) + me foo() (as ExcludedTrait) fn(&self) + me inherent() fn(&self) + sn box Box::new(expr) + sn call function(expr) + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} "#]], ); } @@ -1468,18 +1471,18 @@ fn foo(v: &dyn ExcludedTrait) { me bar() (as ExcludedTrait) fn(&self) me baz() (as ExcludedTrait) fn(&self) me foo() (as ExcludedTrait) fn(&self) - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) + sn box Box::new(expr) + sn call function(expr) + sn dbg dbg!(expr) sn dbgr dbg!(&expr) - sn deref *expr - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr sn return return expr - sn unsafe unsafe {} + sn unsafe unsafe {} "#]], ); check_with_config( @@ -1501,18 +1504,18 @@ fn foo(v: impl ExcludedTrait) { me bar() (as ExcludedTrait) fn(&self) me baz() (as ExcludedTrait) fn(&self) me foo() (as ExcludedTrait) fn(&self) - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) + sn box Box::new(expr) + sn call function(expr) + sn dbg dbg!(expr) sn dbgr dbg!(&expr) - sn deref *expr - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr sn return return expr - sn unsafe unsafe {} + sn unsafe unsafe {} "#]], ); check_with_config( @@ -1534,18 +1537,18 @@ fn foo(v: T) { me bar() (as ExcludedTrait) fn(&self) me baz() (as ExcludedTrait) fn(&self) me foo() (as ExcludedTrait) fn(&self) - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) + sn box Box::new(expr) + sn call function(expr) + sn dbg dbg!(expr) sn dbgr dbg!(&expr) - sn deref *expr - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr sn return return expr - sn unsafe unsafe {} + sn unsafe unsafe {} "#]], ); } @@ -1578,19 +1581,22 @@ fn foo() { } "#, expect![[r#" - me inherent() fn(&self) - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn deref *expr - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr - sn return return expr - sn unsafe unsafe {} + me bar() (use module2::ExcludedTrait) fn(&self) + me baz() (use module2::ExcludedTrait) fn(&self) + me foo() (use module2::ExcludedTrait) fn(&self) + me inherent() fn(&self) + sn box Box::new(expr) + sn call function(expr) + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} "#]], ); } @@ -1623,19 +1629,22 @@ fn foo() { } "#, expect![[r#" - me inherent() fn(&self) - sn box Box::new(expr) - sn call function(expr) - sn dbg dbg!(expr) - sn dbgr dbg!(&expr) - sn deref *expr - sn let let - sn letm let mut - sn match match expr {} - sn ref &expr - sn refm &mut expr - sn return return expr - sn unsafe unsafe {} + me bar() (use module2::ExcludedTrait) fn(&self) + me baz() (use module2::ExcludedTrait) fn(&self) + me foo() (use module2::ExcludedTrait) fn(&self) + me inherent() fn(&self) + sn box Box::new(expr) + sn call function(expr) + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} "#]], ); } @@ -1663,8 +1672,11 @@ fn foo() { } "#, expect![[r#" - me inherent(…) fn(&self) - "#]], + me bar(…) (as ExcludedTrait) fn(&self) + me baz(…) (as ExcludedTrait) fn(&self) + me foo(…) (as ExcludedTrait) fn(&self) + me inherent(…) fn(&self) + "#]], ); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index c53ca230409..b6678c12c70 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -442,50 +442,13 @@ config_data! { completion_autoimport_enable: bool = true, /// A list of full paths to traits to exclude from flyimport. /// - /// Traits in this list won't be suggested to be imported by flyimport for their methods. Methods from them won't be available in flyimport completion. They will still be available if in scope. - /// - /// Note that the trait themselves can still be suggested by flyimport. + /// Traits in this list won't have their methods suggested in completions unless the trait + /// is in scope. /// /// This setting also inherits `#rust-analyzer.completion.excludeTraits#`. - /// - /// This setting defaults to: - /// - /// - [`core::borrow::Borrow`](https://doc.rust-lang.org/nightly/core/borrow/trait.Borrow.html) - /// - [`core::borrow::BorrowMut`](https://doc.rust-lang.org/nightly/core/borrow/trait.BorrowMut.html) - /// - [`core::cmp::PartialEq`](https://doc.rust-lang.org/nightly/core/cmp/trait.PartialEq.html) - /// - All operator traits (in [`core::ops`](https://doc.rust-lang.org/nightly/core/ops)) - /// - /// Note that if you override this setting, those traits won't be automatically inserted, so you may want to insert them manually. completion_autoimport_excludeTraits: Vec = vec![ "core::borrow::Borrow".to_owned(), "core::borrow::BorrowMut".to_owned(), - "core::cmp::PartialEq".to_owned(), - "core::ops::Add".to_owned(), - "core::ops::AddAssign".to_owned(), - "core::ops::BitAnd".to_owned(), - "core::ops::BitAndAssign".to_owned(), - "core::ops::BitOr".to_owned(), - "core::ops::BitOrAssign".to_owned(), - "core::ops::BitXor".to_owned(), - "core::ops::BitXorAssign".to_owned(), - "core::ops::Div".to_owned(), - "core::ops::DivAssign".to_owned(), - "core::ops::Mul".to_owned(), - "core::ops::MulAssign".to_owned(), - "core::ops::Rem".to_owned(), - "core::ops::RemAssign".to_owned(), - "core::ops::Shl".to_owned(), - "core::ops::ShlAssign".to_owned(), - "core::ops::Shr".to_owned(), - "core::ops::ShrAssign".to_owned(), - "core::ops::Sub".to_owned(), - "core::ops::SubAssign".to_owned(), - "core::ops::Neg".to_owned(), - "core::ops::Not".to_owned(), - "core::ops::Index".to_owned(), - "core::ops::IndexMut".to_owned(), - "core::ops::Deref".to_owned(), - "core::ops::DerefMut".to_owned(), ], /// Toggles the additional completions that automatically show method calls and field accesses /// with `self` prefixed to them when inside a method. diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index 27ade71b331..bce26f7dd74 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -293,53 +293,16 @@ Default: ---- [ "core::borrow::Borrow", - "core::borrow::BorrowMut", - "core::cmp::PartialEq", - "core::ops::Add", - "core::ops::AddAssign", - "core::ops::BitAnd", - "core::ops::BitAndAssign", - "core::ops::BitOr", - "core::ops::BitOrAssign", - "core::ops::BitXor", - "core::ops::BitXorAssign", - "core::ops::Div", - "core::ops::DivAssign", - "core::ops::Mul", - "core::ops::MulAssign", - "core::ops::Rem", - "core::ops::RemAssign", - "core::ops::Shl", - "core::ops::ShlAssign", - "core::ops::Shr", - "core::ops::ShrAssign", - "core::ops::Sub", - "core::ops::SubAssign", - "core::ops::Neg", - "core::ops::Not", - "core::ops::Index", - "core::ops::IndexMut", - "core::ops::Deref", - "core::ops::DerefMut" + "core::borrow::BorrowMut" ] ---- A list of full paths to traits to exclude from flyimport. -Traits in this list won't be suggested to be imported by flyimport for their methods. Methods from them won't be available in flyimport completion. They will still be available if in scope. - -Note that the trait themselves can still be suggested by flyimport. +Traits in this list won't have their methods suggested in completions unless the trait +is in scope. This setting also inherits `#rust-analyzer.completion.excludeTraits#`. -This setting defaults to: - - - [`core::borrow::Borrow`](https://doc.rust-lang.org/nightly/core/borrow/trait.Borrow.html) - - [`core::borrow::BorrowMut`](https://doc.rust-lang.org/nightly/core/borrow/trait.BorrowMut.html) - - [`core::cmp::PartialEq`](https://doc.rust-lang.org/nightly/core/cmp/trait.PartialEq.html) - - All operator traits (in [`core::ops`](https://doc.rust-lang.org/nightly/core/ops)) - -Note that if you override this setting, those traits won't be automatically inserted, so you may want to insert them manually. - -- [[rust-analyzer.completion.autoself.enable]]rust-analyzer.completion.autoself.enable (default: `true`):: + diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index a6e92838a06..31419a1942d 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -1143,37 +1143,10 @@ "title": "completion", "properties": { "rust-analyzer.completion.autoimport.excludeTraits": { - "markdownDescription": "A list of full paths to traits to exclude from flyimport.\n\nTraits in this list won't be suggested to be imported by flyimport for their methods. Methods from them won't be available in flyimport completion. They will still be available if in scope.\n\nNote that the trait themselves can still be suggested by flyimport.\n\nThis setting also inherits `#rust-analyzer.completion.excludeTraits#`.\n\nThis setting defaults to:\n\n - [`core::borrow::Borrow`](https://doc.rust-lang.org/nightly/core/borrow/trait.Borrow.html)\n - [`core::borrow::BorrowMut`](https://doc.rust-lang.org/nightly/core/borrow/trait.BorrowMut.html)\n - [`core::cmp::PartialEq`](https://doc.rust-lang.org/nightly/core/cmp/trait.PartialEq.html)\n - All operator traits (in [`core::ops`](https://doc.rust-lang.org/nightly/core/ops))\n\nNote that if you override this setting, those traits won't be automatically inserted, so you may want to insert them manually.", + "markdownDescription": "A list of full paths to traits to exclude from flyimport.\n\nTraits in this list won't have their methods suggested in completions unless the trait\nis in scope.\n\nThis setting also inherits `#rust-analyzer.completion.excludeTraits#`.", "default": [ "core::borrow::Borrow", - "core::borrow::BorrowMut", - "core::cmp::PartialEq", - "core::ops::Add", - "core::ops::AddAssign", - "core::ops::BitAnd", - "core::ops::BitAndAssign", - "core::ops::BitOr", - "core::ops::BitOrAssign", - "core::ops::BitXor", - "core::ops::BitXorAssign", - "core::ops::Div", - "core::ops::DivAssign", - "core::ops::Mul", - "core::ops::MulAssign", - "core::ops::Rem", - "core::ops::RemAssign", - "core::ops::Shl", - "core::ops::ShlAssign", - "core::ops::Shr", - "core::ops::ShrAssign", - "core::ops::Sub", - "core::ops::SubAssign", - "core::ops::Neg", - "core::ops::Not", - "core::ops::Index", - "core::ops::IndexMut", - "core::ops::Deref", - "core::ops::DerefMut" + "core::borrow::BorrowMut" ], "type": "array", "items": { -- cgit 1.4.1-3-g733a5 From c84d09a7c37711533311f99397189de148a79a58 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 1 Jan 2025 15:05:24 +0100 Subject: Revamp auto-import exclude config --- .../ide-completion/src/completions/flyimport.rs | 42 ++++++------ .../crates/ide-completion/src/config.rs | 8 ++- .../crates/ide-completion/src/context.rs | 19 +++--- .../rust-analyzer/crates/ide-completion/src/lib.rs | 2 +- .../crates/ide-completion/src/tests.rs | 2 +- .../crates/ide-completion/src/tests/expression.rs | 6 +- .../crates/rust-analyzer/src/config.rs | 77 ++++++++++++++++++++-- .../rust-analyzer/src/integrated_benchmarks.rs | 6 +- .../rust-analyzer/docs/user/generated_config.adoc | 21 ++++-- src/tools/rust-analyzer/editors/code/package.json | 41 ++++++++++-- 10 files changed, 169 insertions(+), 55 deletions(-) (limited to 'src/tools/rust-analyzer/editors/code') diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs index afa94affb3b..3b2b2fd706e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs @@ -8,6 +8,7 @@ use itertools::Itertools; use syntax::{ast, AstNode, SyntaxNode, ToSmolStr, T}; use crate::{ + config::AutoImportExclusionType, context::{ CompletionContext, DotAccess, PathCompletionCtx, PathKind, PatternContext, Qualified, TypeLocation, @@ -258,8 +259,6 @@ 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) @@ -270,19 +269,17 @@ fn import_on_the_fly( && ctx.check_stability(original_item.attrs(ctx.db).as_deref()) }) .filter(|import| { - 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; - if !excluded || trait_itself_imported { - return true; + let def = import.item_to_import.into_module_def(); + if let Some(&kind) = ctx.exclude_flyimport.get(&def) { + if kind == AutoImportExclusionType::Always { + return false; + } + let method_imported = import.item_to_import != import.original_item; + if method_imported { + return false; } - - 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 } + true }) .sorted_by(|a, b| { let key = |import_path| { @@ -363,8 +360,6 @@ 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| { @@ -372,14 +367,19 @@ fn import_on_the_fly_method( && !ctx.is_item_hidden(&import.original_item) }) .filter(|import| { - if let ModuleDef::Trait(trait_) = import.item_to_import.into_module_def() { - if !ctx.exclude_flyimport_traits.contains(&trait_) { - return true; + let def = import.item_to_import.into_module_def(); + if let Some(&kind) = ctx.exclude_flyimport.get(&def) { + if kind == AutoImportExclusionType::Always { + return false; } + let method_imported = import.item_to_import != import.original_item; + if method_imported { + return false; + } + } - 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)) + if let ModuleDef::Trait(_) = import.item_to_import.into_module_def() { + !ctx.exclude_flyimport.contains_key(&def) } else { true } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs index ed36fe8d028..8b1ce11e8a4 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs @@ -28,10 +28,16 @@ pub struct CompletionConfig<'a> { pub snippets: Vec, pub limit: Option, pub fields_to_resolve: CompletionFieldsToResolve, - pub exclude_flyimport_traits: &'a [String], + pub exclude_flyimport: Vec<(String, AutoImportExclusionType)>, pub exclude_traits: &'a [String], } +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum AutoImportExclusionType { + Always, + Methods, +} + #[derive(Clone, Debug, PartialEq, Eq)] pub enum CallableSnippets { FillArguments, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index c4365284251..183490c2ed8 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -22,6 +22,7 @@ use syntax::{ }; use crate::{ + config::AutoImportExclusionType, context::analysis::{expand_and_analyze, AnalysisResult}, CompletionConfig, }; @@ -466,7 +467,7 @@ pub(crate) struct CompletionContext<'a> { /// importing those traits. /// /// Note the trait *themselves* are not excluded, only their methods are. - pub(crate) exclude_flyimport_traits: FxHashSet, + pub(crate) exclude_flyimport: FxHashMap, /// Traits whose methods should always be excluded, even when in scope (compare `exclude_flyimport_traits`). /// They will *not* be excluded, however, if they are available as a generic bound. /// @@ -780,22 +781,20 @@ impl<'a> CompletionContext<'a> { }) .collect(); - let mut exclude_flyimport_traits: FxHashSet<_> = config - .exclude_flyimport_traits + let mut exclude_flyimport: FxHashMap<_, _> = config + .exclude_flyimport .iter() - .filter_map(|path| { + .flat_map(|(path, kind)| { scope .resolve_mod_path(&ModPath::from_segments( hir::PathKind::Plain, path.split("::").map(Symbol::intern).map(Name::new_symbol_root), )) - .find_map(|it| match it { - hir::ItemInNs::Types(ModuleDef::Trait(t)) => Some(t), - _ => None, - }) + .map(|it| (it.into_module_def(), *kind)) }) .collect(); - exclude_flyimport_traits.extend(exclude_traits.iter().copied()); + exclude_flyimport + .extend(exclude_traits.iter().map(|&t| (t.into(), AutoImportExclusionType::Always))); let complete_semicolon = if config.add_semicolon_to_unit { let inside_closure_ret = token.parent_ancestors().try_for_each(|ancestor| { @@ -861,7 +860,7 @@ impl<'a> CompletionContext<'a> { qualifier_ctx, locals, depth_from_crate_root, - exclude_flyimport_traits, + exclude_flyimport, exclude_traits, complete_semicolon, }; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index 05563bc912d..ca6c9ad9f08 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -31,7 +31,7 @@ use crate::{ }; pub use crate::{ - config::{CallableSnippets, CompletionConfig}, + config::{AutoImportExclusionType, CallableSnippets, CompletionConfig}, item::{ CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch, CompletionRelevanceReturnType, CompletionRelevanceTypeMatch, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index 3b2d3fbbfc1..1815f340532 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -85,7 +85,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig<'_> = CompletionConfig { snippets: Vec::new(), limit: None, fields_to_resolve: CompletionFieldsToResolve::empty(), - exclude_flyimport_traits: &[], + exclude_flyimport: vec![], exclude_traits: &[], }; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index d1bbf1e8d0b..a9db1d95318 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -2,6 +2,7 @@ use expect_test::{expect, Expect}; use crate::{ + config::AutoImportExclusionType, tests::{ check_edit, check_empty, completion_list, completion_list_with_config, BASE_ITEMS_FIXTURE, TEST_CONFIG, @@ -1605,7 +1606,10 @@ fn foo() { fn flyimport_excluded_trait_method_is_excluded_from_flyimport() { check_with_config( CompletionConfig { - exclude_flyimport_traits: &["test::module2::ExcludedTrait".to_owned()], + exclude_flyimport: vec![( + "test::module2::ExcludedTrait".to_owned(), + AutoImportExclusionType::Methods, + )], ..TEST_CONFIG }, r#" diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index b6678c12c70..b7297d0c02a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -440,22 +440,27 @@ config_data! { /// Toggles the additional completions that automatically add imports when completed. /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. completion_autoimport_enable: bool = true, - /// A list of full paths to traits to exclude from flyimport. + /// A list of full paths to items to exclude from auto-importing completions. /// /// Traits in this list won't have their methods suggested in completions unless the trait /// is in scope. /// + /// You can either specify a string path which defaults to type "always" or use the more verbose + /// form `{ "path": "path::to::item", type: "always" }`. + /// + /// For traits the type "methods" can be used to only exclude the methods but not the trait itself. + /// /// This setting also inherits `#rust-analyzer.completion.excludeTraits#`. - completion_autoimport_excludeTraits: Vec = vec![ - "core::borrow::Borrow".to_owned(), - "core::borrow::BorrowMut".to_owned(), + completion_autoimport_exclude: Vec = vec![ + AutoImportExclusion::Verbose { path: "core::borrow::Borrow".to_owned(), r#type: AutoImportExclusionType::Methods }, + AutoImportExclusion::Verbose { path: "core::borrow::BorrowMut".to_owned(), r#type: AutoImportExclusionType::Methods }, ], /// Toggles the additional completions that automatically show method calls and field accesses /// with `self` prefixed to them when inside a method. completion_autoself_enable: bool = true, /// Whether to add parenthesis and argument snippets when completing function. completion_callable_snippets: CallableCompletionDef = CallableCompletionDef::FillArguments, - /// A list of full paths to traits to exclude from completion. + /// A list of full paths to traits whose methods to exclude from completion. /// /// Methods from these traits won't be completed, even if the trait is in scope. However, they will still be suggested on expressions whose type is `dyn Trait`, `impl Trait` or `T where T: Trait`. /// @@ -1478,7 +1483,26 @@ impl Config { } else { CompletionFieldsToResolve::from_client_capabilities(&client_capability_fields) }, - exclude_flyimport_traits: self.completion_autoimport_excludeTraits(source_root), + exclude_flyimport: self + .completion_autoimport_exclude(source_root) + .iter() + .map(|it| match it { + AutoImportExclusion::Path(path) => { + (path.clone(), ide_completion::AutoImportExclusionType::Always) + } + AutoImportExclusion::Verbose { path, r#type } => ( + path.clone(), + match r#type { + AutoImportExclusionType::Always => { + ide_completion::AutoImportExclusionType::Always + } + AutoImportExclusionType::Methods => { + ide_completion::AutoImportExclusionType::Methods + } + }, + ), + }) + .collect(), exclude_traits: self.completion_excludeTraits(source_root), } } @@ -2419,6 +2443,21 @@ enum ExprFillDefaultDef { Default, } +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(untagged)] +#[serde(rename_all = "snake_case")] +pub enum AutoImportExclusion { + Path(String), + Verbose { path: String, r#type: AutoImportExclusionType }, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "snake_case")] +pub enum AutoImportExclusionType { + Always, + Methods, +} + #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "snake_case")] enum ImportGranularityDef { @@ -3490,6 +3529,32 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json } ] }, + "Vec" => set! { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string", + }, + { + "type": "object", + "properties": { + "path": { + "type": "string", + }, + "type": { + "type": "string", + "enum": ["always", "methods"], + "enumDescriptions": [ + "Do not show this item or its methods (if it is a trait) in auto-import completions.", + "Do not show this traits methods in auto-import completions." + ], + }, + } + } + ] + } + }, _ => panic!("missing entry for {ty}: {default} (field {field})"), } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs index bd164fe4408..fcfd06679bf 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -174,7 +174,7 @@ fn integrated_completion_benchmark() { limit: None, add_semicolon_to_unit: true, fields_to_resolve: CompletionFieldsToResolve::empty(), - exclude_flyimport_traits: &[], + exclude_flyimport: vec![], exclude_traits: &[], }; let position = @@ -224,7 +224,7 @@ fn integrated_completion_benchmark() { limit: None, add_semicolon_to_unit: true, fields_to_resolve: CompletionFieldsToResolve::empty(), - exclude_flyimport_traits: &[], + exclude_flyimport: vec![], exclude_traits: &[], }; let position = @@ -272,7 +272,7 @@ fn integrated_completion_benchmark() { limit: None, add_semicolon_to_unit: true, fields_to_resolve: CompletionFieldsToResolve::empty(), - exclude_flyimport_traits: &[], + exclude_flyimport: vec![], exclude_traits: &[], }; let position = diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index bce26f7dd74..a44f5a12b28 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -286,21 +286,32 @@ In `match` arms it completes a comma instead. Toggles the additional completions that automatically add imports when completed. Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. -- -[[rust-analyzer.completion.autoimport.excludeTraits]]rust-analyzer.completion.autoimport.excludeTraits:: +[[rust-analyzer.completion.autoimport.exclude]]rust-analyzer.completion.autoimport.exclude:: + -- Default: ---- [ - "core::borrow::Borrow", - "core::borrow::BorrowMut" + { + "path": "core::borrow::Borrow", + "type": "methods" + }, + { + "path": "core::borrow::BorrowMut", + "type": "methods" + } ] ---- -A list of full paths to traits to exclude from flyimport. +A list of full paths to items to exclude from auto-importing completions. Traits in this list won't have their methods suggested in completions unless the trait is in scope. +You can either specify a string path which defaults to type "always" or use the more verbose +form `{ "path": "path::to::item", type: "always" }`. + +For traits the type "methods" can be used to only exclude the methods but not the trait itself. + This setting also inherits `#rust-analyzer.completion.excludeTraits#`. -- @@ -318,7 +329,7 @@ Whether to add parenthesis and argument snippets when completing function. [[rust-analyzer.completion.excludeTraits]]rust-analyzer.completion.excludeTraits (default: `[]`):: + -- -A list of full paths to traits to exclude from completion. +A list of full paths to traits whose methods to exclude from completion. Methods from these traits won't be completed, even if the trait is in scope. However, they will still be suggested on expressions whose type is `dyn Trait`, `impl Trait` or `T where T: Trait`. diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 31419a1942d..03c00a37fb1 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -1142,15 +1142,44 @@ { "title": "completion", "properties": { - "rust-analyzer.completion.autoimport.excludeTraits": { - "markdownDescription": "A list of full paths to traits to exclude from flyimport.\n\nTraits in this list won't have their methods suggested in completions unless the trait\nis in scope.\n\nThis setting also inherits `#rust-analyzer.completion.excludeTraits#`.", + "rust-analyzer.completion.autoimport.exclude": { + "markdownDescription": "A list of full paths to items to exclude from auto-importing completions.\n\nTraits in this list won't have their methods suggested in completions unless the trait\nis in scope.\n\nYou can either specify a string path which defaults to type \"always\" or use the more verbose\nform `{ \"path\": \"path::to::item\", type: \"always\" }`.\n\nFor traits the type \"methods\" can be used to only exclude the methods but not the trait itself.\n\nThis setting also inherits `#rust-analyzer.completion.excludeTraits#`.", "default": [ - "core::borrow::Borrow", - "core::borrow::BorrowMut" + { + "path": "core::borrow::Borrow", + "type": "methods" + }, + { + "path": "core::borrow::BorrowMut", + "type": "methods" + } ], "type": "array", "items": { - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "always", + "methods" + ], + "enumDescriptions": [ + "Do not show this item or its methods (if it is a trait) in auto-import completions.", + "Do not show this traits methods in auto-import completions." + ] + } + } + } + ] } } } @@ -1189,7 +1218,7 @@ "title": "completion", "properties": { "rust-analyzer.completion.excludeTraits": { - "markdownDescription": "A list of full paths to traits to exclude from completion.\n\nMethods from these traits won't be completed, even if the trait is in scope. However, they will still be suggested on expressions whose type is `dyn Trait`, `impl Trait` or `T where T: Trait`.\n\nNote that the trait themselves can still be completed.", + "markdownDescription": "A list of full paths to traits whose methods to exclude from completion.\n\nMethods from these traits won't be completed, even if the trait is in scope. However, they will still be suggested on expressions whose type is `dyn Trait`, `impl Trait` or `T where T: Trait`.\n\nNote that the trait themselves can still be completed.", "default": [], "type": "array", "items": { -- cgit 1.4.1-3-g733a5