Coverage Report

Created: 2020-02-25 14:32

/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
659
static std::string GetSignature(const FunctionDecl *Target) {
31
659
  if (!Target)
32
0
    return "";
33
659
  std::string Signature;
34
659
35
659
  // When a flow sensitive bug happens in templated code we should not generate
36
659
  // distinct hash value for every instantiation. Use the signature from the
37
659
  // primary template.
38
659
  if (const FunctionDecl *InstantiatedFrom =
39
12
          Target->getTemplateInstantiationPattern())
40
12
    Target = InstantiatedFrom;
41
659
42
659
  if (!isa<CXXConstructorDecl>(Target) && 
!isa<CXXDestructorDecl>(Target)645
&&
43
659
      
!isa<CXXConversionDecl>(Target)642
)
44
640
    Signature.append(Target->getReturnType().getAsString()).append(" ");
45
659
  Signature.append(Target->getQualifiedNameAsString()).append("(");
46
659
47
1.20k
  for (int i = 0, paramsCount = Target->getNumParams(); i < paramsCount; 
++i550
) {
48
550
    if (i)
49
239
      Signature.append(", ");
50
550
    Signature.append(Target->getParamDecl(i)->getType().getAsString());
51
550
  }
52
659
53
659
  if (Target->isVariadic())
54
1
    Signature.append(", ...");
55
659
  Signature.append(")");
56
659
57
659
  const auto *TargetT =
58
659
      llvm::dyn_cast_or_null<FunctionType>(Target->getType().getTypePtr());
59
659
60
659
  if (!TargetT || !isa<CXXMethodDecl>(Target))
61
621
    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
717
static std::string GetEnclosingDeclContextSignature(const Decl *D) {
88
717
  if (!D)
89
2
    return "";
90
715
91
715
  if (const auto *ND = dyn_cast<NamedDecl>(D)) {
92
707
    std::string DeclName;
93
707
94
707
    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
659
    case Decl::CXXConstructor:
102
659
    case Decl::CXXDestructor:
103
659
    case Decl::CXXConversion:
104
659
    case Decl::CXXMethod:
105
659
    case Decl::Function:
106
659
      DeclName = GetSignature(dyn_cast_or_null<FunctionDecl>(ND));
107
659
      break;
108
659
    case Decl::ObjCMethod:
109
48
      // ObjC Methods can not be overloaded, qualified name uniquely identifies
110
48
      // the method.
111
48
      DeclName = ND->getQualifiedNameAsString();
112
48
      break;
113
659
    default:
114
0
      break;
115
707
    }
116
707
117
707
    return DeclName;
118
707
  }
119
8
120
8
  return "";
121
8
}
122
123
717
static StringRef GetNthLineOfFile(const llvm::MemoryBuffer *Buffer, int Line) {
124
717
  if (!Buffer)
125
0
    return "";
126
717
127
717
  llvm::line_iterator LI(*Buffer, false);
128
366k
  for (; !LI.is_at_eof() && LI.line_number() != Line; 
++LI365k
)
129
365k
    ;
130
717
131
717
  return *LI;
132
717
}
133
134
static std::string NormalizeLine(const SourceManager &SM, FullSourceLoc &L,
135
717
                                 const LangOptions &LangOpts) {
136
717
  static StringRef Whitespaces = " \t\n";
137
717
138
717
  StringRef Str = GetNthLineOfFile(SM.getBuffer(L.getFileID(), L),
139
717
                                   L.getExpansionLineNumber());
140
717
  StringRef::size_type col = Str.find_first_not_of(Whitespaces);
141
717
  if (col == StringRef::npos)
142
0
    col = 1; // The line only contains whitespace.
143
717
  else
144
717
    col++;
145
717
  SourceLocation StartOfLine =
146
717
      SM.translateLineCol(SM.getFileID(L), L.getExpansionLineNumber(), col);
147
717
  const llvm::MemoryBuffer *Buffer =
148
717
      SM.getBuffer(SM.getFileID(StartOfLine), StartOfLine);
149
717
  if (!Buffer)
150
0
    return {};
151
717
152
717
  const char *BufferPos = SM.getCharacterData(StartOfLine);
153
717
154
717
  Token Token;
155
717
  Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(StartOfLine)), LangOpts,
156
717
              Buffer->getBufferStart(), BufferPos, Buffer->getBufferEnd());
157
717
158
717
  size_t NextStart = 0;
159
717
  std::ostringstream LineBuff;
160
6.89k
  while (!Lexer.LexFromRawLexer(Token) && 
NextStart < 26.86k
) {
161
6.18k
    if (Token.isAtStartOfLine() && 
NextStart++ > 01.42k
)
162
712
      continue;
163
5.46k
    LineBuff << std::string(SM.getCharacterData(Token.getLocation()),
164
5.46k
                            Token.getLength());
165
5.46k
  }
166
717
167
717
  return LineBuff.str();
168
717
}
169
170
696
static llvm::SmallString<32> GetHashOfContent(StringRef Content) {
171
696
  llvm::MD5 Hash;
172
696
  llvm::MD5::MD5Result MD5Res;
173
696
  SmallString<32> Res;
174
696
175
696
  Hash.update(Content);
176
696
  Hash.final(MD5Res);
177
696
  llvm::MD5::stringifyResult(MD5Res, Res);
178
696
179
696
  return Res;
180
696
}
181
182
std::string clang::GetIssueString(const SourceManager &SM,
183
                                  FullSourceLoc &IssueLoc,
184
                                  StringRef CheckerName, StringRef BugType,
185
                                  const Decl *D,
186
717
                                  const LangOptions &LangOpts) {
187
717
  static StringRef Delimiter = "$";
188
717
189
717
  return (llvm::Twine(CheckerName) + Delimiter +
190
717
          GetEnclosingDeclContextSignature(D) + Delimiter +
191
717
          Twine(IssueLoc.getExpansionColumnNumber()) + Delimiter +
192
717
          NormalizeLine(SM, IssueLoc, LangOpts) + Delimiter + BugType)
193
717
      .str();
194
717
}
195
196
SmallString<32> clang::GetIssueHash(const SourceManager &SM,
197
                                    FullSourceLoc &IssueLoc,
198
                                    StringRef CheckerName, StringRef BugType,
199
                                    const Decl *D,
200
696
                                    const LangOptions &LangOpts) {
201
696
202
696
  return GetHashOfContent(
203
696
      GetIssueString(SM, IssueLoc, CheckerName, BugType, D, LangOpts));
204
696
}