Coverage Report

Created: 2021-09-21 08:58

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- ASTSrcLocProcessor.cpp --------------------------------*- 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 "ASTSrcLocProcessor.h"
10
11
#include "clang/Frontend/CompilerInstance.h"
12
#include "llvm/Support/JSON.h"
13
#include "llvm/Support/MemoryBuffer.h"
14
15
using namespace clang::tooling;
16
using namespace llvm;
17
using namespace clang::ast_matchers;
18
19
ASTSrcLocProcessor::ASTSrcLocProcessor(StringRef JsonPath)
20
0
    : JsonPath(JsonPath) {
21
22
0
  MatchFinder::MatchFinderOptions FinderOptions;
23
24
0
  Finder = std::make_unique<MatchFinder>(std::move(FinderOptions));
25
0
  Finder->addMatcher(
26
0
      cxxRecordDecl(
27
0
          isDefinition(),
28
0
          isSameOrDerivedFrom(
29
0
              namedDecl(
30
0
                  hasAnyName(
31
0
                      "clang::Stmt", "clang::Decl", "clang::CXXCtorInitializer",
32
0
                      "clang::NestedNameSpecifierLoc",
33
0
                      "clang::TemplateArgumentLoc", "clang::CXXBaseSpecifier",
34
0
                      "clang::DeclarationNameInfo", "clang::TypeLoc"))
35
0
                  .bind("nodeClade")),
36
0
          optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom"))))
37
0
          .bind("className"),
38
0
      this);
39
0
  Finder->addMatcher(
40
0
          cxxRecordDecl(isDefinition(), hasAnyName("clang::PointerLikeTypeLoc",
41
0
                                                   "clang::TypeofLikeTypeLoc"))
42
0
              .bind("templateName"),
43
0
      this);
44
0
}
45
46
std::unique_ptr<clang::ASTConsumer>
47
ASTSrcLocProcessor::createASTConsumer(clang::CompilerInstance &Compiler,
48
0
                                      StringRef File) {
49
0
  return Finder->newASTConsumer();
50
0
}
51
52
0
llvm::json::Object toJSON(llvm::StringMap<std::vector<StringRef>> const &Obj) {
53
0
  using llvm::json::toJSON;
54
55
0
  llvm::json::Object JsonObj;
56
0
  for (const auto &Item : Obj) {
57
0
    JsonObj[Item.first()] = Item.second;
58
0
  }
59
0
  return JsonObj;
60
0
}
61
62
0
llvm::json::Object toJSON(llvm::StringMap<std::string> const &Obj) {
63
0
  using llvm::json::toJSON;
64
65
0
  llvm::json::Object JsonObj;
66
0
  for (const auto &Item : Obj) {
67
0
    JsonObj[Item.first()] = Item.second;
68
0
  }
69
0
  return JsonObj;
70
0
}
71
72
0
llvm::json::Object toJSON(ClassData const &Obj) {
73
0
  llvm::json::Object JsonObj;
74
75
0
  if (!Obj.ASTClassLocations.empty())
76
0
    JsonObj["sourceLocations"] = Obj.ASTClassLocations;
77
0
  if (!Obj.ASTClassRanges.empty())
78
0
    JsonObj["sourceRanges"] = Obj.ASTClassRanges;
79
0
  if (!Obj.TemplateParms.empty())
80
0
    JsonObj["templateParms"] = Obj.TemplateParms;
81
0
  if (!Obj.TypeSourceInfos.empty())
82
0
    JsonObj["typeSourceInfos"] = Obj.TypeSourceInfos;
83
0
  if (!Obj.TypeLocs.empty())
84
0
    JsonObj["typeLocs"] = Obj.TypeLocs;
85
0
  if (!Obj.NestedNameLocs.empty())
86
0
    JsonObj["nestedNameLocs"] = Obj.NestedNameLocs;
87
0
  if (!Obj.DeclNameInfos.empty())
88
0
    JsonObj["declNameInfos"] = Obj.DeclNameInfos;
89
0
  return JsonObj;
90
0
}
91
92
0
llvm::json::Object toJSON(llvm::StringMap<ClassData> const &Obj) {
93
0
  using llvm::json::toJSON;
94
95
0
  llvm::json::Object JsonObj;
96
0
  for (const auto &Item : Obj)
97
0
    JsonObj[Item.first()] = ::toJSON(Item.second);
98
0
  return JsonObj;
99
0
}
100
101
void WriteJSON(StringRef JsonPath, llvm::json::Object &&ClassInheritance,
102
               llvm::json::Object &&ClassesInClade,
103
0
               llvm::json::Object &&ClassEntries) {
104
0
  llvm::json::Object JsonObj;
105
106
0
  using llvm::json::toJSON;
107
108
0
  JsonObj["classInheritance"] = std::move(ClassInheritance);
109
0
  JsonObj["classesInClade"] = std::move(ClassesInClade);
110
0
  JsonObj["classEntries"] = std::move(ClassEntries);
111
112
0
  llvm::json::Value JsonVal(std::move(JsonObj));
113
114
0
  bool WriteChange = false;
115
0
  std::string OutString;
116
0
  if (auto ExistingOrErr = MemoryBuffer::getFile(JsonPath, /*IsText=*/true)) {
117
0
    raw_string_ostream Out(OutString);
118
0
    Out << formatv("{0:2}", JsonVal);
119
0
    if (ExistingOrErr.get()->getBuffer() == Out.str())
120
0
      return;
121
0
    WriteChange = true;
122
0
  }
123
124
0
  std::error_code EC;
125
0
  llvm::raw_fd_ostream JsonOut(JsonPath, EC, llvm::sys::fs::OF_Text);
126
0
  if (EC)
127
0
    return;
128
129
0
  if (WriteChange)
130
0
    JsonOut << OutString;
131
0
  else
132
0
    JsonOut << formatv("{0:2}", JsonVal);
133
0
}
134
135
0
void ASTSrcLocProcessor::generate() {
136
0
  WriteJSON(JsonPath, ::toJSON(ClassInheritance), ::toJSON(ClassesInClade),
137
0
            ::toJSON(ClassEntries));
138
0
}
139
140
0
void ASTSrcLocProcessor::generateEmpty() { WriteJSON(JsonPath, {}, {}, {}); }
141
142
std::vector<std::string>
143
CaptureMethods(std::string TypeString, const clang::CXXRecordDecl *ASTClass,
144
0
               const MatchFinder::MatchResult &Result) {
145
146
0
  auto publicAccessor = [](auto... InnerMatcher) {
147
0
    return cxxMethodDecl(isPublic(), parameterCountIs(0), isConst(),
148
0
                         InnerMatcher...);
149
0
  };
150
151
0
  auto BoundNodesVec = match(
152
0
      findAll(
153
0
          publicAccessor(
154
0
              ofClass(cxxRecordDecl(
155
0
                  equalsNode(ASTClass),
156
0
                  optionally(isDerivedFrom(
157
0
                      cxxRecordDecl(hasAnyName("clang::Stmt", "clang::Decl"))
158
0
                          .bind("stmtOrDeclBase"))),
159
0
                  optionally(isDerivedFrom(
160
0
                      cxxRecordDecl(hasName("clang::Expr")).bind("exprBase"))),
161
0
                  optionally(
162
0
                      isDerivedFrom(cxxRecordDecl(hasName("clang::TypeLoc"))
163
0
                                        .bind("typeLocBase"))))),
164
0
              returns(asString(TypeString)))
165
0
              .bind("classMethod")),
166
0
      *ASTClass, *Result.Context);
167
168
0
  std::vector<std::string> Methods;
169
0
  for (const auto &BN : BoundNodesVec) {
170
0
    if (const auto *Node = BN.getNodeAs<clang::NamedDecl>("classMethod")) {
171
0
      const auto *StmtOrDeclBase =
172
0
          BN.getNodeAs<clang::CXXRecordDecl>("stmtOrDeclBase");
173
0
      const auto *TypeLocBase =
174
0
          BN.getNodeAs<clang::CXXRecordDecl>("typeLocBase");
175
0
      const auto *ExprBase = BN.getNodeAs<clang::CXXRecordDecl>("exprBase");
176
      // The clang AST has several methods on base classes which are overriden
177
      // pseudo-virtually by derived classes.
178
      // We record only the pseudo-virtual methods on the base classes to
179
      // avoid duplication.
180
0
      if (StmtOrDeclBase &&
181
0
          (Node->getName() == "getBeginLoc" || Node->getName() == "getEndLoc" ||
182
0
           Node->getName() == "getSourceRange"))
183
0
        continue;
184
0
      if (ExprBase && Node->getName() == "getExprLoc")
185
0
        continue;
186
0
      if (TypeLocBase && Node->getName() == "getLocalSourceRange")
187
0
        continue;
188
0
      if ((ASTClass->getName() == "PointerLikeTypeLoc" ||
189
0
           ASTClass->getName() == "TypeofLikeTypeLoc") &&
190
0
          Node->getName() == "getLocalSourceRange")
191
0
        continue;
192
0
      Methods.push_back(Node->getName().str());
193
0
    }
194
0
  }
195
0
  return Methods;
196
0
}
197
198
0
void ASTSrcLocProcessor::run(const MatchFinder::MatchResult &Result) {
199
200
0
  const auto *ASTClass =
201
0
      Result.Nodes.getNodeAs<clang::CXXRecordDecl>("className");
202
203
0
  StringRef CladeName;
204
0
  if (ASTClass) {
205
0
    if (const auto *NodeClade =
206
0
            Result.Nodes.getNodeAs<clang::CXXRecordDecl>("nodeClade"))
207
0
      CladeName = NodeClade->getName();
208
0
  } else {
209
0
    ASTClass = Result.Nodes.getNodeAs<clang::CXXRecordDecl>("templateName");
210
0
    CladeName = "TypeLoc";
211
0
  }
212
213
0
  StringRef ClassName = ASTClass->getName();
214
215
0
  ClassData CD;
216
217
0
  CD.ASTClassLocations =
218
0
      CaptureMethods("class clang::SourceLocation", ASTClass, Result);
219
0
  CD.ASTClassRanges =
220
0
      CaptureMethods("class clang::SourceRange", ASTClass, Result);
221
0
  CD.TypeSourceInfos =
222
0
      CaptureMethods("class clang::TypeSourceInfo *", ASTClass, Result);
223
0
  CD.TypeLocs = CaptureMethods("class clang::TypeLoc", ASTClass, Result);
224
0
  CD.NestedNameLocs =
225
0
      CaptureMethods("class clang::NestedNameSpecifierLoc", ASTClass, Result);
226
0
  CD.DeclNameInfos =
227
0
      CaptureMethods("struct clang::DeclarationNameInfo", ASTClass, Result);
228
0
  auto DI = CaptureMethods("const struct clang::DeclarationNameInfo &",
229
0
                           ASTClass, Result);
230
0
  CD.DeclNameInfos.insert(CD.DeclNameInfos.end(), DI.begin(), DI.end());
231
232
0
  if (const auto *DerivedFrom =
233
0
          Result.Nodes.getNodeAs<clang::CXXRecordDecl>("derivedFrom")) {
234
235
0
    if (const auto *Templ =
236
0
            llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
237
0
                DerivedFrom)) {
238
239
0
      const auto &TArgs = Templ->getTemplateArgs();
240
241
0
      SmallString<256> TArgsString;
242
0
      llvm::raw_svector_ostream OS(TArgsString);
243
0
      OS << DerivedFrom->getName() << '<';
244
245
0
      clang::PrintingPolicy PPol(Result.Context->getLangOpts());
246
0
      PPol.TerseOutput = true;
247
248
0
      for (unsigned I = 0; I < TArgs.size(); ++I) {
249
0
        if (I > 0)
250
0
          OS << ", ";
251
0
        TArgs.get(I).getAsType().print(OS, PPol);
252
0
      }
253
0
      OS << '>';
254
255
0
      ClassInheritance[ClassName] = TArgsString.str().str();
256
0
    } else {
257
0
      ClassInheritance[ClassName] = DerivedFrom->getName().str();
258
0
    }
259
0
  }
260
261
0
  if (const auto *Templ = ASTClass->getDescribedClassTemplate()) {
262
0
    if (auto *TParams = Templ->getTemplateParameters()) {
263
0
      for (const auto &TParam : *TParams) {
264
0
        CD.TemplateParms.push_back(TParam->getName().str());
265
0
      }
266
0
    }
267
0
  }
268
269
0
  ClassEntries[ClassName] = CD;
270
0
  ClassesInClade[CladeName].push_back(ClassName);
271
0
}