diff --git a/crates/ra_ide_api/src/completion/complete_record_literal.rs b/crates/ra_ide_api/src/completion/complete_record_literal.rs index 4406695d5179..0295b8101373 100644 --- a/crates/ra_ide_api/src/completion/complete_record_literal.rs +++ b/crates/ra_ide_api/src/completion/complete_record_literal.rs @@ -31,6 +31,34 @@ fn complete(code: &str) -> Vec { do_completion(code, CompletionKind::Reference) } + #[test] + fn test_record_literal_deprecated_field() { + let completions = complete( + r" + struct A { + #[deprecated] + the_field: u32, + } + fn foo() { + A { the<|> } + } + ", + ); + assert_debug_snapshot!(completions, @r###" + ⋮[ + ⋮ CompletionItem { + ⋮ label: "the_field", + ⋮ source_range: [142; 145), + ⋮ delete: [142; 145), + ⋮ insert: "the_field", + ⋮ kind: Field, + ⋮ detail: "u32", + ⋮ deprecated: true, + ⋮ }, + ⋮] + "###); + } + #[test] fn test_record_literal_field() { let completions = complete( diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs index 5c9c44704b3b..93f336370915 100644 --- a/crates/ra_ide_api/src/completion/completion_item.rs +++ b/crates/ra_ide_api/src/completion/completion_item.rs @@ -44,6 +44,9 @@ pub struct CompletionItem { /// Additional info to show in the UI pop up. detail: Option, documentation: Option, + + /// Whether this item is marked as deprecated + deprecated: bool, } // We use custom debug for CompletionItem to make `insta`'s diffs more readable. @@ -70,6 +73,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Some(documentation) = self.documentation() { s.field("documentation", &documentation); } + if self.deprecated { + s.field("deprecated", &true); + } s.finish() } } @@ -132,6 +138,7 @@ pub(crate) fn new( lookup: None, kind: None, text_edit: None, + deprecated: None, } } /// What user sees in pop-up in the UI. @@ -166,6 +173,10 @@ pub fn lookup(&self) -> &str { pub fn kind(&self) -> Option { self.kind } + + pub fn deprecated(&self) -> bool { + self.deprecated + } } /// A helper to make `CompletionItem`s. @@ -181,6 +192,7 @@ pub(crate) struct Builder { lookup: Option, kind: Option, text_edit: Option, + deprecated: Option, } impl Builder { @@ -208,6 +220,7 @@ pub(crate) fn build(self) -> CompletionItem { lookup: self.lookup, kind: self.kind, completion_kind: self.completion_kind, + deprecated: self.deprecated.unwrap_or(false), } } pub(crate) fn lookup_by(mut self, lookup: impl Into) -> Builder { @@ -254,6 +267,10 @@ pub(crate) fn set_documentation(mut self, docs: Option) -> Builde self.documentation = docs.map(Into::into); self } + pub(crate) fn set_deprecated(mut self, deprecated: bool) -> Builder { + self.deprecated = Some(deprecated); + self + } } impl<'a> Into for Builder { diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index 65bb639ed508..cb55d18751b3 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs @@ -2,7 +2,7 @@ use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; use join_to_string::join; -use ra_syntax::ast::NameOwner; +use ra_syntax::ast::{AttrsOwner, NameOwner}; use test_utils::tested_by; use crate::completion::{ @@ -18,6 +18,11 @@ pub(crate) fn add_field( field: hir::StructField, substs: &hir::Substs, ) { + let ast_node = field.source(ctx.db).ast; + let is_deprecated = match ast_node { + hir::FieldSource::Named(m) => is_deprecated(m), + hir::FieldSource::Pos(m) => is_deprecated(m), + }; CompletionItem::new( CompletionKind::Reference, ctx.source_range(), @@ -26,6 +31,7 @@ pub(crate) fn add_field( .kind(CompletionItemKind::Field) .detail(field.ty(ctx.db).subst(substs).display(ctx.db).to_string()) .set_documentation(field.docs(ctx.db)) + .set_deprecated(is_deprecated) .add_to(self); } @@ -179,6 +185,7 @@ pub(crate) fn add_macro( CompletionItem::new(CompletionKind::Reference, ctx.source_range(), ¯o_declaration) .kind(CompletionItemKind::Macro) .set_documentation(docs.clone()) + .set_deprecated(is_deprecated(ast_node)) .detail(detail); builder = if ctx.use_item_syntax.is_some() { @@ -211,6 +218,7 @@ fn add_function_with_name( CompletionItemKind::Function }) .set_documentation(func.docs(ctx.db)) + .set_deprecated(is_deprecated(ast_node)) .detail(detail); // Add `<>` for generic types @@ -242,6 +250,7 @@ pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) .kind(CompletionItemKind::Const) .set_documentation(constant.docs(ctx.db)) + .set_deprecated(is_deprecated(ast_node)) .detail(detail) .add_to(self); } @@ -257,11 +266,13 @@ pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) .kind(CompletionItemKind::TypeAlias) .set_documentation(type_alias.docs(ctx.db)) + .set_deprecated(is_deprecated(type_def)) .detail(detail) .add_to(self); } pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { + let is_deprecated = is_deprecated(variant.source(ctx.db).ast); let name = match variant.name(ctx.db) { Some(it) => it, None => return, @@ -274,11 +285,16 @@ pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir: CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) .kind(CompletionItemKind::EnumVariant) .set_documentation(variant.docs(ctx.db)) + .set_deprecated(is_deprecated) .detail(detail) .add_to(self); } } +fn is_deprecated(node: impl AttrsOwner) -> bool { + node.attrs().filter_map(|x| x.simple_name()).any(|x| x == "deprecated") +} + fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { let subst = db.generic_defaults(def); subst.iter().any(|ty| ty == &Ty::Unknown) @@ -295,6 +311,56 @@ fn do_reference_completion(code: &str) -> Vec { do_completion(code, CompletionKind::Reference) } + #[test] + fn sets_deprecated_flag_in_completion_items() { + assert_debug_snapshot!( + do_reference_completion( + r#" + #[deprecated] + fn something_deprecated() {} + + #[deprecated(since = "1.0.0")] + fn something_else_deprecated() {} + + fn main() { som<|> } + "#, + ), + @r###" + [ + CompletionItem { + label: "main()", + source_range: [203; 206), + delete: [203; 206), + insert: "main()$0", + kind: Function, + lookup: "main", + detail: "fn main()", + }, + CompletionItem { + label: "something_deprecated()", + source_range: [203; 206), + delete: [203; 206), + insert: "something_deprecated()$0", + kind: Function, + lookup: "something_deprecated", + detail: "fn something_deprecated()", + deprecated: true, + }, + CompletionItem { + label: "something_else_deprecated()", + source_range: [203; 206), + delete: [203; 206), + insert: "something_else_deprecated()$0", + kind: Function, + lookup: "something_else_deprecated", + detail: "fn something_else_deprecated()", + deprecated: true, + }, + ] + "### + ); + } + #[test] fn inserts_parens_for_function_calls() { covers!(inserts_parens_for_function_calls); diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index ee503633d7ee..94ed619faeca 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -127,6 +127,7 @@ fn conv_with(self, ctx: (&LineIndex, LineEndings)) -> ::lsp_types::CompletionIte text_edit: Some(text_edit), additional_text_edits: Some(additional_text_edits), documentation: self.documentation().map(|it| it.conv()), + deprecated: Some(self.deprecated()), ..Default::default() }; res.insert_text_format = Some(match self.insert_text_format() {