Expose an API to print a group of decls (like "int a,b;").  
Make StmtPrinter use DeclPrinter to print all declarations.  Merge 
declarations in the limited case of an unnamed TagDecl followed by one 
or more declarations using that TagDecl directly.  Change
SuppressTypeSpecifiers to the more general SuppressSpecifiers, and 
use it to suppress stuff like "typedef" and "extern".  Replace 
OwnedTag with SuppressTag, since it's more convenient to print 
declarations from DeclPrinter at the moment.  
improvements to declaration printing.  Fix pretty-printing for K&R 
function definitions and __builtin_va_arg.

We're now to the point where the pretty-printing output for non-trivial 
programs can actually be piped back into clang.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72608 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index b665e2e..950dd9e 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -32,6 +32,7 @@
     unsigned Indentation;
 
     llvm::raw_ostream& Indent();
+    void ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls);
 
   public:
     DeclPrinter(llvm::raw_ostream &Out, ASTContext &Context, 
@@ -79,6 +80,67 @@
   Printer.Visit(this);
 }
 
+static QualType GetBaseType(QualType T) {
+  // FIXME: This should be on the Type class!
+  QualType BaseType = T;
+  while (!BaseType->isSpecifierType()) {
+    if (isa<TypedefType>(BaseType))
+      break;
+    else if (const PointerType* PTy = BaseType->getAsPointerType())
+      BaseType = PTy->getPointeeType();
+    else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType))
+      BaseType = ATy->getElementType();
+    else if (const FunctionType* FTy = BaseType->getAsFunctionType())
+      BaseType = FTy->getResultType();
+    else
+      assert(0 && "Unknown declarator!");
+  }
+  return BaseType;
+}
+
+static QualType getDeclType(Decl* D) {
+  if (TypedefDecl* TDD = dyn_cast<TypedefDecl>(D))
+    return TDD->getUnderlyingType();
+  if (ValueDecl* VD = dyn_cast<ValueDecl>(D))
+    return VD->getType();
+  return QualType();
+}
+
+void Decl::printGroup(Decl** Begin, unsigned NumDecls,
+                      llvm::raw_ostream &Out, ASTContext &Context, 
+                      const PrintingPolicy &Policy,
+                      unsigned Indentation) {
+  if (NumDecls == 1) {
+    (*Begin)->print(Out, Context, Policy, Indentation);
+    return;
+  }
+
+  Decl** End = Begin + NumDecls;
+  TagDecl* TD = dyn_cast<TagDecl>(*Begin);
+  if (TD)
+    ++Begin;
+
+  PrintingPolicy SubPolicy(Policy);
+  if (TD && TD->isDefinition()) {
+    TD->print(Out, Context, Policy, Indentation);
+    Out << " ";
+    SubPolicy.SuppressTag = true;
+  }
+
+  bool isFirst = true;
+  for ( ; Begin != End; ++Begin) {
+    if (isFirst) {
+      SubPolicy.SuppressSpecifiers = false;
+      isFirst = false;
+    } else {
+      if (!isFirst) Out << ", ";
+      SubPolicy.SuppressSpecifiers = true;
+    }
+
+    (*Begin)->print(Out, Context, SubPolicy, Indentation);
+  }
+}
+
 void Decl::dump(ASTContext &Context) {
   print(llvm::errs(), Context);
 }
@@ -89,6 +151,15 @@
   return Out;
 }
 
+void DeclPrinter::ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls) {
+  this->Indent();
+  Decl::printGroup(Decls.data(), Decls.size(), Out, Context,
+                   Policy, Indentation);
+  Out << ";\n";
+  Decls.clear();
+
+}
+
 //----------------------------------------------------------------------------
 // Common C declarations
 //----------------------------------------------------------------------------
@@ -97,9 +168,38 @@
   if (Indent)
     Indentation += Policy.Indentation;
 
+  llvm::SmallVector<Decl*, 2> Decls;
   for (DeclContext::decl_iterator D = DC->decls_begin(Context),
          DEnd = DC->decls_end(Context);
        D != DEnd; ++D) {
+    // The next bits of code handles stuff like "struct {int x;} a,b"; we're
+    // forced to merge the declarations because there's no other way to
+    // refer to the struct in question.  This limited merging is safe without
+    // a bunch of other checks because it only merges declarations directly
+    // referring to the tag, not typedefs.
+    //
+    // Check whether the current declaration should be grouped with a previous
+    // unnamed struct.
+    QualType CurDeclType = getDeclType(*D);
+    if (!Decls.empty() && !CurDeclType.isNull()) {
+      QualType BaseType = GetBaseType(CurDeclType);
+      if (!BaseType.isNull() && isa<TagType>(BaseType) &&
+          cast<TagType>(BaseType)->getDecl() == Decls[0]) {
+        Decls.push_back(*D);
+        continue;
+      }
+    }
+
+    // If we have a merged group waiting to be handled, handle it now.
+    if (!Decls.empty())
+      ProcessDeclGroup(Decls);
+
+    // If the current declaration is an unnamed tag type, save it
+    // so we can merge it with the subsequent declaration(s) using it.
+    if (isa<TagDecl>(*D) && !cast<TagDecl>(*D)->getIdentifier()) {
+      Decls.push_back(*D);
+      continue;
+    }
     this->Indent();
     Visit(*D);
     
@@ -130,6 +230,9 @@
     Out << "\n";
   }
 
+  if (!Decls.empty())
+    ProcessDeclGroup(Decls);
+
   if (Indent)
     Indentation -= Policy.Indentation;
 }
@@ -141,7 +244,9 @@
 void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
   std::string S = D->getNameAsString();
   D->getUnderlyingType().getAsStringInternal(S, Policy);
-  Out << "typedef " << S;
+  if (!Policy.SuppressSpecifiers)
+    Out << "typedef ";
+  Out << S;
 }
 
 void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
@@ -153,8 +258,10 @@
 void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
   // print a free standing tag decl (e.g. "struct x;"). 
   Out << D->getKindName();
-  Out << " ";
-  Out << D->getNameAsString();
+  if (D->getIdentifier()) {
+    Out << " ";
+    Out << D->getNameAsString();
+  }
   
   if (D->isDefinition()) {
     Out << " {\n";
@@ -172,15 +279,17 @@
 }
 
 void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { 
-  switch (D->getStorageClass()) {
-  case FunctionDecl::None: break;
-  case FunctionDecl::Extern: Out << "extern "; break;
-  case FunctionDecl::Static: Out << "static "; break;
-  case FunctionDecl::PrivateExtern: Out << "__private_extern__ "; break;
-  }
+  if (!Policy.SuppressSpecifiers) {
+    switch (D->getStorageClass()) {
+    case FunctionDecl::None: break;
+    case FunctionDecl::Extern: Out << "extern "; break;
+    case FunctionDecl::Static: Out << "static "; break;
+    case FunctionDecl::PrivateExtern: Out << "__private_extern__ "; break;
+    }
 
-  if (D->isInline())           Out << "inline ";
-  if (D->isVirtualAsWritten()) Out << "virtual ";
+    if (D->isInline())           Out << "inline ";
+    if (D->isVirtualAsWritten()) Out << "virtual ";
+  }
 
   std::string Proto = D->getNameAsString();
   if (isa<FunctionType>(D->getType().getTypePtr())) {
@@ -203,6 +312,12 @@
         if (D->getNumParams()) POut << ", ";
         POut << "...";
       }
+    } else if (D->isThisDeclarationADefinition() && !D->hasPrototype()) {
+      for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
+        if (i)
+          Proto += ", ";
+        Proto += D->getParamDecl(i)->getNameAsString();
+      }
     }
 
     Proto += ")";
@@ -238,7 +353,7 @@
 }
 
 void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
-  if (D->isMutable())
+  if (!Policy.SuppressSpecifiers && D->isMutable())
     Out << "mutable ";
 
   std::string Name = D->getNameAsString();
@@ -252,10 +367,10 @@
 }
 
 void DeclPrinter::VisitVarDecl(VarDecl *D) {
-  if (D->getStorageClass() != VarDecl::None)
+  if (!Policy.SuppressSpecifiers && D->getStorageClass() != VarDecl::None)
     Out << VarDecl::getStorageClassSpecifierString(D->getStorageClass()) << " ";
 
-  if (D->isThreadSpecified())
+  if (!Policy.SuppressSpecifiers && D->isThreadSpecified())
     Out << "__thread ";
 
   std::string Name = D->getNameAsString();
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 113cbb4..a698688 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -57,14 +57,9 @@
       IndentLevel -= SubIndent;
     }
 
-    QualType GetBaseType(QualType T);
-    void PrintBaseType(QualType T, TagDecl* TD);
-    void PrintDeclIdentifier(NamedDecl* ND);
     void PrintRawCompoundStmt(CompoundStmt *S);
     void PrintRawDecl(Decl *D);
     void PrintRawDeclStmt(DeclStmt *S);
-    void PrintFieldDecl(FieldDecl *FD);
-    void PrintEnumConstantDecl(EnumConstantDecl *ECD);
     void PrintRawIfStmt(IfStmt *If);
     void PrintRawCXXCatchStmt(CXXCatchStmt *Catch);
     
@@ -116,190 +111,18 @@
   Indent() << "}";
 }
 
-QualType StmtPrinter::GetBaseType(QualType T) {
-  // FIXME: This should be on the Type class!
-  QualType BaseType = T;
-  while (!BaseType->isSpecifierType()) {
-    if (isa<TypedefType>(BaseType))
-      break;
-    else if (const PointerType* PTy = BaseType->getAsPointerType())
-      BaseType = PTy->getPointeeType();
-    else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType))
-      BaseType = ATy->getElementType();
-    else if (const FunctionType* FTy = BaseType->getAsFunctionType())
-      BaseType = FTy->getResultType();
-    else
-      assert(0 && "Unknown declarator!");
-  }
-  return BaseType;
-}
-
-void StmtPrinter::PrintBaseType(QualType BaseType, TagDecl* TD) {
-  std::string BaseString;
-  if (TD && TD->isDefinition()) {
-    // FIXME: This is an ugly hack; perhaps we can expose something better
-    // from Type.h?
-    if (BaseType.isConstQualified())
-      OS << "const ";
-    PrintRawDecl(TD);
-    OS << " ";
-  } else {
-    BaseType.getAsStringInternal(BaseString, Policy);
-    OS << BaseString << " ";
-  }
-}
-
-void StmtPrinter::PrintDeclIdentifier(NamedDecl* ND) {
-  std::string Name = ND->getNameAsString();
-
-  QualType Ty;
-  if (TypedefDecl* TDD = dyn_cast<TypedefDecl>(ND)) {
-    Ty = TDD->getUnderlyingType();
-  } else if (ValueDecl* VD = dyn_cast<ValueDecl>(ND)) {
-    Ty = VD->getType();
-  } else {
-    assert(0 && "Unexpected decl");
-  }
-
-  PrintingPolicy SubPolicy(Policy);
-  SubPolicy.SuppressTypeSpecifiers = true;
-  Ty.getAsStringInternal(Name, SubPolicy);
-  OS << Name;
-}
-
 void StmtPrinter::PrintRawDecl(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();
-    OS << " " << localType->getNameAsString();
-  } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
-    // Emit storage class for vardecls.
-    if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
-      if (V->getStorageClass() != VarDecl::None)
-        OS << VarDecl::getStorageClassSpecifierString(V->getStorageClass()) 
-           << ' ';
-    }
-    
-    std::string Name = VD->getNameAsString();
-    VD->getType().getAsStringInternal(Name, Policy);
-    OS << Name;
-    
-    // If this is a vardecl with an initializer, emit it.
-    if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
-      if (V->getInit()) {
-        OS << " = ";
-        PrintExpr(V->getInit());
-      }
-    }
-  } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
-    // print a free standing tag decl (e.g. "struct x;"). 
-    OS << TD->getKindName();
-    OS << " ";
-    if (const IdentifierInfo *II = TD->getIdentifier())
-      OS << II->getName();
-    if (TD->isDefinition()) {
-      if (RecordDecl *RD = dyn_cast<RecordDecl>(TD)) {
-        OS << "{\n";
-        IndentLevel += 1;
-        // FIXME: The context passed to field_begin/field_end should
-        // never be NULL!
-        ASTContext *Context = 0;
-        for (RecordDecl::field_iterator i = RD->field_begin(*Context);
-             i != RD->field_end(*Context); ++i)
-          PrintFieldDecl(*i);
-        IndentLevel -= 1;
-        Indent() << "}";
-      } else if (EnumDecl *ED = dyn_cast<EnumDecl>(TD)) {
-        OS << "{\n";
-        IndentLevel += 1;
-        // FIXME: The context shouldn't be NULL!
-        ASTContext *Context = 0;
-        for (EnumDecl::enumerator_iterator i = ED->enumerator_begin(*Context);
-             i != ED->enumerator_end(*Context); ++i)
-          PrintEnumConstantDecl(*i);
-        IndentLevel -= 1;
-        Indent() << "}";
-      }
-    }
-  } else {
-    assert(0 && "Unexpected decl");
-  }
-}
-
-void StmtPrinter::PrintFieldDecl(FieldDecl *FD) {
-  Indent();
-  QualType BaseType = GetBaseType(FD->getType());
-  PrintBaseType(BaseType, 0);
-  PrintDeclIdentifier(FD);
-  if (FD->isBitField()) {
-    OS << " : ";
-    PrintExpr(FD->getBitWidth());
-  }
-  OS << ";\n";
-}
-
-void StmtPrinter::PrintEnumConstantDecl(EnumConstantDecl *ECD) {
-  Indent() << ECD->getNameAsString();
-  if (ECD->getInitExpr()) {
-    OS << " = ";
-    PrintExpr(ECD->getInitExpr());
-  }
-  OS << ",\n";
+  D->print(OS, *(ASTContext*)0, Policy, IndentLevel);
 }
 
 void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) {
   DeclStmt::decl_iterator Begin = S->decl_begin(), End = S->decl_end();
+  llvm::SmallVector<Decl*, 2> Decls;
+  for ( ; Begin != End; ++Begin) 
+    Decls.push_back(*Begin);
 
-  TagDecl* TD = dyn_cast<TagDecl>(*Begin);
-  if (TD)
-    ++Begin;
-
-  if (Begin == End) {
-    PrintRawDecl(TD);
-    return;
-  }
-
-  if (isa<TypedefDecl>(*Begin))
-    OS << "typedef ";
-  else if (VarDecl *V = dyn_cast<VarDecl>(*Begin)) {
-    switch (V->getStorageClass()) {
-    default: assert(0 && "Unknown storage class!");
-    case VarDecl::None:          break;
-    case VarDecl::Auto:          OS << "auto "; break;
-    case VarDecl::Register:      OS << "register "; break;
-    case VarDecl::Extern:        OS << "extern "; break;
-    case VarDecl::Static:        OS << "static "; break; 
-    case VarDecl::PrivateExtern: OS << "__private_extern__ "; break; 
-    }
-  } else if (FunctionDecl *V = dyn_cast<FunctionDecl>(*Begin)) {
-    switch (V->getStorageClass()) {
-    default: assert(0 && "Unknown storage class!");
-    case FunctionDecl::None:          break;
-    case FunctionDecl::Extern:        OS << "extern "; break;
-    case FunctionDecl::Static:        OS << "static "; break; 
-    case FunctionDecl::PrivateExtern: OS << "__private_extern__ "; break; 
-    }
-  } else {
-    assert(0 && "Unhandled decl");
-  }
-
-  QualType BaseType;
-  if (ValueDecl* VD = dyn_cast<ValueDecl>(*Begin)) {
-    BaseType = VD->getType();
-  } else {
-    BaseType = cast<TypedefDecl>(*Begin)->getUnderlyingType();
-  }
-  BaseType = GetBaseType(BaseType);
-  PrintBaseType(BaseType, TD);
-
-  bool isFirst = true;
-  for ( ; Begin != End; ++Begin) {
-    if (!isFirst) OS << ", ";
-    else isFirst = false;
-
-    PrintDeclIdentifier(cast<NamedDecl>(*Begin));
-  }
+  Decl::printGroup(Decls.data(), Decls.size(), OS, *(ASTContext*)0, Policy,
+                   IndentLevel);
 }
 
 void StmtPrinter::VisitNullStmt(NullStmt *Node) {
@@ -1042,7 +865,7 @@
 }
 
 void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
-  OS << "va_arg(";
+  OS << "__builtin_va_arg(";
   PrintExpr(Node->getSubExpr());
   OS << ", ";
   OS << Node->getType().getAsString();
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index f7eb41c..b2ee58f 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1168,7 +1168,7 @@
     return;
   }
 
-  if (Policy.SuppressTypeSpecifiers && getTypePtr()->isSpecifierType())
+  if (Policy.SuppressSpecifiers && getTypePtr()->isSpecifierType())
     return;
 
   // Print qualifiers as appropriate.
@@ -1398,7 +1398,7 @@
   S += "(";
   std::string Tmp;
   PrintingPolicy ParamPolicy(Policy);
-  ParamPolicy.SuppressTypeSpecifiers = false;
+  ParamPolicy.SuppressSpecifiers = false;
   for (unsigned i = 0, e = getNumArgs(); i != e; ++i) {
     if (i) S += ", ";
     getArgType(i).getAsStringInternal(Tmp, ParamPolicy);
@@ -1592,6 +1592,9 @@
 }
 
 void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+  if (Policy.SuppressTag)
+    return;
+
   if (!InnerString.empty())    // Prefix the basic type, e.g. 'typedefname X'.
     InnerString = ' ' + InnerString;