ASTSrcLocProcessor.cpp 9.0 KB

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