From e4d3b8f6b4045fa1c963a4da46e75fad3e95c3b7 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 18 Mar 2026 21:40:44 +0100 Subject: [PATCH 1/4] misc improvements --- crates/ide-completion/src/context/analysis.rs | 10 ++--- crates/ide-completion/src/render.rs | 41 +++++++++++-------- crates/ide-db/src/imports/import_assets.rs | 2 +- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 58c0f683a344..c8068d6fc4da 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -2094,12 +2094,12 @@ fn next_non_trivia_token(e: impl Into) -> Option { } fn next_non_trivia_sibling(ele: SyntaxElement) -> Option { - let mut e = ele.next_sibling_or_token(); - while let Some(inner) = e { - if !inner.kind().is_trivia() { - return Some(inner); + let mut e = ele; + while let Some(next) = e.next_sibling_or_token() { + if !next.kind().is_trivia() { + return Some(next); } else { - e = inner.next_sibling_or_token(); + e = next; } } None diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index a636c0603ba5..7e6e76541e7a 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -828,7 +828,7 @@ mod tests { items.push(format!( "{tag} {} {} {relevance}\n", it.label.primary, - it.label.detail_right.clone().unwrap_or_default(), + it.label.detail_right.as_deref().unwrap_or_default(), )); if let Some((label, _indel, relevance)) = it.ref_match() { @@ -844,24 +844,31 @@ mod tests { expect.assert_eq(&actual); fn display_relevance(relevance: CompletionRelevance) -> String { - let relevance_factors = vec![ - (relevance.type_match == Some(CompletionRelevanceTypeMatch::Exact), "type"), - ( - relevance.type_match == Some(CompletionRelevanceTypeMatch::CouldUnify), - "type_could_unify", - ), - (relevance.exact_name_match, "name"), - (relevance.is_local, "local"), - ( - relevance.postfix_match == Some(CompletionRelevancePostfixMatch::Exact), - "snippet", - ), - (relevance.trait_.is_some_and(|it| it.is_op_method), "op_method"), - (relevance.requires_import, "requires_import"), - (relevance.has_local_inherent_impl, "has_local_inherent_impl"), + let CompletionRelevance { + exact_name_match, + type_match, + is_local, + trait_, + is_name_already_imported: _, + requires_import, + is_private_editable: _, + postfix_match, + function: _, + is_skipping_completion: _, + has_local_inherent_impl, + } = relevance; + let relevance_factors = [ + (type_match == Some(CompletionRelevanceTypeMatch::Exact), "type"), + (type_match == Some(CompletionRelevanceTypeMatch::CouldUnify), "type_could_unify"), + (exact_name_match, "name"), + (is_local, "local"), + (postfix_match == Some(CompletionRelevancePostfixMatch::Exact), "snippet"), + (trait_.is_some_and(|it| it.is_op_method), "op_method"), + (requires_import, "requires_import"), + (has_local_inherent_impl, "has_local_inherent_impl"), ] .into_iter() - .filter_map(|(cond, desc)| if cond { Some(desc) } else { None }) + .filter_map(|(cond, desc)| cond.then_some(desc)) .join("+"); format!("[{relevance_factors}]") diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs index 9018552afb4d..4f05714a556a 100644 --- a/crates/ide-db/src/imports/import_assets.rs +++ b/crates/ide-db/src/imports/import_assets.rs @@ -314,7 +314,7 @@ pub struct LocatedImport { pub item_to_import: ItemInNs, /// The path import candidate, resolved. /// - /// Not necessary matches the import: + /// Not necessarily matches the import: /// For any associated constant from the trait, we try to access as `some::path::SomeStruct::ASSOC_` /// the original item is the associated constant, but the import has to be a trait that /// defines this constant. From 378914c310bc87b98b91f1f042f70b7f259697fc Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Tue, 17 Mar 2026 23:32:56 +0100 Subject: [PATCH 2/4] Add test --- crates/ide-completion/src/render.rs | 19 +++++++++++++++++++ crates/test-utils/src/minicore.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 7e6e76541e7a..607ca6ff54f4 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -3647,6 +3647,25 @@ fn f() { ); } + #[test] + /// Issue: https://github.com/rust-lang/rust-analyzer/issues/18554 + fn float_consts_relevance() { + check_relevance( + r#" +//- minicore: float_consts +fn main() { + let x = f32::INF$0 +} +"#, + expect![[r#" + ct INFINITY f32 [type_could_unify+requires_import] + ct NEG_INFINITY f32 [type_could_unify+requires_import] + ct INFINITY pub const INFINITY: f32 [] + ct NEG_INFINITY pub const NEG_INFINITY: f32 [] + "#]], + ); + } + #[test] fn completes_struct_with_raw_identifier() { check_edit( diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 86fb08073253..85bd821ebbd2 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -33,6 +33,7 @@ //! env: option //! eq: sized //! error: fmt +//! float_consts: //! fmt: option, result, transmute, coerce_unsized, copy, clone, derive //! fmt_before_1_93_0: fmt //! fmt_before_1_89_0: fmt_before_1_93_0 @@ -2173,6 +2174,32 @@ pub mod error { } // endregion:error +// region:float_consts +impl f32 { + pub const INFINITY: f32 = 0.0; + pub const NEG_INFINITY: f32 = -0.0; +} + +impl f64 { + pub const INFINITY: f64 = 0.0; + pub const NEG_INFINITY: f64 = -0.0; +} + +pub mod f32 { + #[deprecated] + pub const INFINITY: f32 = 0.0; + #[deprecated] + pub const NEG_INFINITY: f32 = -0.0; +} + +pub mod f64 { + #[deprecated] + pub const INFINITY: f64 = 0.0; + #[deprecated] + pub const NEG_INFINITY: f64 = -0.0; +} +// endregion:float_consts + // region:column #[rustc_builtin_macro] #[macro_export] From 60cc5f2504e9672be375ba5bef5890ddabe94480 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 15 Apr 2026 15:09:54 +0200 Subject: [PATCH 3/4] Duplicate `CompletionItem.deprecated` as `CompletionRelevance.is_deprecated` This also adds `deprecated` reconciliation logic to `Builder` --- crates/ide-completion/src/item.rs | 41 +++++++- crates/ide-completion/src/render.rs | 150 +++++++++++++++++++++++++++- 2 files changed, 187 insertions(+), 4 deletions(-) diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs index 62211a808ca6..da0bdcff0131 100644 --- a/crates/ide-completion/src/item.rs +++ b/crates/ide-completion/src/item.rs @@ -61,6 +61,9 @@ pub struct CompletionItem { pub documentation: Option>, /// Whether this item is marked as deprecated + /// + /// NOTE: this field is used in the LSP protocol. For the use of this information in completion + /// scoring, see [`CompletionRelevance::is_deprecated`]. pub deprecated: bool, /// If completing a function call, ask the editor to show parameter popup @@ -186,6 +189,11 @@ pub struct CompletionRelevance { pub is_skipping_completion: bool, /// if inherent impl already exists in current module, user may not want to implement it again. pub has_local_inherent_impl: bool, + /// Set when the completion item is deprecated. + /// + /// NOTE: This is duplicated from [`CompletionItem::deprecated`] in order to allow using this + /// information in the calculation of the relevance score. + pub is_deprecated: bool, } #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub struct CompletionRelevanceTraitInfo { @@ -278,6 +286,7 @@ impl CompletionRelevance { function, is_skipping_completion, has_local_inherent_impl, + is_deprecated: _, } = self; // only applicable for completions within use items @@ -582,6 +591,9 @@ impl Builder { None => TextEdit::replace(self.source_range, insert_text), }; + // Copy `deprecated` to `self.relevance.is_deprecated` + let relevance = CompletionRelevance { is_deprecated: self.deprecated, ..self.relevance }; + let import_to_add = self .imports_to_add .into_iter() @@ -603,7 +615,7 @@ impl Builder { kind: self.kind, deprecated: self.deprecated, trigger_call_info: self.trigger_call_info, - relevance: self.relevance, + relevance, ref_match: self.ref_match, import_to_add, } @@ -674,6 +686,15 @@ impl Builder { self } pub(crate) fn set_relevance(&mut self, relevance: CompletionRelevance) -> &mut Builder { + // The default value of `CompletionRelevance.is_deprecated` is `false`, so it being `true` + // would mean it was set manually. Advise using the other function instead. + // + // This is technically not necessary, because `deprecated` will get reconciled in + // `Builder::build` anyway -- it just helps keep the callers consistent. + assert!( + !relevance.is_deprecated, + "`deprecated` should be set using `Builder::set_deprecated` instead" + ); self.relevance = relevance; self } @@ -708,9 +729,25 @@ mod tests { use test_utils::assert_eq_text; use super::{ - CompletionRelevance, CompletionRelevancePostfixMatch, CompletionRelevanceTypeMatch, + CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch, + CompletionRelevanceTypeMatch, }; + #[test] + fn builder_deprecated_from_set_deprecated() { + // setting just `item.deprecated` also sets `item.relevance.is_deprecated` + let mut builder = CompletionItem::new( + CompletionItemKind::Expression, + Default::default(), + "", + syntax::Edition::DEFAULT, + ); + builder.set_deprecated(true); + let item = builder.build(&Default::default()); + assert!(item.deprecated); + assert!(item.relevance.is_deprecated); + } + /// Check that these are CompletionRelevance are sorted in ascending order /// by their relevance score. /// diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 607ca6ff54f4..9eaa63040a30 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -856,6 +856,7 @@ mod tests { function: _, is_skipping_completion: _, has_local_inherent_impl, + is_deprecated, } = relevance; let relevance_factors = [ (type_match == Some(CompletionRelevanceTypeMatch::Exact), "type"), @@ -866,6 +867,7 @@ mod tests { (trait_.is_some_and(|it| it.is_op_method), "op_method"), (requires_import, "requires_import"), (has_local_inherent_impl, "has_local_inherent_impl"), + (is_deprecated, "deprecated"), ] .into_iter() .filter_map(|(cond, desc)| cond.then_some(desc)) @@ -1249,6 +1251,7 @@ fn main() { Foo::Fo$0 } ), is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, trigger_call_info: true, }, @@ -1300,6 +1303,7 @@ fn main() { Foo::Fo$0 } ), is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, trigger_call_info: true, }, @@ -1444,6 +1448,7 @@ fn main() { Foo::Fo$0 } ), is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, trigger_call_info: true, }, @@ -1528,6 +1533,7 @@ fn main() { let _: m::Spam = S$0 } ), is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, trigger_call_info: true, }, @@ -1565,6 +1571,7 @@ fn main() { let _: m::Spam = S$0 } ), is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, trigger_call_info: true, }, @@ -1596,6 +1603,20 @@ fn main() { som$0 } Module, ), 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: None, + is_skipping_completion: false, + has_local_inherent_impl: false, + is_deprecated: true, + }, }, ] "#]], @@ -1641,6 +1662,20 @@ fn main() { som$0 } lookup: "something_deprecated", detail: "fn()", 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: None, + is_skipping_completion: false, + has_local_inherent_impl: false, + is_deprecated: true, + }, }, ] "#]], @@ -1670,6 +1705,20 @@ fn main() { A$0 } ), detail: "A", 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: None, + is_skipping_completion: false, + has_local_inherent_impl: false, + is_deprecated: true, + }, }, ] "#]], @@ -1699,6 +1748,20 @@ fn main() { A$0 } ), detail: "A", 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: None, + is_skipping_completion: false, + has_local_inherent_impl: false, + is_deprecated: true, + }, }, ] "#]], @@ -1748,6 +1811,7 @@ fn main() { A::$0 } ), is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, trigger_call_info: true, }, @@ -1783,6 +1847,7 @@ fn main() { A::$0 } ), is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: true, }, trigger_call_info: true, }, @@ -1814,6 +1879,20 @@ fn main() { A$0 } ), detail: "i32", 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: None, + is_skipping_completion: false, + has_local_inherent_impl: false, + is_deprecated: true, + }, }, ] "#]], @@ -1843,6 +1922,20 @@ fn main() { A$0 } ), detail: "i32", 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: None, + is_skipping_completion: false, + has_local_inherent_impl: false, + is_deprecated: true, + }, }, ] "#]], @@ -1869,6 +1962,20 @@ impl A$0 Trait, ), 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: None, + is_skipping_completion: false, + has_local_inherent_impl: false, + is_deprecated: true, + }, }, ] "#]], @@ -1895,6 +2002,20 @@ fn main() { A$0 } TypeAlias, ), 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: None, + is_skipping_completion: false, + has_local_inherent_impl: false, + is_deprecated: true, + }, }, ] "#]], @@ -1925,6 +2046,20 @@ fn main() { a$0 } lookup: "a!", detail: "macro_rules! a", 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: None, + is_skipping_completion: false, + has_local_inherent_impl: false, + is_deprecated: true, + }, }, ] "#]], @@ -1967,6 +2102,7 @@ fn main() { A { the$0 } } function: None, is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: true, }, }, ] @@ -2027,6 +2163,7 @@ impl S { ), is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, }, CompletionItem { @@ -2119,6 +2256,7 @@ use self::E::*; ), is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, trigger_call_info: true, }, @@ -2190,6 +2328,7 @@ fn foo(s: S) { s.$0 } ), is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, }, ] @@ -2403,6 +2542,7 @@ fn f() -> i32 { function: None, is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, }, ] @@ -2509,6 +2649,7 @@ fn main() { function: None, is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, ref_match: "&@65", }, @@ -3306,6 +3447,7 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 } ), is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, ref_match: "&@107", }, @@ -3394,6 +3536,7 @@ fn foo() { function: None, is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, }, ] @@ -3453,6 +3596,7 @@ fn main() { ), is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, ref_match: "&@92", }, @@ -3658,8 +3802,8 @@ fn main() { } "#, expect![[r#" - ct INFINITY f32 [type_could_unify+requires_import] - ct NEG_INFINITY f32 [type_could_unify+requires_import] + ct INFINITY f32 [type_could_unify+requires_import+deprecated] + ct NEG_INFINITY f32 [type_could_unify+requires_import+deprecated] ct INFINITY pub const INFINITY: f32 [] ct NEG_INFINITY pub const NEG_INFINITY: f32 [] "#]], @@ -3943,6 +4087,7 @@ fn main() { function: None, is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, }, CompletionItem { @@ -3978,6 +4123,7 @@ fn main() { function: None, is_skipping_completion: false, has_local_inherent_impl: false, + is_deprecated: false, }, }, ] From 24dca9fd90eec75a051cdb7784446b484fe65386 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 9 Apr 2026 12:05:11 +0200 Subject: [PATCH 4/4] Reduce completion score for deprecated items --- crates/ide-completion/src/item.rs | 7 ++++++- crates/ide-completion/src/render.rs | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs index da0bdcff0131..a138273e7fae 100644 --- a/crates/ide-completion/src/item.rs +++ b/crates/ide-completion/src/item.rs @@ -286,7 +286,7 @@ impl CompletionRelevance { function, is_skipping_completion, has_local_inherent_impl, - is_deprecated: _, + is_deprecated, } = self; // only applicable for completions within use items @@ -363,6 +363,11 @@ impl CompletionRelevance { score -= 5; } + // lower rank for deprecated items + if is_deprecated { + score -= 5; + } + score } diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 9eaa63040a30..608dec1285dc 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -3802,10 +3802,10 @@ fn main() { } "#, expect![[r#" - ct INFINITY f32 [type_could_unify+requires_import+deprecated] - ct NEG_INFINITY f32 [type_could_unify+requires_import+deprecated] ct INFINITY pub const INFINITY: f32 [] ct NEG_INFINITY pub const NEG_INFINITY: f32 [] + ct INFINITY f32 [type_could_unify+requires_import+deprecated] + ct NEG_INFINITY f32 [type_could_unify+requires_import+deprecated] "#]], ); }