1 | //===-- ODRHash.cpp - Hashing to diagnose ODR failures ----------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | /// |
9 | /// \file |
10 | /// This file implements the ODRHash class, which calculates a hash based |
11 | /// on AST nodes, which is stable across different runs. |
12 | /// |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "clang/AST/ODRHash.h" |
16 | |
17 | #include "clang/AST/DeclVisitor.h" |
18 | #include "clang/AST/NestedNameSpecifier.h" |
19 | #include "clang/AST/StmtVisitor.h" |
20 | #include "clang/AST/TypeVisitor.h" |
21 | |
22 | using namespace clang; |
23 | |
24 | void ODRHash::AddStmt(const Stmt *S) { |
25 | assert(S && "Expecting non-null pointer." ); |
26 | S->ProcessODRHash(ID, Hash&: *this); |
27 | } |
28 | |
29 | void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) { |
30 | assert(II && "Expecting non-null pointer." ); |
31 | ID.AddString(String: II->getName()); |
32 | } |
33 | |
34 | void ODRHash::AddDeclarationName(DeclarationName Name, bool TreatAsDecl) { |
35 | if (TreatAsDecl) |
36 | // Matches the NamedDecl check in AddDecl |
37 | AddBoolean(value: true); |
38 | |
39 | AddDeclarationNameImpl(Name); |
40 | |
41 | if (TreatAsDecl) |
42 | // Matches the ClassTemplateSpecializationDecl check in AddDecl |
43 | AddBoolean(value: false); |
44 | } |
45 | |
46 | void ODRHash::AddDeclarationNameImpl(DeclarationName Name) { |
47 | // Index all DeclarationName and use index numbers to refer to them. |
48 | auto Result = DeclNameMap.insert(KV: std::make_pair(x&: Name, y: DeclNameMap.size())); |
49 | ID.AddInteger(I: Result.first->second); |
50 | if (!Result.second) { |
51 | // If found in map, the DeclarationName has previously been processed. |
52 | return; |
53 | } |
54 | |
55 | // First time processing each DeclarationName, also process its details. |
56 | AddBoolean(value: Name.isEmpty()); |
57 | if (Name.isEmpty()) |
58 | return; |
59 | |
60 | auto Kind = Name.getNameKind(); |
61 | ID.AddInteger(I: Kind); |
62 | switch (Kind) { |
63 | case DeclarationName::Identifier: |
64 | AddIdentifierInfo(II: Name.getAsIdentifierInfo()); |
65 | break; |
66 | case DeclarationName::ObjCZeroArgSelector: |
67 | case DeclarationName::ObjCOneArgSelector: |
68 | case DeclarationName::ObjCMultiArgSelector: { |
69 | Selector S = Name.getObjCSelector(); |
70 | AddBoolean(value: S.isNull()); |
71 | AddBoolean(value: S.isKeywordSelector()); |
72 | AddBoolean(value: S.isUnarySelector()); |
73 | unsigned NumArgs = S.getNumArgs(); |
74 | ID.AddInteger(I: NumArgs); |
75 | // Compare all selector slots. For selectors with arguments it means all arg |
76 | // slots. And if there are no arguments, compare the first-and-only slot. |
77 | unsigned SlotsToCheck = NumArgs > 0 ? NumArgs : 1; |
78 | for (unsigned i = 0; i < SlotsToCheck; ++i) { |
79 | const IdentifierInfo *II = S.getIdentifierInfoForSlot(argIndex: i); |
80 | AddBoolean(value: II); |
81 | if (II) { |
82 | AddIdentifierInfo(II); |
83 | } |
84 | } |
85 | break; |
86 | } |
87 | case DeclarationName::CXXConstructorName: |
88 | case DeclarationName::CXXDestructorName: |
89 | AddQualType(T: Name.getCXXNameType()); |
90 | break; |
91 | case DeclarationName::CXXOperatorName: |
92 | ID.AddInteger(I: Name.getCXXOverloadedOperator()); |
93 | break; |
94 | case DeclarationName::CXXLiteralOperatorName: |
95 | AddIdentifierInfo(II: Name.getCXXLiteralIdentifier()); |
96 | break; |
97 | case DeclarationName::CXXConversionFunctionName: |
98 | AddQualType(T: Name.getCXXNameType()); |
99 | break; |
100 | case DeclarationName::CXXUsingDirective: |
101 | break; |
102 | case DeclarationName::CXXDeductionGuideName: { |
103 | auto *Template = Name.getCXXDeductionGuideTemplate(); |
104 | AddBoolean(value: Template); |
105 | if (Template) { |
106 | AddDecl(D: Template); |
107 | } |
108 | } |
109 | } |
110 | } |
111 | |
112 | void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { |
113 | assert(NNS && "Expecting non-null pointer." ); |
114 | const auto *Prefix = NNS->getPrefix(); |
115 | AddBoolean(value: Prefix); |
116 | if (Prefix) { |
117 | AddNestedNameSpecifier(NNS: Prefix); |
118 | } |
119 | auto Kind = NNS->getKind(); |
120 | ID.AddInteger(I: Kind); |
121 | switch (Kind) { |
122 | case NestedNameSpecifier::Identifier: |
123 | AddIdentifierInfo(II: NNS->getAsIdentifier()); |
124 | break; |
125 | case NestedNameSpecifier::Namespace: |
126 | AddDecl(D: NNS->getAsNamespace()); |
127 | break; |
128 | case NestedNameSpecifier::NamespaceAlias: |
129 | AddDecl(D: NNS->getAsNamespaceAlias()); |
130 | break; |
131 | case NestedNameSpecifier::TypeSpec: |
132 | case NestedNameSpecifier::TypeSpecWithTemplate: |
133 | AddType(T: NNS->getAsType()); |
134 | break; |
135 | case NestedNameSpecifier::Global: |
136 | case NestedNameSpecifier::Super: |
137 | break; |
138 | } |
139 | } |
140 | |
141 | void ODRHash::AddTemplateName(TemplateName Name) { |
142 | auto Kind = Name.getKind(); |
143 | ID.AddInteger(I: Kind); |
144 | |
145 | switch (Kind) { |
146 | case TemplateName::Template: |
147 | AddDecl(D: Name.getAsTemplateDecl()); |
148 | break; |
149 | case TemplateName::QualifiedTemplate: { |
150 | QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName(); |
151 | if (NestedNameSpecifier *NNS = QTN->getQualifier()) |
152 | AddNestedNameSpecifier(NNS); |
153 | AddBoolean(value: QTN->hasTemplateKeyword()); |
154 | AddTemplateName(Name: QTN->getUnderlyingTemplate()); |
155 | break; |
156 | } |
157 | // TODO: Support these cases. |
158 | case TemplateName::OverloadedTemplate: |
159 | case TemplateName::AssumedTemplate: |
160 | case TemplateName::DependentTemplate: |
161 | case TemplateName::SubstTemplateTemplateParm: |
162 | case TemplateName::SubstTemplateTemplateParmPack: |
163 | case TemplateName::UsingTemplate: |
164 | break; |
165 | } |
166 | } |
167 | |
168 | void ODRHash::AddTemplateArgument(TemplateArgument TA) { |
169 | const auto Kind = TA.getKind(); |
170 | ID.AddInteger(I: Kind); |
171 | |
172 | switch (Kind) { |
173 | case TemplateArgument::Null: |
174 | llvm_unreachable("Expected valid TemplateArgument" ); |
175 | case TemplateArgument::Type: |
176 | AddQualType(T: TA.getAsType()); |
177 | break; |
178 | case TemplateArgument::Declaration: |
179 | AddDecl(D: TA.getAsDecl()); |
180 | break; |
181 | case TemplateArgument::NullPtr: |
182 | ID.AddPointer(Ptr: nullptr); |
183 | break; |
184 | case TemplateArgument::Integral: { |
185 | // There are integrals (e.g.: _BitInt(128)) that cannot be represented as |
186 | // any builtin integral type, so we use the hash of APSInt instead. |
187 | TA.getAsIntegral().Profile(ID); |
188 | break; |
189 | } |
190 | case TemplateArgument::StructuralValue: |
191 | AddQualType(T: TA.getStructuralValueType()); |
192 | AddStructuralValue(TA.getAsStructuralValue()); |
193 | break; |
194 | case TemplateArgument::Template: |
195 | case TemplateArgument::TemplateExpansion: |
196 | AddTemplateName(Name: TA.getAsTemplateOrTemplatePattern()); |
197 | break; |
198 | case TemplateArgument::Expression: |
199 | AddStmt(S: TA.getAsExpr()); |
200 | break; |
201 | case TemplateArgument::Pack: |
202 | ID.AddInteger(I: TA.pack_size()); |
203 | for (auto SubTA : TA.pack_elements()) { |
204 | AddTemplateArgument(TA: SubTA); |
205 | } |
206 | break; |
207 | } |
208 | } |
209 | |
210 | void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) { |
211 | assert(TPL && "Expecting non-null pointer." ); |
212 | |
213 | ID.AddInteger(I: TPL->size()); |
214 | for (auto *ND : TPL->asArray()) { |
215 | AddSubDecl(D: ND); |
216 | } |
217 | } |
218 | |
219 | void ODRHash::clear() { |
220 | DeclNameMap.clear(); |
221 | Bools.clear(); |
222 | ID.clear(); |
223 | } |
224 | |
225 | unsigned ODRHash::CalculateHash() { |
226 | // Append the bools to the end of the data segment backwards. This allows |
227 | // for the bools data to be compressed 32 times smaller compared to using |
228 | // ID.AddBoolean |
229 | const unsigned unsigned_bits = sizeof(unsigned) * CHAR_BIT; |
230 | const unsigned size = Bools.size(); |
231 | const unsigned remainder = size % unsigned_bits; |
232 | const unsigned loops = size / unsigned_bits; |
233 | auto I = Bools.rbegin(); |
234 | unsigned value = 0; |
235 | for (unsigned i = 0; i < remainder; ++i) { |
236 | value <<= 1; |
237 | value |= *I; |
238 | ++I; |
239 | } |
240 | ID.AddInteger(I: value); |
241 | |
242 | for (unsigned i = 0; i < loops; ++i) { |
243 | value = 0; |
244 | for (unsigned j = 0; j < unsigned_bits; ++j) { |
245 | value <<= 1; |
246 | value |= *I; |
247 | ++I; |
248 | } |
249 | ID.AddInteger(I: value); |
250 | } |
251 | |
252 | assert(I == Bools.rend()); |
253 | Bools.clear(); |
254 | return ID.computeStableHash(); |
255 | } |
256 | |
257 | namespace { |
258 | // Process a Decl pointer. Add* methods call back into ODRHash while Visit* |
259 | // methods process the relevant parts of the Decl. |
260 | class ODRDeclVisitor : public ConstDeclVisitor<ODRDeclVisitor> { |
261 | typedef ConstDeclVisitor<ODRDeclVisitor> Inherited; |
262 | llvm::FoldingSetNodeID &ID; |
263 | ODRHash &Hash; |
264 | |
265 | public: |
266 | ODRDeclVisitor(llvm::FoldingSetNodeID &ID, ODRHash &Hash) |
267 | : ID(ID), Hash(Hash) {} |
268 | |
269 | void AddStmt(const Stmt *S) { |
270 | Hash.AddBoolean(value: S); |
271 | if (S) { |
272 | Hash.AddStmt(S); |
273 | } |
274 | } |
275 | |
276 | void AddIdentifierInfo(const IdentifierInfo *II) { |
277 | Hash.AddBoolean(value: II); |
278 | if (II) { |
279 | Hash.AddIdentifierInfo(II); |
280 | } |
281 | } |
282 | |
283 | void AddQualType(QualType T) { |
284 | Hash.AddQualType(T); |
285 | } |
286 | |
287 | void AddDecl(const Decl *D) { |
288 | Hash.AddBoolean(value: D); |
289 | if (D) { |
290 | Hash.AddDecl(D); |
291 | } |
292 | } |
293 | |
294 | void AddTemplateArgument(TemplateArgument TA) { |
295 | Hash.AddTemplateArgument(TA); |
296 | } |
297 | |
298 | void Visit(const Decl *D) { |
299 | ID.AddInteger(I: D->getKind()); |
300 | Inherited::Visit(D); |
301 | } |
302 | |
303 | void VisitNamedDecl(const NamedDecl *D) { |
304 | Hash.AddDeclarationName(Name: D->getDeclName()); |
305 | Inherited::VisitNamedDecl(D); |
306 | } |
307 | |
308 | void VisitValueDecl(const ValueDecl *D) { |
309 | if (auto *DD = dyn_cast<DeclaratorDecl>(Val: D); DD && DD->getTypeSourceInfo()) |
310 | AddQualType(T: DD->getTypeSourceInfo()->getType()); |
311 | |
312 | Inherited::VisitValueDecl(D); |
313 | } |
314 | |
315 | void VisitVarDecl(const VarDecl *D) { |
316 | Hash.AddBoolean(value: D->isStaticLocal()); |
317 | Hash.AddBoolean(value: D->isConstexpr()); |
318 | const bool HasInit = D->hasInit(); |
319 | Hash.AddBoolean(value: HasInit); |
320 | if (HasInit) { |
321 | AddStmt(S: D->getInit()); |
322 | } |
323 | Inherited::VisitVarDecl(D); |
324 | } |
325 | |
326 | void VisitParmVarDecl(const ParmVarDecl *D) { |
327 | // TODO: Handle default arguments. |
328 | Inherited::VisitParmVarDecl(D); |
329 | } |
330 | |
331 | void VisitAccessSpecDecl(const AccessSpecDecl *D) { |
332 | ID.AddInteger(I: D->getAccess()); |
333 | Inherited::VisitAccessSpecDecl(D); |
334 | } |
335 | |
336 | void VisitStaticAssertDecl(const StaticAssertDecl *D) { |
337 | AddStmt(S: D->getAssertExpr()); |
338 | AddStmt(S: D->getMessage()); |
339 | |
340 | Inherited::VisitStaticAssertDecl(D); |
341 | } |
342 | |
343 | void VisitFieldDecl(const FieldDecl *D) { |
344 | const bool IsBitfield = D->isBitField(); |
345 | Hash.AddBoolean(value: IsBitfield); |
346 | |
347 | if (IsBitfield) { |
348 | AddStmt(S: D->getBitWidth()); |
349 | } |
350 | |
351 | Hash.AddBoolean(value: D->isMutable()); |
352 | AddStmt(S: D->getInClassInitializer()); |
353 | |
354 | Inherited::VisitFieldDecl(D); |
355 | } |
356 | |
357 | void VisitObjCIvarDecl(const ObjCIvarDecl *D) { |
358 | ID.AddInteger(I: D->getCanonicalAccessControl()); |
359 | Inherited::VisitObjCIvarDecl(D); |
360 | } |
361 | |
362 | void VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { |
363 | ID.AddInteger(I: D->getPropertyAttributes()); |
364 | ID.AddInteger(I: D->getPropertyImplementation()); |
365 | AddQualType(T: D->getTypeSourceInfo()->getType()); |
366 | AddDecl(D); |
367 | |
368 | Inherited::VisitObjCPropertyDecl(D); |
369 | } |
370 | |
371 | void VisitFunctionDecl(const FunctionDecl *D) { |
372 | // Handled by the ODRHash for FunctionDecl |
373 | ID.AddInteger(I: D->getODRHash()); |
374 | |
375 | Inherited::VisitFunctionDecl(D); |
376 | } |
377 | |
378 | void VisitCXXMethodDecl(const CXXMethodDecl *D) { |
379 | // Handled by the ODRHash for FunctionDecl |
380 | |
381 | Inherited::VisitCXXMethodDecl(D); |
382 | } |
383 | |
384 | void VisitObjCMethodDecl(const ObjCMethodDecl *Method) { |
385 | ID.AddInteger(I: Method->getDeclKind()); |
386 | Hash.AddBoolean(value: Method->isInstanceMethod()); // false if class method |
387 | Hash.AddBoolean(value: Method->isVariadic()); |
388 | Hash.AddBoolean(value: Method->isSynthesizedAccessorStub()); |
389 | Hash.AddBoolean(value: Method->isDefined()); |
390 | Hash.AddBoolean(value: Method->isDirectMethod()); |
391 | Hash.AddBoolean(value: Method->isThisDeclarationADesignatedInitializer()); |
392 | Hash.AddBoolean(value: Method->hasSkippedBody()); |
393 | |
394 | ID.AddInteger(I: llvm::to_underlying(E: Method->getImplementationControl())); |
395 | ID.AddInteger(I: Method->getMethodFamily()); |
396 | ImplicitParamDecl *Cmd = Method->getCmdDecl(); |
397 | Hash.AddBoolean(value: Cmd); |
398 | if (Cmd) |
399 | ID.AddInteger(I: llvm::to_underlying(E: Cmd->getParameterKind())); |
400 | |
401 | ImplicitParamDecl *Self = Method->getSelfDecl(); |
402 | Hash.AddBoolean(value: Self); |
403 | if (Self) |
404 | ID.AddInteger(I: llvm::to_underlying(E: Self->getParameterKind())); |
405 | |
406 | AddDecl(D: Method); |
407 | |
408 | if (Method->getReturnTypeSourceInfo()) |
409 | AddQualType(T: Method->getReturnTypeSourceInfo()->getType()); |
410 | |
411 | ID.AddInteger(I: Method->param_size()); |
412 | for (auto Param : Method->parameters()) |
413 | Hash.AddSubDecl(D: Param); |
414 | |
415 | if (Method->hasBody()) { |
416 | const bool IsDefinition = Method->isThisDeclarationADefinition(); |
417 | Hash.AddBoolean(value: IsDefinition); |
418 | if (IsDefinition) { |
419 | Stmt *Body = Method->getBody(); |
420 | Hash.AddBoolean(value: Body); |
421 | if (Body) |
422 | AddStmt(S: Body); |
423 | |
424 | // Filter out sub-Decls which will not be processed in order to get an |
425 | // accurate count of Decl's. |
426 | llvm::SmallVector<const Decl *, 16> Decls; |
427 | for (Decl *SubDecl : Method->decls()) |
428 | if (ODRHash::isSubDeclToBeProcessed(D: SubDecl, Parent: Method)) |
429 | Decls.push_back(Elt: SubDecl); |
430 | |
431 | ID.AddInteger(I: Decls.size()); |
432 | for (auto SubDecl : Decls) |
433 | Hash.AddSubDecl(D: SubDecl); |
434 | } |
435 | } else { |
436 | Hash.AddBoolean(value: false); |
437 | } |
438 | |
439 | Inherited::VisitObjCMethodDecl(D: Method); |
440 | } |
441 | |
442 | void VisitTypedefNameDecl(const TypedefNameDecl *D) { |
443 | AddQualType(T: D->getUnderlyingType()); |
444 | |
445 | Inherited::VisitTypedefNameDecl(D); |
446 | } |
447 | |
448 | void VisitTypedefDecl(const TypedefDecl *D) { |
449 | Inherited::VisitTypedefDecl(D); |
450 | } |
451 | |
452 | void VisitTypeAliasDecl(const TypeAliasDecl *D) { |
453 | Inherited::VisitTypeAliasDecl(D); |
454 | } |
455 | |
456 | void VisitFriendDecl(const FriendDecl *D) { |
457 | TypeSourceInfo *TSI = D->getFriendType(); |
458 | Hash.AddBoolean(value: TSI); |
459 | if (TSI) { |
460 | AddQualType(T: TSI->getType()); |
461 | } else { |
462 | AddDecl(D: D->getFriendDecl()); |
463 | } |
464 | } |
465 | |
466 | void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { |
467 | // Only care about default arguments as part of the definition. |
468 | const bool hasDefaultArgument = |
469 | D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); |
470 | Hash.AddBoolean(value: hasDefaultArgument); |
471 | if (hasDefaultArgument) { |
472 | AddTemplateArgument(TA: D->getDefaultArgument().getArgument()); |
473 | } |
474 | Hash.AddBoolean(value: D->isParameterPack()); |
475 | |
476 | const TypeConstraint *TC = D->getTypeConstraint(); |
477 | Hash.AddBoolean(value: TC != nullptr); |
478 | if (TC) |
479 | AddStmt(S: TC->getImmediatelyDeclaredConstraint()); |
480 | |
481 | Inherited::VisitTemplateTypeParmDecl(D); |
482 | } |
483 | |
484 | void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { |
485 | // Only care about default arguments as part of the definition. |
486 | const bool hasDefaultArgument = |
487 | D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); |
488 | Hash.AddBoolean(value: hasDefaultArgument); |
489 | if (hasDefaultArgument) { |
490 | AddTemplateArgument(TA: D->getDefaultArgument().getArgument()); |
491 | } |
492 | Hash.AddBoolean(value: D->isParameterPack()); |
493 | |
494 | Inherited::VisitNonTypeTemplateParmDecl(D); |
495 | } |
496 | |
497 | void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) { |
498 | // Only care about default arguments as part of the definition. |
499 | const bool hasDefaultArgument = |
500 | D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); |
501 | Hash.AddBoolean(value: hasDefaultArgument); |
502 | if (hasDefaultArgument) { |
503 | AddTemplateArgument(TA: D->getDefaultArgument().getArgument()); |
504 | } |
505 | Hash.AddBoolean(value: D->isParameterPack()); |
506 | |
507 | Inherited::VisitTemplateTemplateParmDecl(D); |
508 | } |
509 | |
510 | void VisitTemplateDecl(const TemplateDecl *D) { |
511 | Hash.AddTemplateParameterList(TPL: D->getTemplateParameters()); |
512 | |
513 | Inherited::VisitTemplateDecl(D); |
514 | } |
515 | |
516 | void VisitRedeclarableTemplateDecl(const RedeclarableTemplateDecl *D) { |
517 | Hash.AddBoolean(value: D->isMemberSpecialization()); |
518 | Inherited::VisitRedeclarableTemplateDecl(D); |
519 | } |
520 | |
521 | void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { |
522 | AddDecl(D: D->getTemplatedDecl()); |
523 | ID.AddInteger(I: D->getTemplatedDecl()->getODRHash()); |
524 | Inherited::VisitFunctionTemplateDecl(D); |
525 | } |
526 | |
527 | void VisitEnumConstantDecl(const EnumConstantDecl *D) { |
528 | AddStmt(S: D->getInitExpr()); |
529 | Inherited::VisitEnumConstantDecl(D); |
530 | } |
531 | }; |
532 | } // namespace |
533 | |
534 | // Only allow a small portion of Decl's to be processed. Remove this once |
535 | // all Decl's can be handled. |
536 | bool ODRHash::isSubDeclToBeProcessed(const Decl *D, const DeclContext *Parent) { |
537 | if (D->isImplicit()) return false; |
538 | if (D->getDeclContext() != Parent) return false; |
539 | |
540 | switch (D->getKind()) { |
541 | default: |
542 | return false; |
543 | case Decl::AccessSpec: |
544 | case Decl::CXXConstructor: |
545 | case Decl::CXXDestructor: |
546 | case Decl::CXXMethod: |
547 | case Decl::EnumConstant: // Only found in EnumDecl's. |
548 | case Decl::Field: |
549 | case Decl::Friend: |
550 | case Decl::FunctionTemplate: |
551 | case Decl::StaticAssert: |
552 | case Decl::TypeAlias: |
553 | case Decl::Typedef: |
554 | case Decl::Var: |
555 | case Decl::ObjCMethod: |
556 | case Decl::ObjCIvar: |
557 | case Decl::ObjCProperty: |
558 | return true; |
559 | } |
560 | } |
561 | |
562 | void ODRHash::AddSubDecl(const Decl *D) { |
563 | assert(D && "Expecting non-null pointer." ); |
564 | |
565 | ODRDeclVisitor(ID, *this).Visit(D); |
566 | } |
567 | |
568 | void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) { |
569 | assert(Record && Record->hasDefinition() && |
570 | "Expected non-null record to be a definition." ); |
571 | |
572 | const DeclContext *DC = Record; |
573 | while (DC) { |
574 | if (isa<ClassTemplateSpecializationDecl>(Val: DC)) { |
575 | return; |
576 | } |
577 | DC = DC->getParent(); |
578 | } |
579 | |
580 | AddDecl(D: Record); |
581 | |
582 | // Filter out sub-Decls which will not be processed in order to get an |
583 | // accurate count of Decl's. |
584 | llvm::SmallVector<const Decl *, 16> Decls; |
585 | for (Decl *SubDecl : Record->decls()) { |
586 | if (isSubDeclToBeProcessed(D: SubDecl, Parent: Record)) { |
587 | Decls.push_back(Elt: SubDecl); |
588 | if (auto *Function = dyn_cast<FunctionDecl>(Val: SubDecl)) { |
589 | // Compute/Preload ODRHash into FunctionDecl. |
590 | Function->getODRHash(); |
591 | } |
592 | } |
593 | } |
594 | |
595 | ID.AddInteger(I: Decls.size()); |
596 | for (auto SubDecl : Decls) { |
597 | AddSubDecl(D: SubDecl); |
598 | } |
599 | |
600 | const ClassTemplateDecl *TD = Record->getDescribedClassTemplate(); |
601 | AddBoolean(value: TD); |
602 | if (TD) { |
603 | AddTemplateParameterList(TPL: TD->getTemplateParameters()); |
604 | } |
605 | |
606 | ID.AddInteger(I: Record->getNumBases()); |
607 | auto Bases = Record->bases(); |
608 | for (const auto &Base : Bases) { |
609 | AddQualType(T: Base.getTypeSourceInfo()->getType()); |
610 | ID.AddInteger(I: Base.isVirtual()); |
611 | ID.AddInteger(I: Base.getAccessSpecifierAsWritten()); |
612 | } |
613 | } |
614 | |
615 | void ODRHash::AddRecordDecl(const RecordDecl *Record) { |
616 | assert(!isa<CXXRecordDecl>(Record) && |
617 | "For CXXRecordDecl should call AddCXXRecordDecl." ); |
618 | AddDecl(D: Record); |
619 | |
620 | // Filter out sub-Decls which will not be processed in order to get an |
621 | // accurate count of Decl's. |
622 | llvm::SmallVector<const Decl *, 16> Decls; |
623 | for (Decl *SubDecl : Record->decls()) { |
624 | if (isSubDeclToBeProcessed(D: SubDecl, Parent: Record)) |
625 | Decls.push_back(Elt: SubDecl); |
626 | } |
627 | |
628 | ID.AddInteger(I: Decls.size()); |
629 | for (const Decl *SubDecl : Decls) |
630 | AddSubDecl(D: SubDecl); |
631 | } |
632 | |
633 | void ODRHash::AddObjCInterfaceDecl(const ObjCInterfaceDecl *IF) { |
634 | AddDecl(D: IF); |
635 | |
636 | auto *SuperClass = IF->getSuperClass(); |
637 | AddBoolean(value: SuperClass); |
638 | if (SuperClass) |
639 | ID.AddInteger(I: SuperClass->getODRHash()); |
640 | |
641 | // Hash referenced protocols. |
642 | ID.AddInteger(I: IF->getReferencedProtocols().size()); |
643 | for (const ObjCProtocolDecl *RefP : IF->protocols()) { |
644 | // Hash the name only as a referenced protocol can be a forward declaration. |
645 | AddDeclarationName(Name: RefP->getDeclName()); |
646 | } |
647 | |
648 | // Filter out sub-Decls which will not be processed in order to get an |
649 | // accurate count of Decl's. |
650 | llvm::SmallVector<const Decl *, 16> Decls; |
651 | for (Decl *SubDecl : IF->decls()) |
652 | if (isSubDeclToBeProcessed(D: SubDecl, Parent: IF)) |
653 | Decls.push_back(Elt: SubDecl); |
654 | |
655 | ID.AddInteger(I: Decls.size()); |
656 | for (auto *SubDecl : Decls) |
657 | AddSubDecl(D: SubDecl); |
658 | } |
659 | |
660 | void ODRHash::AddFunctionDecl(const FunctionDecl *Function, |
661 | bool SkipBody) { |
662 | assert(Function && "Expecting non-null pointer." ); |
663 | |
664 | // Skip functions that are specializations or in specialization context. |
665 | const DeclContext *DC = Function; |
666 | while (DC) { |
667 | if (isa<ClassTemplateSpecializationDecl>(Val: DC)) return; |
668 | if (auto *F = dyn_cast<FunctionDecl>(Val: DC)) { |
669 | if (F->isFunctionTemplateSpecialization()) { |
670 | if (!isa<CXXMethodDecl>(Val: DC)) return; |
671 | if (DC->getLexicalParent()->isFileContext()) return; |
672 | // Skip class scope explicit function template specializations, |
673 | // as they have not yet been instantiated. |
674 | if (F->getDependentSpecializationInfo()) |
675 | return; |
676 | // Inline method specializations are the only supported |
677 | // specialization for now. |
678 | } |
679 | } |
680 | DC = DC->getParent(); |
681 | } |
682 | |
683 | ID.AddInteger(I: Function->getDeclKind()); |
684 | |
685 | const auto *SpecializationArgs = Function->getTemplateSpecializationArgs(); |
686 | AddBoolean(value: SpecializationArgs); |
687 | if (SpecializationArgs) { |
688 | ID.AddInteger(I: SpecializationArgs->size()); |
689 | for (const TemplateArgument &TA : SpecializationArgs->asArray()) { |
690 | AddTemplateArgument(TA); |
691 | } |
692 | } |
693 | |
694 | if (const auto *Method = dyn_cast<CXXMethodDecl>(Val: Function)) { |
695 | AddBoolean(value: Method->isConst()); |
696 | AddBoolean(value: Method->isVolatile()); |
697 | } |
698 | |
699 | ID.AddInteger(I: Function->getStorageClass()); |
700 | AddBoolean(value: Function->isInlineSpecified()); |
701 | AddBoolean(value: Function->isVirtualAsWritten()); |
702 | AddBoolean(value: Function->isPureVirtual()); |
703 | AddBoolean(value: Function->isDeletedAsWritten()); |
704 | AddBoolean(value: Function->isExplicitlyDefaulted()); |
705 | |
706 | StringLiteral *DeletedMessage = Function->getDeletedMessage(); |
707 | AddBoolean(value: DeletedMessage); |
708 | |
709 | if (DeletedMessage) |
710 | ID.AddString(String: DeletedMessage->getBytes()); |
711 | |
712 | AddDecl(D: Function); |
713 | |
714 | AddQualType(T: Function->getReturnType()); |
715 | |
716 | ID.AddInteger(I: Function->param_size()); |
717 | for (auto *Param : Function->parameters()) |
718 | AddSubDecl(D: Param); |
719 | |
720 | if (SkipBody) { |
721 | AddBoolean(value: false); |
722 | return; |
723 | } |
724 | |
725 | const bool HasBody = Function->isThisDeclarationADefinition() && |
726 | !Function->isDefaulted() && !Function->isDeleted() && |
727 | !Function->isLateTemplateParsed(); |
728 | AddBoolean(value: HasBody); |
729 | if (!HasBody) { |
730 | return; |
731 | } |
732 | |
733 | auto *Body = Function->getBody(); |
734 | AddBoolean(value: Body); |
735 | if (Body) |
736 | AddStmt(S: Body); |
737 | |
738 | // Filter out sub-Decls which will not be processed in order to get an |
739 | // accurate count of Decl's. |
740 | llvm::SmallVector<const Decl *, 16> Decls; |
741 | for (Decl *SubDecl : Function->decls()) { |
742 | if (isSubDeclToBeProcessed(D: SubDecl, Parent: Function)) { |
743 | Decls.push_back(Elt: SubDecl); |
744 | } |
745 | } |
746 | |
747 | ID.AddInteger(I: Decls.size()); |
748 | for (auto SubDecl : Decls) { |
749 | AddSubDecl(D: SubDecl); |
750 | } |
751 | } |
752 | |
753 | void ODRHash::AddEnumDecl(const EnumDecl *Enum) { |
754 | assert(Enum); |
755 | AddDeclarationName(Name: Enum->getDeclName()); |
756 | |
757 | AddBoolean(value: Enum->isScoped()); |
758 | if (Enum->isScoped()) |
759 | AddBoolean(value: Enum->isScopedUsingClassTag()); |
760 | |
761 | if (Enum->getIntegerTypeSourceInfo()) |
762 | AddQualType(T: Enum->getIntegerType().getCanonicalType()); |
763 | |
764 | // Filter out sub-Decls which will not be processed in order to get an |
765 | // accurate count of Decl's. |
766 | llvm::SmallVector<const Decl *, 16> Decls; |
767 | for (Decl *SubDecl : Enum->decls()) { |
768 | if (isSubDeclToBeProcessed(D: SubDecl, Parent: Enum)) { |
769 | assert(isa<EnumConstantDecl>(SubDecl) && "Unexpected Decl" ); |
770 | Decls.push_back(Elt: SubDecl); |
771 | } |
772 | } |
773 | |
774 | ID.AddInteger(I: Decls.size()); |
775 | for (auto SubDecl : Decls) { |
776 | AddSubDecl(D: SubDecl); |
777 | } |
778 | |
779 | } |
780 | |
781 | void ODRHash::AddObjCProtocolDecl(const ObjCProtocolDecl *P) { |
782 | AddDecl(D: P); |
783 | |
784 | // Hash referenced protocols. |
785 | ID.AddInteger(I: P->getReferencedProtocols().size()); |
786 | for (const ObjCProtocolDecl *RefP : P->protocols()) { |
787 | // Hash the name only as a referenced protocol can be a forward declaration. |
788 | AddDeclarationName(Name: RefP->getDeclName()); |
789 | } |
790 | |
791 | // Filter out sub-Decls which will not be processed in order to get an |
792 | // accurate count of Decl's. |
793 | llvm::SmallVector<const Decl *, 16> Decls; |
794 | for (Decl *SubDecl : P->decls()) { |
795 | if (isSubDeclToBeProcessed(D: SubDecl, Parent: P)) { |
796 | Decls.push_back(Elt: SubDecl); |
797 | } |
798 | } |
799 | |
800 | ID.AddInteger(I: Decls.size()); |
801 | for (auto *SubDecl : Decls) { |
802 | AddSubDecl(D: SubDecl); |
803 | } |
804 | } |
805 | |
806 | void ODRHash::AddDecl(const Decl *D) { |
807 | assert(D && "Expecting non-null pointer." ); |
808 | D = D->getCanonicalDecl(); |
809 | |
810 | const NamedDecl *ND = dyn_cast<NamedDecl>(Val: D); |
811 | AddBoolean(value: ND); |
812 | if (!ND) { |
813 | ID.AddInteger(I: D->getKind()); |
814 | return; |
815 | } |
816 | |
817 | AddDeclarationName(Name: ND->getDeclName()); |
818 | |
819 | const auto *Specialization = |
820 | dyn_cast<ClassTemplateSpecializationDecl>(Val: D); |
821 | AddBoolean(value: Specialization); |
822 | if (Specialization) { |
823 | const TemplateArgumentList &List = Specialization->getTemplateArgs(); |
824 | ID.AddInteger(I: List.size()); |
825 | for (const TemplateArgument &TA : List.asArray()) |
826 | AddTemplateArgument(TA); |
827 | } |
828 | } |
829 | |
830 | namespace { |
831 | // Process a Type pointer. Add* methods call back into ODRHash while Visit* |
832 | // methods process the relevant parts of the Type. |
833 | class ODRTypeVisitor : public TypeVisitor<ODRTypeVisitor> { |
834 | typedef TypeVisitor<ODRTypeVisitor> Inherited; |
835 | llvm::FoldingSetNodeID &ID; |
836 | ODRHash &Hash; |
837 | |
838 | public: |
839 | ODRTypeVisitor(llvm::FoldingSetNodeID &ID, ODRHash &Hash) |
840 | : ID(ID), Hash(Hash) {} |
841 | |
842 | void AddStmt(Stmt *S) { |
843 | Hash.AddBoolean(value: S); |
844 | if (S) { |
845 | Hash.AddStmt(S); |
846 | } |
847 | } |
848 | |
849 | void AddDecl(const Decl *D) { |
850 | Hash.AddBoolean(value: D); |
851 | if (D) { |
852 | Hash.AddDecl(D); |
853 | } |
854 | } |
855 | |
856 | void AddQualType(QualType T) { |
857 | Hash.AddQualType(T); |
858 | } |
859 | |
860 | void AddType(const Type *T) { |
861 | Hash.AddBoolean(value: T); |
862 | if (T) { |
863 | Hash.AddType(T); |
864 | } |
865 | } |
866 | |
867 | void AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { |
868 | Hash.AddBoolean(value: NNS); |
869 | if (NNS) { |
870 | Hash.AddNestedNameSpecifier(NNS); |
871 | } |
872 | } |
873 | |
874 | void AddIdentifierInfo(const IdentifierInfo *II) { |
875 | Hash.AddBoolean(value: II); |
876 | if (II) { |
877 | Hash.AddIdentifierInfo(II); |
878 | } |
879 | } |
880 | |
881 | void VisitQualifiers(Qualifiers Quals) { |
882 | ID.AddInteger(I: Quals.getAsOpaqueValue()); |
883 | } |
884 | |
885 | // Return the RecordType if the typedef only strips away a keyword. |
886 | // Otherwise, return the original type. |
887 | static const Type *RemoveTypedef(const Type *T) { |
888 | const auto *TypedefT = dyn_cast<TypedefType>(Val: T); |
889 | if (!TypedefT) { |
890 | return T; |
891 | } |
892 | |
893 | const TypedefNameDecl *D = TypedefT->getDecl(); |
894 | QualType UnderlyingType = D->getUnderlyingType(); |
895 | |
896 | if (UnderlyingType.hasLocalQualifiers()) { |
897 | return T; |
898 | } |
899 | |
900 | const auto *ElaboratedT = dyn_cast<ElaboratedType>(Val&: UnderlyingType); |
901 | if (!ElaboratedT) { |
902 | return T; |
903 | } |
904 | |
905 | if (ElaboratedT->getQualifier() != nullptr) { |
906 | return T; |
907 | } |
908 | |
909 | QualType NamedType = ElaboratedT->getNamedType(); |
910 | if (NamedType.hasLocalQualifiers()) { |
911 | return T; |
912 | } |
913 | |
914 | const auto *RecordT = dyn_cast<RecordType>(Val&: NamedType); |
915 | if (!RecordT) { |
916 | return T; |
917 | } |
918 | |
919 | const IdentifierInfo *TypedefII = TypedefT->getDecl()->getIdentifier(); |
920 | const IdentifierInfo *RecordII = RecordT->getDecl()->getIdentifier(); |
921 | if (!TypedefII || !RecordII || |
922 | TypedefII->getName() != RecordII->getName()) { |
923 | return T; |
924 | } |
925 | |
926 | return RecordT; |
927 | } |
928 | |
929 | void Visit(const Type *T) { |
930 | T = RemoveTypedef(T); |
931 | ID.AddInteger(I: T->getTypeClass()); |
932 | Inherited::Visit(T); |
933 | } |
934 | |
935 | void VisitType(const Type *T) {} |
936 | |
937 | void VisitAdjustedType(const AdjustedType *T) { |
938 | AddQualType(T: T->getOriginalType()); |
939 | |
940 | VisitType(T); |
941 | } |
942 | |
943 | void VisitDecayedType(const DecayedType *T) { |
944 | // getDecayedType and getPointeeType are derived from getAdjustedType |
945 | // and don't need to be separately processed. |
946 | VisitAdjustedType(T); |
947 | } |
948 | |
949 | void VisitArrayType(const ArrayType *T) { |
950 | AddQualType(T: T->getElementType()); |
951 | ID.AddInteger(I: llvm::to_underlying(E: T->getSizeModifier())); |
952 | VisitQualifiers(Quals: T->getIndexTypeQualifiers()); |
953 | VisitType(T); |
954 | } |
955 | void VisitConstantArrayType(const ConstantArrayType *T) { |
956 | T->getSize().Profile(id&: ID); |
957 | VisitArrayType(T); |
958 | } |
959 | |
960 | void VisitArrayParameterType(const ArrayParameterType *T) { |
961 | VisitConstantArrayType(T); |
962 | } |
963 | |
964 | void VisitDependentSizedArrayType(const DependentSizedArrayType *T) { |
965 | AddStmt(S: T->getSizeExpr()); |
966 | VisitArrayType(T); |
967 | } |
968 | |
969 | void VisitIncompleteArrayType(const IncompleteArrayType *T) { |
970 | VisitArrayType(T); |
971 | } |
972 | |
973 | void VisitVariableArrayType(const VariableArrayType *T) { |
974 | AddStmt(S: T->getSizeExpr()); |
975 | VisitArrayType(T); |
976 | } |
977 | |
978 | void VisitAttributedType(const AttributedType *T) { |
979 | ID.AddInteger(I: T->getAttrKind()); |
980 | AddQualType(T: T->getModifiedType()); |
981 | |
982 | VisitType(T); |
983 | } |
984 | |
985 | void VisitBlockPointerType(const BlockPointerType *T) { |
986 | AddQualType(T: T->getPointeeType()); |
987 | VisitType(T); |
988 | } |
989 | |
990 | void VisitBuiltinType(const BuiltinType *T) { |
991 | ID.AddInteger(I: T->getKind()); |
992 | VisitType(T); |
993 | } |
994 | |
995 | void VisitComplexType(const ComplexType *T) { |
996 | AddQualType(T: T->getElementType()); |
997 | VisitType(T); |
998 | } |
999 | |
1000 | void VisitDecltypeType(const DecltypeType *T) { |
1001 | AddStmt(S: T->getUnderlyingExpr()); |
1002 | VisitType(T); |
1003 | } |
1004 | |
1005 | void VisitDependentDecltypeType(const DependentDecltypeType *T) { |
1006 | VisitDecltypeType(T); |
1007 | } |
1008 | |
1009 | void VisitDeducedType(const DeducedType *T) { |
1010 | AddQualType(T: T->getDeducedType()); |
1011 | VisitType(T); |
1012 | } |
1013 | |
1014 | void VisitAutoType(const AutoType *T) { |
1015 | ID.AddInteger(I: (unsigned)T->getKeyword()); |
1016 | ID.AddInteger(I: T->isConstrained()); |
1017 | if (T->isConstrained()) { |
1018 | AddDecl(D: T->getTypeConstraintConcept()); |
1019 | ID.AddInteger(I: T->getTypeConstraintArguments().size()); |
1020 | for (const auto &TA : T->getTypeConstraintArguments()) |
1021 | Hash.AddTemplateArgument(TA); |
1022 | } |
1023 | VisitDeducedType(T); |
1024 | } |
1025 | |
1026 | void VisitDeducedTemplateSpecializationType( |
1027 | const DeducedTemplateSpecializationType *T) { |
1028 | Hash.AddTemplateName(Name: T->getTemplateName()); |
1029 | VisitDeducedType(T); |
1030 | } |
1031 | |
1032 | void VisitDependentAddressSpaceType(const DependentAddressSpaceType *T) { |
1033 | AddQualType(T: T->getPointeeType()); |
1034 | AddStmt(S: T->getAddrSpaceExpr()); |
1035 | VisitType(T); |
1036 | } |
1037 | |
1038 | void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *T) { |
1039 | AddQualType(T: T->getElementType()); |
1040 | AddStmt(S: T->getSizeExpr()); |
1041 | VisitType(T); |
1042 | } |
1043 | |
1044 | void VisitFunctionType(const FunctionType *T) { |
1045 | AddQualType(T: T->getReturnType()); |
1046 | T->getExtInfo().Profile(ID); |
1047 | Hash.AddBoolean(value: T->isConst()); |
1048 | Hash.AddBoolean(value: T->isVolatile()); |
1049 | Hash.AddBoolean(value: T->isRestrict()); |
1050 | VisitType(T); |
1051 | } |
1052 | |
1053 | void VisitFunctionNoProtoType(const FunctionNoProtoType *T) { |
1054 | VisitFunctionType(T); |
1055 | } |
1056 | |
1057 | void VisitFunctionProtoType(const FunctionProtoType *T) { |
1058 | ID.AddInteger(I: T->getNumParams()); |
1059 | for (auto ParamType : T->getParamTypes()) |
1060 | AddQualType(T: ParamType); |
1061 | |
1062 | VisitFunctionType(T); |
1063 | } |
1064 | |
1065 | void VisitInjectedClassNameType(const InjectedClassNameType *T) { |
1066 | AddDecl(D: T->getDecl()); |
1067 | VisitType(T); |
1068 | } |
1069 | |
1070 | void VisitMemberPointerType(const MemberPointerType *T) { |
1071 | AddQualType(T: T->getPointeeType()); |
1072 | AddType(T: T->getClass()); |
1073 | VisitType(T); |
1074 | } |
1075 | |
1076 | void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { |
1077 | AddQualType(T: T->getPointeeType()); |
1078 | VisitType(T); |
1079 | } |
1080 | |
1081 | void VisitObjCObjectType(const ObjCObjectType *T) { |
1082 | AddDecl(D: T->getInterface()); |
1083 | |
1084 | auto TypeArgs = T->getTypeArgsAsWritten(); |
1085 | ID.AddInteger(I: TypeArgs.size()); |
1086 | for (auto Arg : TypeArgs) { |
1087 | AddQualType(T: Arg); |
1088 | } |
1089 | |
1090 | auto Protocols = T->getProtocols(); |
1091 | ID.AddInteger(I: Protocols.size()); |
1092 | for (auto *Protocol : Protocols) { |
1093 | AddDecl(D: Protocol); |
1094 | } |
1095 | |
1096 | Hash.AddBoolean(value: T->isKindOfType()); |
1097 | |
1098 | VisitType(T); |
1099 | } |
1100 | |
1101 | void VisitObjCInterfaceType(const ObjCInterfaceType *T) { |
1102 | // This type is handled by the parent type ObjCObjectType. |
1103 | VisitObjCObjectType(T); |
1104 | } |
1105 | |
1106 | void VisitObjCTypeParamType(const ObjCTypeParamType *T) { |
1107 | AddDecl(D: T->getDecl()); |
1108 | auto Protocols = T->getProtocols(); |
1109 | ID.AddInteger(I: Protocols.size()); |
1110 | for (auto *Protocol : Protocols) { |
1111 | AddDecl(D: Protocol); |
1112 | } |
1113 | |
1114 | VisitType(T); |
1115 | } |
1116 | |
1117 | void VisitPackExpansionType(const PackExpansionType *T) { |
1118 | AddQualType(T: T->getPattern()); |
1119 | VisitType(T); |
1120 | } |
1121 | |
1122 | void VisitParenType(const ParenType *T) { |
1123 | AddQualType(T: T->getInnerType()); |
1124 | VisitType(T); |
1125 | } |
1126 | |
1127 | void VisitPipeType(const PipeType *T) { |
1128 | AddQualType(T: T->getElementType()); |
1129 | Hash.AddBoolean(value: T->isReadOnly()); |
1130 | VisitType(T); |
1131 | } |
1132 | |
1133 | void VisitPointerType(const PointerType *T) { |
1134 | AddQualType(T: T->getPointeeType()); |
1135 | VisitType(T); |
1136 | } |
1137 | |
1138 | void VisitReferenceType(const ReferenceType *T) { |
1139 | AddQualType(T: T->getPointeeTypeAsWritten()); |
1140 | VisitType(T); |
1141 | } |
1142 | |
1143 | void VisitLValueReferenceType(const LValueReferenceType *T) { |
1144 | VisitReferenceType(T); |
1145 | } |
1146 | |
1147 | void VisitRValueReferenceType(const RValueReferenceType *T) { |
1148 | VisitReferenceType(T); |
1149 | } |
1150 | |
1151 | void |
1152 | VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) { |
1153 | AddDecl(D: T->getAssociatedDecl()); |
1154 | Hash.AddTemplateArgument(TA: T->getArgumentPack()); |
1155 | VisitType(T); |
1156 | } |
1157 | |
1158 | void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { |
1159 | AddDecl(D: T->getAssociatedDecl()); |
1160 | AddQualType(T: T->getReplacementType()); |
1161 | VisitType(T); |
1162 | } |
1163 | |
1164 | void VisitTagType(const TagType *T) { |
1165 | AddDecl(D: T->getDecl()); |
1166 | VisitType(T); |
1167 | } |
1168 | |
1169 | void VisitRecordType(const RecordType *T) { VisitTagType(T); } |
1170 | void VisitEnumType(const EnumType *T) { VisitTagType(T); } |
1171 | |
1172 | void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { |
1173 | ID.AddInteger(I: T->template_arguments().size()); |
1174 | for (const auto &TA : T->template_arguments()) { |
1175 | Hash.AddTemplateArgument(TA); |
1176 | } |
1177 | Hash.AddTemplateName(Name: T->getTemplateName()); |
1178 | VisitType(T); |
1179 | } |
1180 | |
1181 | void VisitTemplateTypeParmType(const TemplateTypeParmType *T) { |
1182 | ID.AddInteger(I: T->getDepth()); |
1183 | ID.AddInteger(I: T->getIndex()); |
1184 | Hash.AddBoolean(value: T->isParameterPack()); |
1185 | AddDecl(D: T->getDecl()); |
1186 | } |
1187 | |
1188 | void VisitTypedefType(const TypedefType *T) { |
1189 | AddDecl(D: T->getDecl()); |
1190 | VisitType(T); |
1191 | } |
1192 | |
1193 | void VisitTypeOfExprType(const TypeOfExprType *T) { |
1194 | AddStmt(S: T->getUnderlyingExpr()); |
1195 | Hash.AddBoolean(value: T->isSugared()); |
1196 | |
1197 | VisitType(T); |
1198 | } |
1199 | void VisitTypeOfType(const TypeOfType *T) { |
1200 | AddQualType(T: T->getUnmodifiedType()); |
1201 | VisitType(T); |
1202 | } |
1203 | |
1204 | void VisitTypeWithKeyword(const TypeWithKeyword *T) { |
1205 | ID.AddInteger(I: llvm::to_underlying(E: T->getKeyword())); |
1206 | VisitType(T); |
1207 | }; |
1208 | |
1209 | void VisitDependentNameType(const DependentNameType *T) { |
1210 | AddNestedNameSpecifier(NNS: T->getQualifier()); |
1211 | AddIdentifierInfo(II: T->getIdentifier()); |
1212 | VisitTypeWithKeyword(T); |
1213 | } |
1214 | |
1215 | void VisitDependentTemplateSpecializationType( |
1216 | const DependentTemplateSpecializationType *T) { |
1217 | AddIdentifierInfo(II: T->getIdentifier()); |
1218 | AddNestedNameSpecifier(NNS: T->getQualifier()); |
1219 | ID.AddInteger(I: T->template_arguments().size()); |
1220 | for (const auto &TA : T->template_arguments()) { |
1221 | Hash.AddTemplateArgument(TA); |
1222 | } |
1223 | VisitTypeWithKeyword(T); |
1224 | } |
1225 | |
1226 | void VisitElaboratedType(const ElaboratedType *T) { |
1227 | AddNestedNameSpecifier(NNS: T->getQualifier()); |
1228 | AddQualType(T: T->getNamedType()); |
1229 | VisitTypeWithKeyword(T); |
1230 | } |
1231 | |
1232 | void VisitUnaryTransformType(const UnaryTransformType *T) { |
1233 | AddQualType(T: T->getUnderlyingType()); |
1234 | AddQualType(T: T->getBaseType()); |
1235 | VisitType(T); |
1236 | } |
1237 | |
1238 | void VisitUnresolvedUsingType(const UnresolvedUsingType *T) { |
1239 | AddDecl(D: T->getDecl()); |
1240 | VisitType(T); |
1241 | } |
1242 | |
1243 | void VisitVectorType(const VectorType *T) { |
1244 | AddQualType(T: T->getElementType()); |
1245 | ID.AddInteger(I: T->getNumElements()); |
1246 | ID.AddInteger(I: llvm::to_underlying(E: T->getVectorKind())); |
1247 | VisitType(T); |
1248 | } |
1249 | |
1250 | void VisitExtVectorType(const ExtVectorType * T) { |
1251 | VisitVectorType(T); |
1252 | } |
1253 | }; |
1254 | } // namespace |
1255 | |
1256 | void ODRHash::AddType(const Type *T) { |
1257 | assert(T && "Expecting non-null pointer." ); |
1258 | ODRTypeVisitor(ID, *this).Visit(T); |
1259 | } |
1260 | |
1261 | void ODRHash::AddQualType(QualType T) { |
1262 | AddBoolean(value: T.isNull()); |
1263 | if (T.isNull()) |
1264 | return; |
1265 | SplitQualType split = T.split(); |
1266 | ID.AddInteger(I: split.Quals.getAsOpaqueValue()); |
1267 | AddType(T: split.Ty); |
1268 | } |
1269 | |
1270 | void ODRHash::AddBoolean(bool Value) { |
1271 | Bools.push_back(Elt: Value); |
1272 | } |
1273 | |
1274 | void ODRHash::AddStructuralValue(const APValue &Value) { |
1275 | ID.AddInteger(I: Value.getKind()); |
1276 | |
1277 | // 'APValue::Profile' uses pointer values to make hash for LValue and |
1278 | // MemberPointer, but they differ from one compiler invocation to another. |
1279 | // So, handle them explicitly here. |
1280 | |
1281 | switch (Value.getKind()) { |
1282 | case APValue::LValue: { |
1283 | const APValue::LValueBase &Base = Value.getLValueBase(); |
1284 | if (!Base) { |
1285 | ID.AddInteger(I: Value.getLValueOffset().getQuantity()); |
1286 | break; |
1287 | } |
1288 | |
1289 | assert(Base.is<const ValueDecl *>()); |
1290 | AddDecl(D: Base.get<const ValueDecl *>()); |
1291 | ID.AddInteger(I: Value.getLValueOffset().getQuantity()); |
1292 | |
1293 | bool OnePastTheEnd = Value.isLValueOnePastTheEnd(); |
1294 | if (Value.hasLValuePath()) { |
1295 | QualType TypeSoFar = Base.getType(); |
1296 | for (APValue::LValuePathEntry E : Value.getLValuePath()) { |
1297 | if (const auto *AT = TypeSoFar->getAsArrayTypeUnsafe()) { |
1298 | if (const auto *CAT = dyn_cast<ConstantArrayType>(Val: AT)) |
1299 | OnePastTheEnd |= CAT->getSize() == E.getAsArrayIndex(); |
1300 | TypeSoFar = AT->getElementType(); |
1301 | } else { |
1302 | const Decl *D = E.getAsBaseOrMember().getPointer(); |
1303 | if (const auto *FD = dyn_cast<FieldDecl>(Val: D)) { |
1304 | if (FD->getParent()->isUnion()) |
1305 | ID.AddInteger(I: FD->getFieldIndex()); |
1306 | TypeSoFar = FD->getType(); |
1307 | } else { |
1308 | TypeSoFar = |
1309 | D->getASTContext().getRecordType(Decl: cast<CXXRecordDecl>(Val: D)); |
1310 | } |
1311 | } |
1312 | } |
1313 | } |
1314 | unsigned Val = 0; |
1315 | if (Value.isNullPointer()) |
1316 | Val |= 1 << 0; |
1317 | if (OnePastTheEnd) |
1318 | Val |= 1 << 1; |
1319 | if (Value.hasLValuePath()) |
1320 | Val |= 1 << 2; |
1321 | ID.AddInteger(I: Val); |
1322 | break; |
1323 | } |
1324 | case APValue::MemberPointer: { |
1325 | const ValueDecl *D = Value.getMemberPointerDecl(); |
1326 | assert(D); |
1327 | AddDecl(D); |
1328 | ID.AddInteger( |
1329 | I: D->getASTContext().getMemberPointerPathAdjustment(MP: Value).getQuantity()); |
1330 | break; |
1331 | } |
1332 | default: |
1333 | Value.Profile(ID); |
1334 | } |
1335 | } |
1336 | |