about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-08-02 13:39:58 +0000
committerbors <bors@rust-lang.org>2023-08-02 13:39:58 +0000
commit2f2cf21da5813cefed66e2c33776bf0a6a4a9539 (patch)
tree514ec83ad2afb38f51bba8ae70247514a8379bce
parent30f526c598bae843d988c83fe0f665d6a2038476 (diff)
parenta743903cf06dfc8b55cd71840895b453a16cf0ae (diff)
downloadrust-2f2cf21da5813cefed66e2c33776bf0a6a4a9539.tar.gz
rust-2f2cf21da5813cefed66e2c33776bf0a6a4a9539.zip
Auto merge of #15348 - max-heller:issue-14692, r=lowr
Exclude non-identifier aliases from completion filtering text

When building `CompletionItem`s, this excludes aliases that aren't valid identifiers from the "lookup" text used to filter completions in the LSP client. Including them results in weird completion filtering behavior e.g. `Partial>` matching a completion for the `PartialOrd` trait because it has a doc alias of ">".

Closes #14692
-rw-r--r--crates/ide-completion/src/item.rs21
-rw-r--r--crates/ide-completion/src/tests/special.rs23
2 files changed, 42 insertions, 2 deletions
diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs
index e850f7bfdf3..0309952c29a 100644
--- a/crates/ide-completion/src/item.rs
+++ b/crates/ide-completion/src/item.rs
@@ -427,9 +427,26 @@ impl Builder {
         let insert_text = self.insert_text.unwrap_or_else(|| label.to_string());
 
         if !self.doc_aliases.is_empty() {
-            let doc_aliases = self.doc_aliases.into_iter().join(", ");
+            let doc_aliases = self.doc_aliases.iter().join(", ");
             label = SmolStr::from(format!("{label} (alias {doc_aliases})"));
-            lookup = SmolStr::from(format!("{lookup} {doc_aliases}"));
+            let lookup_doc_aliases = self
+                .doc_aliases
+                .iter()
+                // Don't include aliases in `lookup` that aren't valid identifiers as including
+                // them results in weird completion filtering behavior e.g. `Partial>` matching
+                // `PartialOrd` because it has an alias of ">".
+                .filter(|alias| {
+                    let mut chars = alias.chars();
+                    chars.next().is_some_and(char::is_alphabetic)
+                        && chars.all(|c| c.is_alphanumeric() || c == '_')
+                })
+                // Deliberately concatenated without separators as adding separators e.g.
+                // `alias1, alias2` results in LSP clients continuing to display the completion even
+                // after typing a comma or space.
+                .join("");
+            if !lookup_doc_aliases.is_empty() {
+                lookup = SmolStr::from(format!("{lookup}{lookup_doc_aliases}"));
+            }
         }
         if let [import_edit] = &*self.imports_to_add {
             // snippets can have multiple imports, but normal completions only have up to one
diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs
index 3824720839e..e80a289049f 100644
--- a/crates/ide-completion/src/tests/special.rs
+++ b/crates/ide-completion/src/tests/special.rs
@@ -1280,3 +1280,26 @@ fn here_we_go() {
         "#]],
     );
 }
+
+#[test]
+fn completion_filtering_excludes_non_identifier_doc_aliases() {
+    check_edit(
+        "PartialOrdcmporder",
+        r#"
+#[doc(alias = ">")]
+#[doc(alias = "cmp")]
+#[doc(alias = "order")]
+trait PartialOrd {}
+
+struct Foo<T: Partial$0
+"#,
+        r#"
+#[doc(alias = ">")]
+#[doc(alias = "cmp")]
+#[doc(alias = "order")]
+trait PartialOrd {}
+
+struct Foo<T: PartialOrd
+"#,
+    );
+}