Files
llvm-project/clang/lib/AST/DumpXML.cpp
James Molloy 6f8780bed1 Reapply r151638 and r151641.
The bug that was caught by Apple's internal buildbots was valid and also showed another bug in my implementation.

These are now fixed, with regression tests added to catch them both (not Darwin-specific).

Original log:
====================

Revert r151638 because it causes assertion hit on PCH creation for Cocoa.h

Original log:
---------------------
Correctly track tags and enum members defined in the prototype of a function, and ensure they are properly scoped.

This fixes code such as:

enum e {x, y};
int f(enum {y, x} n) {
 return 0;
}

This finally fixes PR5464 and PR5477.
---------------------

I also reverted r151641 which was enhancement on top of r151638.

====================

llvm-svn: 151712
2012-02-29 10:24:19 +00:00

1040 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/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);
for (llvm::ArrayRef<NamedDecl*>::iterator
I = D->getDeclsInPrototypeScope().begin(), E = D->getDeclsInPrototypeScope().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