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
22using namespace clang;
23
24void ODRHash::AddStmt(const Stmt *S) {
25 assert(S && "Expecting non-null pointer.");
26 S->ProcessODRHash(ID, Hash&: *this);
27}
28
29void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) {
30 assert(II && "Expecting non-null pointer.");
31 ID.AddString(String: II->getName());
32}
33
34void 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
46void 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
112void 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
141void 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
168void 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
210void 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
219void ODRHash::clear() {
220 DeclNameMap.clear();
221 Bools.clear();
222 ID.clear();
223}
224
225unsigned 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
257namespace {
258// Process a Decl pointer. Add* methods call back into ODRHash while Visit*
259// methods process the relevant parts of the Decl.
260class ODRDeclVisitor : public ConstDeclVisitor<ODRDeclVisitor> {
261 typedef ConstDeclVisitor<ODRDeclVisitor> Inherited;
262 llvm::FoldingSetNodeID &ID;
263 ODRHash &Hash;
264
265public:
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.
536bool 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
562void ODRHash::AddSubDecl(const Decl *D) {
563 assert(D && "Expecting non-null pointer.");
564
565 ODRDeclVisitor(ID, *this).Visit(D);
566}
567
568void 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
615void 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
633void 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
660void 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
753void 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
781void 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
806void 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
830namespace {
831// Process a Type pointer. Add* methods call back into ODRHash while Visit*
832// methods process the relevant parts of the Type.
833class ODRTypeVisitor : public TypeVisitor<ODRTypeVisitor> {
834 typedef TypeVisitor<ODRTypeVisitor> Inherited;
835 llvm::FoldingSetNodeID &ID;
836 ODRHash &Hash;
837
838public:
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
1256void ODRHash::AddType(const Type *T) {
1257 assert(T && "Expecting non-null pointer.");
1258 ODRTypeVisitor(ID, *this).Visit(T);
1259}
1260
1261void 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
1270void ODRHash::AddBoolean(bool Value) {
1271 Bools.push_back(Elt: Value);
1272}
1273
1274void 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