blob: 35af0e98a9129a2958893835dac52cde2c66d519 [file] [log] [blame]
Richard Trieue7f7ed22017-02-22 01:11:25 +00001//===-- ODRHash.cpp - Hashing to diagnose ODR failures ----------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// This file implements the ODRHash class, which calculates a hash based
12/// on AST nodes, which is stable across different runs.
13///
14//===----------------------------------------------------------------------===//
15
16#include "clang/AST/ODRHash.h"
17
18#include "clang/AST/DeclVisitor.h"
19#include "clang/AST/NestedNameSpecifier.h"
20#include "clang/AST/StmtVisitor.h"
21#include "clang/AST/TypeVisitor.h"
22
23using namespace clang;
24
Richard Trieu639d7b62017-02-22 22:22:42 +000025void ODRHash::AddStmt(const Stmt *S) {
26 assert(S && "Expecting non-null pointer.");
27 S->ProcessODRHash(ID, *this);
28}
Richard Trieud0786092017-02-23 00:23:01 +000029
30void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) {
31 assert(II && "Expecting non-null pointer.");
32 ID.AddString(II->getName());
33}
34
Richard Trieue7f7ed22017-02-22 01:11:25 +000035void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {}
36void ODRHash::AddTemplateName(TemplateName Name) {}
37void ODRHash::AddDeclarationName(DeclarationName Name) {}
38void ODRHash::AddTemplateArgument(TemplateArgument TA) {}
39void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) {}
40
41void ODRHash::clear() {
42 DeclMap.clear();
43 TypeMap.clear();
44 Bools.clear();
45 ID.clear();
46}
47
48unsigned ODRHash::CalculateHash() {
49 // Append the bools to the end of the data segment backwards. This allows
50 // for the bools data to be compressed 32 times smaller compared to using
51 // ID.AddBoolean
52 const unsigned unsigned_bits = sizeof(unsigned) * CHAR_BIT;
53 const unsigned size = Bools.size();
54 const unsigned remainder = size % unsigned_bits;
55 const unsigned loops = size / unsigned_bits;
56 auto I = Bools.rbegin();
57 unsigned value = 0;
58 for (unsigned i = 0; i < remainder; ++i) {
59 value <<= 1;
60 value |= *I;
61 ++I;
62 }
63 ID.AddInteger(value);
64
65 for (unsigned i = 0; i < loops; ++i) {
66 value = 0;
67 for (unsigned j = 0; j < unsigned_bits; ++j) {
68 value <<= 1;
69 value |= *I;
70 ++I;
71 }
72 ID.AddInteger(value);
73 }
74
75 assert(I == Bools.rend());
76 Bools.clear();
77 return ID.ComputeHash();
78}
79
80// Process a Decl pointer. Add* methods call back into ODRHash while Visit*
81// methods process the relevant parts of the Decl.
82class ODRDeclVisitor : public ConstDeclVisitor<ODRDeclVisitor> {
83 typedef ConstDeclVisitor<ODRDeclVisitor> Inherited;
84 llvm::FoldingSetNodeID &ID;
Richard Trieu639d7b62017-02-22 22:22:42 +000085 ODRHash &Hash;
Richard Trieue7f7ed22017-02-22 01:11:25 +000086
87public:
Richard Trieu639d7b62017-02-22 22:22:42 +000088 ODRDeclVisitor(llvm::FoldingSetNodeID &ID, ODRHash &Hash)
89 : ID(ID), Hash(Hash) {}
90
91 void AddStmt(const Stmt *S) {
92 Hash.AddBoolean(S);
93 if (S) {
94 Hash.AddStmt(S);
95 }
96 }
Richard Trieue7f7ed22017-02-22 01:11:25 +000097
Richard Trieud0786092017-02-23 00:23:01 +000098 void AddIdentifierInfo(const IdentifierInfo *II) {
99 Hash.AddBoolean(II);
100 if (II) {
101 Hash.AddIdentifierInfo(II);
102 }
103 }
104
Richard Trieue7f7ed22017-02-22 01:11:25 +0000105 void Visit(const Decl *D) {
106 ID.AddInteger(D->getKind());
107 Inherited::Visit(D);
108 }
109
Richard Trieud0786092017-02-23 00:23:01 +0000110 void VisitNamedDecl(const NamedDecl *D) {
111 AddIdentifierInfo(D->getIdentifier());
112 Inherited::VisitNamedDecl(D);
113 }
114
Richard Trieue7f7ed22017-02-22 01:11:25 +0000115 void VisitAccessSpecDecl(const AccessSpecDecl *D) {
116 ID.AddInteger(D->getAccess());
117 Inherited::VisitAccessSpecDecl(D);
118 }
Richard Trieu639d7b62017-02-22 22:22:42 +0000119
120 void VisitStaticAssertDecl(const StaticAssertDecl *D) {
121 AddStmt(D->getAssertExpr());
122 AddStmt(D->getMessage());
123
124 Inherited::VisitStaticAssertDecl(D);
125 }
Richard Trieud0786092017-02-23 00:23:01 +0000126
127 void VisitFieldDecl(const FieldDecl *D) {
128 Inherited::VisitFieldDecl(D);
129 }
Richard Trieue7f7ed22017-02-22 01:11:25 +0000130};
131
132// Only allow a small portion of Decl's to be processed. Remove this once
133// all Decl's can be handled.
134bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) {
135 if (D->isImplicit()) return false;
136 if (D->getDeclContext() != Parent) return false;
137
138 switch (D->getKind()) {
139 default:
140 return false;
141 case Decl::AccessSpec:
Richard Trieud0786092017-02-23 00:23:01 +0000142 case Decl::Field:
Richard Trieu639d7b62017-02-22 22:22:42 +0000143 case Decl::StaticAssert:
Richard Trieue7f7ed22017-02-22 01:11:25 +0000144 return true;
145 }
146}
147
148void ODRHash::AddSubDecl(const Decl *D) {
149 assert(D && "Expecting non-null pointer.");
150 AddDecl(D);
151
Richard Trieu639d7b62017-02-22 22:22:42 +0000152 ODRDeclVisitor(ID, *this).Visit(D);
Richard Trieue7f7ed22017-02-22 01:11:25 +0000153}
154
155void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) {
156 assert(Record && Record->hasDefinition() &&
157 "Expected non-null record to be a definition.");
158 AddDecl(Record);
159
160 // Filter out sub-Decls which will not be processed in order to get an
161 // accurate count of Decl's.
162 llvm::SmallVector<const Decl *, 16> Decls;
163 for (const Decl *SubDecl : Record->decls()) {
164 if (isWhitelistedDecl(SubDecl, Record)) {
165 Decls.push_back(SubDecl);
166 }
167 }
168
169 ID.AddInteger(Decls.size());
170 for (auto SubDecl : Decls) {
171 AddSubDecl(SubDecl);
172 }
173}
174
175void ODRHash::AddDecl(const Decl *D) {
176 assert(D && "Expecting non-null pointer.");
177 auto Result = DeclMap.insert(std::make_pair(D, DeclMap.size()));
178 ID.AddInteger(Result.first->second);
179 // On first encounter of a Decl pointer, process it. Every time afterwards,
180 // only the index value is needed.
181 if (!Result.second) {
182 return;
183 }
184
185 ID.AddInteger(D->getKind());
186}
187
188void ODRHash::AddType(const Type *T) {}
189void ODRHash::AddQualType(QualType T) {}
190void ODRHash::AddBoolean(bool Value) {
191 Bools.push_back(Value);
192}