Coverage Report

Created: 2020-09-19 12:23

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