blob: 9c6f38c2d9da2d97067034f4dce78799e6a764d2 [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 Trieue7f7ed22017-02-22 01:11:25 +000029void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) {}
30void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {}
31void ODRHash::AddTemplateName(TemplateName Name) {}
32void ODRHash::AddDeclarationName(DeclarationName Name) {}
33void ODRHash::AddTemplateArgument(TemplateArgument TA) {}
34void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) {}
35
36void ODRHash::clear() {
37 DeclMap.clear();
38 TypeMap.clear();
39 Bools.clear();
40 ID.clear();
41}
42
43unsigned ODRHash::CalculateHash() {
44 // Append the bools to the end of the data segment backwards. This allows
45 // for the bools data to be compressed 32 times smaller compared to using
46 // ID.AddBoolean
47 const unsigned unsigned_bits = sizeof(unsigned) * CHAR_BIT;
48 const unsigned size = Bools.size();
49 const unsigned remainder = size % unsigned_bits;
50 const unsigned loops = size / unsigned_bits;
51 auto I = Bools.rbegin();
52 unsigned value = 0;
53 for (unsigned i = 0; i < remainder; ++i) {
54 value <<= 1;
55 value |= *I;
56 ++I;
57 }
58 ID.AddInteger(value);
59
60 for (unsigned i = 0; i < loops; ++i) {
61 value = 0;
62 for (unsigned j = 0; j < unsigned_bits; ++j) {
63 value <<= 1;
64 value |= *I;
65 ++I;
66 }
67 ID.AddInteger(value);
68 }
69
70 assert(I == Bools.rend());
71 Bools.clear();
72 return ID.ComputeHash();
73}
74
75// Process a Decl pointer. Add* methods call back into ODRHash while Visit*
76// methods process the relevant parts of the Decl.
77class ODRDeclVisitor : public ConstDeclVisitor<ODRDeclVisitor> {
78 typedef ConstDeclVisitor<ODRDeclVisitor> Inherited;
79 llvm::FoldingSetNodeID &ID;
Richard Trieu639d7b62017-02-22 22:22:42 +000080 ODRHash &Hash;
Richard Trieue7f7ed22017-02-22 01:11:25 +000081
82public:
Richard Trieu639d7b62017-02-22 22:22:42 +000083 ODRDeclVisitor(llvm::FoldingSetNodeID &ID, ODRHash &Hash)
84 : ID(ID), Hash(Hash) {}
85
86 void AddStmt(const Stmt *S) {
87 Hash.AddBoolean(S);
88 if (S) {
89 Hash.AddStmt(S);
90 }
91 }
Richard Trieue7f7ed22017-02-22 01:11:25 +000092
93 void Visit(const Decl *D) {
94 ID.AddInteger(D->getKind());
95 Inherited::Visit(D);
96 }
97
98 void VisitAccessSpecDecl(const AccessSpecDecl *D) {
99 ID.AddInteger(D->getAccess());
100 Inherited::VisitAccessSpecDecl(D);
101 }
Richard Trieu639d7b62017-02-22 22:22:42 +0000102
103 void VisitStaticAssertDecl(const StaticAssertDecl *D) {
104 AddStmt(D->getAssertExpr());
105 AddStmt(D->getMessage());
106
107 Inherited::VisitStaticAssertDecl(D);
108 }
Richard Trieue7f7ed22017-02-22 01:11:25 +0000109};
110
111// Only allow a small portion of Decl's to be processed. Remove this once
112// all Decl's can be handled.
113bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) {
114 if (D->isImplicit()) return false;
115 if (D->getDeclContext() != Parent) return false;
116
117 switch (D->getKind()) {
118 default:
119 return false;
120 case Decl::AccessSpec:
Richard Trieu639d7b62017-02-22 22:22:42 +0000121 case Decl::StaticAssert:
Richard Trieue7f7ed22017-02-22 01:11:25 +0000122 return true;
123 }
124}
125
126void ODRHash::AddSubDecl(const Decl *D) {
127 assert(D && "Expecting non-null pointer.");
128 AddDecl(D);
129
Richard Trieu639d7b62017-02-22 22:22:42 +0000130 ODRDeclVisitor(ID, *this).Visit(D);
Richard Trieue7f7ed22017-02-22 01:11:25 +0000131}
132
133void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) {
134 assert(Record && Record->hasDefinition() &&
135 "Expected non-null record to be a definition.");
136 AddDecl(Record);
137
138 // Filter out sub-Decls which will not be processed in order to get an
139 // accurate count of Decl's.
140 llvm::SmallVector<const Decl *, 16> Decls;
141 for (const Decl *SubDecl : Record->decls()) {
142 if (isWhitelistedDecl(SubDecl, Record)) {
143 Decls.push_back(SubDecl);
144 }
145 }
146
147 ID.AddInteger(Decls.size());
148 for (auto SubDecl : Decls) {
149 AddSubDecl(SubDecl);
150 }
151}
152
153void ODRHash::AddDecl(const Decl *D) {
154 assert(D && "Expecting non-null pointer.");
155 auto Result = DeclMap.insert(std::make_pair(D, DeclMap.size()));
156 ID.AddInteger(Result.first->second);
157 // On first encounter of a Decl pointer, process it. Every time afterwards,
158 // only the index value is needed.
159 if (!Result.second) {
160 return;
161 }
162
163 ID.AddInteger(D->getKind());
164}
165
166void ODRHash::AddType(const Type *T) {}
167void ODRHash::AddQualType(QualType T) {}
168void ODRHash::AddBoolean(bool Value) {
169 Bools.push_back(Value);
170}