//===--- ASTConsumers.cpp - ASTConsumer implementations -------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // 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, StringRef FilterString, bool DumpLookups = false) : Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)), OutputKind(K), FilterString(FilterString), DumpLookups(DumpLookups) {} 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); 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) D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true); else if (OutputKind != None) D->dump(Out, OutputKind == DumpFull); } raw_ostream &Out; std::unique_ptr OwnedOut; /// How to output individual declarations. Kind OutputKind; /// 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; }; 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 llvm::make_unique(std::move(Out), ASTPrinter::Print, FilterString); } std::unique_ptr clang::CreateASTDumper(StringRef FilterString, bool DumpDecls, bool Deserialize, bool DumpLookups) { assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump"); return llvm::make_unique(nullptr, Deserialize ? ASTPrinter::DumpFull : DumpDecls ? ASTPrinter::Dump : ASTPrinter::None, FilterString, DumpLookups); } std::unique_ptr clang::CreateASTDeclNodeLister() { return llvm::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 llvm::make_unique(); } //===----------------------------------------------------------------------===// /// DeclContextPrinter - Decl and DeclContext Visualization namespace { class DeclContextPrinter : public ASTConsumer { raw_ostream& Out; public: DeclContextPrinter() : Out(llvm::errs()) {} void HandleTranslationUnit(ASTContext &C) override { PrintDeclContext(C.getTranslationUnitDecl(), 4); } void PrintDeclContext(const DeclContext* DC, unsigned Indentation); }; } // end anonymous namespace void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, unsigned Indentation) { // Print DeclContext name. switch (DC->getDeclKind()) { case Decl::TranslationUnit: Out << "[translation unit] " << DC; break; case Decl::Namespace: { Out << "[namespace] "; const NamespaceDecl* ND = cast(DC); Out << *ND; break; } case Decl::Enum: { const EnumDecl* ED = cast(DC); if (ED->isCompleteDefinition()) Out << "[enum] "; else Out << " "; Out << *ED; break; } case Decl::Record: { const RecordDecl* RD = cast(DC); if (RD->isCompleteDefinition()) Out << "[struct] "; else Out << " "; Out << *RD; break; } case Decl::CXXRecord: { const CXXRecordDecl* RD = cast(DC); if (RD->isCompleteDefinition()) Out << "[class] "; else Out << " "; Out << *RD << ' ' << DC; break; } case Decl::ObjCMethod: Out << "[objc method]"; break; case Decl::ObjCInterface: Out << "[objc interface]"; break; case Decl::ObjCCategory: Out << "[objc category]"; break; case Decl::ObjCProtocol: Out << "[objc protocol]"; break; case Decl::ObjCImplementation: Out << "[objc implementation]"; break; case Decl::ObjCCategoryImpl: Out << "[objc categoryimpl]"; break; case Decl::LinkageSpec: Out << "[linkage spec]"; break; case Decl::Block: Out << "[block]"; break; case Decl::Function: { const FunctionDecl* FD = cast(DC); if (FD->doesThisDeclarationHaveABody()) Out << "[function] "; else Out << " "; Out << *FD; // Print the parameters. Out << "("; bool PrintComma = false; for (auto I : FD->parameters()) { if (PrintComma) Out << ", "; else PrintComma = true; Out << *I; } Out << ")"; break; } case Decl::CXXMethod: { const CXXMethodDecl* D = cast(DC); if (D->isOutOfLine()) Out << "[c++ method] "; else if (D->isImplicit()) Out << "(c++ method) "; else Out << " "; Out << *D; // Print the parameters. Out << "("; bool PrintComma = false; for (ParmVarDecl *Parameter : D->parameters()) { if (PrintComma) Out << ", "; else PrintComma = true; Out << *Parameter; } Out << ")"; // Check the semantic DeclContext. const DeclContext* SemaDC = D->getDeclContext(); const DeclContext* LexicalDC = D->getLexicalDeclContext(); if (SemaDC != LexicalDC) Out << " [[" << SemaDC << "]]"; break; } case Decl::CXXConstructor: { const CXXConstructorDecl* D = cast(DC); if (D->isOutOfLine()) Out << "[c++ ctor] "; else if (D->isImplicit()) Out << "(c++ ctor) "; else Out << " "; Out << *D; // Print the parameters. Out << "("; bool PrintComma = false; for (ParmVarDecl *Parameter : D->parameters()) { if (PrintComma) Out << ", "; else PrintComma = true; Out << *Parameter; } Out << ")"; // Check the semantic DC. const DeclContext* SemaDC = D->getDeclContext(); const DeclContext* LexicalDC = D->getLexicalDeclContext(); if (SemaDC != LexicalDC) Out << " [[" << SemaDC << "]]"; break; } case Decl::CXXDestructor: { const CXXDestructorDecl* D = cast(DC); if (D->isOutOfLine()) Out << "[c++ dtor] "; else if (D->isImplicit()) Out << "(c++ dtor) "; else Out << " "; Out << *D; // Check the semantic DC. const DeclContext* SemaDC = D->getDeclContext(); const DeclContext* LexicalDC = D->getLexicalDeclContext(); if (SemaDC != LexicalDC) Out << " [[" << SemaDC << "]]"; break; } case Decl::CXXConversion: { const CXXConversionDecl* D = cast(DC); if (D->isOutOfLine()) Out << "[c++ conversion] "; else if (D->isImplicit()) Out << "(c++ conversion) "; else Out << " "; Out << *D; // Check the semantic DC. const DeclContext* SemaDC = D->getDeclContext(); const DeclContext* LexicalDC = D->getLexicalDeclContext(); if (SemaDC != LexicalDC) Out << " [[" << SemaDC << "]]"; break; } case Decl::ClassTemplateSpecialization: { const auto *CTSD = cast(DC); if (CTSD->isCompleteDefinition()) Out << "[class template specialization] "; else Out << " "; Out << *CTSD; break; } case Decl::ClassTemplatePartialSpecialization: { const auto *CTPSD = cast(DC); if (CTPSD->isCompleteDefinition()) Out << "[class template partial specialization] "; else Out << " "; Out << *CTPSD; break; } default: llvm_unreachable("a decl that inherits DeclContext isn't handled"); } Out << "\n"; // Print decls in the DeclContext. for (auto *I : DC->decls()) { for (unsigned i = 0; i < Indentation; ++i) Out << " "; Decl::Kind DK = I->getKind(); switch (DK) { case Decl::Namespace: case Decl::Enum: case Decl::Record: case Decl::CXXRecord: case Decl::ObjCMethod: case Decl::ObjCInterface: case Decl::ObjCCategory: case Decl::ObjCProtocol: case Decl::ObjCImplementation: case Decl::ObjCCategoryImpl: case Decl::LinkageSpec: case Decl::Block: case Decl::Function: case Decl::CXXMethod: case Decl::CXXConstructor: case Decl::CXXDestructor: case Decl::CXXConversion: case Decl::ClassTemplateSpecialization: case Decl::ClassTemplatePartialSpecialization: { DeclContext* DC = cast(I); PrintDeclContext(DC, Indentation+2); break; } case Decl::IndirectField: { IndirectFieldDecl* IFD = cast(I); Out << " " << *IFD << '\n'; break; } case Decl::Label: { LabelDecl *LD = cast(I); Out << "