]> granicus.if.org Git - clang/commitdiff
Expose an API to print a group of decls (like "int a,b;").
authorEli Friedman <eli.friedman@gmail.com>
Sat, 30 May 2009 04:20:30 +0000 (04:20 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Sat, 30 May 2009 04:20:30 +0000 (04:20 +0000)
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

include/clang/AST/DeclBase.h
include/clang/AST/PrettyPrinter.h
lib/AST/DeclPrinter.cpp
lib/AST/StmtPrinter.cpp
lib/AST/Type.cpp

index c25f4677153e3efd28e21a7d545bc635e7e1298b..c061b857063a581d1691a995dede716617776b2d 100644 (file)
@@ -314,6 +314,10 @@ public:
              unsigned Indentation = 0);
   void print(llvm::raw_ostream &Out, ASTContext &Context, 
              const PrintingPolicy &Policy, unsigned Indentation = 0);
+  static void printGroup(Decl** Begin, unsigned NumDecls,
+                         llvm::raw_ostream &Out, ASTContext &Context, 
+                         const PrintingPolicy &Policy,
+                         unsigned Indentation = 0);
   void dump(ASTContext &Context);
 
 private:
index dcbb82305691037d32e2ebd87a07dafba36824ad..385602b1fb9c47185052c64254a2b987359f2f3a 100644 (file)
@@ -34,8 +34,8 @@ public:
 struct PrintingPolicy {
   /// \brief Create a default printing policy for C.
   PrintingPolicy() 
-    : Indentation(2), CPlusPlus(false), SuppressTypeSpecifiers(false),
-      SuppressTagKind(false), Dump(false), OwnedTag(0) { }
+    : Indentation(2), CPlusPlus(false), SuppressSpecifiers(false),
+      SuppressTag(false), SuppressTagKind(false), Dump(false) { }
 
   /// \brief The number of spaces to use to indent each line.
   unsigned Indentation : 8;
@@ -44,8 +44,8 @@ struct PrintingPolicy {
   /// printing C code).
   bool CPlusPlus : 1;
 
-  /// \brief Whether we should suppress printing of the actual type
-  /// specifiers within the type that we are printing.
+  /// \brief Whether we should suppress printing of the actual specifiers for
+  /// the given type or declaration.
   ///
   /// This flag is only used when we are printing declarators beyond
   /// the first declarator within a declaration group. For example, given:
@@ -54,11 +54,21 @@ struct PrintingPolicy {
   /// const int *x, *y;
   /// \endcode
   ///
-  /// SuppressTypeSpecifiers will be false when printing the
+  /// SuppressSpecifiers will be false when printing the
   /// declaration for "x", so that we will print "int *x"; it will be
   /// \c true when we print "y", so that we suppress printing the
   /// "const int" type specifier and instead only print the "*y".
-  bool SuppressTypeSpecifiers : 1;
+  bool SuppressSpecifiers : 1;
+
+  /// \brief Whether type printing should skip printing the actual tag type.
+  ///
+  /// This is used when the caller needs to print a tag definition in front
+  /// of the type, as in constructs like the following:
+  ///
+  /// \code
+  /// typedef struct { int x, y; } Point;
+  /// \endcode
+  bool SuppressTag : 1;
 
   /// \brief If we are printing a tag type, suppresses printing of the
   /// kind of tag, e.g., "struct", "union", "enum".
@@ -69,23 +79,6 @@ struct PrintingPolicy {
   /// and pretty-printing involves printing something similar to
   /// source code.
   bool Dump : 1;
-
-  /// \brief If we are printing a type where the tag type (e.g., a
-  /// class or enum type) was declared or defined within the type
-  /// itself, OwnedTag will point at the declaration node owned by
-  /// this type.
-  ///
-  /// Owned tags occur when a tag type is defined as part of the
-  /// declaration specifiers of another declarator, e.g.,
-  ///
-  /// \code
-  /// typedef struct { int x, y; } Point;
-  /// \endcode
-  ///
-  /// Here, the anonymous struct definition is owned by the type of
-  /// Point. The actual representation uses a DeclGroup to store both
-  /// the RecordDecl and the TypedefDecl.
-  TagDecl *OwnedTag;
 };
 
 } // end namespace clang
index b665e2e0e19d411ae21ae2aaebd0cea6ba85f28a..950dd9e223decb8213d6748e94d145d9ac21e353 100644 (file)
@@ -32,6 +32,7 @@ namespace {
     unsigned Indentation;
 
     llvm::raw_ostream& Indent();
+    void ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls);
 
   public:
     DeclPrinter(llvm::raw_ostream &Out, ASTContext &Context, 
@@ -79,6 +80,67 @@ void Decl::print(llvm::raw_ostream &Out, ASTContext &Context,
   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 @@ llvm::raw_ostream& DeclPrinter::Indent() {
   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 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
   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 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
     Out << "\n";
   }
 
+  if (!Decls.empty())
+    ProcessDeclGroup(Decls);
+
   if (Indent)
     Indentation -= Policy.Indentation;
 }
@@ -141,7 +244,9 @@ void DeclPrinter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
 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::VisitEnumDecl(EnumDecl *D) {
 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::VisitEnumConstantDecl(EnumConstantDecl *D) {
 }
 
 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 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
         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::VisitFunctionDecl(FunctionDecl *D) {
 }
 
 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::VisitFieldDecl(FieldDecl *D) {
 }
 
 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();
index 113cbb48dde4cd5fd8900125693a998a4266c913..a698688e6cee775c08768175180b791fca4e8f98 100644 (file)
@@ -57,14 +57,9 @@ namespace  {
       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 @@ void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) {
   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::VisitImplicitValueInitExpr(ImplicitValueInitExpr *Node) {
 }
 
 void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
-  OS << "va_arg(";
+  OS << "__builtin_va_arg(";
   PrintExpr(Node->getSubExpr());
   OS << ", ";
   OS << Node->getType().getAsString();
index f7eb41c28b320e7763fe1a81c7e83d11f8368fc6..b2ee58f3f355821038d14b83c395bac38aad8f31 100644 (file)
@@ -1168,7 +1168,7 @@ QualType::getAsStringInternal(std::string &S,
     return;
   }
 
-  if (Policy.SuppressTypeSpecifiers && getTypePtr()->isSpecifierType())
+  if (Policy.SuppressSpecifiers && getTypePtr()->isSpecifierType())
     return;
 
   // Print qualifiers as appropriate.
@@ -1398,7 +1398,7 @@ void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy
   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 ObjCQualifiedIdType::getAsStringInternal(std::string &InnerString, const Pr
 }
 
 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;