blob: b4038ddaf9522b93ec760b7a43af7933e4e1cffe [file] [log] [blame]
//===--- 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/SmallString.h"
using namespace clang;
#ifndef NDEBUG
namespace {
enum NodeState {
NS_Attrs, NS_LazyChildren, NS_Children
};
struct Node {
StringRef Name;
NodeState State;
Node(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()) {
#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()) {
#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 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!");
}
struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
public XMLTypeVisitor<XMLDumper> {
raw_ostream &out;
ASTContext &Context;
SmallVector<Node, 16> Stack;
unsigned Indent;
explicit XMLDumper(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(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(StringRef attr, 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(StringRef prop, const void *p) {
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(StringRef prop, const llvm::APSInt &v) {
set(prop, v.toString(10));
}
void setInteger(StringRef prop, unsigned n) {
SmallString<10> buffer;
llvm::raw_svector_ostream os(buffer);
os << n;
os.flush();
set(prop, buffer);
}
void setFlag(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, 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(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::TemplateExpansion:
// FIXME: Implement!
break;
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: {
for (TemplateArgument::pack_iterator P = A.pack_begin(),
PEnd = A.pack_end();
P != PEnd; ++P)
dispatch(*P);
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->getPreviousDecl())
setPointer("previous", Prev);
}
// TranslationUnitDecl
void visitTranslationUnitDeclAsContext(TranslationUnitDecl *D) {
visitDeclContext(D);
}
// LinkageSpecDecl
void visitLinkageSpecDeclAttrs(LinkageSpecDecl *D) {
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()));
StringRef initStyle = "";
switch (D->getInitStyle()) {
case VarDecl::CInit: initStyle = "c"; break;
case VarDecl::CallInit: initStyle = "call"; break;
case VarDecl::ListInit: initStyle = "list"; break;
}
set("initstyle", initStyle);
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->isDeletedAsWritten());
if (D->getStorageClass() != SC_None)
set("storage",
VarDecl::getStorageClassSpecifierString(D->getStorageClass()));
setFlag("inline", D->isInlineSpecified());
if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>())
set("asmlabel", ALA->getLabel());
// 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->doesThisDeclarationHaveABody())
dispatch(D->getBody());
}
// CXXMethodDecl ?
// CXXConstructorDecl ?
// CXXDestructorDecl ?
// CXXConversionDecl ?
void dispatch(CXXCtorInitializer *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<TypedefNameDecl>(D);
}
void visitTypedefDeclChildren(TypedefDecl *D) {
dispatch(D->getTypeSourceInfo()->getTypeLoc());
}
// TypeAliasDecl
void visitTypeAliasDeclAttrs(TypeAliasDecl *D) {
visitRedeclarableAttrs<TypedefNameDecl>(D);
}
void visitTypeAliasDeclChildren(TypeAliasDecl *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());
if (D->getTemplatedDecl())
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);
}
// 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->isThisDeclarationADefinition());
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);
}
}
// ObjCProtocolDecl
void visitObjCProtocolDeclChildren(ObjCProtocolDecl *D) {
if (!D->isThisDeclarationADefinition())
return;
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) {
if (!D->isThisDeclarationADefinition())
return;
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());
setFlag("related_result_type", D->hasRelatedResultType());
}
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(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");
case CC_AAPCS: return set("cc", "aapcs");
case CC_AAPCS_VFP: return set("cc", "aapcs_vfp");
}
}
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->getHasRegParm()) 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->hasDynamicExceptionSpec()) {
push("exception_specifiers");
setFlag("any", T->getExceptionSpecType() == EST_MSAny);
completeAttrs();
for (FunctionProtoType::exception_iterator
I = T->exception_begin(), E = T->exception_end(); I != E; ++I)
dispatch(*I);
pop();
}
// FIXME: noexcept specifier
}
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(raw_ostream &out) const {
XMLDumper(out, getASTContext()).dispatch(const_cast<Decl*>(this));
}
#else /* ifndef NDEBUG */
void Decl::dumpXML() const {}
void Decl::dumpXML(raw_ostream &out) const {}
#endif