I've converted the tests to use FileCheck, and I think they've turned out to 
be simpler and more stable. I've tried to make the tests more focused, so there 
should only need to be a couple of tests for the indentation and source 
locations.

  Adding an -ast-dump-depth option would make these tests even simpler, so that 
each test only checks a node and the presence of its immediate children. This 
option might be generally useful too. It's currently half implemented for Stmts.

  I've also fixed all the existing tests that use -ast-dump.

  test/Tooling/clang-check-ast-dump.cpp needs attribute dumping, so I've added 
an incomplete version of that which only dumps the attribute kind.

  This update also includes the IndentScope class.

  If we're happy this is going in the right direction, should I start splitting 
this up into a proper patchset and submitting pieces as I go?

Hi alexfh, doug.gregor,

http://llvm-reviews.chandlerc.com/D52

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D52?vs=141&id=151#toc

Files:
  include/clang/AST/Stmt.h
  lib/AST/ASTDumper.cpp
  lib/AST/ASTDumper.h
  lib/AST/CMakeLists.txt
  lib/AST/DeclDumper.cpp
  lib/AST/DeclPrinter.cpp
  lib/AST/StmtDumper.cpp
  lib/Frontend/ASTConsumers.cpp
  test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp
  test/CodeGen/bitfield-2.c
  test/Misc/ast-dump-decl.c
  test/Misc/ast-dump-stmt.c
  test/Misc/ast-dump-templates.cpp
  test/Misc/ast-dump-wchar.cpp
  test/PCH/objc_stmts.m
  test/SemaTemplate/default-expr-arguments-2.cpp
  test/Tooling/clang-check-ast-dump.cpp
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -360,17 +360,12 @@
   static void EnableStatistics();
   static void PrintStats();
 
-  /// dump - This does a local dump of the specified AST fragment.  It dumps the
-  /// specified node and a few nodes underneath it, but not the whole subtree.
+  /// dump - This does a dump of the specified AST fragment and all subtrees.
   /// This is useful in a debugger.
   LLVM_ATTRIBUTE_USED void dump() const;
   LLVM_ATTRIBUTE_USED void dump(SourceManager &SM) const;
   void dump(raw_ostream &OS, SourceManager &SM) const;
 
-  /// dumpAll - This does a dump of the specified AST fragment and all subtrees.
-  void dumpAll() const;
-  void dumpAll(SourceManager &SM) const;
-
   /// dumpPretty/printPretty - These two methods do a "pretty print" of the AST
   /// back to its original source language syntax.
   void dumpPretty(ASTContext &Context) const;
Index: lib/AST/ASTDumper.cpp
===================================================================
--- /dev/null
+++ lib/AST/ASTDumper.cpp
@@ -0,0 +1,111 @@
+//===--- 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 defines the ASTDumper class, which dumps out the
+// AST in a form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTDumper.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+void ASTDumper::flush() {
+  if (NeedNewLine)
+    OS << "\n";
+  NeedNewLine = false;
+}
+
+void ASTDumper::indent() {
+  if (NeedNewLine)
+    OS << "\n";
+
+  NeedNewLine = true;
+  for (int i = 0, e = IndentLevel; i < e; ++i)
+    OS << "  ";
+  OS << "(";
+  IndentLevel++;
+}
+
+void ASTDumper::unindent() {
+  OS << ")";
+  IndentLevel--;
+}
+
+void ASTDumper::dumpAttrs(AttrVec &Attrs) {
+  for (AttrVec::const_iterator I=Attrs.begin(), E=Attrs.end(); I != E; ++I) {
+    IndentScope Indent(*this);
+    Attr *A = *I;
+    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" << " " << (const void*)A;
+    dumpSourceRange(A->getRange());
+    // FIXME: implement attribute dumping in a similar manner to serialization
+  }
+}
+
+void ASTDumper::dumpType(QualType T) {
+  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::dumpLocation(SourceLocation Loc) {
+  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 == 0)
+    return;
+
+  // TODO: If the parent expression is available, we can print a delta vs its
+  // location.
+
+  OS << " <";
+  dumpLocation(R.getBegin());
+  if (R.getBegin() != R.getEnd()) {
+    OS << ", ";
+    dumpLocation(R.getEnd());
+  }
+  OS << ">";
+}
Index: lib/AST/ASTDumper.h
===================================================================
--- /dev/null
+++ lib/AST/ASTDumper.h
@@ -0,0 +1,78 @@
+//===--- ASTDumper.h - Dumping implementation for ASTs ----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ASTDumper class, which dumps out the
+// AST in a form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_ASTDUMPER_H
+#define LLVM_CLANG_AST_ASTDUMPER_H
+
+#include "clang/AST/Attr.h"
+#include "clang/Basic/LLVM.h"
+
+namespace clang {
+
+class SourceManager;
+class SourceRange;
+class SourceLocation;
+class QualType;
+class Decl;
+class Stmt;
+
+class ASTDumper {
+public:
+  ASTDumper(SourceManager *SM, raw_ostream &OS)
+    : SM(SM), OS(OS), IndentLevel(0), LastLocFilename(""), LastLocLine(~0U),
+    NeedNewLine(false) {
+  }
+  ~ASTDumper() {
+    flush();
+  }
+
+  void flush();
+  void indent();
+  void unindent();
+
+  class IndentScope {
+    ASTDumper &Dumper;
+  public:
+    IndentScope(ASTDumper &Dumper) : Dumper(Dumper) {
+      Dumper.indent();
+    }
+    ~IndentScope() {
+      Dumper.unindent();
+    }
+  };
+
+  void dumpDecl(Decl *D);
+  void dumpStmt(Stmt *S);
+  void dumpType(QualType T);
+  void dumpAttrs(AttrVec &Attrs);
+  void dumpSourceRange(SourceRange R);
+
+private:
+  void dumpLocation(SourceLocation Loc);
+
+  SourceManager *SM;
+  raw_ostream &OS;
+  unsigned IndentLevel;
+
+  /// LastLocFilename/LastLocLine - 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;
+
+  bool NeedNewLine;
+};
+
+}
+
+#endif
Index: lib/AST/CMakeLists.txt
===================================================================
--- lib/AST/CMakeLists.txt
+++ lib/AST/CMakeLists.txt
@@ -5,6 +5,7 @@
   ASTConsumer.cpp
   ASTContext.cpp
   ASTDiagnostic.cpp
+  ASTDumper.cpp
   ASTImporter.cpp
   AttrImpl.cpp
   CXXInheritance.cpp
@@ -19,6 +20,7 @@
   DeclarationName.cpp
   DeclBase.cpp
   DeclCXX.cpp
+  DeclDumper.cpp
   DeclFriend.cpp
   DeclGroup.cpp
   DeclObjC.cpp
Index: lib/AST/DeclDumper.cpp
===================================================================
--- /dev/null
+++ lib/AST/DeclDumper.cpp
@@ -0,0 +1,114 @@
+//===--- DeclDumper.cpp - Dumping implementation for Decl 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 Decl::dump method, which dumps out the
+// AST in a form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+#include "ASTDumper.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+namespace {
+  class DeclDumper : public DeclVisitor<DeclDumper> {
+    ASTDumper &Dumper;
+    raw_ostream &OS;
+
+  public:
+    DeclDumper(ASTDumper &Dumper, raw_ostream &OS)
+      : Dumper(Dumper), OS(OS) {
+    }
+
+    void dumpDecl(Decl *D);
+    void dumpDeclContext(DeclContext *DC);
+
+    void VisitEnumConstantDecl(EnumConstantDecl *D);
+    void VisitFunctionDecl(FunctionDecl *D);
+    void VisitFieldDecl(FieldDecl *D);
+    void VisitVarDecl(VarDecl *D);
+  };
+}
+
+void DeclDumper::dumpDecl(Decl *D) {
+  ASTDumper::IndentScope Indent(Dumper);
+  if (D) {
+    OS << D->getDeclKindName() << "Decl"
+       << " " << (const void*)D;
+    Dumper.dumpSourceRange(D->getSourceRange());
+    if (isa<NamedDecl>(D))
+      OS << " " << cast<NamedDecl>(D)->getNameAsString();
+    Visit(D);
+    if (D->hasAttrs())
+      Dumper.dumpAttrs(D->getAttrs());
+    dumpDeclContext(dyn_cast<DeclContext>(D));
+  } else {
+    OS << "<<<NULL>>>";
+  }
+}
+
+void DeclDumper::dumpDeclContext(DeclContext *DC) {
+  // Decls within functions are visited by the body
+  if (!DC || isa<FunctionDecl>(*DC))
+    return;
+
+  for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end();
+       D != DEnd; ++D)
+    dumpDecl(*D);
+}
+
+//----------------------------------------------------------------------------
+// Common C declarations
+//----------------------------------------------------------------------------
+
+void DeclDumper::VisitEnumConstantDecl(EnumConstantDecl *D) {
+  if (Expr *Init = D->getInitExpr())
+    Dumper.dumpStmt(Init);
+}
+
+void DeclDumper::VisitFunctionDecl(FunctionDecl *D) {
+  OS << ' ';
+  Dumper.dumpType(D->getType());
+  if (D->doesThisDeclarationHaveABody())
+    Dumper.dumpStmt(D->getBody());
+}
+
+void DeclDumper::VisitFieldDecl(FieldDecl *D) {
+  if (Expr *Init = D->getInClassInitializer())
+    Dumper.dumpStmt(Init);
+}
+
+void DeclDumper::VisitVarDecl(VarDecl *D) {
+  OS << ' ';
+  Dumper.dumpType(D->getType());
+  if (Expr *Init = D->getInit())
+    Dumper.dumpStmt(Init);
+}
+
+//===----------------------------------------------------------------------===//
+// Decl method implementations
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::dumpDecl(Decl *D) {
+  DeclDumper Dumper(*this, OS);
+  Dumper.dumpDecl(D);
+}
+
+void Decl::dump(raw_ostream &OS) const {
+  ASTDumper Dumper(&getASTContext().getSourceManager(), OS);
+  Dumper.dumpDecl(const_cast<Decl*>(this));
+}
+
+void Decl::dump() const {
+  dump(llvm::errs());
+}
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -7,7 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file implements the Decl::dump method, which pretty print the
+// This file implements the Decl::print method, which pretty prints the
 // AST back out to C/Objective-C/C++/Objective-C++ code.
 //
 //===----------------------------------------------------------------------===//
@@ -172,16 +172,6 @@
   Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false);
 }
 
-void Decl::dump() const {
-  dump(llvm::errs());
-}
-
-void Decl::dump(raw_ostream &Out) const {
-  PrintingPolicy Policy = getASTContext().getPrintingPolicy();
-  Policy.DumpSourceManager = &getASTContext().getSourceManager();
-  print(Out, Policy, /*Indentation*/ 0, /*PrintInstantiation*/ true);
-}
-
 raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
   for (unsigned i = 0; i != Indentation; ++i)
     Out << "  ";
Index: lib/AST/StmtDumper.cpp
===================================================================
--- lib/AST/StmtDumper.cpp
+++ lib/AST/StmtDumper.cpp
@@ -7,17 +7,15 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file implements the Stmt::dump/Stmt::print methods, which dump out the
+// This file implements the Stmt::dump method, which dumps out the
 // AST in a form that exposes type details and other fields.
 //
 //===----------------------------------------------------------------------===//
 
+#include "ASTDumper.h"
 #include "clang/AST/StmtVisitor.h"
-#include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclCXX.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "clang/Basic/SourceManager.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
 
@@ -27,79 +25,37 @@
 
 namespace  {
   class StmtDumper : public StmtVisitor<StmtDumper> {
-    SourceManager *SM;
+    ASTDumper &Dumper;
     raw_ostream &OS;
-    unsigned IndentLevel;
-
-    /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump
-    /// the first few levels of an AST.  This keeps track of how many ast levels
-    /// are left.
-    unsigned MaxDepth;
-
-    /// LastLocFilename/LastLocLine - 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;
 
   public:
-    StmtDumper(SourceManager *sm, raw_ostream &os, unsigned maxDepth)
-      : SM(sm), OS(os), IndentLevel(0-1), MaxDepth(maxDepth) {
-      LastLocFilename = "";
-      LastLocLine = ~0U;
+    StmtDumper(ASTDumper &Dumper, raw_ostream &OS)
+      : Dumper(Dumper), OS(OS) {
     }
 
     void DumpSubTree(Stmt *S) {
-      // Prune the recursion if not using dump all.
-      if (MaxDepth == 0) return;
-
-      ++IndentLevel;
+      ASTDumper::IndentScope Indent(Dumper);
       if (S) {
         if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
           VisitDeclStmt(DS);
         else {
           Visit(S);
-
-          // Print out children.
-          Stmt::child_range CI = S->children();
-          if (CI) {
-            while (CI) {
-              OS << '\n';
-              DumpSubTree(*CI++);
-            }
-          }
+          for (Stmt::child_range CI = S->children(); CI; CI++)
+            DumpSubTree(*CI);
         }
-        OS << ')';
       } else {
-        Indent();
         OS << "<<<NULL>>>";
       }
-      --IndentLevel;
-    }
-
-    void DumpDeclarator(Decl *D);
-
-    void Indent() const {
-      for (int i = 0, e = IndentLevel; i < e; ++i)
-        OS << "  ";
     }
 
     void DumpType(QualType T) {
-      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) << "'";
-      }
+      Dumper.dumpType(T);
     }
     void DumpDeclRef(Decl *node);
     void DumpStmt(const Stmt *Node) {
-      Indent();
-      OS << "(" << Node->getStmtClassName()
+      OS << Node->getStmtClassName()
          << " " << (const void*)Node;
-      DumpSourceRange(Node);
+      Dumper.dumpSourceRange(Node->getSourceRange());
     }
     void DumpValueKind(ExprValueKind K) {
       switch (K) {
@@ -124,8 +80,6 @@
       DumpValueKind(Node->getValueKind());
       DumpObjectKind(Node->getObjectKind());
     }
-    void DumpSourceRange(const Stmt *Node);
-    void DumpLocation(SourceLocation Loc);
 
     // Stmts.
     void VisitStmt(Stmt *Node);
@@ -178,146 +132,18 @@
 }
 
 //===----------------------------------------------------------------------===//
-//  Utilities
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::DumpLocation(SourceLocation Loc) {
-  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 StmtDumper::DumpSourceRange(const Stmt *Node) {
-  // Can't translate locations if a SourceManager isn't available.
-  if (SM == 0) 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()) {
-    OS << ", ";
-    DumpLocation(R.getEnd());
-  }
-  OS << ">";
-
-  // <t2.c:123:421[blah], t2.c:412:321>
-
-}
-
-
-//===----------------------------------------------------------------------===//
 //  Stmt printing methods.
 //===----------------------------------------------------------------------===//
 
 void StmtDumper::VisitStmt(Stmt *Node) {
   DumpStmt(Node);
 }
 
-void StmtDumper::DumpDeclarator(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())
-           << " ";
-    }
-
-    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 << " =\n";
-        DumpSubTree(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(\n";
-    DumpSubTree(SAD->getAssertExpr());
-    OS << ",\n";
-    DumpSubTree(SAD->getMessage());
-    OS << ");\"";
-  } else {
-    llvm_unreachable("Unexpected decl");
-  }
-}
-
 void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
   DumpStmt(Node);
-  OS << "\n";
   for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
-       DI != DE; ++DI) {
-    Decl* D = *DI;
-    ++IndentLevel;
-    Indent();
-    OS << (void*) D << " ";
-    DumpDeclarator(D);
-    if (DI+1 != DE)
-      OS << "\n";
-    --IndentLevel;
-  }
+       DI != DE; ++DI)
+    Dumper.dumpDecl(*DI);
 }
 
 void StmtDumper::VisitLabelStmt(LabelStmt *Node) {
@@ -503,35 +329,29 @@
   BlockDecl *block = Node->getBlockDecl();
   OS << " decl=" << block;
 
-  IndentLevel++;
   if (block->capturesCXXThis()) {
-    OS << '\n'; Indent(); OS << "(capture this)";
+    ASTDumper::IndentScope Indent(Dumper);
+    OS << "capture this";
   }
   for (BlockDecl::capture_iterator
          i = block->capture_begin(), e = block->capture_end(); i != e; ++i) {
-    OS << '\n';
-    Indent();
-    OS << "(capture ";
+    ASTDumper::IndentScope Indent(Dumper);
+    OS << "capture ";
     if (i->isByRef()) OS << "byref ";
     if (i->isNested()) OS << "nested ";
     if (i->getVariable())
       DumpDeclRef(i->getVariable());
     if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr());
-    OS << ")";
   }
-  IndentLevel--;
 
-  OS << '\n';
   DumpSubTree(block->getBody());
 }
 
 void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
   DumpExpr(Node);
 
-  if (Expr *Source = Node->getSourceExpr()) {
-    OS << '\n';
+  if (Expr *Source = Node->getSourceExpr())
     DumpSubTree(Source);
-  }
 }
 
 // GNU extensions.
@@ -589,15 +409,11 @@
 
 void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) {
   DumpExpr(Node);
-  ++IndentLevel;
   for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) {
-    OS << "\n";
-    Indent();
-    OS << "(cleanup ";
+    ASTDumper::IndentScope Indent(Dumper);
+    OS << "cleanup ";
     DumpDeclRef(Node->getObject(i));
-    OS << ")";
   }
-  --IndentLevel;
 }
 
 void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) {
@@ -638,8 +454,7 @@
 void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) {
   DumpStmt(Node);
   if (VarDecl *CatchParam = Node->getCatchParamDecl()) {
-    OS << " catch parm = ";
-    DumpDeclarator(CatchParam);
+    Dumper.dumpDecl(CatchParam);
   } else {
     OS << " catch all";
   }
@@ -724,38 +539,24 @@
 // Stmt method implementations
 //===----------------------------------------------------------------------===//
 
-/// dump - This does a local dump of the specified AST fragment.  It dumps the
-/// specified node and a few nodes underneath it, but not the whole subtree.
-/// This is useful in a debugger.
+void ASTDumper::dumpStmt(Stmt *S) {
+  StmtDumper P(*this, OS);
+  P.DumpSubTree(S);
+}
+
+/// \brief This does a dump of the specified AST fragment and all subtrees.
 void Stmt::dump(SourceManager &SM) const {
   dump(llvm::errs(), SM);
 }
 
+/// \brief This does a dump of the specified AST fragment and all subtrees.
 void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
-  StmtDumper P(&SM, OS, 4);
-  P.DumpSubTree(const_cast<Stmt*>(this));
-  OS << "\n";
+  ASTDumper Dumper(&SM, OS);
+  Dumper.dumpStmt(const_cast<Stmt*>(this));
 }
 
-/// dump - This does a local dump of the specified AST fragment.  It dumps the
-/// specified node and a few nodes underneath it, but not the whole subtree.
-/// This is useful in a debugger.
+/// \brief This does a dump of the specified AST fragment and all subtrees.
 void Stmt::dump() const {
-  StmtDumper P(0, llvm::errs(), 4);
-  P.DumpSubTree(const_cast<Stmt*>(this));
-  llvm::errs() << "\n";
-}
-
-/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
-void Stmt::dumpAll(SourceManager &SM) const {
-  StmtDumper P(&SM, llvm::errs(), ~0U);
-  P.DumpSubTree(const_cast<Stmt*>(this));
-  llvm::errs() << "\n";
-}
-
-/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
-void Stmt::dumpAll() const {
-  StmtDumper P(0, llvm::errs(), ~0U);
-  P.DumpSubTree(const_cast<Stmt*>(this));
-  llvm::errs() << "\n";
+  ASTDumper Dumper(0, llvm::errs());
+  Dumper.dumpStmt(const_cast<Stmt*>(this));
 }
Index: lib/Frontend/ASTConsumers.cpp
===================================================================
--- lib/Frontend/ASTConsumers.cpp
+++ lib/Frontend/ASTConsumers.cpp
@@ -62,8 +62,9 @@
         return false;
       if (filterMatches(D)) {
         Out.changeColor(llvm::raw_ostream::BLUE) <<
-            (Dump ? "Dumping " : "Printing ") << getName(D) << ":\n";
+            (Dump ? "Dumping " : "Printing ") << getName(D) << ":";
         Out.resetColor();
+        Out << "\n";
         if (Dump)
           D->dump(Out);
         else
Index: test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp
===================================================================
--- test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp
+++ test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp
@@ -3,10 +3,10 @@
 // CHECK: example0
 void example0() {
   double d = 2.0;
-  // CHECK: double &rd =
+  // CHECK: VarDecl{{.*}}rd 'double &'
   // CHECK-NEXT: DeclRefExpr
   double &rd = d;
-  // CHECK: const double &rcd =
+  // CHECK: VarDecl{{.*}}rcd 'const double &'
   // CHECK-NEXT: ImplicitCastExpr{{.*}}'const double' lvalue <NoOp>
   const double &rcd = d;
 }
@@ -16,10 +16,10 @@
 
 // CHECK: example1
 void example1() {
-  // CHECK: A &ra =
+  // CHECK: VarDecl{{.*}}ra 'struct A &'
   // CHECK: ImplicitCastExpr{{.*}}'struct A' lvalue <DerivedToBase (A)>
   A &ra = b;
-  // CHECK: const A &rca =
+  // CHECK: VarDecl{{.*}}rca 'const struct A &'
   // CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue <NoOp>
   // CHECK: ImplicitCastExpr{{.*}}'struct A' lvalue <DerivedToBase (A)>
   const A& rca = b;
@@ -33,21 +33,21 @@
 
 // CHECK: example2
 void example2() {
-  // CHECK: const A &rca =
+  // CHECK: VarDecl{{.*}}rca 'const struct A &'
   // CHECK: ImplicitCastExpr{{.*}}'const struct A' <NoOp>
   // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)>
   // CHECK: CallExpr{{.*}}B
   const A &rca = f(); 
-  // CHECK: const A &r =
+  // CHECK: VarDecl{{.*}}r 'const struct A &'
   // CHECK: ImplicitCastExpr{{.*}}'const struct A' <NoOp>
   // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)>
   // CHECK: CXXMemberCallExpr{{.*}}'struct B'
   const A& r = x;
 }
 
 // CHECK: example3
 void example3() {
-  // CHECK: const double &rcd2 =
+  // CHECK: VarDecl{{.*}}rcd2 'const double &'
   // CHECK: ImplicitCastExpr{{.*}} <IntegralToFloating>
   const double& rcd2 = 2; 
 }
Index: test/CodeGen/bitfield-2.c
===================================================================
--- test/CodeGen/bitfield-2.c
+++ test/CodeGen/bitfield-2.c
@@ -9,7 +9,7 @@
 // PR6176
 
 // CHECK-RECORD: *** Dumping IRgen Record Layout
-// CHECK-RECORD: Record: struct s0
+// CHECK-RECORD: Record: (RecordDecl{{.*}}s0
 // CHECK-RECORD: Layout: <CGRecordLayout
 // CHECK-RECORD:   LLVMType:%struct.s0 = type <{ [3 x i8] }>
 // CHECK-RECORD:   IsZeroInitializable:1
@@ -54,7 +54,7 @@
 // PR5591
 
 // CHECK-RECORD: *** Dumping IRgen Record Layout
-// CHECK-RECORD: Record: struct s1
+// CHECK-RECORD: Record: (RecordDecl{{.*}}s1
 // CHECK-RECORD: Layout: <CGRecordLayout
 // CHECK-RECORD:   LLVMType:%struct.s1 = type <{ [2 x i8], i8 }>
 // CHECK-RECORD:   IsZeroInitializable:1
@@ -111,7 +111,7 @@
 // PR5567
 
 // CHECK-RECORD: *** Dumping IRgen Record Layout
-// CHECK-RECORD: Record: union u2
+// CHECK-RECORD: Record: (RecordDecl{{.*}}u2
 // CHECK-RECORD: Layout: <CGRecordLayout
 // CHECK-RECORD:   LLVMType:%union.u2 = type <{ i8 }>
 // CHECK-RECORD:   IsZeroInitializable:1
@@ -286,7 +286,7 @@
 // Check that we compute the best alignment possible for each access.
 //
 // CHECK-RECORD: *** Dumping IRgen Record Layout
-// CHECK-RECORD: Record: struct s7
+// CHECK-RECORD: Record: (RecordDecl{{.*}}s7
 // CHECK-RECORD: Layout: <CGRecordLayout
 // CHECK-RECORD:   LLVMType:%struct.s7 = type { i32, i32, i32, i8, [3 x i8], [4 x i8], [12 x i8] }
 // CHECK-RECORD:   IsZeroInitializable:1
Index: test/Misc/ast-dump-decl.c
===================================================================
--- /dev/null
+++ test/Misc/ast-dump-decl.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s
+
+int TestLocation;
+// CHECK: VarDecl 0x{{[^ ]*}} <{{.*}}:3:1, col:5> TestLocation
+
+struct TestIndent {
+  int x;
+};
+// CHECK:      {{^}}(RecordDecl{{.*}}TestIndent{{[^()]*$}}
+// CHECK-NEXT: {{^  }}(FieldDecl{{.*}}x{{[^()]*}})){{$}}
+
+int TestFunctionDecl(int x) {
+  return x;
+}
+// CHECK:      FunctionDecl{{.*}}TestFunctionDecl 'int (int)'
+// CHECK-NEXT:   CompoundStmt
+
+int TestVarDecl = 0;
+// CHECK:      VarDecl{{.*}}TestVarDecl 'int'
+// CHECK-NEXT:   IntegerLiteral
+
Index: test/Misc/ast-dump-stmt.c
===================================================================
--- /dev/null
+++ test/Misc/ast-dump-stmt.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s
+
+int TestLocation = 0;
+// CHECK:      VarDecl{{.*}}TestLocation
+// CHECK-NEXT:   IntegerLiteral 0x{{[^ ]*}} <col:20> 'int' 0
+
+int TestIndent = 0;
+// CHECK:      {{^}}(VarDecl{{.*}}TestIndent{{[^()]*$}}
+// CHECK-NEXT: {{^  }}(IntegerLiteral{{.*}}0{{[^()]*}})){{$}}
+
+void TestDeclStmt() {
+// CHECK: FunctionDecl{{.*}}TestDeclStmt
+
+  int x;
+// CHECK:      DeclStmt
+// CHECK-NEXT:   VarDecl{{.*}}x
+
+  int y, z;
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT:   VarDecl{{.*}}y
+// CHECK-NEXT:   VarDecl{{.*}}z
+}
Index: test/Misc/ast-dump-templates.cpp
===================================================================
--- test/Misc/ast-dump-templates.cpp
+++ test/Misc/ast-dump-templates.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -ast-dump %s > %t
+// RUN: %clang_cc1 -ast-print %s > %t
 // RUN: FileCheck < %t %s -check-prefix=CHECK1
 // RUN: FileCheck < %t %s -check-prefix=CHECK2
 
@@ -27,8 +27,8 @@
 // CHECK2: template <int X = 2, typename Y = double, int Z = 3> struct foo {
 
 // Template definition - foo
-// CHECK1: template <int X, typename Y, int Z = (IntegerLiteral {{.*}} 'int' 5)
-// CHECK2: template <int X, typename Y, int Z = (IntegerLiteral {{.*}} 'int' 5)
+// CHECK1: template <int X, typename Y, int Z = 5> struct foo {
+// CHECK2: template <int X, typename Y, int Z = 5> struct foo {
 
 // Template instantiation - bar
 // CHECK1: template <int A = 5, typename B = int> int bar()
Index: test/Misc/ast-dump-wchar.cpp
===================================================================
--- test/Misc/ast-dump-wchar.cpp
+++ test/Misc/ast-dump-wchar.cpp
@@ -1,13 +1,13 @@
 // RUN: %clang_cc1 -std=c++11 -ast-dump %s -triple x86_64-linux-gnu | FileCheck %s 
 
 char c8[] = u8"test\0\\\"\t\a\b\234";
-// CHECK: char c8[12] = (StringLiteral {{.*}} lvalue u8"test\000\\\"\t\a\b\234")
+// CHECK: (StringLiteral {{.*}} lvalue u8"test\000\\\"\t\a\b\234")
 
 char16_t c16[] = u"test\0\\\"\t\a\b\234\u1234";
-// CHECK: char16_t c16[13] = (StringLiteral {{.*}} lvalue u"test\000\\\"\t\a\b\234\u1234")
+// CHECK: (StringLiteral {{.*}} lvalue u"test\000\\\"\t\a\b\234\u1234")
 
 char32_t c32[] = U"test\0\\\"\t\a\b\234\u1234\U0010ffff"; // \
-// CHECK: char32_t c32[14] = (StringLiteral {{.*}} lvalue U"test\000\\\"\t\a\b\234\u1234\U0010FFFF")
+// CHECK: (StringLiteral {{.*}} lvalue U"test\000\\\"\t\a\b\234\u1234\U0010FFFF")
 
 wchar_t wc[] = L"test\0\\\"\t\a\b\234\u1234\xffffffff"; // \
-// CHECK: wchar_t wc[14] = (StringLiteral {{.*}} lvalue L"test\000\\\"\t\a\b\234\x1234\xFFFFFFFF")
+// CHECK: (StringLiteral {{.*}} lvalue L"test\000\\\"\t\a\b\234\x1234\xFFFFFFFF")
Index: test/PCH/objc_stmts.m
===================================================================
--- test/PCH/objc_stmts.m
+++ test/PCH/objc_stmts.m
@@ -1,12 +1,12 @@
 // Test this without pch.
 // RUN: %clang_cc1 -include %S/objc_stmts.h -emit-llvm -fobjc-exceptions -o - %s
-// RUN: %clang_cc1 -include %S/objc_stmts.h -ast-dump -fobjc-exceptions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -include %S/objc_stmts.h -ast-print -fobjc-exceptions -o - %s | FileCheck %s
 
 // Test with pch.
 // RUN: %clang_cc1 -x objective-c -emit-pch -fobjc-exceptions -o %t %S/objc_stmts.h
 // RUN: %clang_cc1 -include-pch %t -emit-llvm -fobjc-exceptions -o - %s 
-// RUN: %clang_cc1 -include-pch %t -ast-dump -fobjc-exceptions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -include-pch %t -ast-print -fobjc-exceptions -o - %s | FileCheck %s
 
-// CHECK: catch parm = "A *a"
-// CHECK: catch parm = "B *b"
-// CHECK: catch all
+// CHECK: @catch(A *a)
+// CHECK: @catch(B *b)
+// CHECK: @catch()
Index: test/SemaTemplate/default-expr-arguments-2.cpp
===================================================================
--- test/SemaTemplate/default-expr-arguments-2.cpp
+++ test/SemaTemplate/default-expr-arguments-2.cpp
@@ -10,9 +10,9 @@
     bar(int x = kSomeConst) {}
   };
   
-  // CHECK: void f()
+  // CHECK: FunctionDecl{{.*}}f 'void (void)'
   void f() {
-    // CHECK: bar<int> tmp =
+    // CHECK: VarDecl{{.*}}tmp 'bar<int>'
     // CHECK: CXXDefaultArgExpr{{.*}}'int'
     bar<int> tmp;
   }
Index: test/Tooling/clang-check-ast-dump.cpp
===================================================================
--- test/Tooling/clang-check-ast-dump.cpp
+++ test/Tooling/clang-check-ast-dump.cpp
@@ -1,14 +1,16 @@
 // RUN: clang-check -ast-dump "%s" -- 2>&1 | FileCheck %s
-// CHECK: namespace test_namespace
-// CHECK-NEXT: class TheClass
-// CHECK: int theMethod(int x) (CompoundStmt
+// CHECK: (NamespaceDecl{{.*}}test_namespace
+// CHECK-NEXT: (CXXRecordDecl{{.*}}TheClass
+// CHECK: (CXXMethodDecl{{.*}}theMethod
+// CHECK-NEXT: (CompoundStmt
 // CHECK-NEXT:   (ReturnStmt
 // CHECK-NEXT:     (BinaryOperator
 //
 // RUN: clang-check -ast-dump -ast-dump-filter test_namespace::TheClass::theMethod "%s" -- 2>&1 | FileCheck -check-prefix CHECK-FILTER %s
-// CHECK-FILTER-NOT: namespace test_namespace
-// CHECK-FILTER-NOT: class TheClass
-// CHECK-FILTER: int theMethod(int x) (CompoundStmt
+// CHECK-FILTER-NOT: (NamespaceDecl
+// CHECK-FILTER-NOT: (CXXRecordDecl
+// CHECK-FILTER: (CXXMethodDecl{{.*}}theMethod
+// CHECK-FILTER-NEXT: (CompoundStmt
 // CHECK-FILTER-NEXT:   (ReturnStmt
 // CHECK-FILTER-NEXT:     (BinaryOperator
 //
@@ -25,7 +27,9 @@
 //
 // RUN: clang-check -ast-dump -ast-dump-filter test_namespace::TheClass::n "%s" -- 2>&1 | FileCheck -check-prefix CHECK-ATTR %s
 // CHECK-ATTR: test_namespace
-// CHECK-ATTR-NEXT: int n __attribute__((aligned((BinaryOperator
+// CHECK-ATTR: (FieldDecl{{.*}}n
+// CHECK-ATTR-NEXT:   (AlignedAttr
+// FIXME: AlignedAttr should dump its expression
 
 namespace test_namespace {
 
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to