Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/render.rs')
| -rw-r--r-- | crates/ide-completion/src/render.rs | 375 |
1 files changed, 348 insertions, 27 deletions
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index f14fd9221f..a636c0603b 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -92,27 +92,32 @@ impl<'a> RenderContext<'a> { && self.completion.token.parent().is_some_and(|it| it.kind() == SyntaxKind::MACRO_CALL) } - fn is_deprecated(&self, def: impl HasAttrs) -> bool { - def.attrs(self.db()).is_deprecated() - } - - fn is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool { + /// Whether `def` is deprecated. + /// + /// This can happen for two reasons: + /// - the def is marked with `#[deprecated]` + /// - the def is an assoc item whose trait is deprecated + /// + /// In order to be able to check for the latter, we'd ideally want to `try_as_dyn<_, dyn AsAssocItem>(def)` + /// (see [`try_as_dyn`][]), but that function is currently unstable. Therefore, we employ a hack instead: + /// if `def` can be an assoc item, it should be passed to this method as follows: + /// ```ignore + /// self.is_deprecated(def, Some(def)) + /// ``` + /// otherwise, it should be passed as: + /// ```ignore + /// self.is_deprecated(def, None) + /// ``` + /// + /// [`try_as_dyn`]: https://doc.rust-lang.org/std/any/fn.try_as_dyn.html + fn is_deprecated(&self, def: impl HasAttrs, def_as_assoc_item: Option<hir::AssocItem>) -> bool { let db = self.db(); - let assoc = match as_assoc_item.as_assoc_item(db) { - Some(assoc) => assoc, - None => return false, - }; - - let is_assoc_deprecated = match assoc { - hir::AssocItem::Function(it) => self.is_deprecated(it), - hir::AssocItem::Const(it) => self.is_deprecated(it), - hir::AssocItem::TypeAlias(it) => self.is_deprecated(it), - }; - is_assoc_deprecated - || assoc - .container_or_implemented_trait(db) - .map(|trait_| self.is_deprecated(trait_)) - .unwrap_or(false) + def.attrs(db).is_deprecated() + || def_as_assoc_item + .and_then(|assoc| assoc.container_or_implemented_trait(db)) + .is_some_and(|trait_| { + self.is_deprecated(trait_, None /* traits can't be assoc items */) + }) } // FIXME: remove this @@ -129,7 +134,7 @@ pub(crate) fn render_field( ty: &hir::Type<'_>, ) -> CompletionItem { let db = ctx.db(); - let is_deprecated = ctx.is_deprecated(field); + let is_deprecated = ctx.is_deprecated(field, None /* fields can't be assoc items */); let name = field.name(db); let (name, escaped_name) = (name.as_str().to_smolstr(), name.display_no_db(ctx.completion.edition).to_smolstr()); @@ -576,10 +581,15 @@ fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option<Documentati } fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: ScopeDef) -> bool { + let db = ctx.db(); match resolution { - ScopeDef::ModuleDef(it) => ctx.is_deprecated_assoc_item(it), - ScopeDef::GenericParam(it) => ctx.is_deprecated(it), - ScopeDef::AdtSelfType(it) => ctx.is_deprecated(it), + ScopeDef::ModuleDef(it) => ctx.is_deprecated(it, it.as_assoc_item(db)), + ScopeDef::GenericParam(it) => { + ctx.is_deprecated(it, None /* generic params can't be assoc items */) + } + ScopeDef::AdtSelfType(it) => { + ctx.is_deprecated(it, None /* `Self` can't be an assoc item */) + } _ => false, } } @@ -1561,6 +1571,32 @@ fn main() { let _: m::Spam = S$0 } check( r#" #[deprecated] +mod something_deprecated {} + +fn main() { som$0 } +"#, + SymbolKind::Module, + expect![[r#" + [ + CompletionItem { + label: "something_deprecated", + detail_left: None, + detail_right: None, + source_range: 55..58, + delete: 55..58, + insert: "something_deprecated", + kind: SymbolKind( + Module, + ), + deprecated: true, + }, + ] + "#]], + ); + + check( + r#" +#[deprecated] fn something_deprecated() {} fn main() { som$0 } @@ -1605,8 +1641,293 @@ fn main() { som$0 } check( r#" +#[deprecated] +struct A; + +fn main() { A$0 } +"#, + SymbolKind::Struct, + expect![[r#" + [ + CompletionItem { + label: "A", + detail_left: None, + detail_right: Some( + "A", + ), + source_range: 37..38, + delete: 37..38, + insert: "A", + kind: SymbolKind( + Struct, + ), + detail: "A", + deprecated: true, + }, + ] + "#]], + ); + + check( + r#" +#[deprecated] +enum A {} + +fn main() { A$0 } +"#, + SymbolKind::Enum, + expect![[r#" + [ + CompletionItem { + label: "A", + detail_left: None, + detail_right: Some( + "A", + ), + source_range: 37..38, + delete: 37..38, + insert: "A", + kind: SymbolKind( + Enum, + ), + detail: "A", + deprecated: true, + }, + ] + "#]], + ); + + check( + r#" +enum A { + Okay, + #[deprecated] + Old, +} + +fn main() { A::$0 } +"#, + SymbolKind::Variant, + expect![[r#" + [ + CompletionItem { + label: "Okay", + detail_left: None, + detail_right: Some( + "Okay", + ), + source_range: 64..64, + delete: 64..64, + insert: "Okay$0", + kind: SymbolKind( + Variant, + ), + detail: "Okay", + relevance: CompletionRelevance { + exact_name_match: false, + type_match: None, + is_local: false, + trait_: None, + is_name_already_imported: false, + requires_import: false, + is_private_editable: false, + postfix_match: None, + function: Some( + CompletionRelevanceFn { + has_params: false, + has_self_param: false, + return_type: DirectConstructor, + }, + ), + is_skipping_completion: false, + has_local_inherent_impl: false, + }, + trigger_call_info: true, + }, + CompletionItem { + label: "Old", + detail_left: None, + detail_right: Some( + "Old", + ), + source_range: 64..64, + delete: 64..64, + insert: "Old$0", + kind: SymbolKind( + Variant, + ), + detail: "Old", + deprecated: true, + relevance: CompletionRelevance { + exact_name_match: false, + type_match: None, + is_local: false, + trait_: None, + is_name_already_imported: false, + requires_import: false, + is_private_editable: false, + postfix_match: None, + function: Some( + CompletionRelevanceFn { + has_params: false, + has_self_param: false, + return_type: DirectConstructor, + }, + ), + is_skipping_completion: false, + has_local_inherent_impl: false, + }, + trigger_call_info: true, + }, + ] + "#]], + ); + + check( + r#" +#[deprecated] +const A: i32 = 0; + +fn main() { A$0 } +"#, + SymbolKind::Const, + expect![[r#" + [ + CompletionItem { + label: "A", + detail_left: None, + detail_right: Some( + "i32", + ), + source_range: 45..46, + delete: 45..46, + insert: "A", + kind: SymbolKind( + Const, + ), + detail: "i32", + deprecated: true, + }, + ] + "#]], + ); + + check( + r#" +#[deprecated] +static A: i32 = 0; + +fn main() { A$0 } +"#, + SymbolKind::Static, + expect![[r#" + [ + CompletionItem { + label: "A", + detail_left: None, + detail_right: Some( + "i32", + ), + source_range: 46..47, + delete: 46..47, + insert: "A", + kind: SymbolKind( + Static, + ), + detail: "i32", + deprecated: true, + }, + ] + "#]], + ); + + check( + r#" +#[deprecated] +trait A {} + +impl A$0 +"#, + SymbolKind::Trait, + expect![[r#" + [ + CompletionItem { + label: "A", + detail_left: None, + detail_right: None, + source_range: 31..32, + delete: 31..32, + insert: "A", + kind: SymbolKind( + Trait, + ), + deprecated: true, + }, + ] + "#]], + ); + + check( + r#" +#[deprecated] +type A = i32; + +fn main() { A$0 } +"#, + SymbolKind::TypeAlias, + expect![[r#" + [ + CompletionItem { + label: "A", + detail_left: None, + detail_right: None, + source_range: 41..42, + delete: 41..42, + insert: "A", + kind: SymbolKind( + TypeAlias, + ), + deprecated: true, + }, + ] + "#]], + ); + + check( + r#" +#[deprecated] +macro_rules! a { _ => {}} + +fn main() { a$0 } +"#, + SymbolKind::Macro, + expect![[r#" + [ + CompletionItem { + label: "a!(…)", + detail_left: None, + detail_right: Some( + "macro_rules! a", + ), + source_range: 53..54, + delete: 53..54, + insert: "a!($0)", + kind: SymbolKind( + Macro, + ), + lookup: "a!", + detail: "macro_rules! a", + deprecated: true, + }, + ] + "#]], + ); + + check( + r#" struct A { #[deprecated] the_field: u32 } -fn foo() { A { the$0 } } + +fn main() { A { the$0 } } "#, SymbolKind::Field, expect![[r#" @@ -1617,8 +1938,8 @@ fn foo() { A { the$0 } } detail_right: Some( "u32", ), - source_range: 57..60, - delete: 57..60, + source_range: 59..62, + delete: 59..62, insert: "the_field", kind: SymbolKind( Field, |