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:
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;
/// 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:
/// 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".
/// 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
unsigned Indentation;
llvm::raw_ostream& Indent();
+ void ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls);
public:
DeclPrinter(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);
}
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
//----------------------------------------------------------------------------
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);
Out << "\n";
}
+ if (!Decls.empty())
+ ProcessDeclGroup(Decls);
+
if (Indent)
Indentation -= Policy.Indentation;
}
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) {
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";
}
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())) {
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 += ")";
}
void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
- if (D->isMutable())
+ if (!Policy.SuppressSpecifiers && D->isMutable())
Out << "mutable ";
std::string Name = D->getNameAsString();
}
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();
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);
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) {
}
void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
- OS << "va_arg(";
+ OS << "__builtin_va_arg(";
PrintExpr(Node->getSubExpr());
OS << ", ";
OS << Node->getType().getAsString();
return;
}
- if (Policy.SuppressTypeSpecifiers && getTypePtr()->isSpecifierType())
+ if (Policy.SuppressSpecifiers && getTypePtr()->isSpecifierType())
return;
// Print qualifiers as appropriate.
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);
}
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;