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