238 lines · cpp
1//===--- ASTConsumers.cpp - ASTConsumer implementations -------------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// AST Consumer Implementations.10//11//===----------------------------------------------------------------------===//12 13#include "clang/Frontend/ASTConsumers.h"14#include "clang/AST/ASTConsumer.h"15#include "clang/AST/ASTContext.h"16#include "clang/AST/PrettyPrinter.h"17#include "clang/AST/RecordLayout.h"18#include "clang/AST/RecursiveASTVisitor.h"19#include "clang/Basic/Diagnostic.h"20#include "llvm/Support/Timer.h"21#include "llvm/Support/raw_ostream.h"22using namespace clang;23 24//===----------------------------------------------------------------------===//25/// ASTPrinter - Pretty-printer and dumper of ASTs26 27namespace {28 class ASTPrinter : public ASTConsumer,29 public RecursiveASTVisitor<ASTPrinter> {30 typedef RecursiveASTVisitor<ASTPrinter> base;31 32 public:33 enum Kind { DumpFull, Dump, Print, None };34 ASTPrinter(std::unique_ptr<raw_ostream> Out, Kind K,35 ASTDumpOutputFormat Format, StringRef FilterString,36 bool DumpLookups = false, bool DumpDeclTypes = false)37 : Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)),38 OutputKind(K), OutputFormat(Format), FilterString(FilterString),39 DumpLookups(DumpLookups), DumpDeclTypes(DumpDeclTypes) {}40 41 ASTPrinter(raw_ostream &Out, Kind K, ASTDumpOutputFormat Format,42 StringRef FilterString, bool DumpLookups = false,43 bool DumpDeclTypes = false)44 : Out(Out), OwnedOut(nullptr), OutputKind(K), OutputFormat(Format),45 FilterString(FilterString), DumpLookups(DumpLookups),46 DumpDeclTypes(DumpDeclTypes) {}47 48 void HandleTranslationUnit(ASTContext &Context) override {49 TranslationUnitDecl *D = Context.getTranslationUnitDecl();50 51 if (FilterString.empty())52 return print(D);53 54 TraverseDecl(D);55 }56 57 bool shouldWalkTypesOfTypeLocs() const { return false; }58 59 bool TraverseDecl(Decl *D) {60 if (D && filterMatches(D)) {61 bool ShowColors = Out.has_colors();62 if (ShowColors)63 Out.changeColor(raw_ostream::BLUE);64 65 if (OutputFormat == ADOF_Default)66 Out << (OutputKind != Print ? "Dumping " : "Printing ") << getName(D)67 << ":\n";68 69 if (ShowColors)70 Out.resetColor();71 print(D);72 Out << "\n";73 // Don't traverse child nodes to avoid output duplication.74 return true;75 }76 return base::TraverseDecl(D);77 }78 79 private:80 std::string getName(Decl *D) {81 if (isa<NamedDecl>(D))82 return cast<NamedDecl>(D)->getQualifiedNameAsString();83 return "";84 }85 bool filterMatches(Decl *D) {86 return getName(D).find(FilterString) != std::string::npos;87 }88 void print(Decl *D) {89 if (DumpLookups) {90 if (DeclContext *DC = dyn_cast<DeclContext>(D)) {91 if (DC == DC->getPrimaryContext())92 DC->dumpLookups(Out, OutputKind != None, OutputKind == DumpFull);93 else94 Out << "Lookup map is in primary DeclContext "95 << DC->getPrimaryContext() << "\n";96 } else97 Out << "Not a DeclContext\n";98 } else if (OutputKind == Print) {99 PrintingPolicy Policy(D->getASTContext().getLangOpts());100 Policy.IncludeTagDefinition = true;101 D->print(Out, Policy, /*Indentation=*/0, /*PrintInstantiation=*/true);102 } else if (OutputKind != None) {103 D->dump(Out, OutputKind == DumpFull, OutputFormat);104 }105 106 if (DumpDeclTypes) {107 Decl *InnerD = D;108 if (auto *TD = dyn_cast<TemplateDecl>(D))109 if (Decl *TempD = TD->getTemplatedDecl())110 InnerD = TempD;111 112 // FIXME: Support OutputFormat in type dumping.113 // FIXME: Support combining -ast-dump-decl-types with -ast-dump-lookups.114 if (auto *VD = dyn_cast<ValueDecl>(InnerD))115 VD->getType().dump(Out, VD->getASTContext());116 if (auto *TD = dyn_cast<TypeDecl>(InnerD)) {117 const ASTContext &Ctx = TD->getASTContext();118 Ctx.getTypeDeclType(TD)->dump(Out, Ctx);119 }120 }121 }122 123 raw_ostream &Out;124 std::unique_ptr<raw_ostream> OwnedOut;125 126 /// How to output individual declarations.127 Kind OutputKind;128 129 /// What format should the output take?130 ASTDumpOutputFormat OutputFormat;131 132 /// Which declarations or DeclContexts to display.133 std::string FilterString;134 135 /// Whether the primary output is lookup results or declarations. Individual136 /// results will be output with a format determined by OutputKind. This is137 /// incompatible with OutputKind == Print.138 bool DumpLookups;139 140 /// Whether to dump the type for each declaration dumped.141 bool DumpDeclTypes;142 };143 144 class ASTDeclNodeLister : public ASTConsumer,145 public RecursiveASTVisitor<ASTDeclNodeLister> {146 public:147 ASTDeclNodeLister(raw_ostream *Out = nullptr)148 : Out(Out ? *Out : llvm::outs()) {}149 150 void HandleTranslationUnit(ASTContext &Context) override {151 TraverseDecl(Context.getTranslationUnitDecl());152 }153 154 bool shouldWalkTypesOfTypeLocs() const { return false; }155 156 bool VisitNamedDecl(NamedDecl *D) {157 D->printQualifiedName(Out);158 Out << '\n';159 return true;160 }161 162 private:163 raw_ostream &Out;164 };165} // end anonymous namespace166 167std::unique_ptr<ASTConsumer>168clang::CreateASTPrinter(std::unique_ptr<raw_ostream> Out,169 StringRef FilterString) {170 return std::make_unique<ASTPrinter>(std::move(Out), ASTPrinter::Print,171 ADOF_Default, FilterString);172}173 174std::unique_ptr<ASTConsumer>175clang::CreateASTDumper(std::unique_ptr<raw_ostream> Out, StringRef FilterString,176 bool DumpDecls, bool Deserialize, bool DumpLookups,177 bool DumpDeclTypes, ASTDumpOutputFormat Format) {178 assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump");179 return std::make_unique<ASTPrinter>(180 std::move(Out),181 Deserialize ? ASTPrinter::DumpFull182 : DumpDecls ? ASTPrinter::Dump : ASTPrinter::None,183 Format, FilterString, DumpLookups, DumpDeclTypes);184}185 186std::unique_ptr<ASTConsumer>187clang::CreateASTDumper(raw_ostream &Out, StringRef FilterString, bool DumpDecls,188 bool Deserialize, bool DumpLookups, bool DumpDeclTypes,189 ASTDumpOutputFormat Format) {190 assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump");191 return std::make_unique<ASTPrinter>(Out,192 Deserialize ? ASTPrinter::DumpFull193 : DumpDecls ? ASTPrinter::Dump194 : ASTPrinter::None,195 Format, FilterString, DumpLookups,196 DumpDeclTypes);197}198 199std::unique_ptr<ASTConsumer> clang::CreateASTDeclNodeLister() {200 return std::make_unique<ASTDeclNodeLister>(nullptr);201}202 203//===----------------------------------------------------------------------===//204/// ASTViewer - AST Visualization205 206namespace {207class ASTViewer : public ASTConsumer {208 ASTContext *Context = nullptr;209 210public:211 void Initialize(ASTContext &Context) override { this->Context = &Context; }212 213 bool HandleTopLevelDecl(DeclGroupRef D) override {214 for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)215 HandleTopLevelSingleDecl(*I);216 return true;217 }218 219 void HandleTopLevelSingleDecl(Decl *D);220};221}222 223void ASTViewer::HandleTopLevelSingleDecl(Decl *D) {224 if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {225 D->print(llvm::errs());226 227 if (Stmt *Body = D->getBody()) {228 llvm::errs() << '\n';229 Body->viewAST();230 llvm::errs() << '\n';231 }232 }233}234 235std::unique_ptr<ASTConsumer> clang::CreateASTViewer() {236 return std::make_unique<ASTViewer>();237}238