//===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the AST dump methods, which dump out the // AST in a form that exposes type details and other fields. // //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/CommentVisitor.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclLookups.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/raw_ostream.h" using namespace clang; using namespace clang::comments; //===----------------------------------------------------------------------===// // ASTDumper Visitor //===----------------------------------------------------------------------===// namespace { // Colors used for various parts of the AST dump // Do not use bold yellow for any text. It is hard to read on white screens. struct TerminalColor { raw_ostream::Colors Color; bool Bold; }; // Red - CastColor // Green - TypeColor // Bold Green - DeclKindNameColor, UndeserializedColor // Yellow - AddressColor, LocationColor // Blue - CommentColor, NullColor, IndentColor // Bold Blue - AttrColor // Bold Magenta - StmtColor // Cyan - ValueKindColor, ObjectKindColor // Bold Cyan - ValueColor, DeclNameColor // Decl kind names (VarDecl, FunctionDecl, etc) static const TerminalColor DeclKindNameColor = { raw_ostream::GREEN, true }; // Attr names (CleanupAttr, GuardedByAttr, etc) static const TerminalColor AttrColor = { raw_ostream::BLUE, true }; // Statement names (DeclStmt, ImplicitCastExpr, etc) static const TerminalColor StmtColor = { raw_ostream::MAGENTA, true }; // Comment names (FullComment, ParagraphComment, TextComment, etc) static const TerminalColor CommentColor = { raw_ostream::BLUE, false }; // Type names (int, float, etc, plus user defined types) static const TerminalColor TypeColor = { raw_ostream::GREEN, false }; // Pointer address static const TerminalColor AddressColor = { raw_ostream::YELLOW, false }; // Source locations static const TerminalColor LocationColor = { raw_ostream::YELLOW, false }; // lvalue/xvalue static const TerminalColor ValueKindColor = { raw_ostream::CYAN, false }; // bitfield/objcproperty/objcsubscript/vectorcomponent static const TerminalColor ObjectKindColor = { raw_ostream::CYAN, false }; // Null statements static const TerminalColor NullColor = { raw_ostream::BLUE, false }; // Undeserialized entities static const TerminalColor UndeserializedColor = { raw_ostream::GREEN, true }; // CastKind from CastExpr's static const TerminalColor CastColor = { raw_ostream::RED, false }; // Value of the statement static const TerminalColor ValueColor = { raw_ostream::CYAN, true }; // Decl names static const TerminalColor DeclNameColor = { raw_ostream::CYAN, true }; // Indents ( `, -. | ) static const TerminalColor IndentColor = { raw_ostream::BLUE, false }; class ASTDumper : public ConstDeclVisitor, public ConstStmtVisitor, public ConstCommentVisitor { raw_ostream &OS; const CommandTraits *Traits; const SourceManager *SM; bool IsFirstLine; // Indicates whether more child are expected at the current tree depth enum IndentType { IT_Child, IT_LastChild }; /// Indents[i] indicates if another child exists at level i. /// Used by Indent() to print the tree structure. llvm::SmallVector Indents; /// Indicates that more children will be needed at this indent level. /// If true, prevents lastChild() from marking the node as the last child. /// This is used when there are multiple collections of children to be /// dumped as well as during conditional node dumping. bool MoreChildren; /// Keep track of the last location we print out so that we can /// print out deltas from then on out. const char *LastLocFilename; unsigned LastLocLine; /// The \c FullComment parent of the comment being dumped. const FullComment *FC; bool ShowColors; class IndentScope { ASTDumper &Dumper; // Preserve the Dumper's MoreChildren value from the previous IndentScope bool MoreChildren; public: IndentScope(ASTDumper &Dumper) : Dumper(Dumper) { MoreChildren = Dumper.hasMoreChildren(); Dumper.setMoreChildren(false); Dumper.indent(); } ~IndentScope() { Dumper.setMoreChildren(MoreChildren); Dumper.unindent(); } }; class ColorScope { ASTDumper &Dumper; public: ColorScope(ASTDumper &Dumper, TerminalColor Color) : Dumper(Dumper) { if (Dumper.ShowColors) Dumper.OS.changeColor(Color.Color, Color.Bold); } ~ColorScope() { if (Dumper.ShowColors) Dumper.OS.resetColor(); } }; class ChildDumper { ASTDumper &Dumper; const Decl *Prev; bool PrevRef; public: ChildDumper(ASTDumper &Dumper) : Dumper(Dumper), Prev(nullptr) {} ~ChildDumper() { if (Prev) { Dumper.lastChild(); dump(nullptr); } } // FIXME: This should take an arbitrary callable as the dumping action. void dump(const Decl *D, bool Ref = false) { if (Prev) { if (PrevRef) Dumper.dumpDeclRef(Prev); else Dumper.dumpDecl(Prev); } Prev = D; PrevRef = Ref; } void dumpRef(const Decl *D) { dump(D, true); } // Give up ownership of the children of the node. By calling this, // the caller takes back responsibility for calling lastChild(). void release() { dump(nullptr); } }; public: ASTDumper(raw_ostream &OS, const CommandTraits *Traits, const SourceManager *SM) : OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false), LastLocFilename(""), LastLocLine(~0U), FC(nullptr), ShowColors(SM && SM->getDiagnostics().getShowColors()) { } ASTDumper(raw_ostream &OS, const CommandTraits *Traits, const SourceManager *SM, bool ShowColors) : OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false), LastLocFilename(""), LastLocLine(~0U), ShowColors(ShowColors) { } ~ASTDumper() { OS << "\n"; } void dumpDecl(const Decl *D); void dumpStmt(const Stmt *S); void dumpFullComment(const FullComment *C); // Formatting void indent(); void unindent(); void lastChild(); bool hasMoreChildren(); void setMoreChildren(bool Value); // Utilities void dumpPointer(const void *Ptr); void dumpSourceRange(SourceRange R); void dumpLocation(SourceLocation Loc); void dumpBareType(QualType T); void dumpType(QualType T); void dumpBareDeclRef(const Decl *Node); void dumpDeclRef(const Decl *Node, const char *Label = nullptr); void dumpName(const NamedDecl *D); bool hasNodes(const DeclContext *DC); void dumpDeclContext(const DeclContext *DC); void dumpLookups(const DeclContext *DC); void dumpAttr(const Attr *A); // C++ Utilities void dumpAccessSpecifier(AccessSpecifier AS); void dumpCXXCtorInitializer(const CXXCtorInitializer *Init); void dumpTemplateParameters(const TemplateParameterList *TPL); void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI); void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A); void dumpTemplateArgumentList(const TemplateArgumentList &TAL); void dumpTemplateArgument(const TemplateArgument &A, SourceRange R = SourceRange()); // Decls void VisitLabelDecl(const LabelDecl *D); void VisitTypedefDecl(const TypedefDecl *D); void VisitEnumDecl(const EnumDecl *D); void VisitRecordDecl(const RecordDecl *D); void VisitEnumConstantDecl(const EnumConstantDecl *D); void VisitIndirectFieldDecl(const IndirectFieldDecl *D); void VisitFunctionDecl(const FunctionDecl *D); void VisitFieldDecl(const FieldDecl *D); void VisitVarDecl(const VarDecl *D); void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D); void VisitImportDecl(const ImportDecl *D); // C++ Decls void VisitNamespaceDecl(const NamespaceDecl *D); void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D); void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D); void VisitTypeAliasDecl(const TypeAliasDecl *D); void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D); void VisitCXXRecordDecl(const CXXRecordDecl *D); void VisitStaticAssertDecl(const StaticAssertDecl *D); template void VisitTemplateDeclSpecialization(ChildDumper &Children, const SpecializationDecl *D, bool DumpExplicitInst, bool DumpRefOnly); template void VisitTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst); void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D); void VisitClassTemplateDecl(const ClassTemplateDecl *D); void VisitClassTemplateSpecializationDecl( const ClassTemplateSpecializationDecl *D); void VisitClassTemplatePartialSpecializationDecl( const ClassTemplatePartialSpecializationDecl *D); void VisitClassScopeFunctionSpecializationDecl( const ClassScopeFunctionSpecializationDecl *D); void VisitVarTemplateDecl(const VarTemplateDecl *D); void VisitVarTemplateSpecializationDecl( const VarTemplateSpecializationDecl *D); void VisitVarTemplatePartialSpecializationDecl( const VarTemplatePartialSpecializationDecl *D); void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D); void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D); void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D); void VisitUsingDecl(const UsingDecl *D); void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D); void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D); void VisitUsingShadowDecl(const UsingShadowDecl *D); void VisitLinkageSpecDecl(const LinkageSpecDecl *D); void VisitAccessSpecDecl(const AccessSpecDecl *D); void VisitFriendDecl(const FriendDecl *D); // ObjC Decls void VisitObjCIvarDecl(const ObjCIvarDecl *D); void VisitObjCMethodDecl(const ObjCMethodDecl *D); void VisitObjCCategoryDecl(const ObjCCategoryDecl *D); void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D); void VisitObjCProtocolDecl(const ObjCProtocolDecl *D); void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D); void VisitObjCImplementationDecl(const ObjCImplementationDecl *D); void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D); void VisitObjCPropertyDecl(const ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D); void VisitBlockDecl(const BlockDecl *D); // Stmts. void VisitStmt(const Stmt *Node); void VisitDeclStmt(const DeclStmt *Node); void VisitAttributedStmt(const AttributedStmt *Node); void VisitLabelStmt(const LabelStmt *Node); void VisitGotoStmt(const GotoStmt *Node); void VisitCXXCatchStmt(const CXXCatchStmt *Node); // Exprs void VisitExpr(const Expr *Node); void VisitCastExpr(const CastExpr *Node); void VisitDeclRefExpr(const DeclRefExpr *Node); void VisitPredefinedExpr(const PredefinedExpr *Node); void VisitCharacterLiteral(const CharacterLiteral *Node); void VisitIntegerLiteral(const IntegerLiteral *Node); void VisitFloatingLiteral(const FloatingLiteral *Node); void VisitStringLiteral(const StringLiteral *Str); void VisitInitListExpr(const InitListExpr *ILE); void VisitUnaryOperator(const UnaryOperator *Node); void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Node); void VisitMemberExpr(const MemberExpr *Node); void VisitExtVectorElementExpr(const ExtVectorElementExpr *Node); void VisitBinaryOperator(const BinaryOperator *Node); void VisitCompoundAssignOperator(const CompoundAssignOperator *Node); void VisitAddrLabelExpr(const AddrLabelExpr *Node); void VisitBlockExpr(const BlockExpr *Node); void VisitOpaqueValueExpr(const OpaqueValueExpr *Node); // C++ void VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node); void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node); void VisitCXXThisExpr(const CXXThisExpr *Node); void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node); void VisitCXXConstructExpr(const CXXConstructExpr *Node); void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node); void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node); void VisitExprWithCleanups(const ExprWithCleanups *Node); void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node); void dumpCXXTemporary(const CXXTemporary *Temporary); void VisitLambdaExpr(const LambdaExpr *Node) { VisitExpr(Node); dumpDecl(Node->getLambdaClass()); } // ObjC void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node); void VisitObjCEncodeExpr(const ObjCEncodeExpr *Node); void VisitObjCMessageExpr(const ObjCMessageExpr *Node); void VisitObjCBoxedExpr(const ObjCBoxedExpr *Node); void VisitObjCSelectorExpr(const ObjCSelectorExpr *Node); void VisitObjCProtocolExpr(const ObjCProtocolExpr *Node); void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node); void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node); void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node); void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node); // Comments. const char *getCommandName(unsigned CommandID); void dumpComment(const Comment *C); // Inline comments. void visitTextComment(const TextComment *C); void visitInlineCommandComment(const InlineCommandComment *C); void visitHTMLStartTagComment(const HTMLStartTagComment *C); void visitHTMLEndTagComment(const HTMLEndTagComment *C); // Block comments. void visitBlockCommandComment(const BlockCommandComment *C); void visitParamCommandComment(const ParamCommandComment *C); void visitTParamCommandComment(const TParamCommandComment *C); void visitVerbatimBlockComment(const VerbatimBlockComment *C); void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); void visitVerbatimLineComment(const VerbatimLineComment *C); }; } //===----------------------------------------------------------------------===// // Utilities //===----------------------------------------------------------------------===// // Print out the appropriate tree structure using the Indents vector. // Example of tree and the Indents vector at each level. // A { } // |-B { IT_Child } // | `-C { IT_Child, IT_LastChild } // `-D { IT_LastChild } // |-E { IT_LastChild, IT_Child } // `-F { IT_LastChild, IT_LastChild } // Type non-last element, last element // IT_Child "| " "|-" // IT_LastChild " " "`-" void ASTDumper::indent() { if (IsFirstLine) IsFirstLine = false; else OS << "\n"; ColorScope Color(*this, IndentColor); for (SmallVectorImpl::const_iterator I = Indents.begin(), E = Indents.end(); I != E; ++I) { switch (*I) { case IT_Child: if (I == E - 1) OS << "|-"; else OS << "| "; continue; case IT_LastChild: if (I == E - 1) OS << "`-"; else OS << " "; continue; } llvm_unreachable("Invalid IndentType"); } Indents.push_back(IT_Child); } void ASTDumper::unindent() { Indents.pop_back(); } // Call before each potential last child node is to be dumped. If MoreChildren // is false, then this is the last child, otherwise treat as a regular node. void ASTDumper::lastChild() { if (!hasMoreChildren()) Indents.back() = IT_LastChild; } // MoreChildren should be set before calling another function that may print // additional nodes to prevent conflicting final child nodes. bool ASTDumper::hasMoreChildren() { return MoreChildren; } void ASTDumper::setMoreChildren(bool Value) { MoreChildren = Value; } void ASTDumper::dumpPointer(const void *Ptr) { ColorScope Color(*this, AddressColor); OS << ' ' << Ptr; } void ASTDumper::dumpLocation(SourceLocation Loc) { if (!SM) return; ColorScope Color(*this, LocationColor); SourceLocation SpellingLoc = SM->getSpellingLoc(Loc); // The general format we print out is filename:line:col, but we drop pieces // that haven't changed since the last loc printed. PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc); if (PLoc.isInvalid()) { OS << ""; return; } if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) { OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':' << PLoc.getColumn(); LastLocFilename = PLoc.getFilename(); LastLocLine = PLoc.getLine(); } else if (PLoc.getLine() != LastLocLine) { OS << "line" << ':' << PLoc.getLine() << ':' << PLoc.getColumn(); LastLocLine = PLoc.getLine(); } else { OS << "col" << ':' << PLoc.getColumn(); } } void ASTDumper::dumpSourceRange(SourceRange R) { // Can't translate locations if a SourceManager isn't available. if (!SM) return; OS << " <"; dumpLocation(R.getBegin()); if (R.getBegin() != R.getEnd()) { OS << ", "; dumpLocation(R.getEnd()); } OS << ">"; // } void ASTDumper::dumpBareType(QualType T) { ColorScope Color(*this, TypeColor); SplitQualType T_split = T.split(); OS << "'" << QualType::getAsString(T_split) << "'"; if (!T.isNull()) { // If the type is sugared, also dump a (shallow) desugared type. SplitQualType D_split = T.getSplitDesugaredType(); if (T_split != D_split) OS << ":'" << QualType::getAsString(D_split) << "'"; } } void ASTDumper::dumpType(QualType T) { OS << ' '; dumpBareType(T); } void ASTDumper::dumpBareDeclRef(const Decl *D) { { ColorScope Color(*this, DeclKindNameColor); OS << D->getDeclKindName(); } dumpPointer(D); if (const NamedDecl *ND = dyn_cast(D)) { ColorScope Color(*this, DeclNameColor); OS << " '" << ND->getDeclName() << '\''; } if (const ValueDecl *VD = dyn_cast(D)) dumpType(VD->getType()); } void ASTDumper::dumpDeclRef(const Decl *D, const char *Label) { if (!D) return; IndentScope Indent(*this); if (Label) OS << Label << ' '; dumpBareDeclRef(D); } void ASTDumper::dumpName(const NamedDecl *ND) { if (ND->getDeclName()) { ColorScope Color(*this, DeclNameColor); OS << ' ' << ND->getNameAsString(); } } bool ASTDumper::hasNodes(const DeclContext *DC) { if (!DC) return false; return DC->hasExternalLexicalStorage() || DC->noload_decls_begin() != DC->noload_decls_end(); } void ASTDumper::dumpDeclContext(const DeclContext *DC) { if (!DC) return; ChildDumper Children(*this); for (auto *D : DC->noload_decls()) Children.dump(D); if (DC->hasExternalLexicalStorage()) { Children.release(); lastChild(); IndentScope Indent(*this); ColorScope Color(*this, UndeserializedColor); OS << ""; } } void ASTDumper::dumpLookups(const DeclContext *DC) { IndentScope Indent(*this); OS << "StoredDeclsMap "; dumpBareDeclRef(cast(DC)); const DeclContext *Primary = DC->getPrimaryContext(); if (Primary != DC) { OS << " primary"; dumpPointer(cast(Primary)); } bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage(); DeclContext::all_lookups_iterator I = Primary->noload_lookups_begin(), E = Primary->noload_lookups_end(); while (I != E) { DeclarationName Name = I.getLookupName(); DeclContextLookupResult R = *I++; if (I == E && !HasUndeserializedLookups) lastChild(); IndentScope Indent(*this); OS << "DeclarationName "; { ColorScope Color(*this, DeclNameColor); OS << '\'' << Name << '\''; } for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end(); RI != RE; ++RI) { if (RI + 1 == RE) lastChild(); dumpDeclRef(*RI); if ((*RI)->isHidden()) OS << " hidden"; } } if (HasUndeserializedLookups) { lastChild(); IndentScope Indent(*this); ColorScope Color(*this, UndeserializedColor); OS << ""; } } void ASTDumper::dumpAttr(const Attr *A) { IndentScope Indent(*this); { ColorScope Color(*this, AttrColor); switch (A->getKind()) { #define ATTR(X) case attr::X: OS << #X; break; #include "clang/Basic/AttrList.inc" default: llvm_unreachable("unexpected attribute kind"); } OS << "Attr"; } dumpPointer(A); dumpSourceRange(A->getRange()); if (A->isInherited()) OS << " Inherited"; if (A->isImplicit()) OS << " Implicit"; #include "clang/AST/AttrDump.inc" } static void dumpPreviousDeclImpl(raw_ostream &OS, ...) {} template static void dumpPreviousDeclImpl(raw_ostream &OS, const Mergeable *D) { const T *First = D->getFirstDecl(); if (First != D) OS << " first " << First; } template static void dumpPreviousDeclImpl(raw_ostream &OS, const Redeclarable *D) { const T *Prev = D->getPreviousDecl(); if (Prev) OS << " prev " << Prev; } /// Dump the previous declaration in the redeclaration chain for a declaration, /// if any. static void dumpPreviousDecl(raw_ostream &OS, const Decl *D) { switch (D->getKind()) { #define DECL(DERIVED, BASE) \ case Decl::DERIVED: \ return dumpPreviousDeclImpl(OS, cast(D)); #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" } llvm_unreachable("Decl that isn't part of DeclNodes.inc!"); } //===----------------------------------------------------------------------===// // C++ Utilities //===----------------------------------------------------------------------===// void ASTDumper::dumpAccessSpecifier(AccessSpecifier AS) { switch (AS) { case AS_none: break; case AS_public: OS << "public"; break; case AS_protected: OS << "protected"; break; case AS_private: OS << "private"; break; } } void ASTDumper::dumpCXXCtorInitializer(const CXXCtorInitializer *Init) { IndentScope Indent(*this); OS << "CXXCtorInitializer"; if (Init->isAnyMemberInitializer()) { OS << ' '; dumpBareDeclRef(Init->getAnyMember()); } else { dumpType(QualType(Init->getBaseClass(), 0)); } dumpStmt(Init->getInit()); } void ASTDumper::dumpTemplateParameters(const TemplateParameterList *TPL) { if (!TPL) return; for (TemplateParameterList::const_iterator I = TPL->begin(), E = TPL->end(); I != E; ++I) dumpDecl(*I); } void ASTDumper::dumpTemplateArgumentListInfo( const TemplateArgumentListInfo &TALI) { for (unsigned i = 0, e = TALI.size(); i < e; ++i) { if (i + 1 == e) lastChild(); dumpTemplateArgumentLoc(TALI[i]); } } void ASTDumper::dumpTemplateArgumentLoc(const TemplateArgumentLoc &A) { dumpTemplateArgument(A.getArgument(), A.getSourceRange()); } void ASTDumper::dumpTemplateArgumentList(const TemplateArgumentList &TAL) { for (unsigned i = 0, e = TAL.size(); i < e; ++i) dumpTemplateArgument(TAL[i]); } void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) { IndentScope Indent(*this); OS << "TemplateArgument"; if (R.isValid()) dumpSourceRange(R); switch (A.getKind()) { case TemplateArgument::Null: OS << " null"; break; case TemplateArgument::Type: OS << " type"; lastChild(); dumpType(A.getAsType()); break; case TemplateArgument::Declaration: OS << " decl"; lastChild(); dumpDeclRef(A.getAsDecl()); break; case TemplateArgument::NullPtr: OS << " nullptr"; break; case TemplateArgument::Integral: OS << " integral " << A.getAsIntegral(); break; case TemplateArgument::Template: OS << " template "; A.getAsTemplate().dump(OS); break; case TemplateArgument::TemplateExpansion: OS << " template expansion"; A.getAsTemplateOrTemplatePattern().dump(OS); break; case TemplateArgument::Expression: OS << " expr"; lastChild(); dumpStmt(A.getAsExpr()); break; case TemplateArgument::Pack: OS << " pack"; for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end(); I != E; ++I) { if (I + 1 == E) lastChild(); dumpTemplateArgument(*I); } break; } } //===----------------------------------------------------------------------===// // Decl dumping methods. //===----------------------------------------------------------------------===// void ASTDumper::dumpDecl(const Decl *D) { IndentScope Indent(*this); if (!D) { ColorScope Color(*this, NullColor); OS << "<<>>"; return; } { ColorScope Color(*this, DeclKindNameColor); OS << D->getDeclKindName() << "Decl"; } dumpPointer(D); if (D->getLexicalDeclContext() != D->getDeclContext()) OS << " parent " << cast(D->getDeclContext()); dumpPreviousDecl(OS, D); dumpSourceRange(D->getSourceRange()); OS << ' '; dumpLocation(D->getLocation()); if (Module *M = D->getOwningModule()) OS << " in " << M->getFullModuleName(); if (const NamedDecl *ND = dyn_cast(D)) if (ND->isHidden()) OS << " hidden"; if (D->isImplicit()) OS << " implicit"; if (D->isUsed()) OS << " used"; else if (D->isReferenced()) OS << " referenced"; if (D->isInvalidDecl()) OS << " invalid"; bool HasAttrs = D->hasAttrs(); const FullComment *Comment = D->getASTContext().getLocalCommentForDeclUncached(D); // Decls within functions are visited by the body bool HasDeclContext = !isa(*D) && !isa(*D) && hasNodes(dyn_cast(D)); setMoreChildren(HasAttrs || Comment || HasDeclContext); ConstDeclVisitor::Visit(D); setMoreChildren(Comment || HasDeclContext); for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end(); I != E; ++I) { if (I + 1 == E) lastChild(); dumpAttr(*I); } setMoreChildren(HasDeclContext); lastChild(); dumpFullComment(Comment); setMoreChildren(false); if (HasDeclContext) dumpDeclContext(cast(D)); } void ASTDumper::VisitLabelDecl(const LabelDecl *D) { dumpName(D); } void ASTDumper::VisitTypedefDecl(const TypedefDecl *D) { dumpName(D); dumpType(D->getUnderlyingType()); if (D->isModulePrivate()) OS << " __module_private__"; } void ASTDumper::VisitEnumDecl(const EnumDecl *D) { if (D->isScoped()) { if (D->isScopedUsingClassTag()) OS << " class"; else OS << " struct"; } dumpName(D); if (D->isModulePrivate()) OS << " __module_private__"; if (D->isFixed()) dumpType(D->getIntegerType()); } void ASTDumper::VisitRecordDecl(const RecordDecl *D) { OS << ' ' << D->getKindName(); dumpName(D); if (D->isModulePrivate()) OS << " __module_private__"; if (D->isCompleteDefinition()) OS << " definition"; } void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) { dumpName(D); dumpType(D->getType()); if (const Expr *Init = D->getInitExpr()) { lastChild(); dumpStmt(Init); } } void ASTDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) { dumpName(D); dumpType(D->getType()); ChildDumper Children(*this); for (auto *Child : D->chain()) Children.dumpRef(Child); } void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { dumpName(D); dumpType(D->getType()); StorageClass SC = D->getStorageClass(); if (SC != SC_None) OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); if (D->isInlineSpecified()) OS << " inline"; if (D->isVirtualAsWritten()) OS << " virtual"; if (D->isModulePrivate()) OS << " __module_private__"; if (D->isPure()) OS << " pure"; else if (D->isDeletedAsWritten()) OS << " delete"; if (const FunctionProtoType *FPT = D->getType()->getAs()) { FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); switch (EPI.ExceptionSpecType) { default: break; case EST_Unevaluated: OS << " noexcept-unevaluated " << EPI.ExceptionSpecDecl; break; case EST_Uninstantiated: OS << " noexcept-uninstantiated " << EPI.ExceptionSpecTemplate; break; } } bool OldMoreChildren = hasMoreChildren(); const FunctionTemplateSpecializationInfo *FTSI = D->getTemplateSpecializationInfo(); bool HasTemplateSpecialization = FTSI; bool HasNamedDecls = D->getDeclsInPrototypeScope().begin() != D->getDeclsInPrototypeScope().end(); bool HasFunctionDecls = D->param_begin() != D->param_end(); const CXXConstructorDecl *C = dyn_cast(D); bool HasCtorInitializers = C && C->init_begin() != C->init_end(); bool HasDeclarationBody = D->doesThisDeclarationHaveABody(); setMoreChildren(OldMoreChildren || HasNamedDecls || HasFunctionDecls || HasCtorInitializers || HasDeclarationBody); if (HasTemplateSpecialization) { lastChild(); dumpTemplateArgumentList(*FTSI->TemplateArguments); } setMoreChildren(OldMoreChildren || HasFunctionDecls || HasCtorInitializers || HasDeclarationBody); for (ArrayRef::iterator I = D->getDeclsInPrototypeScope().begin(), E = D->getDeclsInPrototypeScope().end(); I != E; ++I) { if (I + 1 == E) lastChild(); dumpDecl(*I); } setMoreChildren(OldMoreChildren || HasCtorInitializers || HasDeclarationBody); for (FunctionDecl::param_const_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) { if (I + 1 == E) lastChild(); dumpDecl(*I); } setMoreChildren(OldMoreChildren || HasDeclarationBody); if (HasCtorInitializers) for (CXXConstructorDecl::init_const_iterator I = C->init_begin(), E = C->init_end(); I != E; ++I) { if (I + 1 == E) lastChild(); dumpCXXCtorInitializer(*I); } setMoreChildren(OldMoreChildren); if (HasDeclarationBody) { lastChild(); dumpStmt(D->getBody()); } } void ASTDumper::VisitFieldDecl(const FieldDecl *D) { dumpName(D); dumpType(D->getType()); if (D->isMutable()) OS << " mutable"; if (D->isModulePrivate()) OS << " __module_private__"; bool OldMoreChildren = hasMoreChildren(); bool IsBitField = D->isBitField(); Expr *Init = D->getInClassInitializer(); bool HasInit = Init; setMoreChildren(OldMoreChildren || HasInit); if (IsBitField) { lastChild(); dumpStmt(D->getBitWidth()); } setMoreChildren(OldMoreChildren); if (HasInit) { lastChild(); dumpStmt(Init); } } void ASTDumper::VisitVarDecl(const VarDecl *D) { dumpName(D); dumpType(D->getType()); StorageClass SC = D->getStorageClass(); if (SC != SC_None) OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); switch (D->getTLSKind()) { case VarDecl::TLS_None: break; case VarDecl::TLS_Static: OS << " tls"; break; case VarDecl::TLS_Dynamic: OS << " tls_dynamic"; break; } if (D->isModulePrivate()) OS << " __module_private__"; if (D->isNRVOVariable()) OS << " nrvo"; if (D->hasInit()) { lastChild(); dumpStmt(D->getInit()); } } void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) { lastChild(); dumpStmt(D->getAsmString()); } void ASTDumper::VisitImportDecl(const ImportDecl *D) { OS << ' ' << D->getImportedModule()->getFullModuleName(); } //===----------------------------------------------------------------------===// // C++ Declarations //===----------------------------------------------------------------------===// void ASTDumper::VisitNamespaceDecl(const NamespaceDecl *D) { dumpName(D); if (D->isInline()) OS << " inline"; if (!D->isOriginalNamespace()) dumpDeclRef(D->getOriginalNamespace(), "original"); } void ASTDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { OS << ' '; dumpBareDeclRef(D->getNominatedNamespace()); } void ASTDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) { dumpName(D); dumpDeclRef(D->getAliasedNamespace()); } void ASTDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) { dumpName(D); dumpType(D->getUnderlyingType()); } void ASTDumper::VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) { dumpName(D); dumpTemplateParameters(D->getTemplateParameters()); dumpDecl(D->getTemplatedDecl()); } void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) { VisitRecordDecl(D); if (!D->isCompleteDefinition()) return; for (const auto &I : D->bases()) { IndentScope Indent(*this); if (I.isVirtual()) OS << "virtual "; dumpAccessSpecifier(I.getAccessSpecifier()); dumpType(I.getType()); if (I.isPackExpansion()) OS << "..."; } } void ASTDumper::VisitStaticAssertDecl(const StaticAssertDecl *D) { dumpStmt(D->getAssertExpr()); lastChild(); dumpStmt(D->getMessage()); } template void ASTDumper::VisitTemplateDeclSpecialization(ChildDumper &Children, const SpecializationDecl *D, bool DumpExplicitInst, bool DumpRefOnly) { bool DumpedAny = false; for (auto *RedeclWithBadType : D->redecls()) { // FIXME: The redecls() range sometimes has elements of a less-specific // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives // us TagDecls, and should give CXXRecordDecls). auto *Redecl = dyn_cast(RedeclWithBadType); if (!Redecl) { // Found the injected-class-name for a class template. This will be dumped // as part of its surrounding class so we don't need to dump it here. assert(isa(RedeclWithBadType) && "expected an injected-class-name"); continue; } switch (Redecl->getTemplateSpecializationKind()) { case TSK_ExplicitInstantiationDeclaration: case TSK_ExplicitInstantiationDefinition: if (!DumpExplicitInst) break; // Fall through. case TSK_Undeclared: case TSK_ImplicitInstantiation: Children.dump(Redecl, DumpRefOnly); DumpedAny = true; break; case TSK_ExplicitSpecialization: break; } } // Ensure we dump at least one decl for each specialization. if (!DumpedAny) Children.dumpRef(D); } template void ASTDumper::VisitTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst) { dumpName(D); dumpTemplateParameters(D->getTemplateParameters()); ChildDumper Children(*this); Children.dump(D->getTemplatedDecl()); for (auto *Child : D->specializations()) VisitTemplateDeclSpecialization(Children, Child, DumpExplicitInst, !D->isCanonicalDecl()); } void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { // FIXME: We don't add a declaration of a function template specialization // to its context when it's explicitly instantiated, so dump explicit // instantiations when we dump the template itself. VisitTemplateDecl(D, true); } void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) { VisitTemplateDecl(D, false); } void ASTDumper::VisitClassTemplateSpecializationDecl( const ClassTemplateSpecializationDecl *D) { VisitCXXRecordDecl(D); dumpTemplateArgumentList(D->getTemplateArgs()); } void ASTDumper::VisitClassTemplatePartialSpecializationDecl( const ClassTemplatePartialSpecializationDecl *D) { VisitClassTemplateSpecializationDecl(D); dumpTemplateParameters(D->getTemplateParameters()); } void ASTDumper::VisitClassScopeFunctionSpecializationDecl( const ClassScopeFunctionSpecializationDecl *D) { dumpDeclRef(D->getSpecialization()); if (D->hasExplicitTemplateArgs()) dumpTemplateArgumentListInfo(D->templateArgs()); } void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) { VisitTemplateDecl(D, false); } void ASTDumper::VisitVarTemplateSpecializationDecl( const VarTemplateSpecializationDecl *D) { dumpTemplateArgumentList(D->getTemplateArgs()); VisitVarDecl(D); } void ASTDumper::VisitVarTemplatePartialSpecializationDecl( const VarTemplatePartialSpecializationDecl *D) { dumpTemplateParameters(D->getTemplateParameters()); VisitVarTemplateSpecializationDecl(D); } void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { if (D->wasDeclaredWithTypename()) OS << " typename"; else OS << " class"; if (D->isParameterPack()) OS << " ..."; dumpName(D); if (D->hasDefaultArgument()) { lastChild(); dumpTemplateArgument(D->getDefaultArgument()); } } void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { dumpType(D->getType()); if (D->isParameterPack()) OS << " ..."; dumpName(D); if (D->hasDefaultArgument()) { lastChild(); dumpTemplateArgument(D->getDefaultArgument()); } } void ASTDumper::VisitTemplateTemplateParmDecl( const TemplateTemplateParmDecl *D) { if (D->isParameterPack()) OS << " ..."; dumpName(D); dumpTemplateParameters(D->getTemplateParameters()); if (D->hasDefaultArgument()) { lastChild(); dumpTemplateArgumentLoc(D->getDefaultArgument()); } } void ASTDumper::VisitUsingDecl(const UsingDecl *D) { OS << ' '; D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); OS << D->getNameAsString(); } void ASTDumper::VisitUnresolvedUsingTypenameDecl( const UnresolvedUsingTypenameDecl *D) { OS << ' '; D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); OS << D->getNameAsString(); } void ASTDumper::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { OS << ' '; D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); OS << D->getNameAsString(); dumpType(D->getType()); } void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) { OS << ' '; dumpBareDeclRef(D->getTargetDecl()); } void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) { switch (D->getLanguage()) { case LinkageSpecDecl::lang_c: OS << " C"; break; case LinkageSpecDecl::lang_cxx: OS << " C++"; break; } } void ASTDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) { OS << ' '; dumpAccessSpecifier(D->getAccess()); } void ASTDumper::VisitFriendDecl(const FriendDecl *D) { lastChild(); if (TypeSourceInfo *T = D->getFriendType()) dumpType(T->getType()); else dumpDecl(D->getFriendDecl()); } //===----------------------------------------------------------------------===// // Obj-C Declarations //===----------------------------------------------------------------------===// void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) { dumpName(D); dumpType(D->getType()); if (D->getSynthesize()) OS << " synthesize"; switch (D->getAccessControl()) { case ObjCIvarDecl::None: OS << " none"; break; case ObjCIvarDecl::Private: OS << " private"; break; case ObjCIvarDecl::Protected: OS << " protected"; break; case ObjCIvarDecl::Public: OS << " public"; break; case ObjCIvarDecl::Package: OS << " package"; break; } } void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) { if (D->isInstanceMethod()) OS << " -"; else OS << " +"; dumpName(D); dumpType(D->getReturnType()); bool OldMoreChildren = hasMoreChildren(); bool IsVariadic = D->isVariadic(); bool HasBody = D->hasBody(); setMoreChildren(OldMoreChildren || IsVariadic || HasBody); if (D->isThisDeclarationADefinition()) { lastChild(); dumpDeclContext(D); } else { for (ObjCMethodDecl::param_const_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) { if (I + 1 == E) lastChild(); dumpDecl(*I); } } setMoreChildren(OldMoreChildren || HasBody); if (IsVariadic) { lastChild(); IndentScope Indent(*this); OS << "..."; } setMoreChildren(OldMoreChildren); if (HasBody) { lastChild(); dumpStmt(D->getBody()); } } void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { dumpName(D); dumpDeclRef(D->getClassInterface()); if (D->protocol_begin() == D->protocol_end()) lastChild(); dumpDeclRef(D->getImplementation()); for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) { if (I + 1 == E) lastChild(); dumpDeclRef(*I); } } void ASTDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { dumpName(D); dumpDeclRef(D->getClassInterface()); lastChild(); dumpDeclRef(D->getCategoryDecl()); } void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { dumpName(D); ChildDumper Children(*this); for (auto *Child : D->protocols()) Children.dumpRef(Child); } void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { dumpName(D); dumpDeclRef(D->getSuperClass(), "super"); ChildDumper Children(*this); Children.dumpRef(D->getImplementation()); for (auto *Child : D->protocols()) Children.dumpRef(Child); } void ASTDumper::VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { dumpName(D); dumpDeclRef(D->getSuperClass(), "super"); if (D->init_begin() == D->init_end()) lastChild(); dumpDeclRef(D->getClassInterface()); for (ObjCImplementationDecl::init_const_iterator I = D->init_begin(), E = D->init_end(); I != E; ++I) { if (I + 1 == E) lastChild(); dumpCXXCtorInitializer(*I); } } void ASTDumper::VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D) { dumpName(D); lastChild(); dumpDeclRef(D->getClassInterface()); } void ASTDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { dumpName(D); dumpType(D->getType()); if (D->getPropertyImplementation() == ObjCPropertyDecl::Required) OS << " required"; else if (D->getPropertyImplementation() == ObjCPropertyDecl::Optional) OS << " optional"; ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes(); if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) { if (Attrs & ObjCPropertyDecl::OBJC_PR_readonly) OS << " readonly"; if (Attrs & ObjCPropertyDecl::OBJC_PR_assign) OS << " assign"; if (Attrs & ObjCPropertyDecl::OBJC_PR_readwrite) OS << " readwrite"; if (Attrs & ObjCPropertyDecl::OBJC_PR_retain) OS << " retain"; if (Attrs & ObjCPropertyDecl::OBJC_PR_copy) OS << " copy"; if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic) OS << " nonatomic"; if (Attrs & ObjCPropertyDecl::OBJC_PR_atomic) OS << " atomic"; if (Attrs & ObjCPropertyDecl::OBJC_PR_weak) OS << " weak"; if (Attrs & ObjCPropertyDecl::OBJC_PR_strong) OS << " strong"; if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) OS << " unsafe_unretained"; if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) { if (!(Attrs & ObjCPropertyDecl::OBJC_PR_setter)) lastChild(); dumpDeclRef(D->getGetterMethodDecl(), "getter"); } if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) { lastChild(); dumpDeclRef(D->getSetterMethodDecl(), "setter"); } } } void ASTDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { dumpName(D->getPropertyDecl()); if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) OS << " synthesize"; else OS << " dynamic"; dumpDeclRef(D->getPropertyDecl()); lastChild(); dumpDeclRef(D->getPropertyIvarDecl()); } void ASTDumper::VisitBlockDecl(const BlockDecl *D) { for (auto I : D->params()) dumpDecl(I); if (D->isVariadic()) { IndentScope Indent(*this); OS << "..."; } if (D->capturesCXXThis()) { IndentScope Indent(*this); OS << "capture this"; } for (const auto &I : D->captures()) { IndentScope Indent(*this); OS << "capture"; if (I.isByRef()) OS << " byref"; if (I.isNested()) OS << " nested"; if (I.getVariable()) { OS << ' '; dumpBareDeclRef(I.getVariable()); } if (I.hasCopyExpr()) dumpStmt(I.getCopyExpr()); } lastChild(); dumpStmt(D->getBody()); } //===----------------------------------------------------------------------===// // Stmt dumping methods. //===----------------------------------------------------------------------===// void ASTDumper::dumpStmt(const Stmt *S) { IndentScope Indent(*this); if (!S) { ColorScope Color(*this, NullColor); OS << "<<>>"; return; } if (const DeclStmt *DS = dyn_cast(S)) { VisitDeclStmt(DS); return; } setMoreChildren(!S->children().empty()); ConstStmtVisitor::Visit(S); setMoreChildren(false); for (Stmt::const_child_range CI = S->children(); CI; ++CI) { Stmt::const_child_range Next = CI; ++Next; if (!Next) lastChild(); dumpStmt(*CI); } } void ASTDumper::VisitStmt(const Stmt *Node) { { ColorScope Color(*this, StmtColor); OS << Node->getStmtClassName(); } dumpPointer(Node); dumpSourceRange(Node->getSourceRange()); } void ASTDumper::VisitDeclStmt(const DeclStmt *Node) { VisitStmt(Node); for (DeclStmt::const_decl_iterator I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) { if (I + 1 == E) lastChild(); dumpDecl(*I); } } void ASTDumper::VisitAttributedStmt(const AttributedStmt *Node) { VisitStmt(Node); for (ArrayRef::iterator I = Node->getAttrs().begin(), E = Node->getAttrs().end(); I != E; ++I) { if (I + 1 == E) lastChild(); dumpAttr(*I); } } void ASTDumper::VisitLabelStmt(const LabelStmt *Node) { VisitStmt(Node); OS << " '" << Node->getName() << "'"; } void ASTDumper::VisitGotoStmt(const GotoStmt *Node) { VisitStmt(Node); OS << " '" << Node->getLabel()->getName() << "'"; dumpPointer(Node->getLabel()); } void ASTDumper::VisitCXXCatchStmt(const CXXCatchStmt *Node) { VisitStmt(Node); dumpDecl(Node->getExceptionDecl()); } //===----------------------------------------------------------------------===// // Expr dumping methods. //===----------------------------------------------------------------------===// void ASTDumper::VisitExpr(const Expr *Node) { VisitStmt(Node); dumpType(Node->getType()); { ColorScope Color(*this, ValueKindColor); switch (Node->getValueKind()) { case VK_RValue: break; case VK_LValue: OS << " lvalue"; break; case VK_XValue: OS << " xvalue"; break; } } { ColorScope Color(*this, ObjectKindColor); switch (Node->getObjectKind()) { case OK_Ordinary: break; case OK_BitField: OS << " bitfield"; break; case OK_ObjCProperty: OS << " objcproperty"; break; case OK_ObjCSubscript: OS << " objcsubscript"; break; case OK_VectorComponent: OS << " vectorcomponent"; break; } } } static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) { if (Node->path_empty()) return; OS << " ("; bool First = true; for (CastExpr::path_const_iterator I = Node->path_begin(), E = Node->path_end(); I != E; ++I) { const CXXBaseSpecifier *Base = *I; if (!First) OS << " -> "; const CXXRecordDecl *RD = cast(Base->getType()->getAs()->getDecl()); if (Base->isVirtual()) OS << "virtual "; OS << RD->getName(); First = false; } OS << ')'; } void ASTDumper::VisitCastExpr(const CastExpr *Node) { VisitExpr(Node); OS << " <"; { ColorScope Color(*this, CastColor); OS << Node->getCastKindName(); } dumpBasePath(OS, Node); OS << ">"; } void ASTDumper::VisitDeclRefExpr(const DeclRefExpr *Node) { VisitExpr(Node); OS << " "; dumpBareDeclRef(Node->getDecl()); if (Node->getDecl() != Node->getFoundDecl()) { OS << " ("; dumpBareDeclRef(Node->getFoundDecl()); OS << ")"; } } void ASTDumper::VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node) { VisitExpr(Node); OS << " ("; if (!Node->requiresADL()) OS << "no "; OS << "ADL) = '" << Node->getName() << '\''; UnresolvedLookupExpr::decls_iterator I = Node->decls_begin(), E = Node->decls_end(); if (I == E) OS << " empty"; for (; I != E; ++I) dumpPointer(*I); } void ASTDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node) { VisitExpr(Node); { ColorScope Color(*this, DeclKindNameColor); OS << " " << Node->getDecl()->getDeclKindName() << "Decl"; } OS << "='" << *Node->getDecl() << "'"; dumpPointer(Node->getDecl()); if (Node->isFreeIvar()) OS << " isFreeIvar"; } void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) { VisitExpr(Node); switch (Node->getIdentType()) { default: llvm_unreachable("unknown case"); case PredefinedExpr::Func: OS << " __func__"; break; case PredefinedExpr::Function: OS << " __FUNCTION__"; break; case PredefinedExpr::FuncDName: OS << " __FUNCDNAME__"; break; case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break; case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break; case PredefinedExpr::FuncSig: OS << " __FUNCSIG__"; break; } } void ASTDumper::VisitCharacterLiteral(const CharacterLiteral *Node) { VisitExpr(Node); ColorScope Color(*this, ValueColor); OS << " " << Node->getValue(); } void ASTDumper::VisitIntegerLiteral(const IntegerLiteral *Node) { VisitExpr(Node); bool isSigned = Node->getType()->isSignedIntegerType(); ColorScope Color(*this, ValueColor); OS << " " << Node->getValue().toString(10, isSigned); } void ASTDumper::VisitFloatingLiteral(const FloatingLiteral *Node) { VisitExpr(Node); ColorScope Color(*this, ValueColor); OS << " " << Node->getValueAsApproximateDouble(); } void ASTDumper::VisitStringLiteral(const StringLiteral *Str) { VisitExpr(Str); ColorScope Color(*this, ValueColor); OS << " "; Str->outputString(OS); } void ASTDumper::VisitInitListExpr(const InitListExpr *ILE) { VisitExpr(ILE); if (auto *Filler = ILE->getArrayFiller()) { if (!ILE->getNumInits()) lastChild(); IndentScope Indent(*this); OS << "array filler"; lastChild(); dumpStmt(Filler); } if (auto *Field = ILE->getInitializedFieldInUnion()) { OS << " field "; dumpBareDeclRef(Field); } } void ASTDumper::VisitUnaryOperator(const UnaryOperator *Node) { VisitExpr(Node); OS << " " << (Node->isPostfix() ? "postfix" : "prefix") << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; } void ASTDumper::VisitUnaryExprOrTypeTraitExpr( const UnaryExprOrTypeTraitExpr *Node) { VisitExpr(Node); switch(Node->getKind()) { case UETT_SizeOf: OS << " sizeof"; break; case UETT_AlignOf: OS << " alignof"; break; case UETT_VecStep: OS << " vec_step"; break; } if (Node->isArgumentType()) dumpType(Node->getArgumentType()); } void ASTDumper::VisitMemberExpr(const MemberExpr *Node) { VisitExpr(Node); OS << " " << (Node->isArrow() ? "->" : ".") << *Node->getMemberDecl(); dumpPointer(Node->getMemberDecl()); } void ASTDumper::VisitExtVectorElementExpr(const ExtVectorElementExpr *Node) { VisitExpr(Node); OS << " " << Node->getAccessor().getNameStart(); } void ASTDumper::VisitBinaryOperator(const BinaryOperator *Node) { VisitExpr(Node); OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; } void ASTDumper::VisitCompoundAssignOperator( const CompoundAssignOperator *Node) { VisitExpr(Node); OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "' ComputeLHSTy="; dumpBareType(Node->getComputationLHSType()); OS << " ComputeResultTy="; dumpBareType(Node->getComputationResultType()); } void ASTDumper::VisitBlockExpr(const BlockExpr *Node) { VisitExpr(Node); dumpDecl(Node->getBlockDecl()); } void ASTDumper::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) { VisitExpr(Node); if (Expr *Source = Node->getSourceExpr()) { lastChild(); dumpStmt(Source); } } // GNU extensions. void ASTDumper::VisitAddrLabelExpr(const AddrLabelExpr *Node) { VisitExpr(Node); OS << " " << Node->getLabel()->getName(); dumpPointer(Node->getLabel()); } //===----------------------------------------------------------------------===// // C++ Expressions //===----------------------------------------------------------------------===// void ASTDumper::VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node) { VisitExpr(Node); OS << " " << Node->getCastName() << "<" << Node->getTypeAsWritten().getAsString() << ">" << " <" << Node->getCastKindName(); dumpBasePath(OS, Node); OS << ">"; } void ASTDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node) { VisitExpr(Node); OS << " " << (Node->getValue() ? "true" : "false"); } void ASTDumper::VisitCXXThisExpr(const CXXThisExpr *Node) { VisitExpr(Node); OS << " this"; } void ASTDumper::VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node) { VisitExpr(Node); OS << " functional cast to " << Node->getTypeAsWritten().getAsString() << " <" << Node->getCastKindName() << ">"; } void ASTDumper::VisitCXXConstructExpr(const CXXConstructExpr *Node) { VisitExpr(Node); CXXConstructorDecl *Ctor = Node->getConstructor(); dumpType(Ctor->getType()); if (Node->isElidable()) OS << " elidable"; if (Node->requiresZeroInitialization()) OS << " zeroing"; } void ASTDumper::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) { VisitExpr(Node); OS << " "; dumpCXXTemporary(Node->getTemporary()); } void ASTDumper::VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node) { VisitExpr(Node); if (const ValueDecl *VD = Node->getExtendingDecl()) { OS << " extended by "; dumpBareDeclRef(VD); } } void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) { VisitExpr(Node); for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) dumpDeclRef(Node->getObject(i), "cleanup"); } void ASTDumper::dumpCXXTemporary(const CXXTemporary *Temporary) { OS << "(CXXTemporary"; dumpPointer(Temporary); OS << ")"; } //===----------------------------------------------------------------------===// // Obj-C Expressions //===----------------------------------------------------------------------===// void ASTDumper::VisitObjCMessageExpr(const ObjCMessageExpr *Node) { VisitExpr(Node); OS << " selector="; Node->getSelector().print(OS); switch (Node->getReceiverKind()) { case ObjCMessageExpr::Instance: break; case ObjCMessageExpr::Class: OS << " class="; dumpBareType(Node->getClassReceiver()); break; case ObjCMessageExpr::SuperInstance: OS << " super (instance)"; break; case ObjCMessageExpr::SuperClass: OS << " super (class)"; break; } } void ASTDumper::VisitObjCBoxedExpr(const ObjCBoxedExpr *Node) { VisitExpr(Node); OS << " selector="; Node->getBoxingMethod()->getSelector().print(OS); } void ASTDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) { VisitStmt(Node); if (const VarDecl *CatchParam = Node->getCatchParamDecl()) dumpDecl(CatchParam); else OS << " catch all"; } void ASTDumper::VisitObjCEncodeExpr(const ObjCEncodeExpr *Node) { VisitExpr(Node); dumpType(Node->getEncodedType()); } void ASTDumper::VisitObjCSelectorExpr(const ObjCSelectorExpr *Node) { VisitExpr(Node); OS << " "; Node->getSelector().print(OS); } void ASTDumper::VisitObjCProtocolExpr(const ObjCProtocolExpr *Node) { VisitExpr(Node); OS << ' ' << *Node->getProtocol(); } void ASTDumper::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node) { VisitExpr(Node); if (Node->isImplicitProperty()) { OS << " Kind=MethodRef Getter=\""; if (Node->getImplicitPropertyGetter()) Node->getImplicitPropertyGetter()->getSelector().print(OS); else OS << "(null)"; OS << "\" Setter=\""; if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter()) Setter->getSelector().print(OS); else OS << "(null)"; OS << "\""; } else { OS << " Kind=PropertyRef Property=\"" << *Node->getExplicitProperty() <<'"'; } if (Node->isSuperReceiver()) OS << " super"; OS << " Messaging="; if (Node->isMessagingGetter() && Node->isMessagingSetter()) OS << "Getter&Setter"; else if (Node->isMessagingGetter()) OS << "Getter"; else if (Node->isMessagingSetter()) OS << "Setter"; } void ASTDumper::VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node) { VisitExpr(Node); if (Node->isArraySubscriptRefExpr()) OS << " Kind=ArraySubscript GetterForArray=\""; else OS << " Kind=DictionarySubscript GetterForDictionary=\""; if (Node->getAtIndexMethodDecl()) Node->getAtIndexMethodDecl()->getSelector().print(OS); else OS << "(null)"; if (Node->isArraySubscriptRefExpr()) OS << "\" SetterForArray=\""; else OS << "\" SetterForDictionary=\""; if (Node->setAtIndexMethodDecl()) Node->setAtIndexMethodDecl()->getSelector().print(OS); else OS << "(null)"; } void ASTDumper::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node) { VisitExpr(Node); OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no"); } //===----------------------------------------------------------------------===// // Comments //===----------------------------------------------------------------------===// const char *ASTDumper::getCommandName(unsigned CommandID) { if (Traits) return Traits->getCommandInfo(CommandID)->Name; const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID); if (Info) return Info->Name; return ""; } void ASTDumper::dumpFullComment(const FullComment *C) { if (!C) return; FC = C; dumpComment(C); FC = nullptr; } void ASTDumper::dumpComment(const Comment *C) { IndentScope Indent(*this); if (!C) { ColorScope Color(*this, NullColor); OS << "<<>>"; return; } { ColorScope Color(*this, CommentColor); OS << C->getCommentKindName(); } dumpPointer(C); dumpSourceRange(C->getSourceRange()); ConstCommentVisitor::visit(C); for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); I != E; ++I) { if (I + 1 == E) lastChild(); dumpComment(*I); } } void ASTDumper::visitTextComment(const TextComment *C) { OS << " Text=\"" << C->getText() << "\""; } void ASTDumper::visitInlineCommandComment(const InlineCommandComment *C) { OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; switch (C->getRenderKind()) { case InlineCommandComment::RenderNormal: OS << " RenderNormal"; break; case InlineCommandComment::RenderBold: OS << " RenderBold"; break; case InlineCommandComment::RenderMonospaced: OS << " RenderMonospaced"; break; case InlineCommandComment::RenderEmphasized: OS << " RenderEmphasized"; break; } for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; } void ASTDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) { OS << " Name=\"" << C->getTagName() << "\""; if (C->getNumAttrs() != 0) { OS << " Attrs: "; for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) { const HTMLStartTagComment::Attribute &Attr = C->getAttr(i); OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\""; } } if (C->isSelfClosing()) OS << " SelfClosing"; } void ASTDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) { OS << " Name=\"" << C->getTagName() << "\""; } void ASTDumper::visitBlockCommandComment(const BlockCommandComment *C) { OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; } void ASTDumper::visitParamCommandComment(const ParamCommandComment *C) { OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection()); if (C->isDirectionExplicit()) OS << " explicitly"; else OS << " implicitly"; if (C->hasParamName()) { if (C->isParamIndexValid()) OS << " Param=\"" << C->getParamName(FC) << "\""; else OS << " Param=\"" << C->getParamNameAsWritten() << "\""; } if (C->isParamIndexValid() && !C->isVarArgParam()) OS << " ParamIndex=" << C->getParamIndex(); } void ASTDumper::visitTParamCommandComment(const TParamCommandComment *C) { if (C->hasParamName()) { if (C->isPositionValid()) OS << " Param=\"" << C->getParamName(FC) << "\""; else OS << " Param=\"" << C->getParamNameAsWritten() << "\""; } if (C->isPositionValid()) { OS << " Position=<"; for (unsigned i = 0, e = C->getDepth(); i != e; ++i) { OS << C->getIndex(i); if (i != e - 1) OS << ", "; } OS << ">"; } } void ASTDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) { OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"" " CloseName=\"" << C->getCloseName() << "\""; } void ASTDumper::visitVerbatimBlockLineComment( const VerbatimBlockLineComment *C) { OS << " Text=\"" << C->getText() << "\""; } void ASTDumper::visitVerbatimLineComment(const VerbatimLineComment *C) { OS << " Text=\"" << C->getText() << "\""; } //===----------------------------------------------------------------------===// // Decl method implementations //===----------------------------------------------------------------------===// LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); } LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS) const { ASTDumper P(OS, &getASTContext().getCommentCommandTraits(), &getASTContext().getSourceManager()); P.dumpDecl(this); } LLVM_DUMP_METHOD void Decl::dumpColor() const { ASTDumper P(llvm::errs(), &getASTContext().getCommentCommandTraits(), &getASTContext().getSourceManager(), /*ShowColors*/true); P.dumpDecl(this); } LLVM_DUMP_METHOD void DeclContext::dumpLookups() const { dumpLookups(llvm::errs()); } LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS) const { const DeclContext *DC = this; while (!DC->isTranslationUnit()) DC = DC->getParent(); ASTContext &Ctx = cast(DC)->getASTContext(); ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager()); P.dumpLookups(this); } //===----------------------------------------------------------------------===// // Stmt method implementations //===----------------------------------------------------------------------===// LLVM_DUMP_METHOD void Stmt::dump(SourceManager &SM) const { dump(llvm::errs(), SM); } LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { ASTDumper P(OS, nullptr, &SM); P.dumpStmt(this); } LLVM_DUMP_METHOD void Stmt::dump() const { ASTDumper P(llvm::errs(), nullptr, nullptr); P.dumpStmt(this); } LLVM_DUMP_METHOD void Stmt::dumpColor() const { ASTDumper P(llvm::errs(), nullptr, nullptr, /*ShowColors*/true); P.dumpStmt(this); } //===----------------------------------------------------------------------===// // Comment method implementations //===----------------------------------------------------------------------===// LLVM_DUMP_METHOD void Comment::dump() const { dump(llvm::errs(), nullptr, nullptr); } LLVM_DUMP_METHOD void Comment::dump(const ASTContext &Context) const { dump(llvm::errs(), &Context.getCommentCommandTraits(), &Context.getSourceManager()); } void Comment::dump(raw_ostream &OS, const CommandTraits *Traits, const SourceManager *SM) const { const FullComment *FC = dyn_cast(this); ASTDumper D(OS, Traits, SM); D.dumpFullComment(FC); } LLVM_DUMP_METHOD void Comment::dumpColor() const { const FullComment *FC = dyn_cast(this); ASTDumper D(llvm::errs(), nullptr, nullptr, /*ShowColors*/true); D.dumpFullComment(FC); }