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 *EnclosingDecl) {
86 if (const auto *ND = dyn_cast_or_null<NamedDecl>(EnclosingDecl)) {
87 if (const auto *FD = dyn_cast<FunctionDecl>(ND))
88 // To distinguish overloads we need to use the signature.
89 return GetSignature(FD);
90 return ND->getQualifiedNameAsString();
91 }
92 return "";
93}
94
95static StringRef GetNthLineOfFile(std::optional<llvm::MemoryBufferRef> Buffer,
96 int Line) {
97 if (!Buffer)
98 return "";
99
100 llvm::line_iterator LI(*Buffer, false);
101 for (; !LI.is_at_eof() && LI.line_number() != Line; ++LI)
102 ;
103
104 return *LI;
105}
106
107static std::string NormalizeLine(const SourceManager &SM, const FullSourceLoc &L,
108 const LangOptions &LangOpts) {
109 static StringRef Whitespaces = " \t\n";
110
111 StringRef Str = GetNthLineOfFile(SM.getBufferOrNone(L.getFileID(), L),
113 StringRef::size_type col = Str.find_first_not_of(Whitespaces);
114 if (col == StringRef::npos)
115 col = 1; // The line only contains whitespace.
116 else
117 col++;
118 SourceLocation StartOfLine =
120 std::optional<llvm::MemoryBufferRef> Buffer =
121 SM.getBufferOrNone(SM.getFileID(StartOfLine), StartOfLine);
122 if (!Buffer)
123 return {};
124
125 const char *BufferPos = SM.getCharacterData(StartOfLine);
126
127 Token Token;
128 Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(StartOfLine)), LangOpts,
129 Buffer->getBufferStart(), BufferPos, Buffer->getBufferEnd());
130
131 size_t NextStart = 0;
132 std::ostringstream LineBuff;
133 while (!Lexer.LexFromRawLexer(Token) && NextStart < 2) {
134 if (Token.isAtStartOfLine() && NextStart++ > 0)
135 continue;
136 LineBuff << std::string(SM.getCharacterData(Token.getLocation()),
137 Token.getLength());
138 }
139
140 return LineBuff.str();
141}
142
144 llvm::MD5 Hash;
145 llvm::MD5::MD5Result MD5Res;
146 SmallString<32> Res;
147
148 Hash.update(Content);
149 Hash.final(MD5Res);
150 llvm::MD5::stringifyResult(MD5Res, Res);
151
152 return Res;
153}
154
155std::string clang::getIssueString(const FullSourceLoc &IssueLoc,
156 StringRef CheckerName,
157 StringRef WarningMessage,
158 const Decl *IssueDecl,
159 const LangOptions &LangOpts) {
160 static StringRef Delimiter = "$";
161
162 return (llvm::Twine(CheckerName) + Delimiter +
163 GetEnclosingDeclContextSignature(IssueDecl) + Delimiter +
164 Twine(IssueLoc.getExpansionColumnNumber()) + Delimiter +
165 NormalizeLine(IssueLoc.getManager(), IssueLoc, LangOpts) +
166 Delimiter + WarningMessage)
167 .str();
168}
169
171 StringRef CheckerName,
172 StringRef WarningMessage,
173 const Decl *IssueDecl,
174 const LangOptions &LangOpts) {
175
177 IssueLoc, CheckerName, WarningMessage, IssueDecl, LangOpts));
178}
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 GetEnclosingDeclContextSignature(const Decl *EnclosingDecl)
Definition IssueHash.cpp:85
static std::string GetSignature(const FunctionDecl *Target)
Definition IssueHash.cpp:28
static StringRef GetNthLineOfFile(std::optional< llvm::MemoryBufferRef > Buffer, int Line)
Definition IssueHash.cpp:95
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:2058
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
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ RQ_LValue
An lvalue ref-qualifier was provided (&).
Definition TypeBase.h:1804
@ RQ_RValue
An rvalue ref-qualifier was provided (&&).
Definition TypeBase.h:1807
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.