From df5c6479823fda0c346e00f6cc89fcaa2f03168e Mon Sep 17 00:00:00 2001 From: dfireBird Date: Sat, 6 Jan 2024 15:48:10 +0530 Subject: [PATCH 1/2] add notable_trait predicate to `CompletionRelevance` implement the predicate set on the case function from traits --- crates/hir-def/src/attr.rs | 7 +++++++ crates/ide-completion/src/context.rs | 5 +++++ crates/ide-completion/src/item.rs | 6 ++++++ crates/ide-completion/src/render.rs | 4 ++++ crates/ide-completion/src/render/function.rs | 6 ++++++ 5 files changed, 28 insertions(+) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index 26f76afb1f09..dfee397619c6 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -207,6 +207,13 @@ impl Attrs { }) } + pub fn has_doc_notable_trait(&self) -> bool { + self.by_key("doc").tt_values().any(|tt| { + tt.delimiter.kind == DelimiterKind::Parenthesis && + matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.text == "notable_trait") + }) + } + pub fn doc_exprs(&self) -> impl Iterator + '_ { self.by_key("doc").tt_values().map(DocExpr::parse) } diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 108b040de6ba..92aa1da89c41 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -529,6 +529,11 @@ impl CompletionContext<'_> { } } + /// Whether the given trait has `#[doc(notable_trait)]` + pub(crate) fn is_doc_notable_trait(&self, trait_: hir::Trait) -> bool { + trait_.attrs(self.db).has_doc_notable_trait() + } + /// Returns the traits in scope, with the [`Drop`] trait removed. pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits { let mut traits_in_scope = self.scope.visible_traits(); diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs index de41a5bd70c4..affd9b729646 100644 --- a/crates/ide-completion/src/item.rs +++ b/crates/ide-completion/src/item.rs @@ -152,6 +152,8 @@ pub struct CompletionRelevance { pub is_local: bool, /// This is set when trait items are completed in an impl of that trait. pub is_item_from_trait: bool, + /// This is set for when trait items are from traits with `#[doc(notable_trait)]` + pub is_item_from_notable_trait: bool, /// This is set when an import is suggested whose name is already imported. pub is_name_already_imported: bool, /// This is set for completions that will insert a `use` item. @@ -228,6 +230,7 @@ impl CompletionRelevance { is_private_editable, postfix_match, is_definite, + is_item_from_notable_trait, } = self; // lower rank private things @@ -266,6 +269,9 @@ impl CompletionRelevance { if is_item_from_trait { score += 1; } + if is_item_from_notable_trait { + score += 1; + } if is_definite { score += 10; } diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 581d557e831a..f924c9aedb60 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -1170,6 +1170,7 @@ fn main() { let _: m::Spam = S$0 } ), is_local: false, is_item_from_trait: false, + is_item_from_notable_trait: false, is_name_already_imported: false, requires_import: false, is_op_method: false, @@ -1196,6 +1197,7 @@ fn main() { let _: m::Spam = S$0 } ), is_local: false, is_item_from_trait: false, + is_item_from_notable_trait: false, is_name_already_imported: false, requires_import: false, is_op_method: false, @@ -1274,6 +1276,7 @@ fn foo() { A { the$0 } } ), is_local: false, is_item_from_trait: false, + is_item_from_notable_trait: false, is_name_already_imported: false, requires_import: false, is_op_method: false, @@ -2089,6 +2092,7 @@ fn foo() { ), is_local: false, is_item_from_trait: false, + is_item_from_notable_trait: false, is_name_already_imported: false, requires_import: false, is_op_method: false, diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs index b306bede653b..ccd312b03fb7 100644 --- a/crates/ide-completion/src/render/function.rs +++ b/crates/ide-completion/src/render/function.rs @@ -79,6 +79,11 @@ fn render( .and_then(|trait_| trait_.containing_trait_or_trait_impl(ctx.db())) .map_or(false, |trait_| completion.is_ops_trait(trait_)); + let is_item_from_notable_trait = func + .as_assoc_item(ctx.db()) + .and_then(|trait_| trait_.containing_trait(ctx.db())) + .map_or(false, |trait_| completion.is_doc_notable_trait(trait_)); + let (has_dot_receiver, has_call_parens, cap) = match func_kind { FuncKind::Function(&PathCompletionCtx { kind: PathKind::Expr { .. }, @@ -105,6 +110,7 @@ fn render( }, exact_name_match: compute_exact_name_match(completion, &call), is_op_method, + is_item_from_notable_trait, ..ctx.completion_relevance() }); From 257870e09f0f56ce5e2588948b00e2bf04ce304c Mon Sep 17 00:00:00 2001 From: dfireBird Date: Wed, 10 Jan 2024 16:30:22 +0530 Subject: [PATCH 2/2] add tests to verify relevance of notable traits and some refactors --- crates/ide-completion/src/render.rs | 77 ++++++++++++++++++++ crates/ide-completion/src/render/function.rs | 16 ++-- 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index f924c9aedb60..8c0e6694761e 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -2443,4 +2443,81 @@ impl S { "#, ) } + + #[test] + fn notable_traits_method_relevance() { + check_kinds( + r#" +#[doc(notable_trait)] +trait Write { + fn write(&self); + fn flush(&self); +} + +struct Writer; + +impl Write for Writer { + fn write(&self) {} + fn flush(&self) {} +} + +fn main() { + Writer.$0 +} +"#, + &[ + CompletionItemKind::Method, + CompletionItemKind::SymbolKind(SymbolKind::Field), + CompletionItemKind::SymbolKind(SymbolKind::Function), + ], + expect![[r#" + [ + CompletionItem { + label: "flush()", + source_range: 193..193, + delete: 193..193, + insert: "flush()$0", + kind: Method, + lookup: "flush", + detail: "fn(&self)", + relevance: CompletionRelevance { + exact_name_match: false, + type_match: None, + is_local: false, + is_item_from_trait: false, + is_item_from_notable_trait: true, + is_name_already_imported: false, + requires_import: false, + is_op_method: false, + is_private_editable: false, + postfix_match: None, + is_definite: false, + }, + }, + CompletionItem { + label: "write()", + source_range: 193..193, + delete: 193..193, + insert: "write()$0", + kind: Method, + lookup: "write", + detail: "fn(&self)", + relevance: CompletionRelevance { + exact_name_match: false, + type_match: None, + is_local: false, + is_item_from_trait: false, + is_item_from_notable_trait: true, + is_name_already_imported: false, + requires_import: false, + is_op_method: false, + is_private_editable: false, + postfix_match: None, + is_definite: false, + }, + }, + ] + "#]], + ); + } } diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs index ccd312b03fb7..6ad84eba33be 100644 --- a/crates/ide-completion/src/render/function.rs +++ b/crates/ide-completion/src/render/function.rs @@ -74,15 +74,13 @@ fn render( ); let ret_type = func.ret_type(db); - let is_op_method = func - .as_assoc_item(ctx.db()) - .and_then(|trait_| trait_.containing_trait_or_trait_impl(ctx.db())) - .map_or(false, |trait_| completion.is_ops_trait(trait_)); + let assoc_item = func.as_assoc_item(db); - let is_item_from_notable_trait = func - .as_assoc_item(ctx.db()) - .and_then(|trait_| trait_.containing_trait(ctx.db())) - .map_or(false, |trait_| completion.is_doc_notable_trait(trait_)); + let trait_ = assoc_item.and_then(|trait_| trait_.containing_trait_or_trait_impl(db)); + let is_op_method = trait_.map_or(false, |trait_| completion.is_ops_trait(trait_)); + + let is_item_from_notable_trait = + trait_.map_or(false, |trait_| completion.is_doc_notable_trait(trait_)); let (has_dot_receiver, has_call_parens, cap) = match func_kind { FuncKind::Function(&PathCompletionCtx { @@ -147,7 +145,7 @@ fn render( item.add_import(import_to_add); } None => { - if let Some(actm) = func.as_assoc_item(db) { + if let Some(actm) = assoc_item { if let Some(trt) = actm.containing_trait_or_trait_impl(db) { item.trait_name(trt.name(db).to_smol_str()); }