123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- //===- ASTSrcLocProcessor.cpp --------------------------------*- C++ -*----===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "ASTSrcLocProcessor.h"
- #include "clang/Frontend/CompilerInstance.h"
- #include "llvm/Support/JSON.h"
- #include "llvm/Support/MemoryBuffer.h"
- using namespace clang::tooling;
- using namespace llvm;
- using namespace clang::ast_matchers;
- ASTSrcLocProcessor::ASTSrcLocProcessor(StringRef JsonPath)
- : JsonPath(JsonPath) {
- MatchFinder::MatchFinderOptions FinderOptions;
- Finder = std::make_unique<MatchFinder>(std::move(FinderOptions));
- Finder->addMatcher(
- cxxRecordDecl(
- isDefinition(),
- isSameOrDerivedFrom(
- namedDecl(
- hasAnyName(
- "clang::Stmt", "clang::Decl", "clang::CXXCtorInitializer",
- "clang::NestedNameSpecifierLoc",
- "clang::TemplateArgumentLoc", "clang::CXXBaseSpecifier",
- "clang::DeclarationNameInfo", "clang::TypeLoc"))
- .bind("nodeClade")),
- optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom"))))
- .bind("className"),
- this);
- Finder->addMatcher(
- cxxRecordDecl(isDefinition(), hasAnyName("clang::PointerLikeTypeLoc",
- "clang::TypeofLikeTypeLoc"))
- .bind("templateName"),
- this);
- }
- std::unique_ptr<clang::ASTConsumer>
- ASTSrcLocProcessor::createASTConsumer(clang::CompilerInstance &Compiler,
- StringRef File) {
- return Finder->newASTConsumer();
- }
- llvm::json::Object toJSON(llvm::StringMap<std::vector<StringRef>> const &Obj) {
- using llvm::json::toJSON;
- llvm::json::Object JsonObj;
- for (const auto &Item : Obj) {
- JsonObj[Item.first()] = Item.second;
- }
- return JsonObj;
- }
- llvm::json::Object toJSON(llvm::StringMap<std::string> const &Obj) {
- using llvm::json::toJSON;
- llvm::json::Object JsonObj;
- for (const auto &Item : Obj) {
- JsonObj[Item.first()] = Item.second;
- }
- return JsonObj;
- }
- llvm::json::Object toJSON(ClassData const &Obj) {
- llvm::json::Object JsonObj;
- if (!Obj.ASTClassLocations.empty())
- JsonObj["sourceLocations"] = Obj.ASTClassLocations;
- if (!Obj.ASTClassRanges.empty())
- JsonObj["sourceRanges"] = Obj.ASTClassRanges;
- if (!Obj.TemplateParms.empty())
- JsonObj["templateParms"] = Obj.TemplateParms;
- if (!Obj.TypeSourceInfos.empty())
- JsonObj["typeSourceInfos"] = Obj.TypeSourceInfos;
- if (!Obj.TypeLocs.empty())
- JsonObj["typeLocs"] = Obj.TypeLocs;
- if (!Obj.NestedNameLocs.empty())
- JsonObj["nestedNameLocs"] = Obj.NestedNameLocs;
- if (!Obj.DeclNameInfos.empty())
- JsonObj["declNameInfos"] = Obj.DeclNameInfos;
- return JsonObj;
- }
- llvm::json::Object toJSON(llvm::StringMap<ClassData> const &Obj) {
- using llvm::json::toJSON;
- llvm::json::Object JsonObj;
- for (const auto &Item : Obj)
- JsonObj[Item.first()] = ::toJSON(Item.second);
- return JsonObj;
- }
- void WriteJSON(StringRef JsonPath, llvm::json::Object &&ClassInheritance,
- llvm::json::Object &&ClassesInClade,
- llvm::json::Object &&ClassEntries) {
- llvm::json::Object JsonObj;
- using llvm::json::toJSON;
- JsonObj["classInheritance"] = std::move(ClassInheritance);
- JsonObj["classesInClade"] = std::move(ClassesInClade);
- JsonObj["classEntries"] = std::move(ClassEntries);
- llvm::json::Value JsonVal(std::move(JsonObj));
- bool WriteChange = false;
- std::string OutString;
- if (auto ExistingOrErr = MemoryBuffer::getFile(JsonPath, /*IsText=*/true)) {
- raw_string_ostream Out(OutString);
- Out << formatv("{0:2}", JsonVal);
- if (ExistingOrErr.get()->getBuffer() == Out.str())
- return;
- WriteChange = true;
- }
- std::error_code EC;
- llvm::raw_fd_ostream JsonOut(JsonPath, EC, llvm::sys::fs::OF_Text);
- if (EC)
- return;
- if (WriteChange)
- JsonOut << OutString;
- else
- JsonOut << formatv("{0:2}", JsonVal);
- }
- void ASTSrcLocProcessor::generate() {
- WriteJSON(JsonPath, ::toJSON(ClassInheritance), ::toJSON(ClassesInClade),
- ::toJSON(ClassEntries));
- }
- void ASTSrcLocProcessor::generateEmpty() { WriteJSON(JsonPath, {}, {}, {}); }
- std::vector<std::string>
- CaptureMethods(std::string TypeString, const clang::CXXRecordDecl *ASTClass,
- const MatchFinder::MatchResult &Result) {
- auto publicAccessor = [](auto... InnerMatcher) {
- return cxxMethodDecl(isPublic(), parameterCountIs(0), isConst(),
- InnerMatcher...);
- };
- auto BoundNodesVec = match(
- findAll(
- publicAccessor(
- ofClass(cxxRecordDecl(
- equalsNode(ASTClass),
- optionally(isDerivedFrom(
- cxxRecordDecl(hasAnyName("clang::Stmt", "clang::Decl"))
- .bind("stmtOrDeclBase"))),
- optionally(isDerivedFrom(
- cxxRecordDecl(hasName("clang::Expr")).bind("exprBase"))),
- optionally(
- isDerivedFrom(cxxRecordDecl(hasName("clang::TypeLoc"))
- .bind("typeLocBase"))))),
- returns(asString(TypeString)))
- .bind("classMethod")),
- *ASTClass, *Result.Context);
- std::vector<std::string> Methods;
- for (const auto &BN : BoundNodesVec) {
- if (const auto *Node = BN.getNodeAs<clang::NamedDecl>("classMethod")) {
- const auto *StmtOrDeclBase =
- BN.getNodeAs<clang::CXXRecordDecl>("stmtOrDeclBase");
- const auto *TypeLocBase =
- BN.getNodeAs<clang::CXXRecordDecl>("typeLocBase");
- const auto *ExprBase = BN.getNodeAs<clang::CXXRecordDecl>("exprBase");
- // The clang AST has several methods on base classes which are overriden
- // pseudo-virtually by derived classes.
- // We record only the pseudo-virtual methods on the base classes to
- // avoid duplication.
- if (StmtOrDeclBase &&
- (Node->getName() == "getBeginLoc" || Node->getName() == "getEndLoc" ||
- Node->getName() == "getSourceRange"))
- continue;
- if (ExprBase && Node->getName() == "getExprLoc")
- continue;
- if (TypeLocBase && Node->getName() == "getLocalSourceRange")
- continue;
- if ((ASTClass->getName() == "PointerLikeTypeLoc" ||
- ASTClass->getName() == "TypeofLikeTypeLoc") &&
- Node->getName() == "getLocalSourceRange")
- continue;
- Methods.push_back(Node->getName().str());
- }
- }
- return Methods;
- }
- void ASTSrcLocProcessor::run(const MatchFinder::MatchResult &Result) {
- const auto *ASTClass =
- Result.Nodes.getNodeAs<clang::CXXRecordDecl>("className");
- StringRef CladeName;
- if (ASTClass) {
- if (const auto *NodeClade =
- Result.Nodes.getNodeAs<clang::CXXRecordDecl>("nodeClade"))
- CladeName = NodeClade->getName();
- } else {
- ASTClass = Result.Nodes.getNodeAs<clang::CXXRecordDecl>("templateName");
- CladeName = "TypeLoc";
- }
- StringRef ClassName = ASTClass->getName();
- ClassData CD;
- CD.ASTClassLocations =
- CaptureMethods("class clang::SourceLocation", ASTClass, Result);
- CD.ASTClassRanges =
- CaptureMethods("class clang::SourceRange", ASTClass, Result);
- CD.TypeSourceInfos =
- CaptureMethods("class clang::TypeSourceInfo *", ASTClass, Result);
- CD.TypeLocs = CaptureMethods("class clang::TypeLoc", ASTClass, Result);
- CD.NestedNameLocs =
- CaptureMethods("class clang::NestedNameSpecifierLoc", ASTClass, Result);
- CD.DeclNameInfos =
- CaptureMethods("struct clang::DeclarationNameInfo", ASTClass, Result);
- auto DI = CaptureMethods("const struct clang::DeclarationNameInfo &",
- ASTClass, Result);
- CD.DeclNameInfos.insert(CD.DeclNameInfos.end(), DI.begin(), DI.end());
- if (const auto *DerivedFrom =
- Result.Nodes.getNodeAs<clang::CXXRecordDecl>("derivedFrom")) {
- if (const auto *Templ =
- llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
- DerivedFrom)) {
- const auto &TArgs = Templ->getTemplateArgs();
- SmallString<256> TArgsString;
- llvm::raw_svector_ostream OS(TArgsString);
- OS << DerivedFrom->getName() << '<';
- clang::PrintingPolicy PPol(Result.Context->getLangOpts());
- PPol.TerseOutput = true;
- for (unsigned I = 0; I < TArgs.size(); ++I) {
- if (I > 0)
- OS << ", ";
- TArgs.get(I).getAsType().print(OS, PPol);
- }
- OS << '>';
- ClassInheritance[ClassName] = TArgsString.str().str();
- } else {
- ClassInheritance[ClassName] = DerivedFrom->getName().str();
- }
- }
- if (const auto *Templ = ASTClass->getDescribedClassTemplate()) {
- if (auto *TParams = Templ->getTemplateParameters()) {
- for (const auto &TParam : *TParams) {
- CD.TemplateParms.push_back(TParam->getName().str());
- }
- }
- }
- ClassEntries[ClassName] = CD;
- ClassesInClade[CladeName].push_back(ClassName);
- }
|