]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/IssueHash.cpp
Fix a memory leak in if_delgroups() introduced in r334118.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Core / IssueHash.cpp
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 #include "clang/StaticAnalyzer/Core/IssueHash.h"
9 #include "clang/AST/ASTContext.h"
10 #include "clang/AST/Decl.h"
11 #include "clang/AST/DeclCXX.h"
12 #include "clang/Basic/SourceManager.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 =
39           Target->getTemplateInstantiationPattern())
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),
139                                    L.getExpansionLineNumber());
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 =
146       SM.translateLineCol(SM.getFileID(L), L.getExpansionLineNumber(), col);
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
196 SmallString<32> clang::GetIssueHash(const SourceManager &SM,
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 }