llvm-project/clang/lib/AST/ASTDumper.cpp

2175 lines
62 KiB
C++
Raw Normal View History

//===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the AST dump methods, which dump out the
// AST in a form that exposes type details and other fields.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CommentVisitor.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclLookups.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace clang::comments;
//===----------------------------------------------------------------------===//
// ASTDumper Visitor
//===----------------------------------------------------------------------===//
namespace {
// Colors used for various parts of the AST dump
struct TerminalColor {
raw_ostream::Colors Color;
bool Bold;
};
// Decl kind names (VarDecl, FunctionDecl, etc)
static const TerminalColor DeclKindNameColor = { raw_ostream::GREEN, true };
// Attr names (CleanupAttr, GuardedByAttr, etc)
static const TerminalColor AttrColor = { raw_ostream::BLUE, true };
// Statement names (DeclStmt, ImplicitCastExpr, etc)
static const TerminalColor StmtColor = { raw_ostream::MAGENTA, true };
// Comment names (FullComment, ParagraphComment, TextComment, etc)
static const TerminalColor CommentColor = { raw_ostream::YELLOW, true };
// Type names (int, float, etc, plus user defined types)
static const TerminalColor TypeColor = { raw_ostream::GREEN, false };
// Pointer address
static const TerminalColor AddressColor = { raw_ostream::YELLOW, false };
// Source locations
static const TerminalColor LocationColor = { raw_ostream::YELLOW, false };
// lvalue/xvalue
static const TerminalColor ValueKindColor = { raw_ostream::CYAN, false };
// bitfield/objcproperty/objcsubscript/vectorcomponent
static const TerminalColor ObjectKindColor = { raw_ostream::CYAN, false };
// Null statements
static const TerminalColor NullColor = { raw_ostream::BLUE, false };
// Undeserialized entities
static const TerminalColor UndeserializedColor = { raw_ostream::GREEN, true };
// CastKind from CastExpr's
static const TerminalColor CastColor = { raw_ostream::RED, false };
// Value of the statement
static const TerminalColor ValueColor = { raw_ostream::CYAN, true };
// Decl names
static const TerminalColor DeclNameColor = { raw_ostream::CYAN, true };
// Indents ( `, -. | )
static const TerminalColor IndentColor = { raw_ostream::BLUE, false };
class ASTDumper
: public ConstDeclVisitor<ASTDumper>, public ConstStmtVisitor<ASTDumper>,
public ConstCommentVisitor<ASTDumper> {
raw_ostream &OS;
const CommandTraits *Traits;
const SourceManager *SM;
bool IsFirstLine;
// Indicates whether more child are expected at the current tree depth
enum IndentType { IT_Child, IT_LastChild };
/// Indents[i] indicates if another child exists at level i.
/// Used by Indent() to print the tree structure.
llvm::SmallVector<IndentType, 32> Indents;
/// Indicates that more children will be needed at this indent level.
/// If true, prevents lastChild() from marking the node as the last child.
/// This is used when there are multiple collections of children to be
/// dumped as well as during conditional node dumping.
bool MoreChildren;
/// Keep track of the last location we print out so that we can
/// print out deltas from then on out.
const char *LastLocFilename;
unsigned LastLocLine;
/// The \c FullComment parent of the comment being dumped.
const FullComment *FC;
bool ShowColors;
class IndentScope {
ASTDumper &Dumper;
// Preserve the Dumper's MoreChildren value from the previous IndentScope
bool MoreChildren;
public:
IndentScope(ASTDumper &Dumper) : Dumper(Dumper) {
MoreChildren = Dumper.hasMoreChildren();
Dumper.setMoreChildren(false);
Dumper.indent();
}
~IndentScope() {
Dumper.setMoreChildren(MoreChildren);
Dumper.unindent();
}
};
class ColorScope {
ASTDumper &Dumper;
public:
ColorScope(ASTDumper &Dumper, TerminalColor Color)
: Dumper(Dumper) {
if (Dumper.ShowColors)
Dumper.OS.changeColor(Color.Color, Color.Bold);
}
~ColorScope() {
if (Dumper.ShowColors)
Dumper.OS.resetColor();
}
};
public:
ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
const SourceManager *SM)
: OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false),
LastLocFilename(""), LastLocLine(~0U), FC(0),
ShowColors(SM && SM->getDiagnostics().getShowColors()) { }
ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
const SourceManager *SM, bool ShowColors)
: OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false),
LastLocFilename(""), LastLocLine(~0U),
ShowColors(ShowColors) { }
~ASTDumper() {
OS << "\n";
}
void dumpDecl(const Decl *D);
void dumpStmt(const Stmt *S);
void dumpFullComment(const FullComment *C);
// Formatting
void indent();
void unindent();
void lastChild();
bool hasMoreChildren();
void setMoreChildren(bool Value);
// Utilities
void dumpPointer(const void *Ptr);
void dumpSourceRange(SourceRange R);
void dumpLocation(SourceLocation Loc);
void dumpBareType(QualType T);
void dumpType(QualType T);
void dumpBareDeclRef(const Decl *Node);
void dumpDeclRef(const Decl *Node, const char *Label = 0);
void dumpName(const NamedDecl *D);
bool hasNodes(const DeclContext *DC);
void dumpDeclContext(const DeclContext *DC);
void dumpLookups(const DeclContext *DC);
void dumpAttr(const Attr *A);
// C++ Utilities
void dumpAccessSpecifier(AccessSpecifier AS);
void dumpCXXCtorInitializer(const CXXCtorInitializer *Init);
void dumpTemplateParameters(const TemplateParameterList *TPL);
void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI);
void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A);
void dumpTemplateArgumentList(const TemplateArgumentList &TAL);
void dumpTemplateArgument(const TemplateArgument &A,
SourceRange R = SourceRange());
// Decls
void VisitLabelDecl(const LabelDecl *D);
void VisitTypedefDecl(const TypedefDecl *D);
void VisitEnumDecl(const EnumDecl *D);
void VisitRecordDecl(const RecordDecl *D);
void VisitEnumConstantDecl(const EnumConstantDecl *D);
void VisitIndirectFieldDecl(const IndirectFieldDecl *D);
void VisitFunctionDecl(const FunctionDecl *D);
void VisitFieldDecl(const FieldDecl *D);
void VisitVarDecl(const VarDecl *D);
void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D);
void VisitImportDecl(const ImportDecl *D);
// C++ Decls
void VisitNamespaceDecl(const NamespaceDecl *D);
void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D);
void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D);
void VisitTypeAliasDecl(const TypeAliasDecl *D);
void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D);
void VisitCXXRecordDecl(const CXXRecordDecl *D);
void VisitStaticAssertDecl(const StaticAssertDecl *D);
void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
void VisitClassTemplateDecl(const ClassTemplateDecl *D);
void VisitClassTemplateSpecializationDecl(
const ClassTemplateSpecializationDecl *D);
void VisitClassTemplatePartialSpecializationDecl(
const ClassTemplatePartialSpecializationDecl *D);
void VisitClassScopeFunctionSpecializationDecl(
const ClassScopeFunctionSpecializationDecl *D);
void VisitVarTemplateDecl(const VarTemplateDecl *D);
void VisitVarTemplateSpecializationDecl(
const VarTemplateSpecializationDecl *D);
void VisitVarTemplatePartialSpecializationDecl(
const VarTemplatePartialSpecializationDecl *D);
void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
void VisitUsingDecl(const UsingDecl *D);
void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D);
void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D);
void VisitUsingShadowDecl(const UsingShadowDecl *D);
void VisitLinkageSpecDecl(const LinkageSpecDecl *D);
void VisitAccessSpecDecl(const AccessSpecDecl *D);
void VisitFriendDecl(const FriendDecl *D);
// ObjC Decls
void VisitObjCIvarDecl(const ObjCIvarDecl *D);
void VisitObjCMethodDecl(const ObjCMethodDecl *D);
void VisitObjCCategoryDecl(const ObjCCategoryDecl *D);
void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D);
void VisitObjCProtocolDecl(const ObjCProtocolDecl *D);
void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D);
void VisitObjCImplementationDecl(const ObjCImplementationDecl *D);
void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D);
void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);
void VisitBlockDecl(const BlockDecl *D);
// Stmts.
void VisitStmt(const Stmt *Node);
void VisitDeclStmt(const DeclStmt *Node);
void VisitAttributedStmt(const AttributedStmt *Node);
void VisitLabelStmt(const LabelStmt *Node);
void VisitGotoStmt(const GotoStmt *Node);
void VisitCXXCatchStmt(const CXXCatchStmt *Node);
// Exprs
void VisitExpr(const Expr *Node);
void VisitCastExpr(const CastExpr *Node);
void VisitDeclRefExpr(const DeclRefExpr *Node);
void VisitPredefinedExpr(const PredefinedExpr *Node);
void VisitCharacterLiteral(const CharacterLiteral *Node);
void VisitIntegerLiteral(const IntegerLiteral *Node);
void VisitFloatingLiteral(const FloatingLiteral *Node);
void VisitStringLiteral(const StringLiteral *Str);
void VisitUnaryOperator(const UnaryOperator *Node);
void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Node);
void VisitMemberExpr(const MemberExpr *Node);
void VisitExtVectorElementExpr(const ExtVectorElementExpr *Node);
void VisitBinaryOperator(const BinaryOperator *Node);
void VisitCompoundAssignOperator(const CompoundAssignOperator *Node);
void VisitAddrLabelExpr(const AddrLabelExpr *Node);
void VisitBlockExpr(const BlockExpr *Node);
void VisitOpaqueValueExpr(const OpaqueValueExpr *Node);
// C++
void VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node);
void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node);
void VisitCXXThisExpr(const CXXThisExpr *Node);
void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node);
void VisitCXXConstructExpr(const CXXConstructExpr *Node);
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node);
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node);
void VisitExprWithCleanups(const ExprWithCleanups *Node);
void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
void dumpCXXTemporary(const CXXTemporary *Temporary);
Implement a rudimentary form of generic lambdas. Specifically, the following features are not included in this commit: - any sort of capturing within generic lambdas - generic lambdas within template functions and nested within other generic lambdas - conversion operator for captureless lambdas - ensuring all visitors are generic lambda aware (Although I have gotten some useful feedback on my patches of the above and will be incorporating that as I submit those patches for commit) As an example of what compiles through this commit: template <class F1, class F2> struct overload : F1, F2 { using F1::operator(); using F2::operator(); overload(F1 f1, F2 f2) : F1(f1), F2(f2) { } }; auto Recursive = [](auto Self, auto h, auto ... rest) { return 1 + Self(Self, rest...); }; auto Base = [](auto Self, auto h) { return 1; }; overload<decltype(Base), decltype(Recursive)> O(Base, Recursive); int num_params = O(O, 5, 3, "abc", 3.14, 'a'); Please see attached tests for more examples. This patch has been reviewed by Doug and Richard. Minor changes (non-functionality affecting) have been made since both of them formally looked at it, but the changes involve removal of supernumerary return type deduction changes (since they are now redundant, with richard having committed a recent patch to address return type deduction for C++11 lambdas using C++14 semantics). Some implementation notes: - Add a new Declarator context => LambdaExprParameterContext to clang::Declarator to allow the use of 'auto' in declaring generic lambda parameters - Add various helpers to CXXRecordDecl to facilitate identifying and querying a closure class - LambdaScopeInfo (which maintains the current lambda's Sema state) was augmented to house the current depth of the template being parsed (id est the Parser calls Sema::RecordParsingTemplateParameterDepth) so that SemaType.cpp::ConvertDeclSpecToType may use it to immediately generate a template-parameter-type when 'auto' is parsed in a generic lambda parameter context. (i.e we do NOT use AutoType deduced to a template parameter type - Richard seemed ok with this approach). We encode that this template type was generated from an auto by simply adding $auto to the name which can be used for better diagnostics if needed. - SemaLambda.h was added to hold some common lambda utility functions (this file is likely to grow ...) - Teach Sema::ActOnStartOfFunctionDef to check whether it is being called to instantiate a generic lambda's call operator, and if so, push an appropriately prepared LambdaScopeInfo object on the stack. - various tests were added - but much more will be needed. There is obviously more work to be done, and both Richard (weakly) and Doug (strongly) have requested that LambdaExpr be removed form the CXXRecordDecl LambdaDefinitionaData in a future patch which is forthcoming. A greatful thanks to all reviewers including Eli Friedman, James Dennett, and especially the two gracious wizards (Richard Smith and Doug Gregor) who spent hours providing feedback (in person in Chicago and on the mailing lists). And yet I am certain that I have allowed unidentified bugs to creep in; bugs, that I will do my best to slay, once identified! Thanks! llvm-svn: 191453
2013-09-27 03:54:12 +08:00
void VisitLambdaExpr(const LambdaExpr *Node) {
VisitExpr(Node);
dumpDecl(Node->getLambdaClass());
}
// ObjC
void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node);
void VisitObjCEncodeExpr(const ObjCEncodeExpr *Node);
void VisitObjCMessageExpr(const ObjCMessageExpr *Node);
void VisitObjCBoxedExpr(const ObjCBoxedExpr *Node);
void VisitObjCSelectorExpr(const ObjCSelectorExpr *Node);
void VisitObjCProtocolExpr(const ObjCProtocolExpr *Node);
void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node);
void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node);
void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node);
void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node);
// Comments.
const char *getCommandName(unsigned CommandID);
void dumpComment(const Comment *C);
// Inline comments.
void visitTextComment(const TextComment *C);
void visitInlineCommandComment(const InlineCommandComment *C);
void visitHTMLStartTagComment(const HTMLStartTagComment *C);
void visitHTMLEndTagComment(const HTMLEndTagComment *C);
// Block comments.
void visitBlockCommandComment(const BlockCommandComment *C);
void visitParamCommandComment(const ParamCommandComment *C);
void visitTParamCommandComment(const TParamCommandComment *C);
void visitVerbatimBlockComment(const VerbatimBlockComment *C);
void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
void visitVerbatimLineComment(const VerbatimLineComment *C);
};
}
//===----------------------------------------------------------------------===//
// Utilities
//===----------------------------------------------------------------------===//
// Print out the appropriate tree structure using the Indents vector.
// Example of tree and the Indents vector at each level.
// A { }
// |-B { IT_Child }
// | `-C { IT_Child, IT_LastChild }
// `-D { IT_LastChild }
// |-E { IT_LastChild, IT_Child }
// `-F { IT_LastChild, IT_LastChild }
// Type non-last element, last element
// IT_Child "| " "|-"
// IT_LastChild " " "`-"
void ASTDumper::indent() {
if (IsFirstLine)
IsFirstLine = false;
else
OS << "\n";
ColorScope Color(*this, IndentColor);
for (SmallVectorImpl<IndentType>::const_iterator I = Indents.begin(),
E = Indents.end();
I != E; ++I) {
switch (*I) {
case IT_Child:
if (I == E - 1)
OS << "|-";
else
OS << "| ";
continue;
case IT_LastChild:
if (I == E - 1)
OS << "`-";
else
OS << " ";
continue;
}
llvm_unreachable("Invalid IndentType");
}
Indents.push_back(IT_Child);
}
void ASTDumper::unindent() {
Indents.pop_back();
}
// Call before each potential last child node is to be dumped. If MoreChildren
// is false, then this is the last child, otherwise treat as a regular node.
void ASTDumper::lastChild() {
if (!hasMoreChildren())
Indents.back() = IT_LastChild;
}
// MoreChildren should be set before calling another function that may print
// additional nodes to prevent conflicting final child nodes.
bool ASTDumper::hasMoreChildren() {
return MoreChildren;
}
void ASTDumper::setMoreChildren(bool Value) {
MoreChildren = Value;
}
void ASTDumper::dumpPointer(const void *Ptr) {
ColorScope Color(*this, AddressColor);
OS << ' ' << Ptr;
}
void ASTDumper::dumpLocation(SourceLocation Loc) {
ColorScope Color(*this, LocationColor);
SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
// The general format we print out is filename:line:col, but we drop pieces
// that haven't changed since the last loc printed.
PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
if (PLoc.isInvalid()) {
OS << "<invalid sloc>";
return;
}
if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
OS << PLoc.getFilename() << ':' << PLoc.getLine()
<< ':' << PLoc.getColumn();
LastLocFilename = PLoc.getFilename();
LastLocLine = PLoc.getLine();
} else if (PLoc.getLine() != LastLocLine) {
OS << "line" << ':' << PLoc.getLine()
<< ':' << PLoc.getColumn();
LastLocLine = PLoc.getLine();
} else {
OS << "col" << ':' << PLoc.getColumn();
}
}
void ASTDumper::dumpSourceRange(SourceRange R) {
// Can't translate locations if a SourceManager isn't available.
if (!SM)
return;
OS << " <";
dumpLocation(R.getBegin());
if (R.getBegin() != R.getEnd()) {
OS << ", ";
dumpLocation(R.getEnd());
}
OS << ">";
// <t2.c:123:421[blah], t2.c:412:321>
}
void ASTDumper::dumpBareType(QualType T) {
ColorScope Color(*this, TypeColor);
SplitQualType T_split = T.split();
OS << "'" << QualType::getAsString(T_split) << "'";
if (!T.isNull()) {
// If the type is sugared, also dump a (shallow) desugared type.
SplitQualType D_split = T.getSplitDesugaredType();
if (T_split != D_split)
OS << ":'" << QualType::getAsString(D_split) << "'";
}
}
void ASTDumper::dumpType(QualType T) {
OS << ' ';
dumpBareType(T);
}
void ASTDumper::dumpBareDeclRef(const Decl *D) {
{
ColorScope Color(*this, DeclKindNameColor);
OS << D->getDeclKindName();
}
dumpPointer(D);
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
ColorScope Color(*this, DeclNameColor);
OS << " '" << ND->getDeclName() << '\'';
}
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
dumpType(VD->getType());
}
void ASTDumper::dumpDeclRef(const Decl *D, const char *Label) {
if (!D)
return;
IndentScope Indent(*this);
if (Label)
OS << Label << ' ';
dumpBareDeclRef(D);
}
void ASTDumper::dumpName(const NamedDecl *ND) {
if (ND->getDeclName()) {
ColorScope Color(*this, DeclNameColor);
OS << ' ' << ND->getNameAsString();
}
}
bool ASTDumper::hasNodes(const DeclContext *DC) {
if (!DC)
return false;
return DC->hasExternalLexicalStorage() ||
DC->noload_decls_begin() != DC->noload_decls_end();
}
void ASTDumper::dumpDeclContext(const DeclContext *DC) {
if (!DC)
return;
bool HasUndeserializedDecls = DC->hasExternalLexicalStorage();
for (DeclContext::decl_iterator I = DC->noload_decls_begin(),
E = DC->noload_decls_end();
I != E; ++I) {
DeclContext::decl_iterator Next = I;
++Next;
if (Next == E && !HasUndeserializedDecls)
lastChild();
dumpDecl(*I);
}
if (HasUndeserializedDecls) {
lastChild();
IndentScope Indent(*this);
ColorScope Color(*this, UndeserializedColor);
OS << "<undeserialized declarations>";
}
}
void ASTDumper::dumpLookups(const DeclContext *DC) {
IndentScope Indent(*this);
OS << "StoredDeclsMap ";
dumpBareDeclRef(cast<Decl>(DC));
const DeclContext *Primary = DC->getPrimaryContext();
if (Primary != DC) {
OS << " primary";
dumpPointer(cast<Decl>(Primary));
}
bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage();
DeclContext::all_lookups_iterator I = Primary->noload_lookups_begin(),
E = Primary->noload_lookups_end();
while (I != E) {
DeclarationName Name = I.getLookupName();
DeclContextLookupResult R = *I++;
if (I == E && !HasUndeserializedLookups)
lastChild();
IndentScope Indent(*this);
OS << "DeclarationName ";
{
ColorScope Color(*this, DeclNameColor);
OS << '\'' << Name << '\'';
}
for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end();
RI != RE; ++RI) {
if (RI + 1 == RE)
lastChild();
dumpDeclRef(*RI);
if ((*RI)->isHidden())
OS << " hidden";
}
}
if (HasUndeserializedLookups) {
lastChild();
IndentScope Indent(*this);
ColorScope Color(*this, UndeserializedColor);
OS << "<undeserialized lookups>";
}
}
void ASTDumper::dumpAttr(const Attr *A) {
IndentScope Indent(*this);
{
ColorScope Color(*this, AttrColor);
switch (A->getKind()) {
#define ATTR(X) case attr::X: OS << #X; break;
#include "clang/Basic/AttrList.inc"
default: llvm_unreachable("unexpected attribute kind");
}
OS << "Attr";
}
dumpPointer(A);
dumpSourceRange(A->getRange());
#include "clang/AST/AttrDump.inc"
}
static void dumpPreviousDeclImpl(raw_ostream &OS, ...) {}
template<typename T>
static void dumpPreviousDeclImpl(raw_ostream &OS, const Mergeable<T> *D) {
const T *First = D->getFirstDecl();
if (First != D)
OS << " first " << First;
}
template<typename T>
static void dumpPreviousDeclImpl(raw_ostream &OS, const Redeclarable<T> *D) {
const T *Prev = D->getPreviousDecl();
if (Prev)
OS << " prev " << Prev;
}
/// Dump the previous declaration in the redeclaration chain for a declaration,
/// if any.
static void dumpPreviousDecl(raw_ostream &OS, const Decl *D) {
switch (D->getKind()) {
#define DECL(DERIVED, BASE) \
case Decl::DERIVED: \
return dumpPreviousDeclImpl(OS, cast<DERIVED##Decl>(D));
#define ABSTRACT_DECL(DECL)
#include "clang/AST/DeclNodes.inc"
}
llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
}
//===----------------------------------------------------------------------===//
// C++ Utilities
//===----------------------------------------------------------------------===//
void ASTDumper::dumpAccessSpecifier(AccessSpecifier AS) {
switch (AS) {
case AS_none:
break;
case AS_public:
OS << "public";
break;
case AS_protected:
OS << "protected";
break;
case AS_private:
OS << "private";
break;
}
}
void ASTDumper::dumpCXXCtorInitializer(const CXXCtorInitializer *Init) {
IndentScope Indent(*this);
OS << "CXXCtorInitializer";
if (Init->isAnyMemberInitializer()) {
OS << ' ';
dumpBareDeclRef(Init->getAnyMember());
} else {
dumpType(QualType(Init->getBaseClass(), 0));
}
dumpStmt(Init->getInit());
}
void ASTDumper::dumpTemplateParameters(const TemplateParameterList *TPL) {
if (!TPL)
return;
for (TemplateParameterList::const_iterator I = TPL->begin(), E = TPL->end();
I != E; ++I)
dumpDecl(*I);
}
void ASTDumper::dumpTemplateArgumentListInfo(
const TemplateArgumentListInfo &TALI) {
for (unsigned i = 0, e = TALI.size(); i < e; ++i) {
if (i + 1 == e)
lastChild();
dumpTemplateArgumentLoc(TALI[i]);
}
}
void ASTDumper::dumpTemplateArgumentLoc(const TemplateArgumentLoc &A) {
dumpTemplateArgument(A.getArgument(), A.getSourceRange());
}
void ASTDumper::dumpTemplateArgumentList(const TemplateArgumentList &TAL) {
for (unsigned i = 0, e = TAL.size(); i < e; ++i)
dumpTemplateArgument(TAL[i]);
}
void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) {
IndentScope Indent(*this);
OS << "TemplateArgument";
if (R.isValid())
dumpSourceRange(R);
switch (A.getKind()) {
case TemplateArgument::Null:
OS << " null";
break;
case TemplateArgument::Type:
OS << " type";
lastChild();
dumpType(A.getAsType());
break;
case TemplateArgument::Declaration:
OS << " decl";
lastChild();
dumpDeclRef(A.getAsDecl());
break;
case TemplateArgument::NullPtr:
OS << " nullptr";
break;
case TemplateArgument::Integral:
OS << " integral " << A.getAsIntegral();
break;
case TemplateArgument::Template:
OS << " template ";
A.getAsTemplate().dump(OS);
break;
case TemplateArgument::TemplateExpansion:
OS << " template expansion";
A.getAsTemplateOrTemplatePattern().dump(OS);
break;
case TemplateArgument::Expression:
OS << " expr";
lastChild();
dumpStmt(A.getAsExpr());
break;
case TemplateArgument::Pack:
OS << " pack";
for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end();
I != E; ++I) {
if (I + 1 == E)
lastChild();
dumpTemplateArgument(*I);
}
break;
}
}
//===----------------------------------------------------------------------===//
// Decl dumping methods.
//===----------------------------------------------------------------------===//
void ASTDumper::dumpDecl(const Decl *D) {
IndentScope Indent(*this);
if (!D) {
ColorScope Color(*this, NullColor);
OS << "<<<NULL>>>";
return;
}
{
ColorScope Color(*this, DeclKindNameColor);
OS << D->getDeclKindName() << "Decl";
}
dumpPointer(D);
if (D->getLexicalDeclContext() != D->getDeclContext())
OS << " parent " << cast<Decl>(D->getDeclContext());
dumpPreviousDecl(OS, D);
dumpSourceRange(D->getSourceRange());
if (Module *M = D->getOwningModule())
OS << " in " << M->getFullModuleName();
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
if (ND->isHidden())
OS << " hidden";
bool HasAttrs = D->attr_begin() != D->attr_end();
const FullComment *Comment =
D->getASTContext().getLocalCommentForDeclUncached(D);
// Decls within functions are visited by the body
bool HasDeclContext = !isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) &&
hasNodes(dyn_cast<DeclContext>(D));
setMoreChildren(HasAttrs || Comment || HasDeclContext);
ConstDeclVisitor<ASTDumper>::Visit(D);
setMoreChildren(Comment || HasDeclContext);
for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end();
I != E; ++I) {
if (I + 1 == E)
lastChild();
dumpAttr(*I);
}
setMoreChildren(HasDeclContext);
lastChild();
dumpFullComment(Comment);
if (D->isInvalidDecl())
OS << " invalid";
setMoreChildren(false);
if (HasDeclContext)
dumpDeclContext(cast<DeclContext>(D));
}
void ASTDumper::VisitLabelDecl(const LabelDecl *D) {
dumpName(D);
}
void ASTDumper::VisitTypedefDecl(const TypedefDecl *D) {
dumpName(D);
dumpType(D->getUnderlyingType());
if (D->isModulePrivate())
OS << " __module_private__";
}
void ASTDumper::VisitEnumDecl(const EnumDecl *D) {
if (D->isScoped()) {
if (D->isScopedUsingClassTag())
OS << " class";
else
OS << " struct";
}
dumpName(D);
if (D->isModulePrivate())
OS << " __module_private__";
if (D->isFixed())
dumpType(D->getIntegerType());
}
void ASTDumper::VisitRecordDecl(const RecordDecl *D) {
OS << ' ' << D->getKindName();
dumpName(D);
if (D->isModulePrivate())
OS << " __module_private__";
if (D->isCompleteDefinition())
OS << " definition";
}
void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) {
dumpName(D);
dumpType(D->getType());
if (const Expr *Init = D->getInitExpr()) {
lastChild();
dumpStmt(Init);
}
}
void ASTDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) {
dumpName(D);
dumpType(D->getType());
for (IndirectFieldDecl::chain_iterator I = D->chain_begin(),
E = D->chain_end();
I != E; ++I) {
if (I + 1 == E)
lastChild();
dumpDeclRef(*I);
}
}
void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
dumpName(D);
dumpType(D->getType());
StorageClass SC = D->getStorageClass();
if (SC != SC_None)
OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
if (D->isInlineSpecified())
OS << " inline";
if (D->isVirtualAsWritten())
OS << " virtual";
if (D->isModulePrivate())
OS << " __module_private__";
if (D->isPure())
OS << " pure";
else if (D->isDeletedAsWritten())
OS << " delete";
if (const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>()) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
switch (EPI.ExceptionSpecType) {
default: break;
case EST_Unevaluated:
OS << " noexcept-unevaluated " << EPI.ExceptionSpecDecl;
break;
case EST_Uninstantiated:
OS << " noexcept-uninstantiated " << EPI.ExceptionSpecTemplate;
break;
}
}
bool OldMoreChildren = hasMoreChildren();
const FunctionTemplateSpecializationInfo *FTSI =
D->getTemplateSpecializationInfo();
bool HasTemplateSpecialization = FTSI;
bool HasNamedDecls = D->getDeclsInPrototypeScope().begin() !=
D->getDeclsInPrototypeScope().end();
bool HasFunctionDecls = D->param_begin() != D->param_end();
const CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(D);
bool HasCtorInitializers = C && C->init_begin() != C->init_end();
bool HasDeclarationBody = D->doesThisDeclarationHaveABody();
setMoreChildren(OldMoreChildren || HasNamedDecls || HasFunctionDecls ||
HasCtorInitializers || HasDeclarationBody);
if (HasTemplateSpecialization) {
lastChild();
dumpTemplateArgumentList(*FTSI->TemplateArguments);
}
setMoreChildren(OldMoreChildren || HasFunctionDecls ||
HasCtorInitializers || HasDeclarationBody);
for (ArrayRef<NamedDecl *>::iterator
I = D->getDeclsInPrototypeScope().begin(),
E = D->getDeclsInPrototypeScope().end(); I != E; ++I) {
if (I + 1 == E)
lastChild();
dumpDecl(*I);
}
setMoreChildren(OldMoreChildren || HasCtorInitializers || HasDeclarationBody);
for (FunctionDecl::param_const_iterator I = D->param_begin(),
E = D->param_end();
I != E; ++I) {
if (I + 1 == E)
lastChild();
dumpDecl(*I);
}
setMoreChildren(OldMoreChildren || HasDeclarationBody);
if (HasCtorInitializers)
for (CXXConstructorDecl::init_const_iterator I = C->init_begin(),
E = C->init_end();
I != E; ++I) {
if (I + 1 == E)
lastChild();
dumpCXXCtorInitializer(*I);
}
setMoreChildren(OldMoreChildren);
if (HasDeclarationBody) {
lastChild();
dumpStmt(D->getBody());
}
}
void ASTDumper::VisitFieldDecl(const FieldDecl *D) {
dumpName(D);
dumpType(D->getType());
if (D->isMutable())
OS << " mutable";
if (D->isModulePrivate())
OS << " __module_private__";
bool OldMoreChildren = hasMoreChildren();
bool IsBitField = D->isBitField();
Expr *Init = D->getInClassInitializer();
bool HasInit = Init;
setMoreChildren(OldMoreChildren || HasInit);
if (IsBitField) {
lastChild();
dumpStmt(D->getBitWidth());
}
setMoreChildren(OldMoreChildren);
if (HasInit) {
lastChild();
dumpStmt(Init);
}
}
void ASTDumper::VisitVarDecl(const VarDecl *D) {
dumpName(D);
dumpType(D->getType());
StorageClass SC = D->getStorageClass();
if (SC != SC_None)
OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
switch (D->getTLSKind()) {
case VarDecl::TLS_None: break;
case VarDecl::TLS_Static: OS << " tls"; break;
case VarDecl::TLS_Dynamic: OS << " tls_dynamic"; break;
}
if (D->isModulePrivate())
OS << " __module_private__";
if (D->isNRVOVariable())
OS << " nrvo";
if (D->hasInit()) {
lastChild();
dumpStmt(D->getInit());
}
}
void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) {
lastChild();
dumpStmt(D->getAsmString());
}
void ASTDumper::VisitImportDecl(const ImportDecl *D) {
OS << ' ' << D->getImportedModule()->getFullModuleName();
}
//===----------------------------------------------------------------------===//
// C++ Declarations
//===----------------------------------------------------------------------===//
void ASTDumper::VisitNamespaceDecl(const NamespaceDecl *D) {
dumpName(D);
if (D->isInline())
OS << " inline";
if (!D->isOriginalNamespace())
dumpDeclRef(D->getOriginalNamespace(), "original");
}
void ASTDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
OS << ' ';
dumpBareDeclRef(D->getNominatedNamespace());
}
void ASTDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
dumpName(D);
dumpDeclRef(D->getAliasedNamespace());
}
void ASTDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) {
dumpName(D);
dumpType(D->getUnderlyingType());
}
void ASTDumper::VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) {
dumpName(D);
dumpTemplateParameters(D->getTemplateParameters());
dumpDecl(D->getTemplatedDecl());
}
void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
VisitRecordDecl(D);
if (!D->isCompleteDefinition())
return;
for (CXXRecordDecl::base_class_const_iterator I = D->bases_begin(),
E = D->bases_end();
I != E; ++I) {
IndentScope Indent(*this);
if (I->isVirtual())
OS << "virtual ";
dumpAccessSpecifier(I->getAccessSpecifier());
dumpType(I->getType());
if (I->isPackExpansion())
OS << "...";
}
}
void ASTDumper::VisitStaticAssertDecl(const StaticAssertDecl *D) {
dumpStmt(D->getAssertExpr());
lastChild();
dumpStmt(D->getMessage());
}
void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
dumpName(D);
dumpTemplateParameters(D->getTemplateParameters());
dumpDecl(D->getTemplatedDecl());
for (FunctionTemplateDecl::spec_iterator I = D->spec_begin(),
E = D->spec_end();
I != E; ++I) {
FunctionTemplateDecl::spec_iterator Next = I;
++Next;
if (Next == E)
lastChild();
switch (I->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
if (D == D->getCanonicalDecl())
dumpDecl(*I);
else
dumpDeclRef(*I);
break;
case TSK_ExplicitSpecialization:
dumpDeclRef(*I);
break;
}
}
}
void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
dumpName(D);
dumpTemplateParameters(D->getTemplateParameters());
ClassTemplateDecl::spec_iterator I = D->spec_begin();
ClassTemplateDecl::spec_iterator E = D->spec_end();
if (I == E)
lastChild();
dumpDecl(D->getTemplatedDecl());
for (; I != E; ++I) {
ClassTemplateDecl::spec_iterator Next = I;
++Next;
if (Next == E)
lastChild();
switch (I->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
if (D == D->getCanonicalDecl())
dumpDecl(*I);
else
dumpDeclRef(*I);
break;
case TSK_ExplicitSpecialization:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
dumpDeclRef(*I);
break;
}
}
}
void ASTDumper::VisitClassTemplateSpecializationDecl(
const ClassTemplateSpecializationDecl *D) {
VisitCXXRecordDecl(D);
dumpTemplateArgumentList(D->getTemplateArgs());
}
void ASTDumper::VisitClassTemplatePartialSpecializationDecl(
const ClassTemplatePartialSpecializationDecl *D) {
VisitClassTemplateSpecializationDecl(D);
dumpTemplateParameters(D->getTemplateParameters());
}
void ASTDumper::VisitClassScopeFunctionSpecializationDecl(
const ClassScopeFunctionSpecializationDecl *D) {
dumpDeclRef(D->getSpecialization());
if (D->hasExplicitTemplateArgs())
dumpTemplateArgumentListInfo(D->templateArgs());
}
void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
dumpName(D);
dumpTemplateParameters(D->getTemplateParameters());
VarTemplateDecl::spec_iterator I = D->spec_begin();
VarTemplateDecl::spec_iterator E = D->spec_end();
if (I == E)
lastChild();
dumpDecl(D->getTemplatedDecl());
for (; I != E; ++I) {
VarTemplateDecl::spec_iterator Next = I;
++Next;
if (Next == E)
lastChild();
switch (I->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
if (D == D->getCanonicalDecl())
dumpDecl(*I);
else
dumpDeclRef(*I);
break;
case TSK_ExplicitSpecialization:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
dumpDeclRef(*I);
break;
}
}
}
void ASTDumper::VisitVarTemplateSpecializationDecl(
const VarTemplateSpecializationDecl *D) {
dumpTemplateArgumentList(D->getTemplateArgs());
VisitVarDecl(D);
}
void ASTDumper::VisitVarTemplatePartialSpecializationDecl(
const VarTemplatePartialSpecializationDecl *D) {
dumpTemplateParameters(D->getTemplateParameters());
VisitVarTemplateSpecializationDecl(D);
}
void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
if (D->wasDeclaredWithTypename())
OS << " typename";
else
OS << " class";
if (D->isParameterPack())
OS << " ...";
dumpName(D);
if (D->hasDefaultArgument())
dumpType(D->getDefaultArgument());
}
void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
dumpType(D->getType());
if (D->isParameterPack())
OS << " ...";
dumpName(D);
if (D->hasDefaultArgument())
dumpStmt(D->getDefaultArgument());
}
void ASTDumper::VisitTemplateTemplateParmDecl(
const TemplateTemplateParmDecl *D) {
if (D->isParameterPack())
OS << " ...";
dumpName(D);
dumpTemplateParameters(D->getTemplateParameters());
if (D->hasDefaultArgument())
dumpTemplateArgumentLoc(D->getDefaultArgument());
}
void ASTDumper::VisitUsingDecl(const UsingDecl *D) {
OS << ' ';
D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
OS << D->getNameAsString();
}
void ASTDumper::VisitUnresolvedUsingTypenameDecl(
const UnresolvedUsingTypenameDecl *D) {
OS << ' ';
D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
OS << D->getNameAsString();
}
void ASTDumper::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
OS << ' ';
D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
OS << D->getNameAsString();
dumpType(D->getType());
}
void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) {
OS << ' ';
dumpBareDeclRef(D->getTargetDecl());
}
void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
switch (D->getLanguage()) {
case LinkageSpecDecl::lang_c: OS << " C"; break;
case LinkageSpecDecl::lang_cxx: OS << " C++"; break;
}
}
void ASTDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) {
OS << ' ';
dumpAccessSpecifier(D->getAccess());
}
void ASTDumper::VisitFriendDecl(const FriendDecl *D) {
lastChild();
if (TypeSourceInfo *T = D->getFriendType())
dumpType(T->getType());
else
dumpDecl(D->getFriendDecl());
}
//===----------------------------------------------------------------------===//
// Obj-C Declarations
//===----------------------------------------------------------------------===//
void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
dumpName(D);
dumpType(D->getType());
if (D->getSynthesize())
OS << " synthesize";
if (D->getBackingIvarReferencedInAccessor())
OS << " BackingIvarReferencedInAccessor";
switch (D->getAccessControl()) {
case ObjCIvarDecl::None:
OS << " none";
break;
case ObjCIvarDecl::Private:
OS << " private";
break;
case ObjCIvarDecl::Protected:
OS << " protected";
break;
case ObjCIvarDecl::Public:
OS << " public";
break;
case ObjCIvarDecl::Package:
OS << " package";
break;
}
}
void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
if (D->isInstanceMethod())
OS << " -";
else
OS << " +";
dumpName(D);
dumpType(D->getResultType());
bool OldMoreChildren = hasMoreChildren();
bool IsVariadic = D->isVariadic();
bool HasBody = D->hasBody();
setMoreChildren(OldMoreChildren || IsVariadic || HasBody);
if (D->isThisDeclarationADefinition()) {
lastChild();
dumpDeclContext(D);
} else {
for (ObjCMethodDecl::param_const_iterator I = D->param_begin(),
E = D->param_end();
I != E; ++I) {
if (I + 1 == E)
lastChild();
dumpDecl(*I);
}
}
setMoreChildren(OldMoreChildren || HasBody);
if (IsVariadic) {
lastChild();
IndentScope Indent(*this);
OS << "...";
}
setMoreChildren(OldMoreChildren);
if (HasBody) {
lastChild();
dumpStmt(D->getBody());
}
}
void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
dumpName(D);
dumpDeclRef(D->getClassInterface());
if (D->protocol_begin() == D->protocol_end())
lastChild();
dumpDeclRef(D->getImplementation());
for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
E = D->protocol_end();
I != E; ++I) {
if (I + 1 == E)
lastChild();
dumpDeclRef(*I);
}
}
void ASTDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
dumpName(D);
dumpDeclRef(D->getClassInterface());
lastChild();
dumpDeclRef(D->getCategoryDecl());
}
void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
dumpName(D);
for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(),
E = D->protocol_end();
I != E; ++I) {
if (I + 1 == E)
lastChild();
dumpDeclRef(*I);
}
}
void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
dumpName(D);
dumpDeclRef(D->getSuperClass(), "super");
if (D->protocol_begin() == D->protocol_end())
lastChild();
dumpDeclRef(D->getImplementation());
for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(),
E = D->protocol_end();
I != E; ++I) {
if (I + 1 == E)
lastChild();
dumpDeclRef(*I);
}
}
void ASTDumper::VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
dumpName(D);
dumpDeclRef(D->getSuperClass(), "super");
if (D->init_begin() == D->init_end())
lastChild();
dumpDeclRef(D->getClassInterface());
for (ObjCImplementationDecl::init_const_iterator I = D->init_begin(),
E = D->init_end();
I != E; ++I) {
if (I + 1 == E)
lastChild();
dumpCXXCtorInitializer(*I);
}
}
void ASTDumper::VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D) {
dumpName(D);
lastChild();
dumpDeclRef(D->getClassInterface());
}
void ASTDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
dumpName(D);
dumpType(D->getType());
if (D->getPropertyImplementation() == ObjCPropertyDecl::Required)
OS << " required";
else if (D->getPropertyImplementation() == ObjCPropertyDecl::Optional)
OS << " optional";
ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes();
if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) {
if (Attrs & ObjCPropertyDecl::OBJC_PR_readonly)
OS << " readonly";
if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
OS << " assign";
if (Attrs & ObjCPropertyDecl::OBJC_PR_readwrite)
OS << " readwrite";
if (Attrs & ObjCPropertyDecl::OBJC_PR_retain)
OS << " retain";
if (Attrs & ObjCPropertyDecl::OBJC_PR_copy)
OS << " copy";
if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic)
OS << " nonatomic";
if (Attrs & ObjCPropertyDecl::OBJC_PR_atomic)
OS << " atomic";
if (Attrs & ObjCPropertyDecl::OBJC_PR_weak)
OS << " weak";
if (Attrs & ObjCPropertyDecl::OBJC_PR_strong)
OS << " strong";
if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained)
OS << " unsafe_unretained";
if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) {
if (!(Attrs & ObjCPropertyDecl::OBJC_PR_setter))
lastChild();
dumpDeclRef(D->getGetterMethodDecl(), "getter");
}
if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) {
lastChild();
dumpDeclRef(D->getSetterMethodDecl(), "setter");
}
}
}
void ASTDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
dumpName(D->getPropertyDecl());
if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize)
OS << " synthesize";
else
OS << " dynamic";
dumpDeclRef(D->getPropertyDecl());
lastChild();
dumpDeclRef(D->getPropertyIvarDecl());
}
void ASTDumper::VisitBlockDecl(const BlockDecl *D) {
for (BlockDecl::param_const_iterator I = D->param_begin(), E = D->param_end();
I != E; ++I)
dumpDecl(*I);
if (D->isVariadic()) {
IndentScope Indent(*this);
OS << "...";
}
if (D->capturesCXXThis()) {
IndentScope Indent(*this);
OS << "capture this";
}
for (BlockDecl::capture_iterator I = D->capture_begin(), E = D->capture_end();
I != E; ++I) {
IndentScope Indent(*this);
OS << "capture";
if (I->isByRef())
OS << " byref";
if (I->isNested())
OS << " nested";
if (I->getVariable()) {
OS << ' ';
dumpBareDeclRef(I->getVariable());
}
if (I->hasCopyExpr())
dumpStmt(I->getCopyExpr());
}
lastChild();
dumpStmt(D->getBody());
}
//===----------------------------------------------------------------------===//
// Stmt dumping methods.
//===----------------------------------------------------------------------===//
void ASTDumper::dumpStmt(const Stmt *S) {
IndentScope Indent(*this);
if (!S) {
ColorScope Color(*this, NullColor);
OS << "<<<NULL>>>";
return;
}
if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
VisitDeclStmt(DS);
return;
}
setMoreChildren(!S->children().empty());
ConstStmtVisitor<ASTDumper>::Visit(S);
setMoreChildren(false);
for (Stmt::const_child_range CI = S->children(); CI; ++CI) {
Stmt::const_child_range Next = CI;
++Next;
if (!Next)
lastChild();
dumpStmt(*CI);
}
}
void ASTDumper::VisitStmt(const Stmt *Node) {
{
ColorScope Color(*this, StmtColor);
OS << Node->getStmtClassName();
}
dumpPointer(Node);
dumpSourceRange(Node->getSourceRange());
}
void ASTDumper::VisitDeclStmt(const DeclStmt *Node) {
VisitStmt(Node);
for (DeclStmt::const_decl_iterator I = Node->decl_begin(),
E = Node->decl_end();
I != E; ++I) {
if (I + 1 == E)
lastChild();
dumpDecl(*I);
}
}
void ASTDumper::VisitAttributedStmt(const AttributedStmt *Node) {
VisitStmt(Node);
for (ArrayRef<const Attr *>::iterator I = Node->getAttrs().begin(),
E = Node->getAttrs().end();
I != E; ++I) {
if (I + 1 == E)
lastChild();
dumpAttr(*I);
}
}
void ASTDumper::VisitLabelStmt(const LabelStmt *Node) {
VisitStmt(Node);
OS << " '" << Node->getName() << "'";
}
void ASTDumper::VisitGotoStmt(const GotoStmt *Node) {
VisitStmt(Node);
OS << " '" << Node->getLabel()->getName() << "'";
dumpPointer(Node->getLabel());
}
void ASTDumper::VisitCXXCatchStmt(const CXXCatchStmt *Node) {
VisitStmt(Node);
dumpDecl(Node->getExceptionDecl());
}
//===----------------------------------------------------------------------===//
// Expr dumping methods.
//===----------------------------------------------------------------------===//
void ASTDumper::VisitExpr(const Expr *Node) {
VisitStmt(Node);
dumpType(Node->getType());
{
ColorScope Color(*this, ValueKindColor);
switch (Node->getValueKind()) {
case VK_RValue:
break;
case VK_LValue:
OS << " lvalue";
break;
case VK_XValue:
OS << " xvalue";
break;
}
}
{
ColorScope Color(*this, ObjectKindColor);
switch (Node->getObjectKind()) {
case OK_Ordinary:
break;
case OK_BitField:
OS << " bitfield";
break;
case OK_ObjCProperty:
OS << " objcproperty";
break;
case OK_ObjCSubscript:
OS << " objcsubscript";
break;
case OK_VectorComponent:
OS << " vectorcomponent";
break;
}
}
}
static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) {
if (Node->path_empty())
return;
OS << " (";
bool First = true;
for (CastExpr::path_const_iterator I = Node->path_begin(),
E = Node->path_end();
I != E; ++I) {
const CXXBaseSpecifier *Base = *I;
if (!First)
OS << " -> ";
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (Base->isVirtual())
OS << "virtual ";
OS << RD->getName();
First = false;
}
OS << ')';
}
void ASTDumper::VisitCastExpr(const CastExpr *Node) {
VisitExpr(Node);
OS << " <";
{
ColorScope Color(*this, CastColor);
OS << Node->getCastKindName();
}
dumpBasePath(OS, Node);
OS << ">";
}
void ASTDumper::VisitDeclRefExpr(const DeclRefExpr *Node) {
VisitExpr(Node);
OS << " ";
dumpBareDeclRef(Node->getDecl());
Add an optional field attached to a DeclRefExpr which points back to the Decl actually found via name lookup & overload resolution when that Decl is different from the ValueDecl which is actually referenced by the expression. This can be used by AST consumers to correctly attribute references to the spelling location of a using declaration, and otherwise gain insight into the name resolution performed by Clang. The public interface to DRE is kept as narrow as possible: we provide a getFoundDecl() which always returns a NamedDecl, either the ValueDecl referenced or the new, more precise NamedDecl if present. This way AST clients can code against getFoundDecl without know when exactly the AST has a split representation. For an example of the data this provides consider: % cat x.cc namespace N1 { struct S {}; void f(const S&); } void test(N1::S s) { f(s); using N1::f; f(s); } % ./bin/clang -fsyntax-only -Xclang -ast-dump x.cc [...] void test(N1::S s) (CompoundStmt 0x5b02010 <x.cc:5:20, line:9:1> (CallExpr 0x5b01df0 <line:6:3, col:6> 'void' (ImplicitCastExpr 0x5b01dd8 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay> (DeclRefExpr 0x5b01d80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)')) (ImplicitCastExpr 0x5b01e20 <col:5> 'const struct N1::S' lvalue <NoOp> (DeclRefExpr 0x5b01d58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S'))) (DeclStmt 0x5b01ee0 <line:7:3, col:14> 0x5b01e40 "UsingN1::;") (CallExpr 0x5b01fc8 <line:8:3, col:6> 'void' (ImplicitCastExpr 0x5b01fb0 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay> (DeclRefExpr 0x5b01f80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)' (UsingShadow 0x5b01ea0 'f'))) (ImplicitCastExpr 0x5b01ff8 <col:5> 'const struct N1::S' lvalue <NoOp> (DeclRefExpr 0x5b01f58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S')))) Now we can tell that the second call is 'using' (no pun intended) the using declaration, and *which* using declaration it sees. Without this, we can mistake calls that go through using declarations for ADL calls, and have no way to attribute names looked up with using declarations to the appropriate UsingDecl. llvm-svn: 130670
2011-05-02 07:48:14 +08:00
if (Node->getDecl() != Node->getFoundDecl()) {
OS << " (";
dumpBareDeclRef(Node->getFoundDecl());
Add an optional field attached to a DeclRefExpr which points back to the Decl actually found via name lookup & overload resolution when that Decl is different from the ValueDecl which is actually referenced by the expression. This can be used by AST consumers to correctly attribute references to the spelling location of a using declaration, and otherwise gain insight into the name resolution performed by Clang. The public interface to DRE is kept as narrow as possible: we provide a getFoundDecl() which always returns a NamedDecl, either the ValueDecl referenced or the new, more precise NamedDecl if present. This way AST clients can code against getFoundDecl without know when exactly the AST has a split representation. For an example of the data this provides consider: % cat x.cc namespace N1 { struct S {}; void f(const S&); } void test(N1::S s) { f(s); using N1::f; f(s); } % ./bin/clang -fsyntax-only -Xclang -ast-dump x.cc [...] void test(N1::S s) (CompoundStmt 0x5b02010 <x.cc:5:20, line:9:1> (CallExpr 0x5b01df0 <line:6:3, col:6> 'void' (ImplicitCastExpr 0x5b01dd8 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay> (DeclRefExpr 0x5b01d80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)')) (ImplicitCastExpr 0x5b01e20 <col:5> 'const struct N1::S' lvalue <NoOp> (DeclRefExpr 0x5b01d58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S'))) (DeclStmt 0x5b01ee0 <line:7:3, col:14> 0x5b01e40 "UsingN1::;") (CallExpr 0x5b01fc8 <line:8:3, col:6> 'void' (ImplicitCastExpr 0x5b01fb0 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay> (DeclRefExpr 0x5b01f80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)' (UsingShadow 0x5b01ea0 'f'))) (ImplicitCastExpr 0x5b01ff8 <col:5> 'const struct N1::S' lvalue <NoOp> (DeclRefExpr 0x5b01f58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S')))) Now we can tell that the second call is 'using' (no pun intended) the using declaration, and *which* using declaration it sees. Without this, we can mistake calls that go through using declarations for ADL calls, and have no way to attribute names looked up with using declarations to the appropriate UsingDecl. llvm-svn: 130670
2011-05-02 07:48:14 +08:00
OS << ")";
}
}
void ASTDumper::VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node) {
VisitExpr(Node);
OS << " (";
if (!Node->requiresADL())
OS << "no ";
OS << "ADL) = '" << Node->getName() << '\'';
UnresolvedLookupExpr::decls_iterator
I = Node->decls_begin(), E = Node->decls_end();
if (I == E)
OS << " empty";
for (; I != E; ++I)
dumpPointer(*I);
}
void ASTDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node) {
VisitExpr(Node);
{
ColorScope Color(*this, DeclKindNameColor);
OS << " " << Node->getDecl()->getDeclKindName() << "Decl";
}
OS << "='" << *Node->getDecl() << "'";
dumpPointer(Node->getDecl());
if (Node->isFreeIvar())
OS << " isFreeIvar";
}
void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) {
VisitExpr(Node);
switch (Node->getIdentType()) {
default: llvm_unreachable("unknown case");
case PredefinedExpr::Func: OS << " __func__"; break;
case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
case PredefinedExpr::FuncDName: OS << " __FUNCDNAME__"; break;
case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
}
}
void ASTDumper::VisitCharacterLiteral(const CharacterLiteral *Node) {
VisitExpr(Node);
ColorScope Color(*this, ValueColor);
OS << " " << Node->getValue();
}
void ASTDumper::VisitIntegerLiteral(const IntegerLiteral *Node) {
VisitExpr(Node);
bool isSigned = Node->getType()->isSignedIntegerType();
ColorScope Color(*this, ValueColor);
OS << " " << Node->getValue().toString(10, isSigned);
}
void ASTDumper::VisitFloatingLiteral(const FloatingLiteral *Node) {
VisitExpr(Node);
ColorScope Color(*this, ValueColor);
OS << " " << Node->getValueAsApproximateDouble();
}
void ASTDumper::VisitStringLiteral(const StringLiteral *Str) {
VisitExpr(Str);
ColorScope Color(*this, ValueColor);
OS << " ";
Str->outputString(OS);
}
void ASTDumper::VisitUnaryOperator(const UnaryOperator *Node) {
VisitExpr(Node);
OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
<< " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
}
void ASTDumper::VisitUnaryExprOrTypeTraitExpr(
const UnaryExprOrTypeTraitExpr *Node) {
VisitExpr(Node);
switch(Node->getKind()) {
case UETT_SizeOf:
OS << " sizeof";
break;
case UETT_AlignOf:
OS << " alignof";
break;
case UETT_VecStep:
OS << " vec_step";
break;
}
if (Node->isArgumentType())
dumpType(Node->getArgumentType());
}
void ASTDumper::VisitMemberExpr(const MemberExpr *Node) {
VisitExpr(Node);
OS << " " << (Node->isArrow() ? "->" : ".") << *Node->getMemberDecl();
dumpPointer(Node->getMemberDecl());
}
void ASTDumper::VisitExtVectorElementExpr(const ExtVectorElementExpr *Node) {
VisitExpr(Node);
OS << " " << Node->getAccessor().getNameStart();
}
void ASTDumper::VisitBinaryOperator(const BinaryOperator *Node) {
VisitExpr(Node);
OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
}
void ASTDumper::VisitCompoundAssignOperator(
const CompoundAssignOperator *Node) {
VisitExpr(Node);
OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode())
<< "' ComputeLHSTy=";
dumpBareType(Node->getComputationLHSType());
OS << " ComputeResultTy=";
dumpBareType(Node->getComputationResultType());
}
void ASTDumper::VisitBlockExpr(const BlockExpr *Node) {
VisitExpr(Node);
dumpDecl(Node->getBlockDecl());
}
void ASTDumper::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) {
VisitExpr(Node);
if (Expr *Source = Node->getSourceExpr()) {
lastChild();
dumpStmt(Source);
}
}
// GNU extensions.
void ASTDumper::VisitAddrLabelExpr(const AddrLabelExpr *Node) {
VisitExpr(Node);
OS << " " << Node->getLabel()->getName();
dumpPointer(Node->getLabel());
}
//===----------------------------------------------------------------------===//
// C++ Expressions
//===----------------------------------------------------------------------===//
void ASTDumper::VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node) {
VisitExpr(Node);
OS << " " << Node->getCastName()
<< "<" << Node->getTypeAsWritten().getAsString() << ">"
<< " <" << Node->getCastKindName();
dumpBasePath(OS, Node);
OS << ">";
}
void ASTDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node) {
VisitExpr(Node);
OS << " " << (Node->getValue() ? "true" : "false");
}
void ASTDumper::VisitCXXThisExpr(const CXXThisExpr *Node) {
VisitExpr(Node);
OS << " this";
}
void ASTDumper::VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node) {
VisitExpr(Node);
OS << " functional cast to " << Node->getTypeAsWritten().getAsString()
<< " <" << Node->getCastKindName() << ">";
}
void ASTDumper::VisitCXXConstructExpr(const CXXConstructExpr *Node) {
VisitExpr(Node);
CXXConstructorDecl *Ctor = Node->getConstructor();
dumpType(Ctor->getType());
if (Node->isElidable())
OS << " elidable";
if (Node->requiresZeroInitialization())
OS << " zeroing";
}
void ASTDumper::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) {
VisitExpr(Node);
OS << " ";
dumpCXXTemporary(Node->getTemporary());
}
void
ASTDumper::VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node) {
VisitExpr(Node);
if (const ValueDecl *VD = Node->getExtendingDecl()) {
OS << " extended by ";
dumpBareDeclRef(VD);
}
}
void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) {
VisitExpr(Node);
for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)
dumpDeclRef(Node->getObject(i), "cleanup");
}
void ASTDumper::dumpCXXTemporary(const CXXTemporary *Temporary) {
OS << "(CXXTemporary";
dumpPointer(Temporary);
OS << ")";
}
//===----------------------------------------------------------------------===//
// Obj-C Expressions
//===----------------------------------------------------------------------===//
void ASTDumper::VisitObjCMessageExpr(const ObjCMessageExpr *Node) {
VisitExpr(Node);
OS << " selector=" << Node->getSelector().getAsString();
Overhaul the AST representation of Objective-C message send expressions, to improve source-location information, clarify the actual receiver of the message, and pave the way for proper C++ support. The ObjCMessageExpr node represents four different kinds of message sends in a single AST node: 1) Send to a object instance described by an expression (e.g., [x method:5]) 2) Send to a class described by the class name (e.g., [NSString method:5]) 3) Send to a superclass class (e.g, [super method:5] in class method) 4) Send to a superclass instance (e.g., [super method:5] in instance method) Previously these four cases where tangled together. Now, they have more distinct representations. Specific changes: 1) Unchanged; the object instance is represented by an Expr*. 2) Previously stored the ObjCInterfaceDecl* referring to the class receiving the message. Now stores a TypeSourceInfo* so that we know how the class was spelled. This both maintains typedef information and opens the door for more complicated C++ types (e.g., dependent types). There was an alternative, unused representation of these sends by naming the class via an IdentifierInfo *. In practice, we either had an ObjCInterfaceDecl *, from which we would get the IdentifierInfo *, or we fell into the case below... 3) Previously represented by a class message whose IdentifierInfo * referred to "super". Sema and CodeGen would use isStr("super") to determine if they had a send to super. Now represented as a "class super" send, where we have both the location of the "super" keyword and the ObjCInterfaceDecl* of the superclass we're targetting (statically). 4) Previously represented by an instance message whose receiver is a an ObjCSuperExpr, which Sema and CodeGen would check for via isa<ObjCSuperExpr>(). Now represented as an "instance super" send, where we have both the location of the "super" keyword and the ObjCInterfaceDecl* of the superclass we're targetting (statically). Note that ObjCSuperExpr only has one remaining use in the AST, which is for "super.prop" references. The new representation of ObjCMessageExpr is 2 pointers smaller than the old one, since it combines more storage. It also eliminates a leak when we loaded message-send expressions from a precompiled header. The representation also feels much cleaner to me; comments welcome! This patch attempts to maintain the same semantics we previously had with Objective-C message sends. In several places, there are massive changes that boil down to simply replacing a nested-if structure such as: if (message has a receiver expression) { // instance message if (isa<ObjCSuperExpr>(...)) { // send to super } else { // send to an object } } else { // class message if (name->isStr("super")) { // class send to super } else { // send to class } } with a switch switch (E->getReceiverKind()) { case ObjCMessageExpr::SuperInstance: ... case ObjCMessageExpr::Instance: ... case ObjCMessageExpr::SuperClass: ... case ObjCMessageExpr::Class:... } There are quite a few places (particularly in the checkers) where send-to-super is effectively ignored. I've placed FIXMEs in most of them, and attempted to address send-to-super in a reasonable way. This could use some review. llvm-svn: 101972
2010-04-21 08:45:42 +08:00
switch (Node->getReceiverKind()) {
case ObjCMessageExpr::Instance:
break;
case ObjCMessageExpr::Class:
OS << " class=";
dumpBareType(Node->getClassReceiver());
Overhaul the AST representation of Objective-C message send expressions, to improve source-location information, clarify the actual receiver of the message, and pave the way for proper C++ support. The ObjCMessageExpr node represents four different kinds of message sends in a single AST node: 1) Send to a object instance described by an expression (e.g., [x method:5]) 2) Send to a class described by the class name (e.g., [NSString method:5]) 3) Send to a superclass class (e.g, [super method:5] in class method) 4) Send to a superclass instance (e.g., [super method:5] in instance method) Previously these four cases where tangled together. Now, they have more distinct representations. Specific changes: 1) Unchanged; the object instance is represented by an Expr*. 2) Previously stored the ObjCInterfaceDecl* referring to the class receiving the message. Now stores a TypeSourceInfo* so that we know how the class was spelled. This both maintains typedef information and opens the door for more complicated C++ types (e.g., dependent types). There was an alternative, unused representation of these sends by naming the class via an IdentifierInfo *. In practice, we either had an ObjCInterfaceDecl *, from which we would get the IdentifierInfo *, or we fell into the case below... 3) Previously represented by a class message whose IdentifierInfo * referred to "super". Sema and CodeGen would use isStr("super") to determine if they had a send to super. Now represented as a "class super" send, where we have both the location of the "super" keyword and the ObjCInterfaceDecl* of the superclass we're targetting (statically). 4) Previously represented by an instance message whose receiver is a an ObjCSuperExpr, which Sema and CodeGen would check for via isa<ObjCSuperExpr>(). Now represented as an "instance super" send, where we have both the location of the "super" keyword and the ObjCInterfaceDecl* of the superclass we're targetting (statically). Note that ObjCSuperExpr only has one remaining use in the AST, which is for "super.prop" references. The new representation of ObjCMessageExpr is 2 pointers smaller than the old one, since it combines more storage. It also eliminates a leak when we loaded message-send expressions from a precompiled header. The representation also feels much cleaner to me; comments welcome! This patch attempts to maintain the same semantics we previously had with Objective-C message sends. In several places, there are massive changes that boil down to simply replacing a nested-if structure such as: if (message has a receiver expression) { // instance message if (isa<ObjCSuperExpr>(...)) { // send to super } else { // send to an object } } else { // class message if (name->isStr("super")) { // class send to super } else { // send to class } } with a switch switch (E->getReceiverKind()) { case ObjCMessageExpr::SuperInstance: ... case ObjCMessageExpr::Instance: ... case ObjCMessageExpr::SuperClass: ... case ObjCMessageExpr::Class:... } There are quite a few places (particularly in the checkers) where send-to-super is effectively ignored. I've placed FIXMEs in most of them, and attempted to address send-to-super in a reasonable way. This could use some review. llvm-svn: 101972
2010-04-21 08:45:42 +08:00
break;
case ObjCMessageExpr::SuperInstance:
OS << " super (instance)";
break;
case ObjCMessageExpr::SuperClass:
OS << " super (class)";
break;
}
}
void ASTDumper::VisitObjCBoxedExpr(const ObjCBoxedExpr *Node) {
VisitExpr(Node);
OS << " selector=" << Node->getBoxingMethod()->getSelector().getAsString();
}
void ASTDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) {
VisitStmt(Node);
if (const VarDecl *CatchParam = Node->getCatchParamDecl())
dumpDecl(CatchParam);
else
OS << " catch all";
}
void ASTDumper::VisitObjCEncodeExpr(const ObjCEncodeExpr *Node) {
VisitExpr(Node);
dumpType(Node->getEncodedType());
}
void ASTDumper::VisitObjCSelectorExpr(const ObjCSelectorExpr *Node) {
VisitExpr(Node);
OS << " " << Node->getSelector().getAsString();
}
void ASTDumper::VisitObjCProtocolExpr(const ObjCProtocolExpr *Node) {
VisitExpr(Node);
OS << ' ' << *Node->getProtocol();
}
void ASTDumper::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node) {
VisitExpr(Node);
if (Node->isImplicitProperty()) {
OS << " Kind=MethodRef Getter=\"";
if (Node->getImplicitPropertyGetter())
OS << Node->getImplicitPropertyGetter()->getSelector().getAsString();
else
OS << "(null)";
OS << "\" Setter=\"";
if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter())
OS << Setter->getSelector().getAsString();
else
OS << "(null)";
OS << "\"";
} else {
OS << " Kind=PropertyRef Property=\"" << *Node->getExplicitProperty() <<'"';
}
if (Node->isSuperReceiver())
OS << " super";
OS << " Messaging=";
if (Node->isMessagingGetter() && Node->isMessagingSetter())
OS << "Getter&Setter";
else if (Node->isMessagingGetter())
OS << "Getter";
else if (Node->isMessagingSetter())
OS << "Setter";
}
void ASTDumper::VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node) {
VisitExpr(Node);
if (Node->isArraySubscriptRefExpr())
OS << " Kind=ArraySubscript GetterForArray=\"";
else
OS << " Kind=DictionarySubscript GetterForDictionary=\"";
if (Node->getAtIndexMethodDecl())
OS << Node->getAtIndexMethodDecl()->getSelector().getAsString();
else
OS << "(null)";
if (Node->isArraySubscriptRefExpr())
OS << "\" SetterForArray=\"";
else
OS << "\" SetterForDictionary=\"";
if (Node->setAtIndexMethodDecl())
OS << Node->setAtIndexMethodDecl()->getSelector().getAsString();
else
OS << "(null)";
}
void ASTDumper::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node) {
VisitExpr(Node);
OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no");
}
//===----------------------------------------------------------------------===//
// Comments
//===----------------------------------------------------------------------===//
const char *ASTDumper::getCommandName(unsigned CommandID) {
if (Traits)
return Traits->getCommandInfo(CommandID)->Name;
const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
if (Info)
return Info->Name;
return "<not a builtin command>";
}
void ASTDumper::dumpFullComment(const FullComment *C) {
if (!C)
return;
FC = C;
dumpComment(C);
FC = 0;
}
void ASTDumper::dumpComment(const Comment *C) {
IndentScope Indent(*this);
if (!C) {
ColorScope Color(*this, NullColor);
OS << "<<<NULL>>>";
return;
}
{
ColorScope Color(*this, CommentColor);
OS << C->getCommentKindName();
}
dumpPointer(C);
dumpSourceRange(C->getSourceRange());
ConstCommentVisitor<ASTDumper>::visit(C);
for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
I != E; ++I) {
if (I + 1 == E)
lastChild();
dumpComment(*I);
}
}
void ASTDumper::visitTextComment(const TextComment *C) {
OS << " Text=\"" << C->getText() << "\"";
}
void ASTDumper::visitInlineCommandComment(const InlineCommandComment *C) {
OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
switch (C->getRenderKind()) {
case InlineCommandComment::RenderNormal:
OS << " RenderNormal";
break;
case InlineCommandComment::RenderBold:
OS << " RenderBold";
break;
case InlineCommandComment::RenderMonospaced:
OS << " RenderMonospaced";
break;
case InlineCommandComment::RenderEmphasized:
OS << " RenderEmphasized";
break;
}
for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
}
void ASTDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
OS << " Name=\"" << C->getTagName() << "\"";
if (C->getNumAttrs() != 0) {
OS << " Attrs: ";
for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
}
}
if (C->isSelfClosing())
OS << " SelfClosing";
}
void ASTDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
OS << " Name=\"" << C->getTagName() << "\"";
}
void ASTDumper::visitBlockCommandComment(const BlockCommandComment *C) {
OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
}
void ASTDumper::visitParamCommandComment(const ParamCommandComment *C) {
OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection());
if (C->isDirectionExplicit())
OS << " explicitly";
else
OS << " implicitly";
if (C->hasParamName()) {
if (C->isParamIndexValid())
OS << " Param=\"" << C->getParamName(FC) << "\"";
else
OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
}
if (C->isParamIndexValid())
OS << " ParamIndex=" << C->getParamIndex();
}
void ASTDumper::visitTParamCommandComment(const TParamCommandComment *C) {
if (C->hasParamName()) {
if (C->isPositionValid())
OS << " Param=\"" << C->getParamName(FC) << "\"";
else
OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
}
if (C->isPositionValid()) {
OS << " Position=<";
for (unsigned i = 0, e = C->getDepth(); i != e; ++i) {
OS << C->getIndex(i);
if (i != e - 1)
OS << ", ";
}
OS << ">";
}
}
void ASTDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) {
OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""
" CloseName=\"" << C->getCloseName() << "\"";
}
void ASTDumper::visitVerbatimBlockLineComment(
const VerbatimBlockLineComment *C) {
OS << " Text=\"" << C->getText() << "\"";
}
void ASTDumper::visitVerbatimLineComment(const VerbatimLineComment *C) {
OS << " Text=\"" << C->getText() << "\"";
}
//===----------------------------------------------------------------------===//
// Decl method implementations
//===----------------------------------------------------------------------===//
void Decl::dump() const {
dump(llvm::errs());
}
void Decl::dump(raw_ostream &OS) const {
ASTDumper P(OS, &getASTContext().getCommentCommandTraits(),
&getASTContext().getSourceManager());
P.dumpDecl(this);
}
void Decl::dumpColor() const {
ASTDumper P(llvm::errs(), &getASTContext().getCommentCommandTraits(),
&getASTContext().getSourceManager(), /*ShowColors*/true);
P.dumpDecl(this);
}
void DeclContext::dumpLookups() const {
dumpLookups(llvm::errs());
}
void DeclContext::dumpLookups(raw_ostream &OS) const {
const DeclContext *DC = this;
while (!DC->isTranslationUnit())
DC = DC->getParent();
ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager());
P.dumpLookups(this);
}
//===----------------------------------------------------------------------===//
// Stmt method implementations
//===----------------------------------------------------------------------===//
void Stmt::dump(SourceManager &SM) const {
dump(llvm::errs(), SM);
}
void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
ASTDumper P(OS, 0, &SM);
P.dumpStmt(this);
}
void Stmt::dump() const {
ASTDumper P(llvm::errs(), 0, 0);
P.dumpStmt(this);
}
void Stmt::dumpColor() const {
ASTDumper P(llvm::errs(), 0, 0, /*ShowColors*/true);
P.dumpStmt(this);
}
//===----------------------------------------------------------------------===//
// Comment method implementations
//===----------------------------------------------------------------------===//
void Comment::dump() const {
dump(llvm::errs(), 0, 0);
}
void Comment::dump(const ASTContext &Context) const {
dump(llvm::errs(), &Context.getCommentCommandTraits(),
&Context.getSourceManager());
}
void Comment::dump(raw_ostream &OS, const CommandTraits *Traits,
const SourceManager *SM) const {
const FullComment *FC = dyn_cast<FullComment>(this);
ASTDumper D(OS, Traits, SM);
D.dumpFullComment(FC);
}
void Comment::dumpColor() const {
const FullComment *FC = dyn_cast<FullComment>(this);
ASTDumper D(llvm::errs(), 0, 0, /*ShowColors*/true);
D.dumpFullComment(FC);
}