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