clang  14.0.0git
ASTSrcLocProcessor.cpp
Go to the documentation of this file.
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 
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 
20  : JsonPath(JsonPath) {
21 
22  MatchFinder::MatchFinderOptions FinderOptions;
23 
24  Finder = std::make_unique<MatchFinder>(std::move(FinderOptions));
25  Finder->addMatcher(
27  isDefinition(),
28  isSameOrDerivedFrom(
29  namedDecl(
30  hasAnyName(
31  "clang::Stmt", "clang::Decl", "clang::CXXCtorInitializer",
32  "clang::NestedNameSpecifierLoc",
33  "clang::TemplateArgumentLoc", "clang::CXXBaseSpecifier",
34  "clang::DeclarationNameInfo", "clang::TypeLoc"))
35  .bind("nodeClade")),
36  optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom"))))
37  .bind("className"),
38  this);
39  Finder->addMatcher(
40  cxxRecordDecl(isDefinition(), hasAnyName("clang::PointerLikeTypeLoc",
41  "clang::TypeofLikeTypeLoc"))
42  .bind("templateName"),
43  this);
44 }
45 
46 std::unique_ptr<clang::ASTConsumer>
48  StringRef File) {
49  return Finder->newASTConsumer();
50 }
51 
52 llvm::json::Object toJSON(llvm::StringMap<std::vector<StringRef>> const &Obj) {
53  using llvm::json::toJSON;
54 
55  llvm::json::Object JsonObj;
56  for (const auto &Item : Obj) {
57  JsonObj[Item.first()] = Item.second;
58  }
59  return JsonObj;
60 }
61 
62 llvm::json::Object toJSON(llvm::StringMap<std::string> const &Obj) {
63  using llvm::json::toJSON;
64 
65  llvm::json::Object JsonObj;
66  for (const auto &Item : Obj) {
67  JsonObj[Item.first()] = Item.second;
68  }
69  return JsonObj;
70 }
71 
72 llvm::json::Object toJSON(ClassData const &Obj) {
73  llvm::json::Object JsonObj;
74 
75  if (!Obj.ASTClassLocations.empty())
76  JsonObj["sourceLocations"] = Obj.ASTClassLocations;
77  if (!Obj.ASTClassRanges.empty())
78  JsonObj["sourceRanges"] = Obj.ASTClassRanges;
79  if (!Obj.TemplateParms.empty())
80  JsonObj["templateParms"] = Obj.TemplateParms;
81  if (!Obj.TypeSourceInfos.empty())
82  JsonObj["typeSourceInfos"] = Obj.TypeSourceInfos;
83  if (!Obj.TypeLocs.empty())
84  JsonObj["typeLocs"] = Obj.TypeLocs;
85  if (!Obj.NestedNameLocs.empty())
86  JsonObj["nestedNameLocs"] = Obj.NestedNameLocs;
87  if (!Obj.DeclNameInfos.empty())
88  JsonObj["declNameInfos"] = Obj.DeclNameInfos;
89  return JsonObj;
90 }
91 
92 llvm::json::Object toJSON(llvm::StringMap<ClassData> const &Obj) {
93  using llvm::json::toJSON;
94 
95  llvm::json::Object JsonObj;
96  for (const auto &Item : Obj)
97  JsonObj[Item.first()] = ::toJSON(Item.second);
98  return JsonObj;
99 }
100 
101 void WriteJSON(StringRef JsonPath, llvm::json::Object &&ClassInheritance,
102  llvm::json::Object &&ClassesInClade,
103  llvm::json::Object &&ClassEntries) {
104  llvm::json::Object JsonObj;
105 
106  using llvm::json::toJSON;
107 
108  JsonObj["classInheritance"] = std::move(ClassInheritance);
109  JsonObj["classesInClade"] = std::move(ClassesInClade);
110  JsonObj["classEntries"] = std::move(ClassEntries);
111 
112  llvm::json::Value JsonVal(std::move(JsonObj));
113 
114  bool WriteChange = false;
115  std::string OutString;
116  if (auto ExistingOrErr = MemoryBuffer::getFile(JsonPath, /*IsText=*/true)) {
117  raw_string_ostream Out(OutString);
118  Out << formatv("{0:2}", JsonVal);
119  if (ExistingOrErr.get()->getBuffer() == Out.str())
120  return;
121  WriteChange = true;
122  }
123 
124  std::error_code EC;
125  llvm::raw_fd_ostream JsonOut(JsonPath, EC, llvm::sys::fs::OF_Text);
126  if (EC)
127  return;
128 
129  if (WriteChange)
130  JsonOut << OutString;
131  else
132  JsonOut << formatv("{0:2}", JsonVal);
133 }
134 
136  WriteJSON(JsonPath, ::toJSON(ClassInheritance), ::toJSON(ClassesInClade),
137  ::toJSON(ClassEntries));
138 }
139 
140 void ASTSrcLocProcessor::generateEmpty() { WriteJSON(JsonPath, {}, {}, {}); }
141 
142 std::vector<std::string>
143 CaptureMethods(std::string TypeString, const clang::CXXRecordDecl *ASTClass,
144  const MatchFinder::MatchResult &Result) {
145 
146  auto publicAccessor = [](auto... InnerMatcher) {
147  return cxxMethodDecl(isPublic(), parameterCountIs(0), isConst(),
148  InnerMatcher...);
149  };
150 
151  auto BoundNodesVec = match(
152  findAll(
153  publicAccessor(
154  ofClass(cxxRecordDecl(
155  equalsNode(ASTClass),
156  optionally(isDerivedFrom(
157  cxxRecordDecl(hasAnyName("clang::Stmt", "clang::Decl"))
158  .bind("stmtOrDeclBase"))),
159  optionally(isDerivedFrom(
160  cxxRecordDecl(hasName("clang::Expr")).bind("exprBase"))),
161  optionally(
162  isDerivedFrom(cxxRecordDecl(hasName("clang::TypeLoc"))
163  .bind("typeLocBase"))))),
164  returns(asString(TypeString)))
165  .bind("classMethod")),
166  *ASTClass, *Result.Context);
167 
168  std::vector<std::string> Methods;
169  for (const auto &BN : BoundNodesVec) {
170  if (const auto *Node = BN.getNodeAs<clang::NamedDecl>("classMethod")) {
171  const auto *StmtOrDeclBase =
172  BN.getNodeAs<clang::CXXRecordDecl>("stmtOrDeclBase");
173  const auto *TypeLocBase =
174  BN.getNodeAs<clang::CXXRecordDecl>("typeLocBase");
175  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  if (StmtOrDeclBase &&
181  (Node->getName() == "getBeginLoc" || Node->getName() == "getEndLoc" ||
182  Node->getName() == "getSourceRange"))
183  continue;
184  if (ExprBase && Node->getName() == "getExprLoc")
185  continue;
186  if (TypeLocBase && Node->getName() == "getLocalSourceRange")
187  continue;
188  if ((ASTClass->getName() == "PointerLikeTypeLoc" ||
189  ASTClass->getName() == "TypeofLikeTypeLoc") &&
190  Node->getName() == "getLocalSourceRange")
191  continue;
192  Methods.push_back(Node->getName().str());
193  }
194  }
195  return Methods;
196 }
197 
198 void ASTSrcLocProcessor::run(const MatchFinder::MatchResult &Result) {
199 
200  const auto *ASTClass =
201  Result.Nodes.getNodeAs<clang::CXXRecordDecl>("className");
202 
203  StringRef CladeName;
204  if (ASTClass) {
205  if (const auto *NodeClade =
206  Result.Nodes.getNodeAs<clang::CXXRecordDecl>("nodeClade"))
207  CladeName = NodeClade->getName();
208  } else {
209  ASTClass = Result.Nodes.getNodeAs<clang::CXXRecordDecl>("templateName");
210  CladeName = "TypeLoc";
211  }
212 
213  StringRef ClassName = ASTClass->getName();
214 
215  ClassData CD;
216 
217  CD.ASTClassLocations =
218  CaptureMethods("class clang::SourceLocation", ASTClass, Result);
219  CD.ASTClassRanges =
220  CaptureMethods("class clang::SourceRange", ASTClass, Result);
221  CD.TypeSourceInfos =
222  CaptureMethods("class clang::TypeSourceInfo *", ASTClass, Result);
223  CD.TypeLocs = CaptureMethods("class clang::TypeLoc", ASTClass, Result);
224  CD.NestedNameLocs =
225  CaptureMethods("class clang::NestedNameSpecifierLoc", ASTClass, Result);
226  CD.DeclNameInfos =
227  CaptureMethods("struct clang::DeclarationNameInfo", ASTClass, Result);
228  auto DI = CaptureMethods("const struct clang::DeclarationNameInfo &",
229  ASTClass, Result);
230  CD.DeclNameInfos.insert(CD.DeclNameInfos.end(), DI.begin(), DI.end());
231 
232  if (const auto *DerivedFrom =
233  Result.Nodes.getNodeAs<clang::CXXRecordDecl>("derivedFrom")) {
234 
235  if (const auto *Templ =
236  llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
237  DerivedFrom)) {
238 
239  const auto &TArgs = Templ->getTemplateArgs();
240 
241  SmallString<256> TArgsString;
242  llvm::raw_svector_ostream OS(TArgsString);
243  OS << DerivedFrom->getName() << '<';
244 
245  clang::PrintingPolicy PPol(Result.Context->getLangOpts());
246  PPol.TerseOutput = true;
247 
248  for (unsigned I = 0; I < TArgs.size(); ++I) {
249  if (I > 0)
250  OS << ", ";
251  TArgs.get(I).getAsType().print(OS, PPol);
252  }
253  OS << '>';
254 
255  ClassInheritance[ClassName] = TArgsString.str().str();
256  } else {
257  ClassInheritance[ClassName] = DerivedFrom->getName().str();
258  }
259  }
260 
261  if (const auto *Templ = ASTClass->getDescribedClassTemplate()) {
262  if (auto *TParams = Templ->getTemplateParameters()) {
263  for (const auto &TParam : *TParams) {
264  CD.TemplateParms.push_back(TParam->getName().str());
265  }
266  }
267  }
268 
269  ClassEntries[ClassName] = CD;
270  ClassesInClade[CladeName].push_back(ClassName);
271 }
clang::tooling::ClassData::TypeSourceInfos
std::vector< std::string > TypeSourceInfos
Definition: APIData.h:22
clang::ast_matchers::hasAnyName
const internal::VariadicFunction< internal::Matcher< NamedDecl >, StringRef, internal::hasAnyNameFunc > hasAnyName
Matches NamedDecl nodes that have any of the specified names.
Definition: ASTMatchersInternal.cpp:997
llvm
Definition: Dominators.h:30
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::tooling::ClassData::TemplateParms
std::vector< std::string > TemplateParms
Definition: APIData.h:21
clang::ast_matchers::findAll
internal::Matcher< T > findAll(const internal::Matcher< T > &Matcher)
Matches if the node or any descendant matches.
Definition: ASTMatchers.h:3480
clang::NamedDecl
This represents a decl that may have a name.
Definition: Decl.h:249
clang::tooling::ClassData::TypeLocs
std::vector< std::string > TypeLocs
Definition: APIData.h:23
clang::tooling::ASTSrcLocProcessor::ASTSrcLocProcessor
ASTSrcLocProcessor(StringRef JsonPath)
Definition: ASTSrcLocProcessor.cpp:19
clang::ast_matchers::MatchFinder::MatchFinderOptions
Definition: ASTMatchFinder.h:128
clang::tooling::ASTSrcLocProcessor::createASTConsumer
std::unique_ptr< ASTConsumer > createASTConsumer(CompilerInstance &Compiler, StringRef File)
Definition: ASTSrcLocProcessor.cpp:47
clang::PrintingPolicy
Describes how types, statements, expressions, and declarations should be printed.
Definition: PrettyPrinter.h:59
toJSON
llvm::json::Object toJSON(llvm::StringMap< std::vector< StringRef >> const &Obj)
Definition: ASTSrcLocProcessor.cpp:52
clang::tooling::ClassData::ASTClassLocations
std::vector< std::string > ASTClassLocations
Definition: APIData.h:19
clang::tooling::ASTSrcLocProcessor::generate
void generate()
Definition: ASTSrcLocProcessor.cpp:135
WriteJSON
void WriteJSON(StringRef JsonPath, llvm::json::Object &&ClassInheritance, llvm::json::Object &&ClassesInClade, llvm::json::Object &&ClassEntries)
Definition: ASTSrcLocProcessor.cpp:101
clang::ast_matchers
Definition: ASTMatchers.h:98
Node
DynTypedNode Node
Definition: ASTMatchFinder.cpp:67
clang::ast_matchers::cxxMethodDecl
const internal::VariadicDynCastAllOfMatcher< Decl, CXXMethodDecl > cxxMethodDecl
Matches method declarations.
Definition: ASTMatchersInternal.cpp:799
clang::tooling::ASTSrcLocProcessor::generateEmpty
void generateEmpty()
Definition: ASTSrcLocProcessor.cpp:140
clang::tooling
Definition: AllTUsExecution.h:21
llvm::SmallString
Definition: LLVM.h:37
CaptureMethods
std::vector< std::string > CaptureMethods(std::string TypeString, const clang::CXXRecordDecl *ASTClass, const MatchFinder::MatchResult &Result)
Definition: ASTSrcLocProcessor.cpp:143
clang::tooling::ClassData::NestedNameLocs
std::vector< std::string > NestedNameLocs
Definition: APIData.h:24
clang::CompilerInstance
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Definition: CompilerInstance.h:74
clang::CXXRecordDecl
Represents a C++ struct/union/class.
Definition: DeclCXX.h:255
Value
Value
Definition: UninitializedValues.cpp:102
ASTSrcLocProcessor.h
clang::tooling::ClassData
Definition: APIData.h:18
clang::ast_matchers::MatchFinder::MatchResult
Contains all information for a given match.
Definition: ASTMatchFinder.h:74
clang::ast_matchers::optionally
const internal::VariadicOperatorMatcherFunc< 1, 1 > optionally
Matches any node regardless of the submatcher.
Definition: ASTMatchersInternal.cpp:993
clang::ast_matchers::match
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
Definition: ASTMatchFinder.h:312
clang::ast_matchers::hasName
internal::Matcher< NamedDecl > hasName(StringRef Name)
Matches NamedDecl nodes that have the specified name.
Definition: ASTMatchers.h:2991
clang::ast_matchers::namedDecl
const internal::VariadicDynCastAllOfMatcher< Decl, NamedDecl > namedDecl
Matches a declaration of anything that could have a name.
Definition: ASTMatchersInternal.cpp:739
CompilerInstance.h
clang::ast_matchers::cxxRecordDecl
const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class declarations.
Definition: ASTMatchersInternal.cpp:745
clang::tooling::ClassData::ASTClassRanges
std::vector< std::string > ASTClassRanges
Definition: APIData.h:20
clang::tooling::ClassData::DeclNameInfos
std::vector< std::string > DeclNameInfos
Definition: APIData.h:25
clang::ento::ObjKind::OS
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
clang::NamedDecl::getName
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:276