Implement AST dumper for Decls.
http://llvm-reviews.chandlerc.com/D52

Patch by Philip Craig!



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@170634 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 51d0f26..31331f1 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -12,11 +12,12 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclCXX.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;
@@ -26,7 +27,8 @@
 //===----------------------------------------------------------------------===//
 
 namespace  {
-  class ASTDumper : public StmtVisitor<ASTDumper> {
+  class ASTDumper
+      : public DeclVisitor<ASTDumper>, public StmtVisitor<ASTDumper> {
     SourceManager *SM;
     raw_ostream &OS;
     unsigned IndentLevel;
@@ -63,10 +65,78 @@
     // Utilities
     void indent();
     void unindent();
-    void dumpSourceRange(const Stmt *Node);
+    void dumpPointer(const void *Ptr);
+    void dumpSourceRange(SourceRange R);
     void dumpLocation(SourceLocation Loc);
+    void dumpBareType(QualType T);
     void dumpType(QualType T);
-    void dumpDeclRef(Decl *node);
+    void dumpBareDeclRef(Decl *node);
+    void dumpDeclRef(Decl *node, const char *Label = NULL);
+    void dumpName(NamedDecl *D);
+    void dumpDeclContext(DeclContext *DC);
+
+    // C++ Utilities
+    void dumpAccessSpecifier(AccessSpecifier AS);
+    void dumpCXXCtorInitializer(CXXCtorInitializer *Init);
+    void dumpTemplateParameters(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(LabelDecl *D);
+    void VisitTypedefDecl(TypedefDecl *D);
+    void VisitEnumDecl(EnumDecl *D);
+    void VisitRecordDecl(RecordDecl *D);
+    void VisitEnumConstantDecl(EnumConstantDecl *D);
+    void VisitIndirectFieldDecl(IndirectFieldDecl *D);
+    void VisitFunctionDecl(FunctionDecl *D);
+    void VisitFieldDecl(FieldDecl *D);
+    void VisitVarDecl(VarDecl *D);
+    void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+    void VisitImportDecl(ImportDecl *D);
+
+    // C++ Decls
+    void VisitNamespaceDecl(NamespaceDecl *D);
+    void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
+    void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
+    void VisitTypeAliasDecl(TypeAliasDecl *D);
+    void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
+    void VisitCXXRecordDecl(CXXRecordDecl *D);
+    void VisitStaticAssertDecl(StaticAssertDecl *D);
+    void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
+    void VisitClassTemplateDecl(ClassTemplateDecl *D);
+    void VisitClassTemplateSpecializationDecl(
+        ClassTemplateSpecializationDecl *D);
+    void VisitClassTemplatePartialSpecializationDecl(
+        ClassTemplatePartialSpecializationDecl *D);
+    void VisitClassScopeFunctionSpecializationDecl(
+        ClassScopeFunctionSpecializationDecl *D);
+    void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
+    void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
+    void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+    void VisitUsingDecl(UsingDecl *D);
+    void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
+    void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
+    void VisitUsingShadowDecl(UsingShadowDecl *D);
+    void VisitLinkageSpecDecl(LinkageSpecDecl *D);
+    void VisitAccessSpecDecl(AccessSpecDecl *D);
+    void VisitFriendDecl(FriendDecl *D);
+
+    // ObjC Decls
+    void VisitObjCIvarDecl(ObjCIvarDecl *D);
+    void VisitObjCMethodDecl(ObjCMethodDecl *D);
+    void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
+    void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
+    void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
+    void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+    void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
+    void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
+    void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+    void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+    void VisitBlockDecl(BlockDecl *D);
 
     // Stmts.
     void VisitStmt(Stmt *Node);
@@ -137,6 +207,10 @@
   IndentLevel--;
 }
 
+void ASTDumper::dumpPointer(const void *Ptr) {
+  OS << ' ' << Ptr;
+}
+
 void ASTDumper::dumpLocation(SourceLocation Loc) {
   SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
 
@@ -163,15 +237,11 @@
   }
 }
 
-void ASTDumper::dumpSourceRange(const Stmt *Node) {
+void ASTDumper::dumpSourceRange(SourceRange R) {
   // Can't translate locations if a SourceManager isn't available.
   if (!SM)
     return;
 
-  // TODO: If the parent expression is available, we can print a delta vs its
-  // location.
-  SourceRange R = Node->getSourceRange();
-
   OS << " <";
   dumpLocation(R.getBegin());
   if (R.getBegin() != R.getEnd()) {
@@ -184,7 +254,7 @@
 
 }
 
-void ASTDumper::dumpType(QualType T) {
+void ASTDumper::dumpBareType(QualType T) {
   SplitQualType T_split = T.split();
   OS << "'" << QualType::getAsString(T_split) << "'";
 
@@ -196,8 +266,14 @@
   }
 }
 
-void ASTDumper::dumpDeclRef(Decl *D) {
-  OS << D->getDeclKindName() << ' ' << (void*) D;
+void ASTDumper::dumpType(QualType T) {
+  OS << ' ';
+  dumpBareType(T);
+}
+
+void ASTDumper::dumpBareDeclRef(Decl *D) {
+  OS << D->getDeclKindName();
+  dumpPointer(D);
 
   if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
     OS << " '";
@@ -205,9 +281,132 @@
     OS << "'";
   }
 
-  if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
-    OS << ' ';
+  if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
     dumpType(VD->getType());
+}
+
+void ASTDumper::dumpDeclRef(Decl *D, const char *Label) {
+  if (!D)
+    return;
+
+  IndentScope Indent(*this);
+  if (Label)
+    OS << Label << ' ';
+  dumpBareDeclRef(D);
+}
+
+void ASTDumper::dumpName(NamedDecl *ND) {
+  if (ND->getDeclName())
+    OS << ' ' << ND->getNameAsString();
+}
+
+void ASTDumper::dumpDeclContext(DeclContext *DC) {
+  if (!DC)
+    return;
+  for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
+       I != E; ++I)
+    dumpDecl(*I);
+}
+
+//===----------------------------------------------------------------------===//
+//  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(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(TemplateParameterList *TPL) {
+  if (!TPL)
+    return;
+
+  for (TemplateParameterList::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)
+    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";
+    dumpType(A.getAsType());
+    break;
+  case TemplateArgument::Declaration:
+    OS << " decl";
+    dumpDeclRef(A.getAsDecl());
+    break;
+  case TemplateArgument::NullPtr:
+    OS << " nullptr";
+    break;
+  case TemplateArgument::Integral:
+    OS << " integral";
+    OS << ' ' << 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";
+    dumpStmt(A.getAsExpr());
+    break;
+  case TemplateArgument::Pack:
+    OS << " pack";
+    for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end();
+         I != E; ++I)
+      dumpTemplateArgument(*I);
+    break;
   }
 }
 
@@ -216,71 +415,514 @@
 //===----------------------------------------------------------------------===//
 
 void ASTDumper::dumpDecl(Decl *D) {
-  // FIXME: Need to complete/beautify this... this code simply shows the
-  // nodes are where they need to be.
-  if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
-    OS << "\"typedef " << localType->getUnderlyingType().getAsString()
-       << ' ' << *localType << '"';
-  } else if (TypeAliasDecl *localType = dyn_cast<TypeAliasDecl>(D)) {
-    OS << "\"using " << *localType << " = "
-       << localType->getUnderlyingType().getAsString() << '"';
-  } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
-    OS << "\"";
-    // Emit storage class for vardecls.
-    if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
-      if (V->getStorageClass() != SC_None)
-        OS << VarDecl::getStorageClassSpecifierString(V->getStorageClass())
-           << " ";
-    }
+  IndentScope Indent(*this);
 
-    std::string Name = VD->getNameAsString();
-    VD->getType().getAsStringInternal(Name,
-                          PrintingPolicy(VD->getASTContext().getLangOpts()));
-    OS << Name;
-
-    // If this is a vardecl with an initializer, emit it.
-    if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
-      if (V->getInit()) {
-        OS << " =";
-        dumpStmt(V->getInit());
-      }
-    }
-    OS << '"';
-  } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
-    // print a free standing tag decl (e.g. "struct x;").
-    const char *tagname;
-    if (const IdentifierInfo *II = TD->getIdentifier())
-      tagname = II->getNameStart();
-    else
-      tagname = "<anonymous>";
-    OS << '"' << TD->getKindName() << ' ' << tagname << ";\"";
-    // FIXME: print tag bodies.
-  } else if (UsingDirectiveDecl *UD = dyn_cast<UsingDirectiveDecl>(D)) {
-    // print using-directive decl (e.g. "using namespace x;")
-    const char *ns;
-    if (const IdentifierInfo *II = UD->getNominatedNamespace()->getIdentifier())
-      ns = II->getNameStart();
-    else
-      ns = "<anonymous>";
-    OS << '"' << UD->getDeclKindName() << ns << ";\"";
-  } else if (UsingDecl *UD = dyn_cast<UsingDecl>(D)) {
-    // print using decl (e.g. "using std::string;")
-    const char *tn = UD->isTypeName() ? "typename " : "";
-    OS << '"' << UD->getDeclKindName() << tn;
-    UD->getQualifier()->print(OS,
-                        PrintingPolicy(UD->getASTContext().getLangOpts()));
-    OS << ";\"";
-  } else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) {
-    OS << "label " << *LD;
-  } else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) {
-    OS << "\"static_assert(";
-    dumpStmt(SAD->getAssertExpr());
-    OS << ",";
-    dumpStmt(SAD->getMessage());
-    OS << ");\"";
-  } else {
-    llvm_unreachable("Unexpected decl");
+  if (!D) {
+    OS << "<<<NULL>>>";
+    return;
   }
+
+  OS << D->getDeclKindName() << "Decl";
+  dumpPointer(D);
+  dumpSourceRange(D->getSourceRange());
+  DeclVisitor<ASTDumper>::Visit(D);
+  // Decls within functions are visited by the body
+  if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D))
+    dumpDeclContext(dyn_cast<DeclContext>(D));
+}
+
+void ASTDumper::VisitLabelDecl(LabelDecl *D) {
+  dumpName(D);
+}
+
+void ASTDumper::VisitTypedefDecl(TypedefDecl *D) {
+  dumpName(D);
+  dumpType(D->getUnderlyingType());
+  if (D->isModulePrivate())
+    OS << " __module_private__";
+}
+
+void ASTDumper::VisitEnumDecl(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(RecordDecl *D) {
+  OS << ' ' << D->getKindName();
+  dumpName(D);
+  if (D->isModulePrivate())
+    OS << " __module_private__";
+}
+
+void ASTDumper::VisitEnumConstantDecl(EnumConstantDecl *D) {
+  dumpName(D);
+  dumpType(D->getType());
+  if (Expr *Init = D->getInitExpr())
+    dumpStmt(Init);
+}
+
+void ASTDumper::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
+  dumpName(D);
+  dumpType(D->getType());
+  for (IndirectFieldDecl::chain_iterator I = D->chain_begin(),
+       E = D->chain_end(); I != E; ++I)
+    dumpDeclRef(*I);
+}
+
+void ASTDumper::VisitFunctionDecl(FunctionDecl *D) {
+  dumpName(D);
+  dumpType(D->getType());
+
+  StorageClass SC = D->getStorageClassAsWritten();
+  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 FunctionTemplateSpecializationInfo *FTSI =
+      D->getTemplateSpecializationInfo())
+    dumpTemplateArgumentList(*FTSI->TemplateArguments);
+
+  for (llvm::ArrayRef<NamedDecl*>::iterator
+       I = D->getDeclsInPrototypeScope().begin(),
+       E = D->getDeclsInPrototypeScope().end(); I != E; ++I)
+    dumpDecl(*I);
+
+  for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end();
+       I != E; ++I)
+    dumpDecl(*I);
+
+  if (CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(D))
+    for (CXXConstructorDecl::init_const_iterator I = C->init_begin(),
+         E = C->init_end(); I != E; ++I)
+      dumpCXXCtorInitializer(*I);
+
+  if (D->doesThisDeclarationHaveABody())
+    dumpStmt(D->getBody());
+}
+
+void ASTDumper::VisitFieldDecl(FieldDecl *D) {
+  dumpName(D);
+  dumpType(D->getType());
+  if (D->isMutable())
+    OS << " mutable";
+  if (D->isModulePrivate())
+    OS << " __module_private__";
+  if (D->isBitField())
+    dumpStmt(D->getBitWidth());
+  if (Expr *Init = D->getInClassInitializer())
+    dumpStmt(Init);
+}
+
+void ASTDumper::VisitVarDecl(VarDecl *D) {
+  dumpName(D);
+  dumpType(D->getType());
+  StorageClass SC = D->getStorageClassAsWritten();
+  if (SC != SC_None)
+    OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
+  if (D->isThreadSpecified())
+    OS << " __thread";
+  if (D->isModulePrivate())
+    OS << " __module_private__";
+  if (D->isNRVOVariable())
+    OS << " nrvo";
+  if (D->hasInit())
+    dumpStmt(D->getInit());
+}
+
+void ASTDumper::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
+  dumpStmt(D->getAsmString());
+}
+
+void ASTDumper::VisitImportDecl(ImportDecl *D) {
+  OS << ' ' << D->getImportedModule()->getFullModuleName();
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Declarations
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitNamespaceDecl(NamespaceDecl *D) {
+  dumpName(D);
+  if (D->isInline())
+    OS << " inline";
+  if (!D->isOriginalNamespace())
+    dumpDeclRef(D->getOriginalNamespace(), "original");
+}
+
+void ASTDumper::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+  OS << ' ';
+  dumpBareDeclRef(D->getNominatedNamespace());
+}
+
+void ASTDumper::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+  dumpName(D);
+  dumpDeclRef(D->getAliasedNamespace());
+}
+
+void ASTDumper::VisitTypeAliasDecl(TypeAliasDecl *D) {
+  dumpName(D);
+  dumpType(D->getUnderlyingType());
+}
+
+void ASTDumper::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+  dumpName(D);
+  dumpTemplateParameters(D->getTemplateParameters());
+  dumpDecl(D->getTemplatedDecl());
+}
+
+void ASTDumper::VisitCXXRecordDecl(CXXRecordDecl *D) {
+  VisitRecordDecl(D);
+  if (!D->isCompleteDefinition())
+    return;
+
+  for (CXXRecordDecl::base_class_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(StaticAssertDecl *D) {
+  dumpStmt(D->getAssertExpr());
+  dumpStmt(D->getMessage());
+}
+
+void ASTDumper::VisitFunctionTemplateDecl(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) {
+    switch (I->getTemplateSpecializationKind()) {
+    case TSK_Undeclared:
+    case TSK_ImplicitInstantiation:
+    case TSK_ExplicitInstantiationDeclaration:
+    case TSK_ExplicitInstantiationDefinition:
+      dumpDecl(*I);
+      break;
+    case TSK_ExplicitSpecialization:
+      dumpDeclRef(*I);
+      break;
+    }
+  }
+}
+
+void ASTDumper::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+  dumpName(D);
+  dumpTemplateParameters(D->getTemplateParameters());
+  dumpDecl(D->getTemplatedDecl());
+  for (ClassTemplateDecl::spec_iterator I = D->spec_begin(), E = D->spec_end();
+       I != E; ++I) {
+    switch (I->getTemplateSpecializationKind()) {
+    case TSK_Undeclared:
+    case TSK_ImplicitInstantiation:
+      dumpDecl(*I);
+      break;
+    case TSK_ExplicitSpecialization:
+    case TSK_ExplicitInstantiationDeclaration:
+    case TSK_ExplicitInstantiationDefinition:
+      dumpDeclRef(*I);
+      break;
+    }
+  }
+}
+
+void ASTDumper::VisitClassTemplateSpecializationDecl(
+    ClassTemplateSpecializationDecl *D) {
+  VisitCXXRecordDecl(D);
+  dumpTemplateArgumentList(D->getTemplateArgs());
+}
+
+void ASTDumper::VisitClassTemplatePartialSpecializationDecl(
+    ClassTemplatePartialSpecializationDecl *D) {
+  VisitClassTemplateSpecializationDecl(D);
+  dumpTemplateParameters(D->getTemplateParameters());
+}
+
+void ASTDumper::VisitClassScopeFunctionSpecializationDecl(
+    ClassScopeFunctionSpecializationDecl *D) {
+  dumpDeclRef(D->getSpecialization());
+  if (D->hasExplicitTemplateArgs())
+    dumpTemplateArgumentListInfo(D->templateArgs());
+}
+
+void ASTDumper::VisitTemplateTypeParmDecl(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(NonTypeTemplateParmDecl *D) {
+  dumpType(D->getType());
+  if (D->isParameterPack())
+    OS << " ...";
+  dumpName(D);
+  if (D->hasDefaultArgument())
+    dumpStmt(D->getDefaultArgument());
+}
+
+void ASTDumper::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+  if (D->isParameterPack())
+    OS << " ...";
+  dumpName(D);
+  dumpTemplateParameters(D->getTemplateParameters());
+  if (D->hasDefaultArgument())
+    dumpTemplateArgumentLoc(D->getDefaultArgument());
+}
+
+void ASTDumper::VisitUsingDecl(UsingDecl *D) {
+  OS << ' ';
+  D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+  OS << D->getNameAsString();
+}
+
+void
+ASTDumper::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
+  OS << ' ';
+  D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+  OS << D->getNameAsString();
+}
+
+void ASTDumper::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
+  OS << ' ';
+  D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+  OS << D->getNameAsString();
+  dumpType(D->getType());
+}
+
+void ASTDumper::VisitUsingShadowDecl(UsingShadowDecl *D) {
+  OS << ' ';
+  dumpBareDeclRef(D->getTargetDecl());
+}
+
+void ASTDumper::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+  switch (D->getLanguage()) {
+  case LinkageSpecDecl::lang_c: OS << " C"; break;
+  case LinkageSpecDecl::lang_cxx: OS << " C++"; break;
+  }
+}
+
+void ASTDumper::VisitAccessSpecDecl(AccessSpecDecl *D) {
+  OS << ' ';
+  dumpAccessSpecifier(D->getAccess());
+}
+
+void ASTDumper::VisitFriendDecl(FriendDecl *D) {
+  if (TypeSourceInfo *T = D->getFriendType())
+    dumpType(T->getType());
+  else
+    dumpDecl(D->getFriendDecl());
+}
+
+//===----------------------------------------------------------------------===//
+// Obj-C Declarations
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitObjCIvarDecl(ObjCIvarDecl *D) {
+  dumpName(D);
+  dumpType(D->getType());
+  if (D->getSynthesize())
+    OS << " synthesize";
+
+  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(ObjCMethodDecl *D) {
+  if (D->isInstanceMethod())
+    OS << " -";
+  else
+    OS << " +";
+  dumpName(D);
+  dumpType(D->getResultType());
+
+  if (D->isThisDeclarationADefinition())
+    dumpDeclContext(D);
+  else {
+    for (ObjCMethodDecl::param_iterator I = D->param_begin(),
+         E = D->param_end(); I != E; ++I) {
+      dumpDecl(*I);
+    }
+  }
+
+  if (D->isVariadic()) {
+    IndentScope Indent(*this);
+    OS << "...";
+  }
+
+  if (D->hasBody())
+    dumpStmt(D->getBody());
+}
+
+void ASTDumper::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
+  dumpName(D);
+  dumpDeclRef(D->getClassInterface());
+  dumpDeclRef(D->getImplementation());
+  for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
+       E = D->protocol_end(); I != E; ++I)
+    dumpDeclRef(*I);
+}
+
+void ASTDumper::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+  dumpName(D);
+  dumpDeclRef(D->getClassInterface());
+  dumpDeclRef(D->getCategoryDecl());
+}
+
+void ASTDumper::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
+  dumpName(D);
+  for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(),
+       E = D->protocol_end(); I != E; ++I)
+    dumpDeclRef(*I);
+}
+
+void ASTDumper::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+  dumpName(D);
+  dumpDeclRef(D->getSuperClass(), "super");
+  dumpDeclRef(D->getImplementation());
+  for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(),
+       E = D->protocol_end(); I != E; ++I)
+    dumpDeclRef(*I);
+}
+
+void ASTDumper::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+  dumpName(D);
+  dumpDeclRef(D->getSuperClass(), "super");
+  dumpDeclRef(D->getClassInterface());
+  for (ObjCImplementationDecl::init_iterator I = D->init_begin(),
+       E = D->init_end(); I != E; ++I)
+    dumpCXXCtorInitializer(*I);
+}
+
+void ASTDumper::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) {
+  dumpName(D);
+  dumpDeclRef(D->getClassInterface());
+}
+
+void ASTDumper::VisitObjCPropertyDecl(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)
+      dumpDeclRef(D->getGetterMethodDecl(), "getter");
+    if (Attrs & ObjCPropertyDecl::OBJC_PR_setter)
+      dumpDeclRef(D->getSetterMethodDecl(), "setter");
+  }
+}
+
+void ASTDumper::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+  dumpName(D->getPropertyDecl());
+  if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize)
+    OS << " synthesize";
+  else
+    OS << " dynamic";
+  dumpDeclRef(D->getPropertyDecl());
+  dumpDeclRef(D->getPropertyIvarDecl());
+}
+
+void ASTDumper::VisitBlockDecl(BlockDecl *D) {
+  for (BlockDecl::param_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());
+  }
+
+  dumpStmt(D->getBody());
 }
 
 //===----------------------------------------------------------------------===//
@@ -300,25 +942,22 @@
     return;
   }
 
-  Visit(S);
+  StmtVisitor<ASTDumper>::Visit(S);
   for (Stmt::child_range CI = S->children(); CI; ++CI)
     dumpStmt(*CI);
 }
 
 void ASTDumper::VisitStmt(Stmt *Node) {
-  OS << Node->getStmtClassName() << " " << (const void *)Node;
-  dumpSourceRange(Node);
+  OS << Node->getStmtClassName();
+  dumpPointer(Node);
+  dumpSourceRange(Node->getSourceRange());
 }
 
 void ASTDumper::VisitDeclStmt(DeclStmt *Node) {
   VisitStmt(Node);
-  for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
-       DI != DE; ++DI) {
-    IndentScope Indent(*this);
-    Decl *D = *DI;
-    OS << (void*) D << " ";
-    dumpDecl(D);
-  }
+  for (DeclStmt::decl_iterator I = Node->decl_begin(), E = Node->decl_end();
+       I != E; ++I)
+    dumpDecl(*I);
 }
 
 void ASTDumper::VisitLabelStmt(LabelStmt *Node) {
@@ -328,8 +967,8 @@
 
 void ASTDumper::VisitGotoStmt(GotoStmt *Node) {
   VisitStmt(Node);
-  OS << " '" << Node->getLabel()->getName()
-     << "':" << (void*)Node->getLabel();
+  OS << " '" << Node->getLabel()->getName() << "'";
+  dumpPointer(Node->getLabel());
 }
 
 //===----------------------------------------------------------------------===//
@@ -338,7 +977,6 @@
 
 void ASTDumper::VisitExpr(Expr *Node) {
   VisitStmt(Node);
-  OS << ' ';
   dumpType(Node->getType());
 
   switch (Node->getValueKind()) {
@@ -405,10 +1043,10 @@
   VisitExpr(Node);
 
   OS << " ";
-  dumpDeclRef(Node->getDecl());
+  dumpBareDeclRef(Node->getDecl());
   if (Node->getDecl() != Node->getFoundDecl()) {
     OS << " (";
-    dumpDeclRef(Node->getFoundDecl());
+    dumpBareDeclRef(Node->getFoundDecl());
     OS << ")";
   }
 }
@@ -425,15 +1063,15 @@
   if (I == E)
     OS << " empty";
   for (; I != E; ++I)
-    OS << " " << (void*) *I;
+    dumpPointer(*I);
 }
 
 void ASTDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
   VisitExpr(Node);
 
   OS << " " << Node->getDecl()->getDeclKindName()
-     << "Decl='" << *Node->getDecl()
-     << "' " << (void*)Node->getDecl();
+     << "Decl='" << *Node->getDecl() << "'";
+  dumpPointer(Node->getDecl());
   if (Node->isFreeIvar())
     OS << " isFreeIvar";
 }
@@ -482,13 +1120,13 @@
   VisitExpr(Node);
   switch(Node->getKind()) {
   case UETT_SizeOf:
-    OS << " sizeof ";
+    OS << " sizeof";
     break;
   case UETT_AlignOf:
-    OS << " alignof ";
+    OS << " alignof";
     break;
   case UETT_VecStep:
-    OS << " vec_step ";
+    OS << " vec_step";
     break;
   }
   if (Node->isArgumentType())
@@ -497,9 +1135,8 @@
 
 void ASTDumper::VisitMemberExpr(MemberExpr *Node) {
   VisitExpr(Node);
-  OS << " " << (Node->isArrow() ? "->" : ".")
-     << *Node->getMemberDecl() << ' '
-     << (void*)Node->getMemberDecl();
+  OS << " " << (Node->isArrow() ? "->" : ".") << *Node->getMemberDecl();
+  dumpPointer(Node->getMemberDecl());
 }
 
 void ASTDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
@@ -516,36 +1153,14 @@
   VisitExpr(Node);
   OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode())
      << "' ComputeLHSTy=";
-  dumpType(Node->getComputationLHSType());
+  dumpBareType(Node->getComputationLHSType());
   OS << " ComputeResultTy=";
-  dumpType(Node->getComputationResultType());
+  dumpBareType(Node->getComputationResultType());
 }
 
 void ASTDumper::VisitBlockExpr(BlockExpr *Node) {
   VisitExpr(Node);
-
-  BlockDecl *block = Node->getBlockDecl();
-  OS << " decl=" << block;
-
-  if (block->capturesCXXThis()) {
-    IndentScope Indent(*this);
-    OS << "capture this";
-  }
-  for (BlockDecl::capture_iterator
-         i = block->capture_begin(), e = block->capture_end(); i != e; ++i) {
-    IndentScope Indent(*this);
-    OS << "capture ";
-    if (i->isByRef())
-      OS << "byref ";
-    if (i->isNested())
-      OS << "nested ";
-    if (i->getVariable())
-      dumpDeclRef(i->getVariable());
-    if (i->hasCopyExpr())
-      dumpStmt(i->getCopyExpr());
-  }
-
-  dumpStmt(block->getBody());
+  dumpDecl(Node->getBlockDecl());
 }
 
 void ASTDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
@@ -559,8 +1174,8 @@
 
 void ASTDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
   VisitExpr(Node);
-  OS << " " << Node->getLabel()->getName()
-     << " " << (void*)Node->getLabel();
+  OS << " " << Node->getLabel()->getName();
+  dumpPointer(Node->getLabel());
 }
 
 //===----------------------------------------------------------------------===//
@@ -610,15 +1225,14 @@
 
 void ASTDumper::VisitExprWithCleanups(ExprWithCleanups *Node) {
   VisitExpr(Node);
-  for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) {
-    IndentScope Indent(*this);
-    OS << "cleanup ";
-    dumpDeclRef(Node->getObject(i));
-  }
+  for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)
+    dumpDeclRef(Node->getObject(i), "cleanup");
 }
 
 void ASTDumper::dumpCXXTemporary(CXXTemporary *Temporary) {
-  OS << "(CXXTemporary " << (void *)Temporary << ")";
+  OS << "(CXXTemporary";
+  dumpPointer(Temporary);
+  OS << ")";
 }
 
 //===----------------------------------------------------------------------===//
@@ -634,7 +1248,7 @@
 
   case ObjCMessageExpr::Class:
     OS << " class=";
-    dumpType(Node->getClassReceiver());
+    dumpBareType(Node->getClassReceiver());
     break;
 
   case ObjCMessageExpr::SuperInstance:
@@ -654,17 +1268,14 @@
 
 void ASTDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) {
   VisitStmt(Node);
-  if (VarDecl *CatchParam = Node->getCatchParamDecl()) {
-    OS << " catch parm = ";
+  if (VarDecl *CatchParam = Node->getCatchParamDecl())
     dumpDecl(CatchParam);
-  } else {
+  else
     OS << " catch all";
-  }
 }
 
 void ASTDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
   VisitExpr(Node);
-  OS << " ";
   dumpType(Node->getEncodedType());
 }
 
@@ -738,6 +1349,19 @@
 }
 
 //===----------------------------------------------------------------------===//
+// Decl method implementations
+//===----------------------------------------------------------------------===//
+
+void Decl::dump() const {
+  dump(llvm::errs());
+}
+
+void Decl::dump(raw_ostream &OS) const {
+  ASTDumper P(&getASTContext().getSourceManager(), OS);
+  P.dumpDecl(const_cast<Decl*>(this));
+}
+
+//===----------------------------------------------------------------------===//
 // Stmt method implementations
 //===----------------------------------------------------------------------===//