Skip to content

Commit da96fff

Browse files
authored
Merge pull request rust-lang#19072 from cessen/concat_uniquely
Fix rust-lang#19071: ensure `completion_item_hash` serializes items uniquely
2 parents 9c30fec + 7ffccb0 commit da96fff

File tree

1 file changed

+51
-25
lines changed
  • src/tools/rust-analyzer/crates/rust-analyzer/src

1 file changed

+51
-25
lines changed

src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs

+51-25
Original file line numberDiff line numberDiff line change
@@ -79,32 +79,34 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
7979
u8::from(relevance.requires_import),
8080
u8::from(relevance.is_private_editable),
8181
]);
82-
if let Some(type_match) = &relevance.type_match {
83-
let label = match type_match {
84-
CompletionRelevanceTypeMatch::CouldUnify => "could_unify",
85-
CompletionRelevanceTypeMatch::Exact => "exact",
86-
};
87-
hasher.update(label);
82+
83+
match relevance.type_match {
84+
None => hasher.update([0u8]),
85+
Some(CompletionRelevanceTypeMatch::CouldUnify) => hasher.update([1u8]),
86+
Some(CompletionRelevanceTypeMatch::Exact) => hasher.update([2u8]),
8887
}
88+
89+
hasher.update([u8::from(relevance.trait_.is_some())]);
8990
if let Some(trait_) = &relevance.trait_ {
9091
hasher.update([u8::from(trait_.is_op_method), u8::from(trait_.notable_trait)]);
9192
}
92-
if let Some(postfix_match) = &relevance.postfix_match {
93-
let label = match postfix_match {
94-
CompletionRelevancePostfixMatch::NonExact => "non_exact",
95-
CompletionRelevancePostfixMatch::Exact => "exact",
96-
};
97-
hasher.update(label);
93+
94+
match relevance.postfix_match {
95+
None => hasher.update([0u8]),
96+
Some(CompletionRelevancePostfixMatch::NonExact) => hasher.update([1u8]),
97+
Some(CompletionRelevancePostfixMatch::Exact) => hasher.update([2u8]),
9898
}
99+
100+
hasher.update([u8::from(relevance.function.is_some())]);
99101
if let Some(function) = &relevance.function {
100102
hasher.update([u8::from(function.has_params), u8::from(function.has_self_param)]);
101-
let label = match function.return_type {
102-
CompletionRelevanceReturnType::Other => "other",
103-
CompletionRelevanceReturnType::DirectConstructor => "direct_constructor",
104-
CompletionRelevanceReturnType::Constructor => "constructor",
105-
CompletionRelevanceReturnType::Builder => "builder",
103+
let discriminant: u8 = match function.return_type {
104+
CompletionRelevanceReturnType::Other => 0,
105+
CompletionRelevanceReturnType::DirectConstructor => 1,
106+
CompletionRelevanceReturnType::Constructor => 2,
107+
CompletionRelevanceReturnType::Builder => 3,
106108
};
107-
hasher.update(label);
109+
hasher.update([discriminant]);
108110
}
109111
}
110112

@@ -115,35 +117,59 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
115117
u8::from(item.deprecated),
116118
u8::from(item.trigger_call_info),
117119
]);
120+
121+
hasher.update(item.label.primary.len().to_ne_bytes());
118122
hasher.update(&item.label.primary);
123+
124+
hasher.update([u8::from(item.label.detail_left.is_some())]);
119125
if let Some(label_detail) = &item.label.detail_left {
126+
hasher.update(label_detail.len().to_ne_bytes());
120127
hasher.update(label_detail);
121128
}
129+
130+
hasher.update([u8::from(item.label.detail_right.is_some())]);
122131
if let Some(label_detail) = &item.label.detail_right {
132+
hasher.update(label_detail.len().to_ne_bytes());
123133
hasher.update(label_detail);
124134
}
135+
125136
// NB: do not hash edits or source range, as those may change between the time the client sends the resolve request
126137
// and the time it receives it: some editors do allow changing the buffer between that, leading to ranges being different.
127138
//
128139
// Documentation hashing is skipped too, as it's a large blob to process,
129140
// while not really making completion properties more unique as they are already.
130-
hasher.update(item.kind.tag());
141+
142+
let kind_tag = item.kind.tag();
143+
hasher.update(kind_tag.len().to_ne_bytes());
144+
hasher.update(kind_tag);
145+
146+
hasher.update(item.lookup.len().to_ne_bytes());
131147
hasher.update(&item.lookup);
148+
149+
hasher.update([u8::from(item.detail.is_some())]);
132150
if let Some(detail) = &item.detail {
151+
hasher.update(detail.len().to_ne_bytes());
133152
hasher.update(detail);
134153
}
154+
135155
hash_completion_relevance(&mut hasher, &item.relevance);
156+
157+
hasher.update([u8::from(item.ref_match.is_some())]);
136158
if let Some((ref_mode, text_size)) = &item.ref_match {
137-
let prefix = match ref_mode {
138-
CompletionItemRefMode::Reference(Mutability::Shared) => "&",
139-
CompletionItemRefMode::Reference(Mutability::Mut) => "&mut ",
140-
CompletionItemRefMode::Dereference => "*",
159+
let discriminant = match ref_mode {
160+
CompletionItemRefMode::Reference(Mutability::Shared) => 0u8,
161+
CompletionItemRefMode::Reference(Mutability::Mut) => 1u8,
162+
CompletionItemRefMode::Dereference => 2u8,
141163
};
142-
hasher.update(prefix);
143-
hasher.update(u32::from(*text_size).to_le_bytes());
164+
hasher.update([discriminant]);
165+
hasher.update(u32::from(*text_size).to_ne_bytes());
144166
}
167+
168+
hasher.update(item.import_to_add.len().to_ne_bytes());
145169
for import_path in &item.import_to_add {
170+
hasher.update(import_path.len().to_ne_bytes());
146171
hasher.update(import_path);
147172
}
173+
148174
hasher.finalize()
149175
}

0 commit comments

Comments
 (0)