Coverage Report

Created: 2022-01-22 13:19

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Analysis/IssueHash.cpp
Line
Count
Source (jump to first uncovered line)
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 <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
792
static std::string GetSignature(const FunctionDecl *Target) {
32
792
  if (!Target)
33
0
    return "";
34
792
  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
792
  if (const FunctionDecl *InstantiatedFrom =
40
792
          Target->getTemplateInstantiationPattern())
41
12
    Target = InstantiatedFrom;
42
43
792
  if (!isa<CXXConstructorDecl>(Target) && 
!isa<CXXDestructorDecl>(Target)778
&&
44
792
      
!isa<CXXConversionDecl>(Target)775
)
45
773
    Signature.append(Target->getReturnType().getAsString()).append(" ");
46
792
  Signature.append(Target->getQualifiedNameAsString()).append("(");
47
48
1.38k
  for (int i = 0, paramsCount = Target->getNumParams(); i < paramsCount; 
++i594
) {
49
594
    if (i)
50
243
      Signature.append(", ");
51
594
    Signature.append(Target->getParamDecl(i)->getType().getAsString());
52
594
  }
53
54
792
  if (Target->isVariadic())
55
1
    Signature.append(", ...");
56
792
  Signature.append(")");
57
58
792
  const auto *TargetT =
59
792
      llvm::dyn_cast_or_null<FunctionType>(Target->getType().getTypePtr());
60
61
792
  if (!TargetT || !isa<CXXMethodDecl>(Target))
62
752
    return Signature;
63
64
40
  if (TargetT->isConst())
65
7
    Signature.append(" const");
66
40
  if (TargetT->isVolatile())
67
0
    Signature.append(" volatile");
68
40
  if (TargetT->isRestrict())
69
0
    Signature.append(" restrict");
70
71
40
  if (const auto *TargetPT =
72
40
          dyn_cast_or_null<FunctionProtoType>(Target->getType().getTypePtr())) {
73
40
    switch (TargetPT->getRefQualifier()) {
74
1
    case RQ_LValue:
75
1
      Signature.append(" &");
76
1
      break;
77
1
    case RQ_RValue:
78
1
      Signature.append(" &&");
79
1
      break;
80
38
    default:
81
38
      break;
82
40
    }
83
40
  }
84
85
40
  return Signature;
86
40
}
87
88
862
static std::string GetEnclosingDeclContextSignature(const Decl *D) {
89
862
  if (!D)
90
2
    return "";
91
92
860
  if (const auto *ND = dyn_cast<NamedDecl>(D)) {
93
850
    std::string DeclName;
94
95
850
    switch (ND->getKind()) {
96
0
    case Decl::Namespace:
97
0
    case Decl::Record:
98
0
    case Decl::CXXRecord:
99
0
    case Decl::Enum:
100
0
      DeclName = ND->getQualifiedNameAsString();
101
0
      break;
102
14
    case Decl::CXXConstructor:
103
17
    case Decl::CXXDestructor:
104
19
    case Decl::CXXConversion:
105
40
    case Decl::CXXMethod:
106
792
    case Decl::Function:
107
792
      DeclName = GetSignature(dyn_cast_or_null<FunctionDecl>(ND));
108
792
      break;
109
58
    case Decl::ObjCMethod:
110
      // ObjC Methods can not be overloaded, qualified name uniquely identifies
111
      // the method.
112
58
      DeclName = ND->getQualifiedNameAsString();
113
58
      break;
114
0
    default:
115
0
      break;
116
850
    }
117
118
850
    return DeclName;
119
850
  }
120
121
10
  return "";
122
860
}
123
124
static StringRef GetNthLineOfFile(llvm::Optional<llvm::MemoryBufferRef> Buffer,
125
862
                                  int Line) {
126
862
  if (!Buffer)
127
0
    return "";
128
129
862
  llvm::line_iterator LI(*Buffer, false);
130
392k
  for (; !LI.is_at_eof() && LI.line_number() != Line; 
++LI391k
)
131
391k
    ;
132
133
862
  return *LI;
134
862
}
135
136
static std::string NormalizeLine(const SourceManager &SM, const FullSourceLoc &L,
137
862
                                 const LangOptions &LangOpts) {
138
862
  static StringRef Whitespaces = " \t\n";
139
140
862
  StringRef Str = GetNthLineOfFile(SM.getBufferOrNone(L.getFileID(), L),
141
862
                                   L.getExpansionLineNumber());
142
862
  StringRef::size_type col = Str.find_first_not_of(Whitespaces);
143
862
  if (col == StringRef::npos)
144
0
    col = 1; // The line only contains whitespace.
145
862
  else
146
862
    col++;
147
862
  SourceLocation StartOfLine =
148
862
      SM.translateLineCol(SM.getFileID(L), L.getExpansionLineNumber(), col);
149
862
  Optional<llvm::MemoryBufferRef> Buffer =
150
862
      SM.getBufferOrNone(SM.getFileID(StartOfLine), StartOfLine);
151
862
  if (!Buffer)
152
0
    return {};
153
154
862
  const char *BufferPos = SM.getCharacterData(StartOfLine);
155
156
862
  Token Token;
157
862
  Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(StartOfLine)), LangOpts,
158
862
              Buffer->getBufferStart(), BufferPos, Buffer->getBufferEnd());
159
160
862
  size_t NextStart = 0;
161
862
  std::ostringstream LineBuff;
162
8.12k
  while (!Lexer.LexFromRawLexer(Token) && 
NextStart < 28.06k
) {
163
7.26k
    if (Token.isAtStartOfLine() && 
NextStart++ > 01.72k
)
164
858
      continue;
165
6.40k
    LineBuff << std::string(SM.getCharacterData(Token.getLocation()),
166
6.40k
                            Token.getLength());
167
6.40k
  }
168
169
862
  return LineBuff.str();
170
862
}
171
172
841
static llvm::SmallString<32> GetMD5HashOfContent(StringRef Content) {
173
841
  llvm::MD5 Hash;
174
841
  llvm::MD5::MD5Result MD5Res;
175
841
  SmallString<32> Res;
176
177
841
  Hash.update(Content);
178
841
  Hash.final(MD5Res);
179
841
  llvm::MD5::stringifyResult(MD5Res, Res);
180
181
841
  return Res;
182
841
}
183
184
std::string clang::getIssueString(const FullSourceLoc &IssueLoc,
185
                                  StringRef CheckerName,
186
                                  StringRef WarningMessage,
187
                                  const Decl *IssueDecl,
188
862
                                  const LangOptions &LangOpts) {
189
862
  static StringRef Delimiter = "$";
190
191
862
  return (llvm::Twine(CheckerName) + Delimiter +
192
862
          GetEnclosingDeclContextSignature(IssueDecl) + Delimiter +
193
862
          Twine(IssueLoc.getExpansionColumnNumber()) + Delimiter +
194
862
          NormalizeLine(IssueLoc.getManager(), IssueLoc, LangOpts) +
195
862
          Delimiter + WarningMessage)
196
862
      .str();
197
862
}
198
199
SmallString<32> clang::getIssueHash(const FullSourceLoc &IssueLoc,
200
                                    StringRef CheckerName,
201
                                    StringRef WarningMessage,
202
                                    const Decl *IssueDecl,
203
841
                                    const LangOptions &LangOpts) {
204
205
841
  return GetMD5HashOfContent(getIssueString(
206
841
      IssueLoc, CheckerName, WarningMessage, IssueDecl, LangOpts));
207
841
}