|  | //===--- DumpXML.cpp - Detailed XML dumping ---------------------*- C++ -*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | //  This file defines the Decl::dumpXML() method, a debugging tool to | 
|  | //  print a detailed graph of an AST in an unspecified XML format. | 
|  | // | 
|  | //  There is no guarantee of stability for this format. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | // Only pay for this in code size in assertions-enabled builds. | 
|  |  | 
|  | #include "clang/AST/ASTContext.h" | 
|  | #include "clang/AST/Decl.h" | 
|  | #include "clang/AST/DeclCXX.h" | 
|  | #include "clang/AST/DeclFriend.h" | 
|  | #include "clang/AST/DeclObjC.h" | 
|  | #include "clang/AST/DeclTemplate.h" | 
|  | #include "clang/AST/DeclVisitor.h" | 
|  | #include "clang/AST/Expr.h" | 
|  | #include "clang/AST/ExprCXX.h" | 
|  | #include "clang/AST/ExprObjC.h" | 
|  | #include "clang/AST/NestedNameSpecifier.h" | 
|  | #include "clang/AST/Stmt.h" | 
|  | #include "clang/AST/StmtCXX.h" | 
|  | #include "clang/AST/StmtObjC.h" | 
|  | #include "clang/AST/StmtVisitor.h" | 
|  | #include "clang/AST/TemplateBase.h" | 
|  | #include "clang/AST/TemplateName.h" | 
|  | #include "clang/AST/Type.h" | 
|  | #include "clang/AST/TypeLoc.h" | 
|  | #include "clang/AST/TypeLocVisitor.h" | 
|  | #include "clang/AST/TypeVisitor.h" | 
|  | #include "clang/AST/Expr.h" | 
|  | #include "clang/AST/ExprCXX.h" | 
|  | #include "llvm/ADT/SmallVector.h" | 
|  | #include "llvm/ADT/StringRef.h" | 
|  |  | 
|  | using namespace clang; | 
|  |  | 
|  | #ifndef NDEBUG | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | enum NodeState { | 
|  | NS_Attrs, NS_LazyChildren, NS_Children | 
|  | }; | 
|  |  | 
|  | struct Node { | 
|  | llvm::StringRef Name; | 
|  | NodeState State; | 
|  | Node(llvm::StringRef name) : Name(name), State(NS_Attrs) {} | 
|  |  | 
|  | bool isDoneWithAttrs() const { return State != NS_Attrs; } | 
|  | }; | 
|  |  | 
|  | template <class Impl> struct XMLDeclVisitor { | 
|  | #define DISPATCH(NAME, CLASS) \ | 
|  | static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(D)) | 
|  |  | 
|  | void dispatch(Decl *D) { | 
|  | switch (D->getKind()) { | 
|  | default: llvm_unreachable("Decl that isn't part of DeclNodes.inc!"); | 
|  | #define DECL(DERIVED, BASE) \ | 
|  | case Decl::DERIVED: \ | 
|  | DISPATCH(dispatch##DERIVED##DeclAttrs, DERIVED##Decl); \ | 
|  | static_cast<Impl*>(this)->completeAttrs(); \ | 
|  | DISPATCH(dispatch##DERIVED##DeclChildren, DERIVED##Decl); \ | 
|  | DISPATCH(dispatch##DERIVED##DeclAsContext, DERIVED##Decl); \ | 
|  | break; | 
|  | #define ABSTRACT_DECL(DECL) | 
|  | #include "clang/AST/DeclNodes.inc" | 
|  | } | 
|  | } | 
|  |  | 
|  | #define DECL(DERIVED, BASE) \ | 
|  | void dispatch##DERIVED##DeclAttrs(DERIVED##Decl *D) { \ | 
|  | DISPATCH(dispatch##BASE##Attrs, BASE); \ | 
|  | DISPATCH(visit##DERIVED##DeclAttrs, DERIVED##Decl); \ | 
|  | } \ | 
|  | void visit##DERIVED##DeclAttrs(DERIVED##Decl *D) {} \ | 
|  | void dispatch##DERIVED##DeclChildren(DERIVED##Decl *D) { \ | 
|  | DISPATCH(dispatch##BASE##Children, BASE); \ | 
|  | DISPATCH(visit##DERIVED##DeclChildren, DERIVED##Decl); \ | 
|  | } \ | 
|  | void visit##DERIVED##DeclChildren(DERIVED##Decl *D) {} \ | 
|  | void dispatch##DERIVED##DeclAsContext(DERIVED##Decl *D) { \ | 
|  | DISPATCH(dispatch##BASE##AsContext, BASE); \ | 
|  | DISPATCH(visit##DERIVED##DeclAsContext, DERIVED##Decl); \ | 
|  | } \ | 
|  | void visit##DERIVED##DeclAsContext(DERIVED##Decl *D) {} | 
|  | #include "clang/AST/DeclNodes.inc" | 
|  |  | 
|  | void dispatchDeclAttrs(Decl *D) { | 
|  | DISPATCH(visitDeclAttrs, Decl); | 
|  | } | 
|  | void visitDeclAttrs(Decl *D) {} | 
|  |  | 
|  | void dispatchDeclChildren(Decl *D) { | 
|  | DISPATCH(visitDeclChildren, Decl); | 
|  | } | 
|  | void visitDeclChildren(Decl *D) {} | 
|  |  | 
|  | void dispatchDeclAsContext(Decl *D) { | 
|  | DISPATCH(visitDeclAsContext, Decl); | 
|  | } | 
|  | void visitDeclAsContext(Decl *D) {} | 
|  |  | 
|  | #undef DISPATCH | 
|  | }; | 
|  |  | 
|  | template <class Impl> struct XMLTypeVisitor { | 
|  | #define DISPATCH(NAME, CLASS) \ | 
|  | static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(T)) | 
|  |  | 
|  | void dispatch(Type *T) { | 
|  | switch (T->getTypeClass()) { | 
|  | default: llvm_unreachable("Type that isn't part of TypeNodes.inc!"); | 
|  | #define TYPE(DERIVED, BASE) \ | 
|  | case Type::DERIVED: \ | 
|  | DISPATCH(dispatch##DERIVED##TypeAttrs, DERIVED##Type); \ | 
|  | static_cast<Impl*>(this)->completeAttrs(); \ | 
|  | DISPATCH(dispatch##DERIVED##TypeChildren, DERIVED##Type); \ | 
|  | break; | 
|  | #define ABSTRACT_TYPE(DERIVED, BASE) | 
|  | #include "clang/AST/TypeNodes.def" | 
|  | } | 
|  | } | 
|  |  | 
|  | #define TYPE(DERIVED, BASE) \ | 
|  | void dispatch##DERIVED##TypeAttrs(DERIVED##Type *T) { \ | 
|  | DISPATCH(dispatch##BASE##Attrs, BASE); \ | 
|  | DISPATCH(visit##DERIVED##TypeAttrs, DERIVED##Type); \ | 
|  | } \ | 
|  | void visit##DERIVED##TypeAttrs(DERIVED##Type *T) {} \ | 
|  | void dispatch##DERIVED##TypeChildren(DERIVED##Type *T) { \ | 
|  | DISPATCH(dispatch##BASE##Children, BASE); \ | 
|  | DISPATCH(visit##DERIVED##TypeChildren, DERIVED##Type); \ | 
|  | } \ | 
|  | void visit##DERIVED##TypeChildren(DERIVED##Type *T) {} | 
|  | #include "clang/AST/TypeNodes.def" | 
|  |  | 
|  | void dispatchTypeAttrs(Type *T) { | 
|  | DISPATCH(visitTypeAttrs, Type); | 
|  | } | 
|  | void visitTypeAttrs(Type *T) {} | 
|  |  | 
|  | void dispatchTypeChildren(Type *T) { | 
|  | DISPATCH(visitTypeChildren, Type); | 
|  | } | 
|  | void visitTypeChildren(Type *T) {} | 
|  |  | 
|  | #undef DISPATCH | 
|  | }; | 
|  |  | 
|  | static llvm::StringRef getTypeKindName(Type *T) { | 
|  | switch (T->getTypeClass()) { | 
|  | #define TYPE(DERIVED, BASE) case Type::DERIVED: return #DERIVED "Type"; | 
|  | #define ABSTRACT_TYPE(DERIVED, BASE) | 
|  | #include "clang/AST/TypeNodes.def" | 
|  | } | 
|  |  | 
|  | llvm_unreachable("unknown type kind!"); | 
|  | return "unknown_type"; | 
|  | } | 
|  |  | 
|  | struct XMLDumper : public XMLDeclVisitor<XMLDumper>, | 
|  | public XMLTypeVisitor<XMLDumper> { | 
|  | llvm::raw_ostream &out; | 
|  | ASTContext &Context; | 
|  | llvm::SmallVector<Node, 16> Stack; | 
|  | unsigned Indent; | 
|  | explicit XMLDumper(llvm::raw_ostream &OS, ASTContext &context) | 
|  | : out(OS), Context(context), Indent(0) {} | 
|  |  | 
|  | void indent() { | 
|  | for (unsigned I = Indent; I; --I) | 
|  | out << ' '; | 
|  | } | 
|  |  | 
|  | /// Push a new node on the stack. | 
|  | void push(llvm::StringRef name) { | 
|  | if (!Stack.empty()) { | 
|  | assert(Stack.back().isDoneWithAttrs()); | 
|  | if (Stack.back().State == NS_LazyChildren) { | 
|  | Stack.back().State = NS_Children; | 
|  | out << ">\n"; | 
|  | } | 
|  | Indent++; | 
|  | indent(); | 
|  | } | 
|  | Stack.push_back(Node(name)); | 
|  | out << '<' << name; | 
|  | } | 
|  |  | 
|  | /// Set the given attribute to the given value. | 
|  | void set(llvm::StringRef attr, llvm::StringRef value) { | 
|  | assert(!Stack.empty() && !Stack.back().isDoneWithAttrs()); | 
|  | out << ' ' << attr << '=' << '"' << value << '"'; // TODO: quotation | 
|  | } | 
|  |  | 
|  | /// Finish attributes. | 
|  | void completeAttrs() { | 
|  | assert(!Stack.empty() && !Stack.back().isDoneWithAttrs()); | 
|  | Stack.back().State = NS_LazyChildren; | 
|  | } | 
|  |  | 
|  | /// Pop a node. | 
|  | void pop() { | 
|  | assert(!Stack.empty() && Stack.back().isDoneWithAttrs()); | 
|  | if (Stack.back().State == NS_LazyChildren) { | 
|  | out << "/>\n"; | 
|  | } else { | 
|  | indent(); | 
|  | out << "</" << Stack.back().Name << ">\n"; | 
|  | } | 
|  | if (Stack.size() > 1) Indent--; | 
|  | Stack.pop_back(); | 
|  | } | 
|  |  | 
|  | //---- General utilities -------------------------------------------// | 
|  |  | 
|  | void setPointer(llvm::StringRef prop, void *p) { | 
|  | llvm::SmallString<10> buffer; | 
|  | llvm::raw_svector_ostream os(buffer); | 
|  | os << p; | 
|  | os.flush(); | 
|  | set(prop, buffer); | 
|  | } | 
|  |  | 
|  | void setPointer(void *p) { | 
|  | setPointer("ptr", p); | 
|  | } | 
|  |  | 
|  | void setInteger(llvm::StringRef prop, const llvm::APSInt &v) { | 
|  | set(prop, v.toString(10)); | 
|  | } | 
|  |  | 
|  | void setInteger(llvm::StringRef prop, unsigned n) { | 
|  | llvm::SmallString<10> buffer; | 
|  | llvm::raw_svector_ostream os(buffer); | 
|  | os << n; | 
|  | os.flush(); | 
|  | set(prop, buffer); | 
|  | } | 
|  |  | 
|  | void setFlag(llvm::StringRef prop, bool flag) { | 
|  | if (flag) set(prop, "true"); | 
|  | } | 
|  |  | 
|  | void setName(DeclarationName Name) { | 
|  | if (!Name) | 
|  | return set("name", ""); | 
|  |  | 
|  | // Common case. | 
|  | if (Name.isIdentifier()) | 
|  | return set("name", Name.getAsIdentifierInfo()->getName()); | 
|  |  | 
|  | set("name", Name.getAsString()); | 
|  | } | 
|  |  | 
|  | class TemporaryContainer { | 
|  | XMLDumper &Dumper; | 
|  | public: | 
|  | TemporaryContainer(XMLDumper &dumper, llvm::StringRef name) | 
|  | : Dumper(dumper) { | 
|  | Dumper.push(name); | 
|  | Dumper.completeAttrs(); | 
|  | } | 
|  |  | 
|  | ~TemporaryContainer() { | 
|  | Dumper.pop(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | void visitTemplateParameters(TemplateParameterList *L) { | 
|  | push("template_parameters"); | 
|  | completeAttrs(); | 
|  | for (TemplateParameterList::iterator | 
|  | I = L->begin(), E = L->end(); I != E; ++I) | 
|  | dispatch(*I); | 
|  | pop(); | 
|  | } | 
|  |  | 
|  | void visitTemplateArguments(const TemplateArgumentList &L) { | 
|  | push("template_arguments"); | 
|  | completeAttrs(); | 
|  | for (unsigned I = 0, E = L.size(); I != E; ++I) | 
|  | dispatch(L[I]); | 
|  | pop(); | 
|  | } | 
|  |  | 
|  | /// Visits a reference to the given declaration. | 
|  | void visitDeclRef(Decl *D) { | 
|  | push(D->getDeclKindName()); | 
|  | setPointer("ref", D); | 
|  | completeAttrs(); | 
|  | pop(); | 
|  | } | 
|  | void visitDeclRef(llvm::StringRef Name, Decl *D) { | 
|  | TemporaryContainer C(*this, Name); | 
|  | if (D) visitDeclRef(D); | 
|  | } | 
|  |  | 
|  | void dispatch(const TemplateArgument &A) { | 
|  | switch (A.getKind()) { | 
|  | case TemplateArgument::Null: { | 
|  | TemporaryContainer C(*this, "null"); | 
|  | break; | 
|  | } | 
|  | case TemplateArgument::Type: { | 
|  | dispatch(A.getAsType()); | 
|  | break; | 
|  | } | 
|  | case TemplateArgument::Template: | 
|  | case TemplateArgument::Declaration: { | 
|  | visitDeclRef(A.getAsDecl()); | 
|  | break; | 
|  | } | 
|  | case TemplateArgument::Integral: { | 
|  | push("integer"); | 
|  | setInteger("value", *A.getAsIntegral()); | 
|  | completeAttrs(); | 
|  | pop(); | 
|  | break; | 
|  | } | 
|  | case TemplateArgument::Expression: { | 
|  | dispatch(A.getAsExpr()); | 
|  | break; | 
|  | } | 
|  | case TemplateArgument::Pack: { | 
|  | // TODO | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void dispatch(const TemplateArgumentLoc &A) { | 
|  | dispatch(A.getArgument()); | 
|  | } | 
|  |  | 
|  | //---- Declarations ------------------------------------------------// | 
|  | // Calls are made in this order: | 
|  | //   # Enter a new node. | 
|  | //   push("FieldDecl") | 
|  | // | 
|  | //   # In this phase, attributes are set on the node. | 
|  | //   visitDeclAttrs(D) | 
|  | //   visitNamedDeclAttrs(D) | 
|  | //   ... | 
|  | //   visitFieldDeclAttrs(D) | 
|  | // | 
|  | //   # No more attributes after this point. | 
|  | //   completeAttrs() | 
|  | // | 
|  | //   # Create "header" child nodes, i.e. those which logically | 
|  | //   # belong to the declaration itself. | 
|  | //   visitDeclChildren(D) | 
|  | //   visitNamedDeclChildren(D) | 
|  | //   ... | 
|  | //   visitFieldDeclChildren(D) | 
|  | // | 
|  | //   # Create nodes for the lexical children. | 
|  | //   visitDeclAsContext(D) | 
|  | //   visitNamedDeclAsContext(D) | 
|  | //   ... | 
|  | //   visitFieldDeclAsContext(D) | 
|  | // | 
|  | //   # Finish the node. | 
|  | //   pop(); | 
|  | void dispatch(Decl *D) { | 
|  | push(D->getDeclKindName()); | 
|  | XMLDeclVisitor<XMLDumper>::dispatch(D); | 
|  | pop(); | 
|  | } | 
|  | void visitDeclAttrs(Decl *D) { | 
|  | setPointer(D); | 
|  | } | 
|  |  | 
|  | /// Visit all the lexical decls in the given context. | 
|  | void visitDeclContext(DeclContext *DC) { | 
|  | for (DeclContext::decl_iterator | 
|  | I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) | 
|  | dispatch(*I); | 
|  |  | 
|  | // FIXME: point out visible declarations not in lexical context? | 
|  | } | 
|  |  | 
|  | /// Set the "access" attribute on the current node according to the | 
|  | /// given specifier. | 
|  | void setAccess(AccessSpecifier AS) { | 
|  | switch (AS) { | 
|  | case AS_public: return set("access", "public"); | 
|  | case AS_protected: return set("access", "protected"); | 
|  | case AS_private: return set("access", "private"); | 
|  | case AS_none: llvm_unreachable("explicit forbidden access"); | 
|  | } | 
|  | } | 
|  |  | 
|  | template <class T> void visitRedeclarableAttrs(T *D) { | 
|  | if (T *Prev = D->getPreviousDeclaration()) | 
|  | setPointer("previous", Prev); | 
|  | } | 
|  |  | 
|  |  | 
|  | // TranslationUnitDecl | 
|  | void visitTranslationUnitDeclAsContext(TranslationUnitDecl *D) { | 
|  | visitDeclContext(D); | 
|  | } | 
|  |  | 
|  | // LinkageSpecDecl | 
|  | void visitLinkageSpecDeclAttrs(LinkageSpecDecl *D) { | 
|  | llvm::StringRef lang = ""; | 
|  | switch (D->getLanguage()) { | 
|  | case LinkageSpecDecl::lang_c: lang = "C"; break; | 
|  | case LinkageSpecDecl::lang_cxx: lang = "C++"; break; | 
|  | } | 
|  | set("lang", lang); | 
|  | } | 
|  | void visitLinkageSpecDeclAsContext(LinkageSpecDecl *D) { | 
|  | visitDeclContext(D); | 
|  | } | 
|  |  | 
|  | // NamespaceDecl | 
|  | void visitNamespaceDeclAttrs(NamespaceDecl *D) { | 
|  | setFlag("inline", D->isInline()); | 
|  | if (!D->isOriginalNamespace()) | 
|  | setPointer("original", D->getOriginalNamespace()); | 
|  | } | 
|  | void visitNamespaceDeclAsContext(NamespaceDecl *D) { | 
|  | visitDeclContext(D); | 
|  | } | 
|  |  | 
|  | // NamedDecl | 
|  | void visitNamedDeclAttrs(NamedDecl *D) { | 
|  | setName(D->getDeclName()); | 
|  | } | 
|  |  | 
|  | // ValueDecl | 
|  | void visitValueDeclChildren(ValueDecl *D) { | 
|  | dispatch(D->getType()); | 
|  | } | 
|  |  | 
|  | // DeclaratorDecl | 
|  | void visitDeclaratorDeclChildren(DeclaratorDecl *D) { | 
|  | //dispatch(D->getTypeSourceInfo()->getTypeLoc()); | 
|  | } | 
|  |  | 
|  | // VarDecl | 
|  | void visitVarDeclAttrs(VarDecl *D) { | 
|  | visitRedeclarableAttrs(D); | 
|  | if (D->getStorageClass() != SC_None) | 
|  | set("storage", | 
|  | VarDecl::getStorageClassSpecifierString(D->getStorageClass())); | 
|  | setFlag("directinit", D->hasCXXDirectInitializer()); | 
|  | setFlag("nrvo", D->isNRVOVariable()); | 
|  | // TODO: instantiation, etc. | 
|  | } | 
|  | void visitVarDeclChildren(VarDecl *D) { | 
|  | if (D->hasInit()) dispatch(D->getInit()); | 
|  | } | 
|  |  | 
|  | // ParmVarDecl? | 
|  |  | 
|  | // FunctionDecl | 
|  | void visitFunctionDeclAttrs(FunctionDecl *D) { | 
|  | visitRedeclarableAttrs(D); | 
|  | setFlag("pure", D->isPure()); | 
|  | setFlag("trivial", D->isTrivial()); | 
|  | setFlag("returnzero", D->hasImplicitReturnZero()); | 
|  | setFlag("prototype", D->hasWrittenPrototype()); | 
|  | setFlag("deleted", D->isDeleted()); | 
|  | if (D->getStorageClass() != SC_None) | 
|  | set("storage", | 
|  | VarDecl::getStorageClassSpecifierString(D->getStorageClass())); | 
|  | setFlag("inline", D->isInlineSpecified()); | 
|  | // TODO: instantiation, etc. | 
|  | } | 
|  | void visitFunctionDeclChildren(FunctionDecl *D) { | 
|  | for (FunctionDecl::param_iterator | 
|  | I = D->param_begin(), E = D->param_end(); I != E; ++I) | 
|  | dispatch(*I); | 
|  | if (D->isThisDeclarationADefinition()) | 
|  | dispatch(D->getBody()); | 
|  | } | 
|  |  | 
|  | // CXXMethodDecl ? | 
|  | // CXXConstructorDecl ? | 
|  | // CXXDestructorDecl ? | 
|  | // CXXConversionDecl ? | 
|  |  | 
|  | void dispatch(CXXBaseOrMemberInitializer *Init) { | 
|  | // TODO | 
|  | } | 
|  |  | 
|  | // FieldDecl | 
|  | void visitFieldDeclAttrs(FieldDecl *D) { | 
|  | setFlag("mutable", D->isMutable()); | 
|  | } | 
|  | void visitFieldDeclChildren(FieldDecl *D) { | 
|  | if (D->isBitField()) { | 
|  | TemporaryContainer C(*this, "bitwidth"); | 
|  | dispatch(D->getBitWidth()); | 
|  | } | 
|  | // TODO: C++0x member initializer | 
|  | } | 
|  |  | 
|  | // EnumConstantDecl | 
|  | void visitEnumConstantDeclChildren(EnumConstantDecl *D) { | 
|  | // value in any case? | 
|  | if (D->getInitExpr()) dispatch(D->getInitExpr()); | 
|  | } | 
|  |  | 
|  | // IndirectFieldDecl | 
|  | void visitIndirectFieldDeclChildren(IndirectFieldDecl *D) { | 
|  | for (IndirectFieldDecl::chain_iterator | 
|  | I = D->chain_begin(), E = D->chain_end(); I != E; ++I) { | 
|  | NamedDecl *VD = const_cast<NamedDecl*>(*I); | 
|  | push(isa<VarDecl>(VD) ? "variable" : "field"); | 
|  | setPointer("ptr", VD); | 
|  | completeAttrs(); | 
|  | pop(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // TypeDecl | 
|  | void visitTypeDeclAttrs(TypeDecl *D) { | 
|  | setPointer("typeptr", D->getTypeForDecl()); | 
|  | } | 
|  |  | 
|  | // TypedefDecl | 
|  | void visitTypedefDeclAttrs(TypedefDecl *D) { | 
|  | visitRedeclarableAttrs(D); | 
|  | } | 
|  | void visitTypedefDeclChildren(TypedefDecl *D) { | 
|  | dispatch(D->getTypeSourceInfo()->getTypeLoc()); | 
|  | } | 
|  |  | 
|  | // TagDecl | 
|  | void visitTagDeclAttrs(TagDecl *D) { | 
|  | visitRedeclarableAttrs(D); | 
|  | } | 
|  | void visitTagDeclAsContext(TagDecl *D) { | 
|  | visitDeclContext(D); | 
|  | } | 
|  |  | 
|  | // EnumDecl | 
|  | void visitEnumDeclAttrs(EnumDecl *D) { | 
|  | setFlag("scoped", D->isScoped()); | 
|  | setFlag("fixed", D->isFixed()); | 
|  | } | 
|  | void visitEnumDeclChildren(EnumDecl *D) { | 
|  | { | 
|  | TemporaryContainer C(*this, "promotion_type"); | 
|  | dispatch(D->getPromotionType()); | 
|  | } | 
|  | { | 
|  | TemporaryContainer C(*this, "integer_type"); | 
|  | dispatch(D->getIntegerType()); | 
|  | } | 
|  | } | 
|  |  | 
|  | // RecordDecl ? | 
|  |  | 
|  | void visitCXXRecordDeclChildren(CXXRecordDecl *D) { | 
|  | if (!D->isThisDeclarationADefinition()) return; | 
|  |  | 
|  | for (CXXRecordDecl::base_class_iterator | 
|  | I = D->bases_begin(), E = D->bases_end(); I != E; ++I) { | 
|  | push("base"); | 
|  | setAccess(I->getAccessSpecifier()); | 
|  | completeAttrs(); | 
|  | dispatch(I->getTypeSourceInfo()->getTypeLoc()); | 
|  | pop(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // ClassTemplateSpecializationDecl ? | 
|  |  | 
|  | // FileScopeAsmDecl ? | 
|  |  | 
|  | // BlockDecl | 
|  | void visitBlockDeclAttrs(BlockDecl *D) { | 
|  | setFlag("variadic", D->isVariadic()); | 
|  | } | 
|  | void visitBlockDeclChildren(BlockDecl *D) { | 
|  | for (FunctionDecl::param_iterator | 
|  | I = D->param_begin(), E = D->param_end(); I != E; ++I) | 
|  | dispatch(*I); | 
|  | dispatch(D->getBody()); | 
|  | } | 
|  |  | 
|  | // AccessSpecDecl | 
|  | void visitAccessSpecDeclAttrs(AccessSpecDecl *D) { | 
|  | setAccess(D->getAccess()); | 
|  | } | 
|  |  | 
|  | // TemplateDecl | 
|  | void visitTemplateDeclChildren(TemplateDecl *D) { | 
|  | visitTemplateParameters(D->getTemplateParameters()); | 
|  | dispatch(D->getTemplatedDecl()); | 
|  | } | 
|  |  | 
|  | // FunctionTemplateDecl | 
|  | void visitFunctionTemplateDeclAttrs(FunctionTemplateDecl *D) { | 
|  | visitRedeclarableAttrs(D); | 
|  | } | 
|  | void visitFunctionTemplateDeclChildren(FunctionTemplateDecl *D) { | 
|  | // Mention all the specializations which don't have explicit | 
|  | // declarations elsewhere. | 
|  | for (FunctionTemplateDecl::spec_iterator | 
|  | I = D->spec_begin(), E = D->spec_end(); I != E; ++I) { | 
|  | FunctionTemplateSpecializationInfo *Info | 
|  | = I->getTemplateSpecializationInfo(); | 
|  |  | 
|  | bool Unknown = false; | 
|  | switch (Info->getTemplateSpecializationKind()) { | 
|  | case TSK_ImplicitInstantiation: Unknown = false; break; | 
|  | case TSK_Undeclared: Unknown = true; break; | 
|  |  | 
|  | // These will be covered at their respective sites. | 
|  | case TSK_ExplicitSpecialization: continue; | 
|  | case TSK_ExplicitInstantiationDeclaration: continue; | 
|  | case TSK_ExplicitInstantiationDefinition: continue; | 
|  | } | 
|  |  | 
|  | TemporaryContainer C(*this, | 
|  | Unknown ? "uninstantiated" : "instantiation"); | 
|  | visitTemplateArguments(*Info->TemplateArguments); | 
|  | dispatch(Info->Function); | 
|  | } | 
|  | } | 
|  |  | 
|  | // ClasTemplateDecl | 
|  | void visitClassTemplateDeclAttrs(ClassTemplateDecl *D) { | 
|  | visitRedeclarableAttrs(D); | 
|  | } | 
|  | void visitClassTemplateDeclChildren(ClassTemplateDecl *D) { | 
|  | // Mention all the specializations which don't have explicit | 
|  | // declarations elsewhere. | 
|  | for (ClassTemplateDecl::spec_iterator | 
|  | I = D->spec_begin(), E = D->spec_end(); I != E; ++I) { | 
|  |  | 
|  | bool Unknown = false; | 
|  | switch (I->getTemplateSpecializationKind()) { | 
|  | case TSK_ImplicitInstantiation: Unknown = false; break; | 
|  | case TSK_Undeclared: Unknown = true; break; | 
|  |  | 
|  | // These will be covered at their respective sites. | 
|  | case TSK_ExplicitSpecialization: continue; | 
|  | case TSK_ExplicitInstantiationDeclaration: continue; | 
|  | case TSK_ExplicitInstantiationDefinition: continue; | 
|  | } | 
|  |  | 
|  | TemporaryContainer C(*this, | 
|  | Unknown ? "uninstantiated" : "instantiation"); | 
|  | visitTemplateArguments(I->getTemplateArgs()); | 
|  | dispatch(*I); | 
|  | } | 
|  | } | 
|  |  | 
|  | // TemplateTypeParmDecl | 
|  | void visitTemplateTypeParmDeclAttrs(TemplateTypeParmDecl *D) { | 
|  | setInteger("depth", D->getDepth()); | 
|  | setInteger("index", D->getIndex()); | 
|  | } | 
|  | void visitTemplateTypeParmDeclChildren(TemplateTypeParmDecl *D) { | 
|  | if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) | 
|  | dispatch(D->getDefaultArgumentInfo()->getTypeLoc()); | 
|  | // parameter pack? | 
|  | } | 
|  |  | 
|  | // NonTypeTemplateParmDecl | 
|  | void visitNonTypeTemplateParmDeclAttrs(NonTypeTemplateParmDecl *D) { | 
|  | setInteger("depth", D->getDepth()); | 
|  | setInteger("index", D->getIndex()); | 
|  | } | 
|  | void visitNonTypeTemplateParmDeclChildren(NonTypeTemplateParmDecl *D) { | 
|  | if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) | 
|  | dispatch(D->getDefaultArgument()); | 
|  | // parameter pack? | 
|  | } | 
|  |  | 
|  | // TemplateTemplateParmDecl | 
|  | void visitTemplateTemplateParmDeclAttrs(TemplateTemplateParmDecl *D) { | 
|  | setInteger("depth", D->getDepth()); | 
|  | setInteger("index", D->getIndex()); | 
|  | } | 
|  | void visitTemplateTemplateParmDeclChildren(TemplateTemplateParmDecl *D) { | 
|  | if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) | 
|  | dispatch(D->getDefaultArgument()); | 
|  | // parameter pack? | 
|  | } | 
|  |  | 
|  | // FriendDecl | 
|  | void visitFriendDeclChildren(FriendDecl *D) { | 
|  | if (TypeSourceInfo *T = D->getFriendType()) | 
|  | dispatch(T->getTypeLoc()); | 
|  | else | 
|  | dispatch(D->getFriendDecl()); | 
|  | } | 
|  |  | 
|  | // UsingDirectiveDecl ? | 
|  | // UsingDecl ? | 
|  | // UsingShadowDecl ? | 
|  | // NamespaceAliasDecl ? | 
|  | // UnresolvedUsingValueDecl ? | 
|  | // UnresolvedUsingTypenameDecl ? | 
|  | // StaticAssertDecl ? | 
|  |  | 
|  | // ObjCImplDecl | 
|  | void visitObjCImplDeclChildren(ObjCImplDecl *D) { | 
|  | visitDeclRef(D->getClassInterface()); | 
|  | } | 
|  | void visitObjCImplDeclAsContext(ObjCImplDecl *D) { | 
|  | visitDeclContext(D); | 
|  | } | 
|  |  | 
|  | // ObjCClassDecl | 
|  | void visitObjCClassDeclChildren(ObjCClassDecl *D) { | 
|  | for (ObjCClassDecl::iterator I = D->begin(), E = D->end(); I != E; ++I) | 
|  | visitDeclRef(I->getInterface()); | 
|  | } | 
|  |  | 
|  | // ObjCInterfaceDecl | 
|  | void visitCategoryList(ObjCCategoryDecl *D) { | 
|  | if (!D) return; | 
|  |  | 
|  | TemporaryContainer C(*this, "categories"); | 
|  | for (; D; D = D->getNextClassCategory()) | 
|  | visitDeclRef(D); | 
|  | } | 
|  | void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) { | 
|  | setPointer("typeptr", D->getTypeForDecl()); | 
|  | setFlag("forward_decl", D->isForwardDecl()); | 
|  | setFlag("implicit_interface", D->isImplicitInterfaceDecl()); | 
|  | } | 
|  | void visitObjCInterfaceDeclChildren(ObjCInterfaceDecl *D) { | 
|  | visitDeclRef("super", D->getSuperClass()); | 
|  | visitDeclRef("implementation", D->getImplementation()); | 
|  | if (D->protocol_begin() != D->protocol_end()) { | 
|  | TemporaryContainer C(*this, "protocols"); | 
|  | for (ObjCInterfaceDecl::protocol_iterator | 
|  | I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) | 
|  | visitDeclRef(*I); | 
|  | } | 
|  | visitCategoryList(D->getCategoryList()); | 
|  | } | 
|  | void visitObjCInterfaceDeclAsContext(ObjCInterfaceDecl *D) { | 
|  | visitDeclContext(D); | 
|  | } | 
|  |  | 
|  | // ObjCCategoryDecl | 
|  | void visitObjCCategoryDeclAttrs(ObjCCategoryDecl *D) { | 
|  | setFlag("extension", D->IsClassExtension()); | 
|  | setFlag("synth_bitfield", D->hasSynthBitfield()); | 
|  | } | 
|  | void visitObjCCategoryDeclChildren(ObjCCategoryDecl *D) { | 
|  | visitDeclRef("interface", D->getClassInterface()); | 
|  | visitDeclRef("implementation", D->getImplementation()); | 
|  | if (D->protocol_begin() != D->protocol_end()) { | 
|  | TemporaryContainer C(*this, "protocols"); | 
|  | for (ObjCCategoryDecl::protocol_iterator | 
|  | I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) | 
|  | visitDeclRef(*I); | 
|  | } | 
|  | } | 
|  | void visitObjCCategoryDeclAsContext(ObjCCategoryDecl *D) { | 
|  | visitDeclContext(D); | 
|  | } | 
|  |  | 
|  | // ObjCCategoryImplDecl | 
|  | void visitObjCCategoryImplDeclAttrs(ObjCCategoryImplDecl *D) { | 
|  | set("identifier", D->getName()); | 
|  | } | 
|  | void visitObjCCategoryImplDeclChildren(ObjCCategoryImplDecl *D) { | 
|  | visitDeclRef(D->getCategoryDecl()); | 
|  | } | 
|  |  | 
|  | // ObjCImplementationDecl | 
|  | void visitObjCImplementationDeclAttrs(ObjCImplementationDecl *D) { | 
|  | setFlag("synth_bitfield", D->hasSynthBitfield()); | 
|  | set("identifier", D->getName()); | 
|  | } | 
|  | void visitObjCImplementationDeclChildren(ObjCImplementationDecl *D) { | 
|  | visitDeclRef("super", D->getSuperClass()); | 
|  | if (D->init_begin() != D->init_end()) { | 
|  | TemporaryContainer C(*this, "initializers"); | 
|  | for (ObjCImplementationDecl::init_iterator | 
|  | I = D->init_begin(), E = D->init_end(); I != E; ++I) | 
|  | dispatch(*I); | 
|  | } | 
|  | } | 
|  |  | 
|  | // ObjCForwardProtocolDecl | 
|  | void visitObjCForwardProtocolDeclChildren(ObjCForwardProtocolDecl *D) { | 
|  | for (ObjCForwardProtocolDecl::protocol_iterator | 
|  | I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) | 
|  | visitDeclRef(*I); | 
|  | } | 
|  |  | 
|  | // ObjCProtocolDecl | 
|  | void visitObjCProtocolDeclAttrs(ObjCProtocolDecl *D) { | 
|  | setFlag("forward_decl", D->isForwardDecl()); | 
|  | } | 
|  | void visitObjCProtocolDeclChildren(ObjCProtocolDecl *D) { | 
|  | if (D->protocol_begin() != D->protocol_end()) { | 
|  | TemporaryContainer C(*this, "protocols"); | 
|  | for (ObjCInterfaceDecl::protocol_iterator | 
|  | I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) | 
|  | visitDeclRef(*I); | 
|  | } | 
|  | } | 
|  | void visitObjCProtocolDeclAsContext(ObjCProtocolDecl *D) { | 
|  | visitDeclContext(D); | 
|  | } | 
|  |  | 
|  | // ObjCMethodDecl | 
|  | void visitObjCMethodDeclAttrs(ObjCMethodDecl *D) { | 
|  | // decl qualifier? | 
|  | // implementation control? | 
|  |  | 
|  | setFlag("instance", D->isInstanceMethod()); | 
|  | setFlag("variadic", D->isVariadic()); | 
|  | setFlag("synthesized", D->isSynthesized()); | 
|  | setFlag("defined", D->isDefined()); | 
|  | } | 
|  | void visitObjCMethodDeclChildren(ObjCMethodDecl *D) { | 
|  | dispatch(D->getResultType()); | 
|  | for (ObjCMethodDecl::param_iterator | 
|  | I = D->param_begin(), E = D->param_end(); I != E; ++I) | 
|  | dispatch(*I); | 
|  | if (D->isThisDeclarationADefinition()) | 
|  | dispatch(D->getBody()); | 
|  | } | 
|  |  | 
|  | // ObjCIvarDecl | 
|  | void setAccessControl(llvm::StringRef prop, ObjCIvarDecl::AccessControl AC) { | 
|  | switch (AC) { | 
|  | case ObjCIvarDecl::None: return set(prop, "none"); | 
|  | case ObjCIvarDecl::Private: return set(prop, "private"); | 
|  | case ObjCIvarDecl::Protected: return set(prop, "protected"); | 
|  | case ObjCIvarDecl::Public: return set(prop, "public"); | 
|  | case ObjCIvarDecl::Package: return set(prop, "package"); | 
|  | } | 
|  | } | 
|  | void visitObjCIvarDeclAttrs(ObjCIvarDecl *D) { | 
|  | setFlag("synthesize", D->getSynthesize()); | 
|  | setAccessControl("access", D->getAccessControl()); | 
|  | } | 
|  |  | 
|  | // ObjCCompatibleAliasDecl | 
|  | void visitObjCCompatibleAliasDeclChildren(ObjCCompatibleAliasDecl *D) { | 
|  | visitDeclRef(D->getClassInterface()); | 
|  | } | 
|  |  | 
|  | // FIXME: ObjCPropertyDecl | 
|  | // FIXME: ObjCPropertyImplDecl | 
|  |  | 
|  | //---- Types -----------------------------------------------------// | 
|  | void dispatch(TypeLoc TL) { | 
|  | dispatch(TL.getType()); // for now | 
|  | } | 
|  |  | 
|  | void dispatch(QualType T) { | 
|  | if (T.hasLocalQualifiers()) { | 
|  | push("QualType"); | 
|  | Qualifiers Qs = T.getLocalQualifiers(); | 
|  | setFlag("const", Qs.hasConst()); | 
|  | setFlag("volatile", Qs.hasVolatile()); | 
|  | setFlag("restrict", Qs.hasRestrict()); | 
|  | if (Qs.hasAddressSpace()) setInteger("addrspace", Qs.getAddressSpace()); | 
|  | if (Qs.hasObjCGCAttr()) { | 
|  | switch (Qs.getObjCGCAttr()) { | 
|  | case Qualifiers::Weak: set("gc", "weak"); break; | 
|  | case Qualifiers::Strong: set("gc", "strong"); break; | 
|  | case Qualifiers::GCNone: llvm_unreachable("explicit none"); | 
|  | } | 
|  | } | 
|  |  | 
|  | completeAttrs(); | 
|  | dispatch(QualType(T.getTypePtr(), 0)); | 
|  | pop(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | Type *Ty = const_cast<Type*>(T.getTypePtr()); | 
|  | push(getTypeKindName(Ty)); | 
|  | XMLTypeVisitor<XMLDumper>::dispatch(const_cast<Type*>(T.getTypePtr())); | 
|  | pop(); | 
|  | } | 
|  |  | 
|  | void setCallingConv(CallingConv CC) { | 
|  | switch (CC) { | 
|  | case CC_Default: return; | 
|  | case CC_C: return set("cc", "cdecl"); | 
|  | case CC_X86FastCall: return set("cc", "x86_fastcall"); | 
|  | case CC_X86StdCall: return set("cc", "x86_stdcall"); | 
|  | case CC_X86ThisCall: return set("cc", "x86_thiscall"); | 
|  | case CC_X86Pascal: return set("cc", "x86_pascal"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void visitTypeAttrs(Type *D) { | 
|  | setPointer(D); | 
|  | setFlag("dependent", D->isDependentType()); | 
|  | setFlag("variably_modified", D->isVariablyModifiedType()); | 
|  |  | 
|  | setPointer("canonical", D->getCanonicalTypeInternal().getAsOpaquePtr()); | 
|  | } | 
|  |  | 
|  | void visitPointerTypeChildren(PointerType *T) { | 
|  | dispatch(T->getPointeeType()); | 
|  | } | 
|  | void visitReferenceTypeChildren(ReferenceType *T) { | 
|  | dispatch(T->getPointeeType()); | 
|  | } | 
|  | void visitObjCObjectPointerTypeChildren(ObjCObjectPointerType *T) { | 
|  | dispatch(T->getPointeeType()); | 
|  | } | 
|  | void visitBlockPointerTypeChildren(BlockPointerType *T) { | 
|  | dispatch(T->getPointeeType()); | 
|  | } | 
|  |  | 
|  | // Types that just wrap declarations. | 
|  | void visitTagTypeChildren(TagType *T) { | 
|  | visitDeclRef(T->getDecl()); | 
|  | } | 
|  | void visitTypedefTypeChildren(TypedefType *T) { | 
|  | visitDeclRef(T->getDecl()); | 
|  | } | 
|  | void visitObjCInterfaceTypeChildren(ObjCInterfaceType *T) { | 
|  | visitDeclRef(T->getDecl()); | 
|  | } | 
|  | void visitUnresolvedUsingTypeChildren(UnresolvedUsingType *T) { | 
|  | visitDeclRef(T->getDecl()); | 
|  | } | 
|  | void visitInjectedClassNameTypeChildren(InjectedClassNameType *T) { | 
|  | visitDeclRef(T->getDecl()); | 
|  | } | 
|  |  | 
|  | void visitFunctionTypeAttrs(FunctionType *T) { | 
|  | setFlag("noreturn", T->getNoReturnAttr()); | 
|  | setCallingConv(T->getCallConv()); | 
|  | if (T->getRegParmType()) setInteger("regparm", T->getRegParmType()); | 
|  | } | 
|  | void visitFunctionTypeChildren(FunctionType *T) { | 
|  | dispatch(T->getResultType()); | 
|  | } | 
|  |  | 
|  | void visitFunctionProtoTypeAttrs(FunctionProtoType *T) { | 
|  | setFlag("const", T->getTypeQuals() & Qualifiers::Const); | 
|  | setFlag("volatile", T->getTypeQuals() & Qualifiers::Volatile); | 
|  | setFlag("restrict", T->getTypeQuals() & Qualifiers::Restrict); | 
|  | } | 
|  | void visitFunctionProtoTypeChildren(FunctionProtoType *T) { | 
|  | push("parameters"); | 
|  | setFlag("variadic", T->isVariadic()); | 
|  | completeAttrs(); | 
|  | for (FunctionProtoType::arg_type_iterator | 
|  | I = T->arg_type_begin(), E = T->arg_type_end(); I != E; ++I) | 
|  | dispatch(*I); | 
|  | pop(); | 
|  |  | 
|  | if (T->hasExceptionSpec()) { | 
|  | push("exception_specifiers"); | 
|  | setFlag("any", T->hasAnyExceptionSpec()); | 
|  | completeAttrs(); | 
|  | for (FunctionProtoType::exception_iterator | 
|  | I = T->exception_begin(), E = T->exception_end(); I != E; ++I) | 
|  | dispatch(*I); | 
|  | pop(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void visitTemplateSpecializationTypeChildren(TemplateSpecializationType *T) { | 
|  | if (const RecordType *RT = T->getAs<RecordType>()) | 
|  | visitDeclRef(RT->getDecl()); | 
|  |  | 
|  | // TODO: TemplateName | 
|  |  | 
|  | push("template_arguments"); | 
|  | completeAttrs(); | 
|  | for (unsigned I = 0, E = T->getNumArgs(); I != E; ++I) | 
|  | dispatch(T->getArg(I)); | 
|  | pop(); | 
|  | } | 
|  |  | 
|  | //---- Statements ------------------------------------------------// | 
|  | void dispatch(Stmt *S) { | 
|  | // FIXME: this is not really XML at all | 
|  | push("Stmt"); | 
|  | out << ">\n"; | 
|  | Stack.back().State = NS_Children; // explicitly become non-lazy | 
|  | S->dump(out, Context.getSourceManager()); | 
|  | out << '\n'; | 
|  | pop(); | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | void Decl::dumpXML() const { | 
|  | dumpXML(llvm::errs()); | 
|  | } | 
|  |  | 
|  | void Decl::dumpXML(llvm::raw_ostream &out) const { | 
|  | XMLDumper(out, getASTContext()).dispatch(const_cast<Decl*>(this)); | 
|  | } | 
|  |  | 
|  | #else /* ifndef NDEBUG */ | 
|  |  | 
|  | void Decl::dumpXML() const {} | 
|  | void Decl::dumpXML(llvm::raw_ostream &out) const {} | 
|  |  | 
|  | #endif |