clang  6.0.0svn
IssueHash.cpp
Go to the documentation of this file.
1 //===---------- IssueHash.cpp - Generate identification hashes --*- 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 //===----------------------------------------------------------------------===//
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/Decl.h"
12 #include "clang/AST/DeclCXX.h"
14 #include "clang/Basic/Specifiers.h"
15 #include "clang/Lex/Lexer.h"
16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/ADT/Twine.h"
19 #include "llvm/Support/LineIterator.h"
20 #include "llvm/Support/MD5.h"
21 #include "llvm/Support/Path.h"
22 
23 #include <functional>
24 #include <sstream>
25 #include <string>
26 
27 using namespace clang;
28 
29 // Get a string representation of the parts of the signature that can be
30 // overloaded on.
31 static std::string GetSignature(const FunctionDecl *Target) {
32  if (!Target)
33  return "";
34  std::string Signature;
35 
36  // When a flow sensitive bug happens in templated code we should not generate
37  // distinct hash value for every instantiation. Use the signature from the
38  // primary template.
39  if (const FunctionDecl *InstantiatedFrom =
41  Target = InstantiatedFrom;
42 
43  if (!isa<CXXConstructorDecl>(Target) && !isa<CXXDestructorDecl>(Target) &&
44  !isa<CXXConversionDecl>(Target))
45  Signature.append(Target->getReturnType().getAsString()).append(" ");
46  Signature.append(Target->getQualifiedNameAsString()).append("(");
47 
48  for (int i = 0, paramsCount = Target->getNumParams(); i < paramsCount; ++i) {
49  if (i)
50  Signature.append(", ");
51  Signature.append(Target->getParamDecl(i)->getType().getAsString());
52  }
53 
54  if (Target->isVariadic())
55  Signature.append(", ...");
56  Signature.append(")");
57 
58  const auto *TargetT =
59  llvm::dyn_cast_or_null<FunctionType>(Target->getType().getTypePtr());
60 
61  if (!TargetT || !isa<CXXMethodDecl>(Target))
62  return Signature;
63 
64  if (TargetT->isConst())
65  Signature.append(" const");
66  if (TargetT->isVolatile())
67  Signature.append(" volatile");
68  if (TargetT->isRestrict())
69  Signature.append(" restrict");
70 
71  if (const auto *TargetPT =
72  dyn_cast_or_null<FunctionProtoType>(Target->getType().getTypePtr())) {
73  switch (TargetPT->getRefQualifier()) {
74  case RQ_LValue:
75  Signature.append(" &");
76  break;
77  case RQ_RValue:
78  Signature.append(" &&");
79  break;
80  default:
81  break;
82  }
83  }
84 
85  return Signature;
86 }
87 
88 static std::string GetEnclosingDeclContextSignature(const Decl *D) {
89  if (!D)
90  return "";
91 
92  if (const auto *ND = dyn_cast<NamedDecl>(D)) {
93  std::string DeclName;
94 
95  switch (ND->getKind()) {
96  case Decl::Namespace:
97  case Decl::Record:
98  case Decl::CXXRecord:
99  case Decl::Enum:
100  DeclName = ND->getQualifiedNameAsString();
101  break;
102  case Decl::CXXConstructor:
103  case Decl::CXXDestructor:
104  case Decl::CXXConversion:
105  case Decl::CXXMethod:
106  case Decl::Function:
107  DeclName = GetSignature(dyn_cast_or_null<FunctionDecl>(ND));
108  break;
109  case Decl::ObjCMethod:
110  // ObjC Methods can not be overloaded, qualified name uniquely identifies
111  // the method.
112  DeclName = ND->getQualifiedNameAsString();
113  break;
114  default:
115  break;
116  }
117 
118  return DeclName;
119  }
120 
121  return "";
122 }
123 
124 static StringRef GetNthLineOfFile(llvm::MemoryBuffer *Buffer, int Line) {
125  if (!Buffer)
126  return "";
127 
128  llvm::line_iterator LI(*Buffer, false);
129  for (; !LI.is_at_eof() && LI.line_number() != Line; ++LI)
130  ;
131 
132  return *LI;
133 }
134 
135 static std::string NormalizeLine(const SourceManager &SM, FullSourceLoc &L,
136  const LangOptions &LangOpts) {
137  static StringRef Whitespaces = " \t\n";
138 
139  StringRef Str = GetNthLineOfFile(SM.getBuffer(L.getFileID(), L),
141  StringRef::size_type col = Str.find_first_not_of(Whitespaces);
142  if (col == StringRef::npos)
143  col = 1; // The line only contains whitespace.
144  else
145  col++;
146  SourceLocation StartOfLine =
148  llvm::MemoryBuffer *Buffer =
149  SM.getBuffer(SM.getFileID(StartOfLine), StartOfLine);
150  if (!Buffer)
151  return {};
152 
153  const char *BufferPos = SM.getCharacterData(StartOfLine);
154 
155  Token Token;
156  Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(StartOfLine)), LangOpts,
157  Buffer->getBufferStart(), BufferPos, Buffer->getBufferEnd());
158 
159  size_t NextStart = 0;
160  std::ostringstream LineBuff;
161  while (!Lexer.LexFromRawLexer(Token) && NextStart < 2) {
162  if (Token.isAtStartOfLine() && NextStart++ > 0)
163  continue;
164  LineBuff << std::string(SM.getCharacterData(Token.getLocation()),
165  Token.getLength());
166  }
167 
168  return LineBuff.str();
169 }
170 
171 static llvm::SmallString<32> GetHashOfContent(StringRef Content) {
172  llvm::MD5 Hash;
173  llvm::MD5::MD5Result MD5Res;
174  SmallString<32> Res;
175 
176  Hash.update(Content);
177  Hash.final(MD5Res);
178  llvm::MD5::stringifyResult(MD5Res, Res);
179 
180  return Res;
181 }
182 
183 std::string clang::GetIssueString(const SourceManager &SM,
184  FullSourceLoc &IssueLoc,
185  StringRef CheckerName, StringRef BugType,
186  const Decl *D,
187  const LangOptions &LangOpts) {
188  static StringRef Delimiter = "$";
189 
190  return (llvm::Twine(CheckerName) + Delimiter +
191  GetEnclosingDeclContextSignature(D) + Delimiter +
192  Twine(IssueLoc.getExpansionColumnNumber()) + Delimiter +
193  NormalizeLine(SM, IssueLoc, LangOpts) + Delimiter + BugType)
194  .str();
195 }
196 
198  FullSourceLoc &IssueLoc,
199  StringRef CheckerName, StringRef BugType,
200  const Decl *D,
201  const LangOptions &LangOpts) {
202 
203  return GetHashOfContent(
204  GetIssueString(SM, IssueLoc, CheckerName, BugType, D, LangOpts));
205 }
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file. ...
Defines the clang::ASTContext interface.
An instance of this class is created to represent a function declaration or definition.
Definition: Decl.h:1697
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens...
Definition: Lexer.h:77
bool LexFromRawLexer(Token &Result)
LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...
Definition: Lexer.h:195
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
const char * getCharacterData(SourceLocation SL, bool *Invalid=nullptr) const
Return a pointer to the start of the specified location in the appropriate spelling MemoryBuffer...
llvm::SmallString< 32 > GetIssueHash(const SourceManager &SM, FullSourceLoc &IssueLoc, llvm::StringRef CheckerName, llvm::StringRef BugType, const Decl *D, const LangOptions &LangOpts)
Get an MD5 hash to help identify bugs.
QualType getReturnType() const
Definition: Decl.h:2201
FileID getFileID() const
static std::string GetEnclosingDeclContextSignature(const Decl *D)
Definition: IssueHash.cpp:88
Token - This structure provides full information about a lexed token.
Definition: Token.h:35
static StringRef GetNthLineOfFile(llvm::MemoryBuffer *Buffer, int Line)
Definition: IssueHash.cpp:124
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:48
An lvalue ref-qualifier was provided (&).
Definition: Type.h:1309
std::string getAsString() const
Definition: Type.h:979
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:5720
unsigned getExpansionColumnNumber(bool *Invalid=nullptr) const
bool isVariadic() const
Whether this function is variadic.
Definition: Decl.cpp:2570
const AnnotatedLine * Line
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file. ...
Definition: Token.h:124
static std::string GetSignature(const FunctionDecl *Target)
Definition: IssueHash.cpp:31
const SourceManager & SM
Definition: Format.cpp:1337
llvm::MemoryBuffer * getBuffer(FileID FID, SourceLocation Loc, bool *Invalid=nullptr) const
Return the buffer for the specified FileID.
Encodes a location in the source.
const ParmVarDecl * getParamDecl(unsigned i) const
Definition: Decl.h:2184
bool isAtStartOfLine() const
isAtStartOfLine - Return true if this token is at the start of a line.
Definition: Token.h:266
An rvalue ref-qualifier was provided (&&).
Definition: Type.h:1312
static std::string NormalizeLine(const SourceManager &SM, FullSourceLoc &L, const LangOptions &LangOpts)
Definition: IssueHash.cpp:135
Defines various enumerations that describe declaration and type specifiers.
Dataflow Directional Tag Classes.
FunctionDecl * getTemplateInstantiationPattern() const
Retrieve the function declaration from which this function could be instantiated, if it is an instant...
Definition: Decl.cpp:3282
SourceLocation translateLineCol(FileID FID, unsigned Line, unsigned Col) const
Get the source location in FID for the given line:col.
unsigned getLength() const
Definition: Token.h:127
unsigned getExpansionLineNumber(bool *Invalid=nullptr) const
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
std::string GetIssueString(const SourceManager &SM, FullSourceLoc &IssueLoc, llvm::StringRef CheckerName, llvm::StringRef BugType, const Decl *D, const LangOptions &LangOpts)
Get the string representation of issue hash.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
A SourceLocation and its associated SourceManager.
std::string getQualifiedNameAsString() const
Definition: Decl.cpp:1471
QualType getType() const
Definition: Decl.h:638
static llvm::SmallString< 32 > GetHashOfContent(StringRef Content)
Definition: IssueHash.cpp:171
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition: Decl.cpp:2906
This class handles loading and caching of source files into memory.