about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLaurențiu Nicola <lnicola@users.noreply.github.com>2025-01-30 08:15:31 +0000
committerGitHub <noreply@github.com>2025-01-30 08:15:31 +0000
commitda96fffce02ef8ecf788b1626d6338d024f78be8 (patch)
treee225dc778352f65d41306d0ce0e8260a52b62439
parent9c30fecf09305728f9fce186c7d8f8a7d2209ce9 (diff)
parent7ffccb03468d5573da2b4ff2587e953346e05bf3 (diff)
downloadrust-da96fffce02ef8ecf788b1626d6338d024f78be8.tar.gz
rust-da96fffce02ef8ecf788b1626d6338d024f78be8.zip
Merge pull request #19072 from cessen/concat_uniquely
Fix #19071: ensure `completion_item_hash` serializes items uniquely
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs76
1 files changed, 51 insertions, 25 deletions
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index 02361a22328..1221f7c7012 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -79,32 +79,34 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
             u8::from(relevance.requires_import),
             u8::from(relevance.is_private_editable),
         ]);
-        if let Some(type_match) = &relevance.type_match {
-            let label = match type_match {
-                CompletionRelevanceTypeMatch::CouldUnify => "could_unify",
-                CompletionRelevanceTypeMatch::Exact => "exact",
-            };
-            hasher.update(label);
+
+        match relevance.type_match {
+            None => hasher.update([0u8]),
+            Some(CompletionRelevanceTypeMatch::CouldUnify) => hasher.update([1u8]),
+            Some(CompletionRelevanceTypeMatch::Exact) => hasher.update([2u8]),
         }
+
+        hasher.update([u8::from(relevance.trait_.is_some())]);
         if let Some(trait_) = &relevance.trait_ {
             hasher.update([u8::from(trait_.is_op_method), u8::from(trait_.notable_trait)]);
         }
-        if let Some(postfix_match) = &relevance.postfix_match {
-            let label = match postfix_match {
-                CompletionRelevancePostfixMatch::NonExact => "non_exact",
-                CompletionRelevancePostfixMatch::Exact => "exact",
-            };
-            hasher.update(label);
+
+        match relevance.postfix_match {
+            None => hasher.update([0u8]),
+            Some(CompletionRelevancePostfixMatch::NonExact) => hasher.update([1u8]),
+            Some(CompletionRelevancePostfixMatch::Exact) => hasher.update([2u8]),
         }
+
+        hasher.update([u8::from(relevance.function.is_some())]);
         if let Some(function) = &relevance.function {
             hasher.update([u8::from(function.has_params), u8::from(function.has_self_param)]);
-            let label = match function.return_type {
-                CompletionRelevanceReturnType::Other => "other",
-                CompletionRelevanceReturnType::DirectConstructor => "direct_constructor",
-                CompletionRelevanceReturnType::Constructor => "constructor",
-                CompletionRelevanceReturnType::Builder => "builder",
+            let discriminant: u8 = match function.return_type {
+                CompletionRelevanceReturnType::Other => 0,
+                CompletionRelevanceReturnType::DirectConstructor => 1,
+                CompletionRelevanceReturnType::Constructor => 2,
+                CompletionRelevanceReturnType::Builder => 3,
             };
-            hasher.update(label);
+            hasher.update([discriminant]);
         }
     }
 
@@ -115,35 +117,59 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
         u8::from(item.deprecated),
         u8::from(item.trigger_call_info),
     ]);
+
+    hasher.update(item.label.primary.len().to_ne_bytes());
     hasher.update(&item.label.primary);
+
+    hasher.update([u8::from(item.label.detail_left.is_some())]);
     if let Some(label_detail) = &item.label.detail_left {
+        hasher.update(label_detail.len().to_ne_bytes());
         hasher.update(label_detail);
     }
+
+    hasher.update([u8::from(item.label.detail_right.is_some())]);
     if let Some(label_detail) = &item.label.detail_right {
+        hasher.update(label_detail.len().to_ne_bytes());
         hasher.update(label_detail);
     }
+
     // NB: do not hash edits or source range, as those may change between the time the client sends the resolve request
     // and the time it receives it: some editors do allow changing the buffer between that, leading to ranges being different.
     //
     // Documentation hashing is skipped too, as it's a large blob to process,
     // while not really making completion properties more unique as they are already.
-    hasher.update(item.kind.tag());
+
+    let kind_tag = item.kind.tag();
+    hasher.update(kind_tag.len().to_ne_bytes());
+    hasher.update(kind_tag);
+
+    hasher.update(item.lookup.len().to_ne_bytes());
     hasher.update(&item.lookup);
+
+    hasher.update([u8::from(item.detail.is_some())]);
     if let Some(detail) = &item.detail {
+        hasher.update(detail.len().to_ne_bytes());
         hasher.update(detail);
     }
+
     hash_completion_relevance(&mut hasher, &item.relevance);
+
+    hasher.update([u8::from(item.ref_match.is_some())]);
     if let Some((ref_mode, text_size)) = &item.ref_match {
-        let prefix = match ref_mode {
-            CompletionItemRefMode::Reference(Mutability::Shared) => "&",
-            CompletionItemRefMode::Reference(Mutability::Mut) => "&mut ",
-            CompletionItemRefMode::Dereference => "*",
+        let discriminant = match ref_mode {
+            CompletionItemRefMode::Reference(Mutability::Shared) => 0u8,
+            CompletionItemRefMode::Reference(Mutability::Mut) => 1u8,
+            CompletionItemRefMode::Dereference => 2u8,
         };
-        hasher.update(prefix);
-        hasher.update(u32::from(*text_size).to_le_bytes());
+        hasher.update([discriminant]);
+        hasher.update(u32::from(*text_size).to_ne_bytes());
     }
+
+    hasher.update(item.import_to_add.len().to_ne_bytes());
     for import_path in &item.import_to_add {
+        hasher.update(import_path.len().to_ne_bytes());
         hasher.update(import_path);
     }
+
     hasher.finalize()
 }