Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/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
634
static std::string GetSignature(const FunctionDecl *Target) {
31
634
  if (!Target)
32
0
    return "";
33
634
  std::string Signature;
34
634
35
634
  // When a flow sensitive bug happens in templated code we should not generate
36
634
  // distinct hash value for every instantiation. Use the signature from the
37
634
  // primary template.
38
634
  if (const FunctionDecl *InstantiatedFrom =
39
12
          Target->getTemplateInstantiationPattern())
40
12
    Target = InstantiatedFrom;
41
634
42
634
  if (!isa<CXXConstructorDecl>(Target) && 
!isa<CXXDestructorDecl>(Target)625
&&
43
634
      
!isa<CXXConversionDecl>(Target)622
)
44
620
    Signature.append(Target->getReturnType().getAsString()).append(" ");
45
634
  Signature.append(Target->getQualifiedNameAsString()).append("(");
46
634
47
1.17k
  for (int i = 0, paramsCount = Target->getNumParams(); i < paramsCount; 
++i544
) {
48
544
    if (i)
49
239
      Signature.append(", ");
50
544
    Signature.append(Target->getParamDecl(i)->getType().getAsString());
51
544
  }
52
634
53
634
  if (Target->isVariadic())
54
1
    Signature.append(", ...");
55
634
  Signature.append(")");
56
634
57
634
  const auto *TargetT =
58
634
      llvm::dyn_cast_or_null<FunctionType>(Target->getType().getTypePtr());
59
634
60
634
  if (!TargetT || !isa<CXXMethodDecl>(Target))
61
601
    return Signature;
62
33
63
33
  if (TargetT->isConst())
64
5
    Signature.append(" const");
65
33
  if (TargetT->isVolatile())
66
0
    Signature.append(" volatile");
67
33
  if (TargetT->isRestrict())
68
0
    Signature.append(" restrict");
69
33
70
33
  if (const auto *TargetPT =
71
33
          dyn_cast_or_null<FunctionProtoType>(Target->getType().getTypePtr())) {
72
33
    switch (TargetPT->getRefQualifier()) {
73
33
    case RQ_LValue:
74
1
      Signature.append(" &");
75
1
      break;
76
33
    case RQ_RValue:
77
1
      Signature.append(" &&");
78
1
      break;
79
33
    default:
80
31
      break;
81
33
    }
82
33
  }
83
33
84
33
  return Signature;
85
33
}
86
87
692
static std::string GetEnclosingDeclContextSignature(const Decl *D) {
88
692
  if (!D)
89
2
    return "";
90
690
91
690
  if (const auto *ND = dyn_cast<NamedDecl>(D)) {
92
682
    std::string DeclName;
93
682
94
682
    switch (ND->getKind()) {
95
682
    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
634
    case Decl::CXXConstructor:
102
634
    case Decl::CXXDestructor:
103
634
    case Decl::CXXConversion:
104
634
    case Decl::CXXMethod:
105
634
    case Decl::Function:
106
634
      DeclName = GetSignature(dyn_cast_or_null<FunctionDecl>(ND));
107
634
      break;
108
634
    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
634
    default:
114
0
      break;
115
682
    }
116
682
117
682
    return DeclName;
118
682
  }
119
8
120
8
  return "";
121
8
}
122
123
692
static StringRef GetNthLineOfFile(const llvm::MemoryBuffer *Buffer, int Line) {
124
692
  if (!Buffer)
125
0
    return "";
126
692
127
692
  llvm::line_iterator LI(*Buffer, false);
128
365k
  for (; !LI.is_at_eof() && LI.line_number() != Line; 
++LI364k
)
129
364k
    ;
130
692
131
692
  return *LI;
132
692
}
133
134
static std::string NormalizeLine(const SourceManager &SM, FullSourceLoc &L,
135
692
                                 const LangOptions &LangOpts) {
136
692
  static StringRef Whitespaces = " \t\n";
137
692
138
692
  StringRef Str = GetNthLineOfFile(SM.getBuffer(L.getFileID(), L),
139
692
                                   L.getExpansionLineNumber());
140
692
  StringRef::size_type col = Str.find_first_not_of(Whitespaces);
141
692
  if (col == StringRef::npos)
142
0
    col = 1; // The line only contains whitespace.
143
692
  else
144
692
    col++;
145
692
  SourceLocation StartOfLine =
146
692
      SM.translateLineCol(SM.getFileID(L), L.getExpansionLineNumber(), col);
147
692
  const llvm::MemoryBuffer *Buffer =
148
692
      SM.getBuffer(SM.getFileID(StartOfLine), StartOfLine);
149
692
  if (!Buffer)
150
0
    return {};
151
692
152
692
  const char *BufferPos = SM.getCharacterData(StartOfLine);
153
692
154
692
  Token Token;
155
692
  Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(StartOfLine)), LangOpts,
156
692
              Buffer->getBufferStart(), BufferPos, Buffer->getBufferEnd());
157
692
158
692
  size_t NextStart = 0;
159
692
  std::ostringstream LineBuff;
160
6.72k
  while (!Lexer.LexFromRawLexer(Token) && 
NextStart < 26.69k
) {
161
6.03k
    if (Token.isAtStartOfLine() && 
NextStart++ > 01.37k
)
162
687
      continue;
163
5.34k
    LineBuff << std::string(SM.getCharacterData(Token.getLocation()),
164
5.34k
                            Token.getLength());
165
5.34k
  }
166
692
167
692
  return LineBuff.str();
168
692
}
169
170
671
static llvm::SmallString<32> GetHashOfContent(StringRef Content) {
171
671
  llvm::MD5 Hash;
172
671
  llvm::MD5::MD5Result MD5Res;
173
671
  SmallString<32> Res;
174
671
175
671
  Hash.update(Content);
176
671
  Hash.final(MD5Res);
177
671
  llvm::MD5::stringifyResult(MD5Res, Res);
178
671
179
671
  return Res;
180
671
}
181
182
std::string clang::GetIssueString(const SourceManager &SM,
183
                                  FullSourceLoc &IssueLoc,
184
                                  StringRef CheckerName, StringRef BugType,
185
                                  const Decl *D,
186
692
                                  const LangOptions &LangOpts) {
187
692
  static StringRef Delimiter = "$";
188
692
189
692
  return (llvm::Twine(CheckerName) + Delimiter +
190
692
          GetEnclosingDeclContextSignature(D) + Delimiter +
191
692
          Twine(IssueLoc.getExpansionColumnNumber()) + Delimiter +
192
692
          NormalizeLine(SM, IssueLoc, LangOpts) + Delimiter + BugType)
193
692
      .str();
194
692
}
195
196
SmallString<32> clang::GetIssueHash(const SourceManager &SM,
197
                                    FullSourceLoc &IssueLoc,
198
                                    StringRef CheckerName, StringRef BugType,
199
                                    const Decl *D,
200
671
                                    const LangOptions &LangOpts) {
201
671
202
671
  return GetHashOfContent(
203
671
      GetIssueString(SM, IssueLoc, CheckerName, BugType, D, LangOpts));
204
671
}