Coverage Report

Created: 2023-11-11 10:31

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