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  if (!isa<CXXConstructorDecl>(Target) && !isa<CXXDestructorDecl>(Target) &&
37  !isa<CXXConversionDecl>(Target))
38  Signature.append(Target->getReturnType().getAsString()).append(" ");
39  Signature.append(Target->getQualifiedNameAsString()).append("(");
40 
41  for (int i = 0, paramsCount = Target->getNumParams(); i < paramsCount; ++i) {
42  if (i)
43  Signature.append(", ");
44  Signature.append(Target->getParamDecl(i)->getType().getAsString());
45  }
46 
47  if (Target->isVariadic())
48  Signature.append(", ...");
49  Signature.append(")");
50 
51  const auto *TargetT =
52  llvm::dyn_cast_or_null<FunctionType>(Target->getType().getTypePtr());
53 
54  if (!TargetT || !isa<CXXMethodDecl>(Target))
55  return Signature;
56 
57  if (TargetT->isConst())
58  Signature.append(" const");
59  if (TargetT->isVolatile())
60  Signature.append(" volatile");
61  if (TargetT->isRestrict())
62  Signature.append(" restrict");
63 
64  if (const auto *TargetPT =
65  dyn_cast_or_null<FunctionProtoType>(Target->getType().getTypePtr())) {
66  switch (TargetPT->getRefQualifier()) {
67  case RQ_LValue:
68  Signature.append(" &");
69  break;
70  case RQ_RValue:
71  Signature.append(" &&");
72  break;
73  default:
74  break;
75  }
76  }
77 
78  return Signature;
79 }
80 
81 static std::string GetEnclosingDeclContextSignature(const Decl *D) {
82  if (!D)
83  return "";
84 
85  if (const auto *ND = dyn_cast<NamedDecl>(D)) {
86  std::string DeclName;
87 
88  switch (ND->getKind()) {
89  case Decl::Namespace:
90  case Decl::Record:
91  case Decl::CXXRecord:
92  case Decl::Enum:
93  DeclName = ND->getQualifiedNameAsString();
94  break;
95  case Decl::CXXConstructor:
96  case Decl::CXXDestructor:
97  case Decl::CXXConversion:
98  case Decl::CXXMethod:
99  case Decl::Function:
100  DeclName = GetSignature(dyn_cast_or_null<FunctionDecl>(ND));
101  break;
102  case Decl::ObjCMethod:
103  // ObjC Methods can not be overloaded, qualified name uniquely identifies
104  // the method.
105  DeclName = ND->getQualifiedNameAsString();
106  break;
107  default:
108  break;
109  }
110 
111  return DeclName;
112  }
113 
114  return "";
115 }
116 
117 static StringRef GetNthLineOfFile(llvm::MemoryBuffer *Buffer, int Line) {
118  if (!Buffer)
119  return "";
120 
121  llvm::line_iterator LI(*Buffer, false);
122  for (; !LI.is_at_eof() && LI.line_number() != Line; ++LI)
123  ;
124 
125  return *LI;
126 }
127 
128 static std::string NormalizeLine(const SourceManager &SM, FullSourceLoc &L,
129  const LangOptions &LangOpts) {
130  static StringRef Whitespaces = " \t\n";
131 
132  StringRef Str = GetNthLineOfFile(SM.getBuffer(L.getFileID(), L),
134  StringRef::size_type col = Str.find_first_not_of(Whitespaces);
135  if (col == StringRef::npos)
136  col = 1; // The line only contains whitespace.
137  else
138  col++;
139  SourceLocation StartOfLine =
141  llvm::MemoryBuffer *Buffer =
142  SM.getBuffer(SM.getFileID(StartOfLine), StartOfLine);
143  if (!Buffer)
144  return {};
145 
146  const char *BufferPos = SM.getCharacterData(StartOfLine);
147 
148  Token Token;
149  Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(StartOfLine)), LangOpts,
150  Buffer->getBufferStart(), BufferPos, Buffer->getBufferEnd());
151 
152  size_t NextStart = 0;
153  std::ostringstream LineBuff;
154  while (!Lexer.LexFromRawLexer(Token) && NextStart < 2) {
155  if (Token.isAtStartOfLine() && NextStart++ > 0)
156  continue;
157  LineBuff << std::string(SM.getCharacterData(Token.getLocation()),
158  Token.getLength());
159  }
160 
161  return LineBuff.str();
162 }
163 
164 static llvm::SmallString<32> GetHashOfContent(StringRef Content) {
165  llvm::MD5 Hash;
166  llvm::MD5::MD5Result MD5Res;
167  SmallString<32> Res;
168 
169  Hash.update(Content);
170  Hash.final(MD5Res);
171  llvm::MD5::stringifyResult(MD5Res, Res);
172 
173  return Res;
174 }
175 
176 std::string clang::GetIssueString(const SourceManager &SM,
177  FullSourceLoc &IssueLoc,
178  StringRef CheckerName, StringRef BugType,
179  const Decl *D,
180  const LangOptions &LangOpts) {
181  static StringRef Delimiter = "$";
182 
183  return (llvm::Twine(CheckerName) + Delimiter +
184  GetEnclosingDeclContextSignature(D) + Delimiter +
185  Twine(IssueLoc.getExpansionColumnNumber()) + Delimiter +
186  NormalizeLine(SM, IssueLoc, LangOpts) + Delimiter + BugType)
187  .str();
188 }
189 
191  FullSourceLoc &IssueLoc,
192  StringRef CheckerName, StringRef BugType,
193  const Decl *D,
194  const LangOptions &LangOpts) {
195 
196  return GetHashOfContent(
197  GetIssueString(SM, IssueLoc, CheckerName, BugType, D, LangOpts));
198 }
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file. ...
Defines the clang::ASTContext interface.
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
Definition: Decl.h:1631
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens...
Definition: Lexer.h:63
bool LexFromRawLexer(Token &Result)
LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...
Definition: Lexer.h:171
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:81
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:2130
FileID getFileID() const
static std::string GetEnclosingDeclContextSignature(const Decl *D)
Definition: IssueHash.cpp:81
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:117
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:1259
std::string getAsString() const
Definition: Type.h:940
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:5543
unsigned getExpansionColumnNumber(bool *Invalid=nullptr) const
bool isVariadic() const
Whether this function is variadic.
Definition: Decl.cpp:2540
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:1308
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:2112
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:1261
static std::string NormalizeLine(const SourceManager &SM, FullSourceLoc &L, const LangOptions &LangOpts)
Definition: IssueHash.cpp:128
Defines various enumerations that describe declaration and type specifiers.
Dataflow Directional Tag Classes.
Kind getKind() const
Definition: DeclBase.h:410
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:1436
QualType getType() const
Definition: Decl.h:602
static llvm::SmallString< 32 > GetHashOfContent(StringRef Content)
Definition: IssueHash.cpp:164
unsigned getNumParams() const
getNumParams - Return the number of parameters this function must have based on its FunctionType...
Definition: Decl.cpp:2877
This class handles loading and caching of source files into memory.