clang  14.0.0git
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 //===----------------------------------------------------------------------===//
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 =
40  Target->getTemplateInstantiationPattern())
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 
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 
125  int Line) {
126  if (!Buffer)
127  return "";
128 
129  llvm::line_iterator LI(*Buffer, false);
130  for (; !LI.is_at_eof() && LI.line_number() != Line; ++LI)
131  ;
132 
133  return *LI;
134 }
135 
137  const LangOptions &LangOpts) {
138  static StringRef Whitespaces = " \t\n";
139 
140  StringRef Str = GetNthLineOfFile(SM.getBufferOrNone(L.getFileID(), L),
142  StringRef::size_type col = Str.find_first_not_of(Whitespaces);
143  if (col == StringRef::npos)
144  col = 1; // The line only contains whitespace.
145  else
146  col++;
147  SourceLocation StartOfLine =
148  SM.translateLineCol(SM.getFileID(L), L.getExpansionLineNumber(), col);
150  SM.getBufferOrNone(SM.getFileID(StartOfLine), StartOfLine);
151  if (!Buffer)
152  return {};
153 
154  const char *BufferPos = SM.getCharacterData(StartOfLine);
155 
156  Token Token;
157  Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(StartOfLine)), LangOpts,
158  Buffer->getBufferStart(), BufferPos, Buffer->getBufferEnd());
159 
160  size_t NextStart = 0;
161  std::ostringstream LineBuff;
162  while (!Lexer.LexFromRawLexer(Token) && NextStart < 2) {
163  if (Token.isAtStartOfLine() && NextStart++ > 0)
164  continue;
165  LineBuff << std::string(SM.getCharacterData(Token.getLocation()),
166  Token.getLength());
167  }
168 
169  return LineBuff.str();
170 }
171 
172 static llvm::SmallString<32> GetMD5HashOfContent(StringRef Content) {
173  llvm::MD5 Hash;
174  llvm::MD5::MD5Result MD5Res;
175  SmallString<32> Res;
176 
177  Hash.update(Content);
178  Hash.final(MD5Res);
179  llvm::MD5::stringifyResult(MD5Res, Res);
180 
181  return Res;
182 }
183 
185  StringRef CheckerName,
186  StringRef WarningMessage,
187  const Decl *IssueDecl,
188  const LangOptions &LangOpts) {
189  static StringRef Delimiter = "$";
190 
191  return (llvm::Twine(CheckerName) + Delimiter +
192  GetEnclosingDeclContextSignature(IssueDecl) + Delimiter +
193  Twine(IssueLoc.getExpansionColumnNumber()) + Delimiter +
194  NormalizeLine(IssueLoc.getManager(), IssueLoc, LangOpts) +
195  Delimiter + WarningMessage)
196  .str();
197 }
198 
200  StringRef CheckerName,
201  StringRef WarningMessage,
202  const Decl *IssueDecl,
203  const LangOptions &LangOpts) {
204 
206  IssueLoc, CheckerName, WarningMessage, IssueDecl, LangOpts));
207 }
clang::FullSourceLoc::getManager
const SourceManager & getManager() const
Definition: SourceLocation.h:384
Specifiers.h
GetEnclosingDeclContextSignature
static std::string GetEnclosingDeclContextSignature(const Decl *D)
Definition: IssueHash.cpp:88
clang::FullSourceLoc
A SourceLocation and its associated SourceManager.
Definition: SourceLocation.h:370
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::getIssueString
std::string getIssueString(const FullSourceLoc &IssueLoc, llvm::StringRef CheckerName, llvm::StringRef WarningMessage, const Decl *IssueDecl, const LangOptions &LangOpts)
Get the unhashed string representation of the V1 issue hash.
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:88
clang::MultiVersionKind::Target
@ Target
GetMD5HashOfContent
static llvm::SmallString< 32 > GetMD5HashOfContent(StringRef Content)
Definition: IssueHash.cpp:172
DeclCXX.h
clang::Token::isAtStartOfLine
bool isAtStartOfLine() const
isAtStartOfLine - Return true if this token is at the start of a line.
Definition: Token.h:268
llvm::Optional< llvm::MemoryBufferRef >
clang::RQ_RValue
@ RQ_RValue
An rvalue ref-qualifier was provided (&&).
Definition: Type.h:1449
SourceManager.h
clang::Lexer::LexFromRawLexer
bool LexFromRawLexer(Token &Result)
LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...
Definition: Lexer.h:198
clang::Token
Token - This structure provides full information about a lexed token.
Definition: Token.h:34
clang::SourceManager
This class handles loading and caching of source files into memory.
Definition: SourceManager.h:626
Decl.h
clang::Lexer
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens.
Definition: Lexer.h:76
clang::FullSourceLoc::getExpansionLineNumber
unsigned getExpansionLineNumber(bool *Invalid=nullptr) const
Definition: SourceLocation.cpp:226
IssueHash.h
GetSignature
static std::string GetSignature(const FunctionDecl *Target)
Definition: IssueHash.cpp:31
llvm::SmallString< 32 >
ASTContext.h
Line
const AnnotatedLine * Line
Definition: UsingDeclarationsSorter.cpp:68
clang::Token::getLength
unsigned getLength() const
Definition: Token.h:129
Lexer.h
clang::Decl
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:89
clang::FullSourceLoc::getFileID
FileID getFileID() const
Definition: SourceLocation.cpp:159
clang::Token::getLocation
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
Definition: Token.h:126
clang::LangOptions
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:58
clang
Definition: CalledOnceCheck.h:17
GetNthLineOfFile
static StringRef GetNthLineOfFile(llvm::Optional< llvm::MemoryBufferRef > Buffer, int Line)
Definition: IssueHash.cpp:124
clang::RQ_LValue
@ RQ_LValue
An lvalue ref-qualifier was provided (&).
Definition: Type.h:1446
NormalizeLine
static std::string NormalizeLine(const SourceManager &SM, const FullSourceLoc &L, const LangOptions &LangOpts)
Definition: IssueHash.cpp:136
SM
#define SM(sm)
Definition: Cuda.cpp:78
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1856
clang::FullSourceLoc::getExpansionColumnNumber
unsigned getExpansionColumnNumber(bool *Invalid=nullptr) const
Definition: SourceLocation.cpp:231
clang::getIssueHash
llvm::SmallString< 32 > getIssueHash(const FullSourceLoc &IssueLoc, llvm::StringRef CheckerName, llvm::StringRef WarningMessage, const Decl *IssueDecl, const LangOptions &LangOpts)
Returns an opaque identifier for a diagnostic.