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
1040 lines
30 KiB
C++
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
|