Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Analysis/IssueHash.cpp
35233 views
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
9
#include "clang/Analysis/IssueHash.h"
10
#include "clang/AST/ASTContext.h"
11
#include "clang/AST/Decl.h"
12
#include "clang/AST/DeclCXX.h"
13
#include "clang/Basic/SourceManager.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 <optional>
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
// When a flow sensitive bug happens in templated code we should not generate
38
// distinct hash value for every instantiation. Use the signature from the
39
// primary template.
40
if (const FunctionDecl *InstantiatedFrom =
41
Target->getTemplateInstantiationPattern())
42
Target = InstantiatedFrom;
43
44
if (!isa<CXXConstructorDecl>(Target) && !isa<CXXDestructorDecl>(Target) &&
45
!isa<CXXConversionDecl>(Target))
46
Signature.append(Target->getReturnType().getAsString()).append(" ");
47
Signature.append(Target->getQualifiedNameAsString()).append("(");
48
49
for (int i = 0, paramsCount = Target->getNumParams(); i < paramsCount; ++i) {
50
if (i)
51
Signature.append(", ");
52
Signature.append(Target->getParamDecl(i)->getType().getAsString());
53
}
54
55
if (Target->isVariadic())
56
Signature.append(", ...");
57
Signature.append(")");
58
59
const auto *TargetT =
60
llvm::dyn_cast_or_null<FunctionType>(Target->getType().getTypePtr());
61
62
if (!TargetT || !isa<CXXMethodDecl>(Target))
63
return Signature;
64
65
if (TargetT->isConst())
66
Signature.append(" const");
67
if (TargetT->isVolatile())
68
Signature.append(" volatile");
69
if (TargetT->isRestrict())
70
Signature.append(" restrict");
71
72
if (const auto *TargetPT =
73
dyn_cast_or_null<FunctionProtoType>(Target->getType().getTypePtr())) {
74
switch (TargetPT->getRefQualifier()) {
75
case RQ_LValue:
76
Signature.append(" &");
77
break;
78
case RQ_RValue:
79
Signature.append(" &&");
80
break;
81
default:
82
break;
83
}
84
}
85
86
return Signature;
87
}
88
89
static std::string GetEnclosingDeclContextSignature(const Decl *D) {
90
if (!D)
91
return "";
92
93
if (const auto *ND = dyn_cast<NamedDecl>(D)) {
94
std::string DeclName;
95
96
switch (ND->getKind()) {
97
case Decl::Namespace:
98
case Decl::Record:
99
case Decl::CXXRecord:
100
case Decl::Enum:
101
DeclName = ND->getQualifiedNameAsString();
102
break;
103
case Decl::CXXConstructor:
104
case Decl::CXXDestructor:
105
case Decl::CXXConversion:
106
case Decl::CXXMethod:
107
case Decl::Function:
108
DeclName = GetSignature(dyn_cast_or_null<FunctionDecl>(ND));
109
break;
110
case Decl::ObjCMethod:
111
// ObjC Methods can not be overloaded, qualified name uniquely identifies
112
// the method.
113
DeclName = ND->getQualifiedNameAsString();
114
break;
115
default:
116
break;
117
}
118
119
return DeclName;
120
}
121
122
return "";
123
}
124
125
static StringRef GetNthLineOfFile(std::optional<llvm::MemoryBufferRef> Buffer,
126
int Line) {
127
if (!Buffer)
128
return "";
129
130
llvm::line_iterator LI(*Buffer, false);
131
for (; !LI.is_at_eof() && LI.line_number() != Line; ++LI)
132
;
133
134
return *LI;
135
}
136
137
static std::string NormalizeLine(const SourceManager &SM, const FullSourceLoc &L,
138
const LangOptions &LangOpts) {
139
static StringRef Whitespaces = " \t\n";
140
141
StringRef Str = GetNthLineOfFile(SM.getBufferOrNone(L.getFileID(), L),
142
L.getExpansionLineNumber());
143
StringRef::size_type col = Str.find_first_not_of(Whitespaces);
144
if (col == StringRef::npos)
145
col = 1; // The line only contains whitespace.
146
else
147
col++;
148
SourceLocation StartOfLine =
149
SM.translateLineCol(SM.getFileID(L), L.getExpansionLineNumber(), col);
150
std::optional<llvm::MemoryBufferRef> Buffer =
151
SM.getBufferOrNone(SM.getFileID(StartOfLine), StartOfLine);
152
if (!Buffer)
153
return {};
154
155
const char *BufferPos = SM.getCharacterData(StartOfLine);
156
157
Token Token;
158
Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(StartOfLine)), LangOpts,
159
Buffer->getBufferStart(), BufferPos, Buffer->getBufferEnd());
160
161
size_t NextStart = 0;
162
std::ostringstream LineBuff;
163
while (!Lexer.LexFromRawLexer(Token) && NextStart < 2) {
164
if (Token.isAtStartOfLine() && NextStart++ > 0)
165
continue;
166
LineBuff << std::string(SM.getCharacterData(Token.getLocation()),
167
Token.getLength());
168
}
169
170
return LineBuff.str();
171
}
172
173
static llvm::SmallString<32> GetMD5HashOfContent(StringRef Content) {
174
llvm::MD5 Hash;
175
llvm::MD5::MD5Result MD5Res;
176
SmallString<32> Res;
177
178
Hash.update(Content);
179
Hash.final(MD5Res);
180
llvm::MD5::stringifyResult(MD5Res, Res);
181
182
return Res;
183
}
184
185
std::string clang::getIssueString(const FullSourceLoc &IssueLoc,
186
StringRef CheckerName,
187
StringRef WarningMessage,
188
const Decl *IssueDecl,
189
const LangOptions &LangOpts) {
190
static StringRef Delimiter = "$";
191
192
return (llvm::Twine(CheckerName) + Delimiter +
193
GetEnclosingDeclContextSignature(IssueDecl) + Delimiter +
194
Twine(IssueLoc.getExpansionColumnNumber()) + Delimiter +
195
NormalizeLine(IssueLoc.getManager(), IssueLoc, LangOpts) +
196
Delimiter + WarningMessage)
197
.str();
198
}
199
200
SmallString<32> clang::getIssueHash(const FullSourceLoc &IssueLoc,
201
StringRef CheckerName,
202
StringRef WarningMessage,
203
const Decl *IssueDecl,
204
const LangOptions &LangOpts) {
205
206
return GetMD5HashOfContent(getIssueString(
207
IssueLoc, CheckerName, WarningMessage, IssueDecl, LangOpts));
208
}
209
210