Fixup -ast-print so that:

  We handle indentation of decls better.
  We Indent extern "C" { } stuff better.
  We print out structure contents more often.
  We handle pass indentation information into the statement printer, so that
  nested things come out more indented.
  We print out FieldDecls.
  We print out Vars.
  We print out namespaces.
  We indent functions better.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64232 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Driver/ASTConsumers.cpp b/Driver/ASTConsumers.cpp
index 78b1996..c504f0f 100644
--- a/Driver/ASTConsumers.cpp
+++ b/Driver/ASTConsumers.cpp
@@ -34,12 +34,26 @@
   class DeclPrinter {
   public:
     llvm::raw_ostream& Out;
+    unsigned Indentation;
 
-    DeclPrinter(llvm::raw_ostream* out) : Out(out ? *out : llvm::errs()) {}
-    DeclPrinter() : Out(llvm::errs()) {}
+    DeclPrinter(llvm::raw_ostream* out) : Out(out ? *out : llvm::errs()),
+                                          Indentation(0) {}
+    DeclPrinter() : Out(llvm::errs()), Indentation(0) {}
     virtual ~DeclPrinter();
     
+    void ChangeIndent(int I) {
+      Indentation += I;
+    }
+    
+    llvm::raw_ostream& Indent() {
+      for (unsigned i = 0; i < Indentation; ++i)
+        Out << "  ";
+      return Out;
+    }
+
     void PrintDecl(Decl *D);
+    void Print(NamedDecl *ND);
+    void Print(NamespaceDecl *NS);
     void PrintFunctionDeclStart(FunctionDecl *FD);    
     void PrintTypeDefDecl(TypedefDecl *TD);    
     void PrintLinkageSpec(LinkageSpecDecl *LS);
@@ -62,12 +76,13 @@
 }
 
 void DeclPrinter:: PrintDecl(Decl *D) {
+  Indent();
   if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
     PrintFunctionDeclStart(FD);
 
     if (FD->getBody()) {
       Out << ' ';
-      FD->getBody()->printPretty(Out);
+      FD->getBody()->printPretty(Out, 0, Indentation, true);
       Out << '\n';
     }
   } else if (isa<ObjCMethodDecl>(D)) {
@@ -117,7 +132,23 @@
       Out << "  " << (*E)->getNameAsString() << ",\n";
     Out << "};\n";
   } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
-    Out << "Read top-level tag decl: '" << TD->getNameAsString() << "'\n";
+    // print a free standing tag decl (e.g. "struct x;"). 
+    Out << TD->getKindName();
+    Out << " ";
+    if (const IdentifierInfo *II = TD->getIdentifier())
+      Out << II->getName();
+
+    Out << " {\n";
+    ChangeIndent(1);
+    for (DeclContext::decl_iterator i = TD->decls_begin();
+         i != TD->decls_end();
+         ++i)
+      PrintDecl(*i);    
+    ChangeIndent(-1);
+    Indent();
+    Out << "}";
+
+    Out << "\n";
   } else if (TemplateDecl *TempD = dyn_cast<TemplateDecl>(D)) {
     PrintTemplateDecl(TempD);
   } else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
@@ -127,17 +158,61 @@
     AD->getAsmString()->printPretty(Out);
     Out << ")\n";
   } else if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
-    Out << "Read top-level variable decl: '" << ND->getNameAsString() << "'\n";
+    Print(ND);
   } else {
     assert(0 && "Unknown decl type!");
   }
 }
 
+void DeclPrinter::Print(NamedDecl *ND) {
+  switch (ND->getKind()) {
+  default:
+    // FIXME: Handle the rest of the NamedDecls.
+    Out << "### NamedDecl " << ND->getNameAsString() << "\n";
+    break;
+  case Decl::Field:
+  case Decl::Var: {
+    // Emit storage class for vardecls.
+    if (VarDecl *V = dyn_cast<VarDecl>(ND)) {
+      switch (V->getStorageClass()) {
+      default: assert(0 && "Unknown storage class!");
+      case VarDecl::None:     break;
+      case VarDecl::Extern:   Out << "extern "; break;
+      case VarDecl::Static:   Out << "static "; break; 
+      case VarDecl::Auto:     Out << "auto "; break;
+      case VarDecl::Register: Out << "register "; break;
+      }
+    }
+    std::string Name = ND->getNameAsString();
+    // This forms: "int a".
+    dyn_cast<ValueDecl>(ND)->getType().getAsStringInternal(Name);
+    Out << Name << ";\n";
+    break;
+  }
+  case Decl::Namespace:
+    Print(dyn_cast<NamespaceDecl>(ND));
+    break;
+  }
+}
+
+void DeclPrinter::Print(NamespaceDecl *NS) {
+  Out << "namespace " << NS->getNameAsString() << " {\n";
+  ChangeIndent(1);
+  for (DeclContext::decl_iterator i = NS->decls_begin();
+       i != NS->decls_end();
+       ++i)
+    PrintDecl(*i);    
+  ChangeIndent(-1);
+  Indent();
+  Out << "}\n";
+}
+
 void DeclPrinter::PrintFunctionDeclStart(FunctionDecl *FD) {
   bool HasBody = FD->getBody();
   
   Out << '\n';
 
+  Indent();
   switch (FD->getStorageClass()) {
   default: assert(0 && "Unknown storage class");
   case FunctionDecl::None: break;
@@ -198,16 +273,20 @@
   }
 
   Out << "extern \"" << l << "\" ";
-  if (LS->hasBraces()) 
+  if (LS->hasBraces()) {
     Out << "{\n";
+    ChangeIndent(1);
+  }
 
   for (LinkageSpecDecl::decl_iterator D = LS->decls_begin(), 
                                    DEnd = LS->decls_end();
        D != DEnd; ++D)
     PrintDecl(*D);
 
-  if (LS->hasBraces())
-    Out << "}";
+  if (LS->hasBraces()) {
+    ChangeIndent(-1);
+    Indent() << "}";
+  }
   Out << "\n";
 }
 
@@ -774,7 +853,7 @@
   for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
        I != E; ++I) {
     for (unsigned i = 0; i < Indentation; ++i)
-      Out << " ";
+      Out << "  ";
 
     Decl::Kind DK = I->getKind();
     switch (DK) {
@@ -797,7 +876,7 @@
     case Decl::CXXConversion:
     {
       DeclContext* DC = Decl::castToDeclContext(*I);
-      PrintDeclContext(DC, Indentation+4);
+      PrintDeclContext(DC, Indentation+2);
       break;
     }
     case Decl::Field: {
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 3f76c95..ae7596a 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -176,7 +176,8 @@
   /// dumpPretty/printPretty - These two methods do a "pretty print" of the AST
   /// back to its original source language syntax.
   void dumpPretty() const;
-  void printPretty(llvm::raw_ostream &OS, PrinterHelper* = NULL) const;
+  void printPretty(llvm::raw_ostream &OS, PrinterHelper* = NULL, unsigned = 0,
+                   bool NoIndent=false) const;
   
   /// viewAST - Visualize an AST rooted at this Stmt* using GraphViz.  Only
   ///   works on systems with GraphViz (Mac OS X) or dot+gv installed.
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 49292af..cc32fa2 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -29,10 +29,12 @@
   class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor<StmtPrinter> {
     llvm::raw_ostream &OS;
     unsigned IndentLevel;
+    bool NoIndent;
     clang::PrinterHelper* Helper;
   public:
-    StmtPrinter(llvm::raw_ostream &os, PrinterHelper* helper) : 
-      OS(os), IndentLevel(0), Helper(helper) {}
+    StmtPrinter(llvm::raw_ostream &os, PrinterHelper* helper, unsigned I=0,
+                bool noIndent=false) :
+      OS(os), IndentLevel(I), NoIndent(noIndent), Helper(helper) {}
     
     void PrintStmt(Stmt *S, int SubIndent = 1) {
       IndentLevel += SubIndent;
@@ -52,6 +54,7 @@
     void PrintRawCompoundStmt(CompoundStmt *S);
     void PrintRawDecl(Decl *D);
     void PrintRawDeclStmt(DeclStmt *S);
+    void PrintFieldDecl(FieldDecl *FD);
     void PrintRawIfStmt(IfStmt *If);
     void PrintRawCXXCatchStmt(CXXCatchStmt *Catch);
     
@@ -62,9 +65,11 @@
         OS << "<null expr>";
     }
     
-    llvm::raw_ostream &Indent(int Delta = 0) const {
-      for (int i = 0, e = IndentLevel+Delta; i < e; ++i)
-        OS << "  ";
+    llvm::raw_ostream &Indent(int Delta = 0) {
+      if (!NoIndent) {
+        for (int i = 0, e = IndentLevel+Delta; i < e; ++i)
+          OS << "  ";
+      } else NoIndent = false;
       return OS;
     }
     
@@ -139,16 +144,25 @@
     OS << " ";
     if (const IdentifierInfo *II = TD->getIdentifier())
       OS << II->getName();
-    else
-      OS << "<anonymous>";
-    // FIXME: print tag bodies.
+    if (RecordDecl *RD = dyn_cast<RecordDecl>(TD)) {
+      OS << "{\n";
+      IndentLevel += 1;
+      for (RecordDecl::field_iterator i = RD->field_begin(); i != RD->field_end(); ++i) {
+        PrintFieldDecl(*i);
+      IndentLevel -= 1;
+      }
+    }
   } else {
     assert(0 && "Unexpected decl");
   }
 }
 
+void StmtPrinter::PrintFieldDecl(FieldDecl *FD) {
+  Indent() << FD->getNameAsString() << "\n";
+}
+
 void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) {
-  bool isFirst = false;
+  bool isFirst = true;
   
   for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();
        I != E; ++I) {
@@ -1222,13 +1236,14 @@
   OS.flush();
 }
 
-void Stmt::printPretty(llvm::raw_ostream &OS, PrinterHelper* Helper) const {
+void Stmt::printPretty(llvm::raw_ostream &OS, PrinterHelper* Helper,
+                       unsigned I, bool NoIndent) const {
   if (this == 0) {
     OS << "<NULL>";
     return;
   }
 
-  StmtPrinter P(OS, Helper);
+  StmtPrinter P(OS, Helper, I, NoIndent);
   P.Visit(const_cast<Stmt*>(this));
 }