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