mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 12:04:43 +00:00 
			
		
		
		
	Merge pull request #19072 from cessen/concat_uniquely
Fix #19071: ensure `completion_item_hash` serializes items uniquely
This commit is contained in:
		
						commit
						3c2aca1e5e
					
				
					 1 changed files with 51 additions and 25 deletions
				
			
		|  | @ -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() | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Laurențiu Nicola
						Laurențiu Nicola