//===--- ASTConsumers.cpp - ASTConsumer implementations -------------------===// // // 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 // //===----------------------------------------------------------------------===// // // AST Consumer Implementations. // //===----------------------------------------------------------------------===// #include "clang/Frontend/ASTConsumers.h" #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/Path.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" using namespace clang; //===----------------------------------------------------------------------===// /// ASTPrinter - Pretty-printer and dumper of ASTs namespace { class ASTPrinter : public ASTConsumer, public RecursiveASTVisitor { typedef RecursiveASTVisitor base; public: enum Kind { DumpFull, Dump, Print, None }; ASTPrinter(std::unique_ptr Out, Kind K, ASTDumpOutputFormat Format, StringRef FilterString, bool DumpLookups = false, bool DumpDeclTypes = false) : Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)), OutputKind(K), OutputFormat(Format), FilterString(FilterString), DumpLookups(DumpLookups), DumpDeclTypes(DumpDeclTypes) {} void HandleTranslationUnit(ASTContext &Context) override { TranslationUnitDecl *D = Context.getTranslationUnitDecl(); if (FilterString.empty()) return print(D); TraverseDecl(D); } bool shouldWalkTypesOfTypeLocs() const { return false; } bool TraverseDecl(Decl *D) { if (D && filterMatches(D)) { bool ShowColors = Out.has_colors(); if (ShowColors) Out.changeColor(raw_ostream::BLUE); if (OutputFormat == ADOF_Default) Out << (OutputKind != Print ? "Dumping " : "Printing ") << getName(D) << ":\n"; if (ShowColors) Out.resetColor(); print(D); Out << "\n"; // Don't traverse child nodes to avoid output duplication. return true; } return base::TraverseDecl(D); } private: std::string getName(Decl *D) { if (isa(D)) return cast(D)->getQualifiedNameAsString(); return ""; } bool filterMatches(Decl *D) { return getName(D).find(FilterString) != std::string::npos; } void print(Decl *D) { if (DumpLookups) { if (DeclContext *DC = dyn_cast(D)) { if (DC == DC->getPrimaryContext()) DC->dumpLookups(Out, OutputKind != None, OutputKind == DumpFull); else Out << "Lookup map is in primary DeclContext " << DC->getPrimaryContext() << "\n"; } else Out << "Not a DeclContext\n"; } else if (OutputKind == Print) { PrintingPolicy Policy(D->getASTContext().getLangOpts()); D->print(Out, Policy, /*Indentation=*/0, /*PrintInstantiation=*/true); } else if (OutputKind != None) { D->dump(Out, OutputKind == DumpFull, OutputFormat); } if (DumpDeclTypes) { Decl *InnerD = D; if (auto *TD = dyn_cast(D)) InnerD = TD->getTemplatedDecl(); // FIXME: Support OutputFormat in type dumping. // FIXME: Support combining -ast-dump-decl-types with -ast-dump-lookups. if (auto *VD = dyn_cast(InnerD)) VD->getType().dump(Out, VD->getASTContext()); if (auto *TD = dyn_cast(InnerD)) TD->getTypeForDecl()->dump(Out, TD->getASTContext()); } } raw_ostream &Out; std::unique_ptr OwnedOut; /// How to output individual declarations. Kind OutputKind; /// What format should the output take? ASTDumpOutputFormat OutputFormat; /// Which declarations or DeclContexts to display. std::string FilterString; /// Whether the primary output is lookup results or declarations. Individual /// results will be output with a format determined by OutputKind. This is /// incompatible with OutputKind == Print. bool DumpLookups; /// Whether to dump the type for each declaration dumped. bool DumpDeclTypes; }; class ASTDeclNodeLister : public ASTConsumer, public RecursiveASTVisitor { public: ASTDeclNodeLister(raw_ostream *Out = nullptr) : Out(Out ? *Out : llvm::outs()) {} void HandleTranslationUnit(ASTContext &Context) override { TraverseDecl(Context.getTranslationUnitDecl()); } bool shouldWalkTypesOfTypeLocs() const { return false; } bool VisitNamedDecl(NamedDecl *D) { D->printQualifiedName(Out); Out << '\n'; return true; } private: raw_ostream &Out; }; } // end anonymous namespace std::unique_ptr clang::CreateASTPrinter(std::unique_ptr Out, StringRef FilterString) { return std::make_unique(std::move(Out), ASTPrinter::Print, ADOF_Default, FilterString); } std::unique_ptr clang::CreateASTDumper(std::unique_ptr Out, StringRef FilterString, bool DumpDecls, bool Deserialize, bool DumpLookups, bool DumpDeclTypes, ASTDumpOutputFormat Format) { assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump"); return std::make_unique( std::move(Out), Deserialize ? ASTPrinter::DumpFull : DumpDecls ? ASTPrinter::Dump : ASTPrinter::None, Format, FilterString, DumpLookups, DumpDeclTypes); } std::unique_ptr clang::CreateASTDeclNodeLister() { return std::make_unique(nullptr); } //===----------------------------------------------------------------------===// /// ASTViewer - AST Visualization namespace { class ASTViewer : public ASTConsumer { ASTContext *Context; public: void Initialize(ASTContext &Context) override { this->Context = &Context; } bool HandleTopLevelDecl(DeclGroupRef D) override { for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) HandleTopLevelSingleDecl(*I); return true; } void HandleTopLevelSingleDecl(Decl *D); }; } void ASTViewer::HandleTopLevelSingleDecl(Decl *D) { if (isa(D) || isa(D)) { D->print(llvm::errs()); if (Stmt *Body = D->getBody()) { llvm::errs() << '\n'; Body->viewAST(); llvm::errs() << '\n'; } } } std::unique_ptr clang::CreateASTViewer() { return std::make_unique(); }