@@ -29,6 +29,16 @@ struct IndexRecordHasher {
2929 llvm::HashBuilder<llvm::TruncatedBLAKE3<8 >, llvm::endianness::little>
3030 HashBuilder;
3131
32+ // / Maps declarations that have already been hashed in this
33+ // / `IndexRecordHasher` to a unique ID that identifies this declaration.
34+ // /
35+ // / The ID assigned to a declaration is consistent across multiple runs of the
36+ // / `IndexRecordHasher` on the same AST structure, even across multiple
37+ // / process runs.
38+ // /
39+ // / See `hashDecl` for its use.
40+ llvm::DenseMap<const Decl *, size_t > HashedDecls;
41+
3242 explicit IndexRecordHasher (ASTContext &context) : Ctx(context) {}
3343
3444 void hashDecl (const Decl *D);
@@ -185,6 +195,19 @@ void IndexRecordHasher::hashMacro(const IdentifierInfo *name,
185195void IndexRecordHasher::hashDecl (const Decl *D) {
186196 assert (D->isCanonicalDecl ());
187197
198+ auto emplaceResult = HashedDecls.try_emplace (D, HashedDecls.size ());
199+ bool inserted = emplaceResult.second ;
200+ if (!inserted) {
201+ // If we have already serialized this declaration, just add the
202+ // declaration's hash to the hash builder. This is significantly
203+ // cheaper than visiting the declaration again.
204+ HashBuilder.add (emplaceResult.first ->second );
205+ return ;
206+ }
207+
208+ // If we haven't serialized the declaration yet,`try_emplace` will insert the
209+ // new unique ID into `HashedDecls`. We just need to hash the declaration
210+ // once.
188211 if (auto *NS = dyn_cast<NamespaceDecl>(D)) {
189212 if (NS->isAnonymousNamespace ()) {
190213 HashBuilder.add (" @aN" );
0 commit comments