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