llvm-capstone/clang/lib/AST/DumpXML.cpp
Sebastian Redl fa453cfdc3 Propagate the new exception information to FunctionProtoType.
Change the interface to expose the new information and deal with the enormous fallout.
Introduce the new ExceptionSpecificationType value EST_DynamicNone to more easily deal with empty throw specifications.
Update the tests for noexcept and fix the various bugs uncovered, such as lack of tentative parsing support.

llvm-svn: 127537
2011-03-12 11:50:43 +00:00

1030 lines
30 KiB
C++

//===--- 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, const 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::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->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(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(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->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(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