From: Argyrios Kyrtzidis Date: Sat, 5 May 2012 04:20:37 +0000 (+0000) Subject: Use raw_ostream in TypePrinter and eliminate uses of temporary std::strings. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7ad5c996e9519ed4e9afd1f0166be1cd2be8415a;p=clang Use raw_ostream in TypePrinter and eliminate uses of temporary std::strings. Part of rdar://10796159 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156228 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index cc636196e8..1f6b106ee0 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -2603,6 +2603,7 @@ public: void setCompleteDefinition(bool V) { IsCompleteDefinition = V; } + // FIXME: Return StringRef; const char *getKindName() const { return TypeWithKeyword::getTagTypeKindName(getTagKind()); } diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 32e55e9ef6..3c958b21af 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -29,6 +29,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/Twine.h" #include "clang/Basic/LLVM.h" namespace clang { @@ -412,12 +413,11 @@ public: } std::string getAsString() const; - std::string getAsString(const PrintingPolicy &Policy) const { - std::string Buffer; - getAsStringInternal(Buffer, Policy); - return Buffer; - } - void getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const; + std::string getAsString(const PrintingPolicy &Policy) const; + + bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const; + void print(raw_ostream &OS, const PrintingPolicy &Policy, + bool appendSpaceIfNonEmpty = false) const; void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Mask); @@ -829,11 +829,20 @@ public: } static std::string getAsString(const Type *ty, Qualifiers qs); - std::string getAsString(const PrintingPolicy &Policy) const { - std::string S; - getAsStringInternal(S, Policy); - return S; + std::string getAsString(const PrintingPolicy &Policy) const; + + void print(raw_ostream &OS, const PrintingPolicy &Policy, + const Twine &PlaceHolder = Twine()) const { + print(split(), OS, Policy, PlaceHolder); + } + static void print(SplitQualType split, raw_ostream &OS, + const PrintingPolicy &policy, const Twine &PlaceHolder) { + return print(split.Ty, split.Quals, OS, policy, PlaceHolder); } + static void print(const Type *ty, Qualifiers qs, + raw_ostream &OS, const PrintingPolicy &policy, + const Twine &PlaceHolder); + void getAsStringInternal(std::string &Str, const PrintingPolicy &Policy) const { return getAsStringInternal(split(), Str, Policy); @@ -846,6 +855,27 @@ public: std::string &out, const PrintingPolicy &policy); + class StreamedQualTypeHelper { + const QualType &T; + const PrintingPolicy &Policy; + const Twine &PlaceHolder; + public: + StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy, + const Twine &PlaceHolder) + : T(T), Policy(Policy), PlaceHolder(PlaceHolder) { } + + friend raw_ostream &operator<<(raw_ostream &OS, + const StreamedQualTypeHelper &SQT) { + SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder); + return OS; + } + }; + + StreamedQualTypeHelper stream(const PrintingPolicy &Policy, + const Twine &PlaceHolder = Twine()) const { + return StreamedQualTypeHelper(*this, Policy, PlaceHolder); + } + void dump(const char *s) const; void dump() const; @@ -2939,8 +2969,11 @@ public: bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } + // FIXME: Remove the string version. void printExceptionSpecification(std::string &S, PrintingPolicy Policy) const; + void printExceptionSpecification(raw_ostream &OS, + PrintingPolicy Policy) const; static bool classof(const Type *T) { return T->getTypeClass() == FunctionProto; @@ -3593,6 +3626,7 @@ public: /// \brief Print a template argument list, including the '<' and '>' /// enclosing the template arguments. + // FIXME: remove the string ones. static std::string PrintTemplateArgumentList(const TemplateArgument *Args, unsigned NumArgs, const PrintingPolicy &Policy, @@ -3605,6 +3639,23 @@ public: static std::string PrintTemplateArgumentList(const TemplateArgumentListInfo &, const PrintingPolicy &Policy); + /// \brief Print a template argument list, including the '<' and '>' + /// enclosing the template arguments. + static void PrintTemplateArgumentList(raw_ostream &OS, + const TemplateArgument *Args, + unsigned NumArgs, + const PrintingPolicy &Policy, + bool SkipBrackets = false); + + static void PrintTemplateArgumentList(raw_ostream &OS, + const TemplateArgumentLoc *Args, + unsigned NumArgs, + const PrintingPolicy &Policy); + + static void PrintTemplateArgumentList(raw_ostream &OS, + const TemplateArgumentListInfo &, + const PrintingPolicy &Policy); + /// True if this template specialization type matches a current /// instantiation in the context in which it is found. bool isCurrentInstantiation() const { diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index d79e28b295..dffebebd0c 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -669,6 +669,7 @@ public: /// getAsString - Derive the full selector name (e.g. "foo:bar:") and return /// it as an std::string. + // FIXME: Add a print method that uses a raw_ostream. std::string getAsString() const; /// getMethodFamily - Derive the conventional family of this method. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 3efa55ea0f..15fa790203 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -861,9 +861,7 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { for (unsigned i = 0; i < NumParams; ++i) { if (i) OS << ", "; - std::string Param; - FD->getParamDecl(i)->getType().getAsStringInternal(Param, P); - OS << Param; + OS << FD->getParamDecl(i)->getType().stream(P); } if (FT->isVariadic()) { diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 5df0fbe540..d65825e395 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -322,15 +322,13 @@ void DeclPrinter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { } void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) { - std::string S = D->getNameAsString(); - D->getUnderlyingType().getAsStringInternal(S, Policy); if (!Policy.SuppressSpecifiers) { Out << "typedef "; if (D->isModulePrivate()) Out << "__module_private__ "; } - Out << S; + D->getUnderlyingType().print(Out, Policy, D->getName()); prettyPrintAttributes(D); } @@ -350,11 +348,8 @@ void DeclPrinter::VisitEnumDecl(EnumDecl *D) { } Out << *D; - if (D->isFixed()) { - std::string Underlying; - D->getIntegerType().getAsStringInternal(Underlying, Policy); - Out << " : " << Underlying; - } + if (D->isFixed()) + Out << " : " << D->getIntegerType().stream(Policy); if (D->isCompleteDefinition()) { Out << " {\n"; @@ -460,9 +455,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (I) Proto += ", "; - std::string ExceptionType; - FT->getExceptionType(I).getAsStringInternal(ExceptionType, SubPolicy); - Proto += ExceptionType; + Proto += FT->getExceptionType(I).getAsString(SubPolicy);; } Proto += ")"; } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) { @@ -542,12 +535,11 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } } else - AFT->getResultType().getAsStringInternal(Proto, Policy); + AFT->getResultType().print(Out, Policy, Proto); } else { - Ty.getAsStringInternal(Proto, Policy); + Ty.print(Out, Policy, Proto); } - Out << Proto; prettyPrintAttributes(D); if (D->isPure()) @@ -581,9 +573,7 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) { if (!Policy.SuppressSpecifiers && D->isModulePrivate()) Out << "__module_private__ "; - std::string Name = D->getNameAsString(); - D->getType().getAsStringInternal(Name, Policy); - Out << Name; + Out << D->getType().stream(Policy, D->getName()); if (D->isBitField()) { Out << " : "; @@ -613,12 +603,10 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { if (!Policy.SuppressSpecifiers && D->isModulePrivate()) Out << "__module_private__ "; - std::string Name = D->getNameAsString(); QualType T = D->getType(); if (ParmVarDecl *Parm = dyn_cast(D)) T = Parm->getOriginalType(); - T.getAsStringInternal(Name, Policy); - Out << Name; + T.print(Out, Policy, D->getName()); Expr *Init = D->getInit(); if (!Policy.SuppressInitializers && Init) { bool ImplicitInit = false; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index fcde5429b3..afc7410a81 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -414,9 +414,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { if (FT) { for (unsigned i = 0, e = Decl->getNumParams(); i != e; ++i) { if (i) POut << ", "; - std::string Param; - Decl->getParamDecl(i)->getType().getAsStringInternal(Param, Policy); - POut << Param; + POut << Decl->getParamDecl(i)->getType().stream(Policy); } if (FT->isVariadic()) { diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 5ec548f3f9..111fee9d88 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -19,8 +19,10 @@ #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/SaveAndRestore.h" using namespace clang; namespace { @@ -40,62 +42,124 @@ namespace { Policy.SuppressStrongLifetime = Old; } }; + + class ParamPolicyRAII { + PrintingPolicy &Policy; + bool Old; + + public: + explicit ParamPolicyRAII(PrintingPolicy &Policy) + : Policy(Policy), Old(Policy.SuppressSpecifiers) { + Policy.SuppressSpecifiers = false; + } + + ~ParamPolicyRAII() { + Policy.SuppressSpecifiers = Old; + } + }; + + class ElaboratedTypePolicyRAII { + PrintingPolicy &Policy; + bool SuppressTagKeyword; + bool SuppressScope; + + public: + explicit ElaboratedTypePolicyRAII(PrintingPolicy &Policy) : Policy(Policy) { + SuppressTagKeyword = Policy.SuppressTagKeyword; + SuppressScope = Policy.SuppressScope; + Policy.SuppressTagKeyword = true; + Policy.SuppressScope = true; + } + + ~ElaboratedTypePolicyRAII() { + Policy.SuppressTagKeyword = SuppressTagKeyword; + Policy.SuppressScope = SuppressScope; + } + }; class TypePrinter { PrintingPolicy Policy; + bool HasEmptyPlaceHolder; public: - explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { } - - void print(const Type *ty, Qualifiers qs, std::string &buffer); - void print(QualType T, std::string &S); - void AppendScope(DeclContext *DC, std::string &S); - void printTag(TagDecl *T, std::string &S); + explicit TypePrinter(const PrintingPolicy &Policy) + : Policy(Policy), HasEmptyPlaceHolder(false) { } + + void print(const Type *ty, Qualifiers qs, raw_ostream &OS, + StringRef PlaceHolder); + void print(QualType T, raw_ostream &OS, StringRef PlaceHolder); + + static bool canPrefixQualifiers(const Type *T, bool &NeedARCStrongQualifier); + void spaceBeforePlaceHolder(raw_ostream &OS); + void printTypeSpec(const NamedDecl *D, raw_ostream &OS); + + void printBefore(const Type *ty, Qualifiers qs, raw_ostream &OS); + void printBefore(QualType T, raw_ostream &OS); + void printAfter(const Type *ty, Qualifiers qs, raw_ostream &OS); + void printAfter(QualType T, raw_ostream &OS); + void AppendScope(DeclContext *DC, raw_ostream &OS); + void printTag(TagDecl *T, raw_ostream &OS); #define ABSTRACT_TYPE(CLASS, PARENT) #define TYPE(CLASS, PARENT) \ - void print##CLASS(const CLASS##Type *T, std::string &S); + void print##CLASS##Before(const CLASS##Type *T, raw_ostream &OS); \ + void print##CLASS##After(const CLASS##Type *T, raw_ostream &OS); #include "clang/AST/TypeNodes.def" }; } -static void AppendTypeQualList(std::string &S, unsigned TypeQuals) { +static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals) { + bool appendSpace = false; if (TypeQuals & Qualifiers::Const) { - if (!S.empty()) S += ' '; - S += "const"; + OS << "const"; + appendSpace = true; } if (TypeQuals & Qualifiers::Volatile) { - if (!S.empty()) S += ' '; - S += "volatile"; + if (appendSpace) OS << ' '; + OS << "volatile"; + appendSpace = true; } if (TypeQuals & Qualifiers::Restrict) { - if (!S.empty()) S += ' '; - S += "restrict"; + if (appendSpace) OS << ' '; + OS << "restrict"; } } -void TypePrinter::print(QualType t, std::string &buffer) { +void TypePrinter::spaceBeforePlaceHolder(raw_ostream &OS) { + if (!HasEmptyPlaceHolder) + OS << ' '; +} + +void TypePrinter::print(QualType t, raw_ostream &OS, StringRef PlaceHolder) { SplitQualType split = t.split(); - print(split.Ty, split.Quals, buffer); + print(split.Ty, split.Quals, OS, PlaceHolder); } -void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) { +void TypePrinter::print(const Type *T, Qualifiers Quals, raw_ostream &OS, + StringRef PlaceHolder) { if (!T) { - buffer += "NULL TYPE"; + OS << "NULL TYPE"; return; } if (Policy.SuppressSpecifiers && T->isSpecifierType()) return; - - // Print qualifiers as appropriate. - + + SaveAndRestore PHVal(HasEmptyPlaceHolder, PlaceHolder.empty()); + + printBefore(T, Quals, OS); + OS << PlaceHolder; + printAfter(T, Quals, OS); +} + +bool TypePrinter::canPrefixQualifiers(const Type *T, + bool &NeedARCStrongQualifier) { // CanPrefixQualifiers - We prefer to print type qualifiers before the type, // so that we get "const int" instead of "int const", but we can't do this if // the type is complex. For example if the type is "int*", we *must* print // "int * const", printing "const int *" is different. Only do this when the // type expands to a simple string. bool CanPrefixQualifiers = false; - bool NeedARCStrongQualifier = false; + NeedARCStrongQualifier = false; Type::TypeClass TC = T->getTypeClass(); if (const AutoType *AT = dyn_cast(T)) TC = AT->desugar()->getTypeClass(); @@ -157,493 +221,608 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) { CanPrefixQualifiers = false; break; } - - if (!CanPrefixQualifiers && !Quals.empty()) { - std::string qualsBuffer; + + return CanPrefixQualifiers; +} + +void TypePrinter::printBefore(QualType t, raw_ostream &OS) { + SplitQualType split = t.split(); + printBefore(split.Ty, split.Quals, OS); +} + +/// \brief Prints the part of the type string before an identifier, e.g. for +/// "int foo[10]" it prints "int ". +void TypePrinter::printBefore(const Type *T,Qualifiers Quals, raw_ostream &OS) { + if (Policy.SuppressSpecifiers && T->isSpecifierType()) + return; + + SaveAndRestore PrevPHIsEmpty(HasEmptyPlaceHolder); + + // Print qualifiers as appropriate. + + bool CanPrefixQualifiers = false; + bool NeedARCStrongQualifier = false; + CanPrefixQualifiers = canPrefixQualifiers(T, NeedARCStrongQualifier); + + if (CanPrefixQualifiers && !Quals.empty()) { if (NeedARCStrongQualifier) { IncludeStrongLifetimeRAII Strong(Policy); - Quals.getAsStringInternal(qualsBuffer, Policy); + Quals.print(OS, Policy, /*appendSpaceIfNonEmpty=*/true); } else { - Quals.getAsStringInternal(qualsBuffer, Policy); - } - - if (!qualsBuffer.empty()) { - if (!buffer.empty()) { - qualsBuffer += ' '; - qualsBuffer += buffer; - } - std::swap(buffer, qualsBuffer); + Quals.print(OS, Policy, /*appendSpaceIfNonEmpty=*/true); } } - + + bool hasAfterQuals = false; + if (!CanPrefixQualifiers && !Quals.empty()) { + hasAfterQuals = !Quals.isEmptyWhenPrinted(Policy); + if (hasAfterQuals) + HasEmptyPlaceHolder = false; + } + switch (T->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) #define TYPE(CLASS, PARENT) case Type::CLASS: \ - print##CLASS(cast(T), buffer); \ + print##CLASS##Before(cast(T), OS); \ break; #include "clang/AST/TypeNodes.def" } - - // If we're adding the qualifiers as a prefix, do it now. - if (CanPrefixQualifiers && !Quals.empty()) { - std::string qualsBuffer; + + if (hasAfterQuals) { if (NeedARCStrongQualifier) { IncludeStrongLifetimeRAII Strong(Policy); - Quals.getAsStringInternal(qualsBuffer, Policy); + Quals.print(OS, Policy, /*appendSpaceIfNonEmpty=*/!PrevPHIsEmpty.get()); } else { - Quals.getAsStringInternal(qualsBuffer, Policy); - } - - if (!qualsBuffer.empty()) { - if (!buffer.empty()) { - qualsBuffer += ' '; - qualsBuffer += buffer; - } - std::swap(buffer, qualsBuffer); + Quals.print(OS, Policy, /*appendSpaceIfNonEmpty=*/!PrevPHIsEmpty.get()); } } } -void TypePrinter::printBuiltin(const BuiltinType *T, std::string &S) { - if (S.empty()) { - S = T->getName(Policy); - } else { - // Prefix the basic type, e.g. 'int X'. - S = ' ' + S; - S = T->getNameAsCString(Policy) + S; +void TypePrinter::printAfter(QualType t, raw_ostream &OS) { + SplitQualType split = t.split(); + printAfter(split.Ty, split.Quals, OS); +} + +/// \brief Prints the part of the type string after an identifier, e.g. for +/// "int foo[10]" it prints "[10]". +void TypePrinter::printAfter(const Type *T, Qualifiers Quals, raw_ostream &OS) { + switch (T->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) case Type::CLASS: \ + print##CLASS##After(cast(T), OS); \ + break; +#include "clang/AST/TypeNodes.def" } } -void TypePrinter::printComplex(const ComplexType *T, std::string &S) { - print(T->getElementType(), S); - S = "_Complex " + S; +void TypePrinter::printBuiltinBefore(const BuiltinType *T, raw_ostream &OS) { + OS << T->getName(Policy); + spaceBeforePlaceHolder(OS); } +void TypePrinter::printBuiltinAfter(const BuiltinType *T, raw_ostream &OS) { } -void TypePrinter::printPointer(const PointerType *T, std::string &S) { - S = '*' + S; - +void TypePrinter::printComplexBefore(const ComplexType *T, raw_ostream &OS) { + OS << "_Complex "; + printBefore(T->getElementType(), OS); +} +void TypePrinter::printComplexAfter(const ComplexType *T, raw_ostream &OS) { + printAfter(T->getElementType(), OS); +} + +void TypePrinter::printPointerBefore(const PointerType *T, raw_ostream &OS) { + IncludeStrongLifetimeRAII Strong(Policy); + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + printBefore(T->getPointeeType(), OS); // Handle things like 'int (*A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. if (isa(T->getPointeeType())) - S = '(' + S + ')'; - + OS << '('; + OS << '*'; +} +void TypePrinter::printPointerAfter(const PointerType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - print(T->getPointeeType(), S); + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + // Handle things like 'int (*A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa(T->getPointeeType())) + OS << ')'; + printAfter(T->getPointeeType(), OS); } -void TypePrinter::printBlockPointer(const BlockPointerType *T, std::string &S) { - S = '^' + S; - print(T->getPointeeType(), S); +void TypePrinter::printBlockPointerBefore(const BlockPointerType *T, + raw_ostream &OS) { + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + printBefore(T->getPointeeType(), OS); + OS << '^'; +} +void TypePrinter::printBlockPointerAfter(const BlockPointerType *T, + raw_ostream &OS) { + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + printAfter(T->getPointeeType(), OS); } -void TypePrinter::printLValueReference(const LValueReferenceType *T, - std::string &S) { - S = '&' + S; - +void TypePrinter::printLValueReferenceBefore(const LValueReferenceType *T, + raw_ostream &OS) { + IncludeStrongLifetimeRAII Strong(Policy); + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + printBefore(T->getPointeeTypeAsWritten(), OS); // Handle things like 'int (&A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. if (isa(T->getPointeeTypeAsWritten())) - S = '(' + S + ')'; - + OS << '('; + OS << '&'; +} +void TypePrinter::printLValueReferenceAfter(const LValueReferenceType *T, + raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - print(T->getPointeeTypeAsWritten(), S); + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + // Handle things like 'int (&A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa(T->getPointeeTypeAsWritten())) + OS << ')'; + printAfter(T->getPointeeTypeAsWritten(), OS); } -void TypePrinter::printRValueReference(const RValueReferenceType *T, - std::string &S) { - S = "&&" + S; - +void TypePrinter::printRValueReferenceBefore(const RValueReferenceType *T, + raw_ostream &OS) { + IncludeStrongLifetimeRAII Strong(Policy); + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + printBefore(T->getPointeeTypeAsWritten(), OS); // Handle things like 'int (&&A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. if (isa(T->getPointeeTypeAsWritten())) - S = '(' + S + ')'; - + OS << '('; + OS << "&&"; +} +void TypePrinter::printRValueReferenceAfter(const RValueReferenceType *T, + raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - print(T->getPointeeTypeAsWritten(), S); + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + // Handle things like 'int (&&A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa(T->getPointeeTypeAsWritten())) + OS << ')'; + printAfter(T->getPointeeTypeAsWritten(), OS); } -void TypePrinter::printMemberPointer(const MemberPointerType *T, - std::string &S) { - PrintingPolicy InnerPolicy(Policy); - Policy.SuppressTag = true; - std::string C = QualType(T->getClass(), 0).getAsString(InnerPolicy); - C += "::*"; - S = C + S; - +void TypePrinter::printMemberPointerBefore(const MemberPointerType *T, + raw_ostream &OS) { + IncludeStrongLifetimeRAII Strong(Policy); + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + printBefore(T->getPointeeType(), OS); // Handle things like 'int (Cls::*A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. if (isa(T->getPointeeType())) - S = '(' + S + ')'; - + OS << '('; + + PrintingPolicy InnerPolicy(Policy); + InnerPolicy.SuppressTag = false; + TypePrinter(InnerPolicy).print(QualType(T->getClass(), 0), OS, StringRef()); + + OS << "::*"; +} +void TypePrinter::printMemberPointerAfter(const MemberPointerType *T, + raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - print(T->getPointeeType(), S); + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + // Handle things like 'int (Cls::*A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa(T->getPointeeType())) + OS << ')'; + printAfter(T->getPointeeType(), OS); } -void TypePrinter::printConstantArray(const ConstantArrayType *T, - std::string &S) { - S += '['; - S += llvm::utostr(T->getSize().getZExtValue()); - S += ']'; - +void TypePrinter::printConstantArrayBefore(const ConstantArrayType *T, + raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - print(T->getElementType(), S); + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + printBefore(T->getElementType(), OS); +} +void TypePrinter::printConstantArrayAfter(const ConstantArrayType *T, + raw_ostream &OS) { + OS << '[' << T->getSize().getZExtValue() << ']'; + printAfter(T->getElementType(), OS); } -void TypePrinter::printIncompleteArray(const IncompleteArrayType *T, - std::string &S) { - S += "[]"; +void TypePrinter::printIncompleteArrayBefore(const IncompleteArrayType *T, + raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - print(T->getElementType(), S); + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + printBefore(T->getElementType(), OS); +} +void TypePrinter::printIncompleteArrayAfter(const IncompleteArrayType *T, + raw_ostream &OS) { + OS << "[]"; + printAfter(T->getElementType(), OS); } -void TypePrinter::printVariableArray(const VariableArrayType *T, - std::string &S) { - S += '['; - +void TypePrinter::printVariableArrayBefore(const VariableArrayType *T, + raw_ostream &OS) { + IncludeStrongLifetimeRAII Strong(Policy); + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + printBefore(T->getElementType(), OS); +} +void TypePrinter::printVariableArrayAfter(const VariableArrayType *T, + raw_ostream &OS) { + OS << '['; if (T->getIndexTypeQualifiers().hasQualifiers()) { - AppendTypeQualList(S, T->getIndexTypeCVRQualifiers()); - S += ' '; + AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers()); + OS << ' '; } if (T->getSizeModifier() == VariableArrayType::Static) - S += "static"; + OS << "static"; else if (T->getSizeModifier() == VariableArrayType::Star) - S += '*'; - - if (T->getSizeExpr()) { - std::string SStr; - llvm::raw_string_ostream s(SStr); - T->getSizeExpr()->printPretty(s, 0, Policy); - S += s.str(); - } - S += ']'; + OS << '*'; - IncludeStrongLifetimeRAII Strong(Policy); - print(T->getElementType(), S); + if (T->getSizeExpr()) + T->getSizeExpr()->printPretty(OS, 0, Policy); + OS << ']'; + + printAfter(T->getElementType(), OS); } -void TypePrinter::printDependentSizedArray(const DependentSizedArrayType *T, - std::string &S) { - S += '['; - - if (T->getSizeExpr()) { - std::string SStr; - llvm::raw_string_ostream s(SStr); - T->getSizeExpr()->printPretty(s, 0, Policy); - S += s.str(); - } - S += ']'; - +void TypePrinter::printDependentSizedArrayBefore( + const DependentSizedArrayType *T, + raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - print(T->getElementType(), S); + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + printBefore(T->getElementType(), OS); +} +void TypePrinter::printDependentSizedArrayAfter( + const DependentSizedArrayType *T, + raw_ostream &OS) { + OS << '['; + if (T->getSizeExpr()) + T->getSizeExpr()->printPretty(OS, 0, Policy); + OS << ']'; + printAfter(T->getElementType(), OS); } -void TypePrinter::printDependentSizedExtVector( +void TypePrinter::printDependentSizedExtVectorBefore( const DependentSizedExtVectorType *T, - std::string &S) { - print(T->getElementType(), S); - - S += " __attribute__((ext_vector_type("; - if (T->getSizeExpr()) { - std::string SStr; - llvm::raw_string_ostream s(SStr); - T->getSizeExpr()->printPretty(s, 0, Policy); - S += s.str(); - } - S += ")))"; + raw_ostream &OS) { + printBefore(T->getElementType(), OS); +} +void TypePrinter::printDependentSizedExtVectorAfter( + const DependentSizedExtVectorType *T, + raw_ostream &OS) { + OS << " __attribute__((ext_vector_type("; + if (T->getSizeExpr()) + T->getSizeExpr()->printPretty(OS, 0, Policy); + OS << ")))"; + printAfter(T->getElementType(), OS); } -void TypePrinter::printVector(const VectorType *T, std::string &S) { +void TypePrinter::printVectorBefore(const VectorType *T, raw_ostream &OS) { switch (T->getVectorKind()) { case VectorType::AltiVecPixel: - S = "__vector __pixel " + S; + OS << "__vector __pixel "; break; case VectorType::AltiVecBool: - print(T->getElementType(), S); - S = "__vector __bool " + S; + OS << "__vector __bool "; + printBefore(T->getElementType(), OS); break; case VectorType::AltiVecVector: - print(T->getElementType(), S); - S = "__vector " + S; + OS << "__vector "; + printBefore(T->getElementType(), OS); break; case VectorType::NeonVector: - print(T->getElementType(), S); - S = ("__attribute__((neon_vector_type(" + - llvm::utostr_32(T->getNumElements()) + "))) " + S); + OS << "__attribute__((neon_vector_type(" + << T->getNumElements() << "))) "; + printBefore(T->getElementType(), OS); break; case VectorType::NeonPolyVector: - print(T->getElementType(), S); - S = ("__attribute__((neon_polyvector_type(" + - llvm::utostr_32(T->getNumElements()) + "))) " + S); + OS << "__attribute__((neon_polyvector_type(" << + T->getNumElements() << "))) "; + printBefore(T->getElementType(), OS); break; case VectorType::GenericVector: { // FIXME: We prefer to print the size directly here, but have no way // to get the size of the type. - print(T->getElementType(), S); - std::string V = "__attribute__((__vector_size__("; - V += llvm::utostr_32(T->getNumElements()); // convert back to bytes. - std::string ET; - print(T->getElementType(), ET); - V += " * sizeof(" + ET + ")))) "; - S = V + S; + OS << "__attribute__((__vector_size__(" + << T->getNumElements() + << " * sizeof("; + print(T->getElementType(), OS, StringRef()); + OS << ")))) "; + printBefore(T->getElementType(), OS); break; } } } +void TypePrinter::printVectorAfter(const VectorType *T, raw_ostream &OS) { + printAfter(T->getElementType(), OS); +} -void TypePrinter::printExtVector(const ExtVectorType *T, std::string &S) { - S += " __attribute__((ext_vector_type("; - S += llvm::utostr_32(T->getNumElements()); - S += ")))"; - print(T->getElementType(), S); +void TypePrinter::printExtVectorBefore(const ExtVectorType *T, + raw_ostream &OS) { + printBefore(T->getElementType(), OS); +} +void TypePrinter::printExtVectorAfter(const ExtVectorType *T, raw_ostream &OS) { + printAfter(T->getElementType(), OS); + OS << " __attribute__((ext_vector_type("; + OS << T->getNumElements(); + OS << ")))"; } void -FunctionProtoType::printExceptionSpecification(std::string &S, +FunctionProtoType::printExceptionSpecification(raw_ostream &OS, PrintingPolicy Policy) const { if (hasDynamicExceptionSpec()) { - S += " throw("; + OS << " throw("; if (getExceptionSpecType() == EST_MSAny) - S += "..."; + OS << "..."; else for (unsigned I = 0, N = getNumExceptions(); I != N; ++I) { if (I) - S += ", "; + OS << ", "; - S += getExceptionType(I).getAsString(Policy); + OS << getExceptionType(I).stream(Policy); } - S += ")"; + OS << ')'; } else if (isNoexceptExceptionSpec(getExceptionSpecType())) { - S += " noexcept"; + OS << " noexcept"; if (getExceptionSpecType() == EST_ComputedNoexcept) { - S += "("; - llvm::raw_string_ostream EOut(S); - getNoexceptExpr()->printPretty(EOut, 0, Policy); - EOut.flush(); - S += EOut.str(); - S += ")"; + OS << '('; + getNoexceptExpr()->printPretty(OS, 0, Policy); + OS << ')'; } } } -void TypePrinter::printFunctionProto(const FunctionProtoType *T, - std::string &S) { +void TypePrinter::printFunctionProtoBefore(const FunctionProtoType *T, + raw_ostream &OS) { + if (T->hasTrailingReturn()) { + OS << "auto "; + if (!HasEmptyPlaceHolder) + OS << '('; + } else { + // If needed for precedence reasons, wrap the inner part in grouping parens. + SaveAndRestore PrevPHIsEmpty(HasEmptyPlaceHolder, false); + printBefore(T->getResultType(), OS); + if (!PrevPHIsEmpty.get()) + OS << '('; + } +} + +void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, + raw_ostream &OS) { // If needed for precedence reasons, wrap the inner part in grouping parens. - if (!S.empty()) - S = "(" + S + ")"; - - S += "("; - std::string Tmp; - PrintingPolicy ParamPolicy(Policy); - ParamPolicy.SuppressSpecifiers = false; - for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) { - if (i) S += ", "; - print(T->getArgType(i), Tmp); - S += Tmp; - Tmp.clear(); + if (!HasEmptyPlaceHolder) + OS << ')'; + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); + + OS << '('; + { + ParamPolicyRAII ParamPolicy(Policy); + for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) { + if (i) OS << ", "; + print(T->getArgType(i), OS, StringRef()); + } } if (T->isVariadic()) { if (T->getNumArgs()) - S += ", "; - S += "..."; + OS << ", "; + OS << "..."; } else if (T->getNumArgs() == 0 && !Policy.LangOpts.CPlusPlus) { // Do not emit int() if we have a proto, emit 'int(void)'. - S += "void"; + OS << "void"; } - S += ")"; + OS << ')'; FunctionType::ExtInfo Info = T->getExtInfo(); switch(Info.getCC()) { case CC_Default: break; case CC_C: - S += " __attribute__((cdecl))"; + OS << " __attribute__((cdecl))"; break; case CC_X86StdCall: - S += " __attribute__((stdcall))"; + OS << " __attribute__((stdcall))"; break; case CC_X86FastCall: - S += " __attribute__((fastcall))"; + OS << " __attribute__((fastcall))"; break; case CC_X86ThisCall: - S += " __attribute__((thiscall))"; + OS << " __attribute__((thiscall))"; break; case CC_X86Pascal: - S += " __attribute__((pascal))"; + OS << " __attribute__((pascal))"; break; case CC_AAPCS: - S += " __attribute__((pcs(\"aapcs\")))"; + OS << " __attribute__((pcs(\"aapcs\")))"; break; case CC_AAPCS_VFP: - S += " __attribute__((pcs(\"aapcs-vfp\")))"; + OS << " __attribute__((pcs(\"aapcs-vfp\")))"; break; } if (Info.getNoReturn()) - S += " __attribute__((noreturn))"; + OS << " __attribute__((noreturn))"; if (Info.getRegParm()) - S += " __attribute__((regparm (" + - llvm::utostr_32(Info.getRegParm()) + ")))"; - - AppendTypeQualList(S, T->getTypeQuals()); + OS << " __attribute__((regparm (" + << Info.getRegParm() << ")))"; + + if (unsigned quals = T->getTypeQuals()) { + OS << ' '; + AppendTypeQualList(OS, quals); + } switch (T->getRefQualifier()) { case RQ_None: break; case RQ_LValue: - S += " &"; + OS << " &"; break; case RQ_RValue: - S += " &&"; + OS << " &&"; break; } - T->printExceptionSpecification(S, Policy); + T->printExceptionSpecification(OS, Policy); + if (T->hasTrailingReturn()) { - std::string ResultS; - print(T->getResultType(), ResultS); - S = "auto " + S + " -> " + ResultS; + OS << " -> "; + print(T->getResultType(), OS, StringRef()); } else - print(T->getResultType(), S); + printAfter(T->getResultType(), OS); } -void TypePrinter::printFunctionNoProto(const FunctionNoProtoType *T, - std::string &S) { +void TypePrinter::printFunctionNoProtoBefore(const FunctionNoProtoType *T, + raw_ostream &OS) { // If needed for precedence reasons, wrap the inner part in grouping parens. - if (!S.empty()) - S = "(" + S + ")"; + SaveAndRestore PrevPHIsEmpty(HasEmptyPlaceHolder, false); + printBefore(T->getResultType(), OS); + if (!PrevPHIsEmpty.get()) + OS << '('; +} +void TypePrinter::printFunctionNoProtoAfter(const FunctionNoProtoType *T, + raw_ostream &OS) { + // If needed for precedence reasons, wrap the inner part in grouping parens. + if (!HasEmptyPlaceHolder) + OS << ')'; + SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); - S += "()"; + OS << "()"; if (T->getNoReturnAttr()) - S += " __attribute__((noreturn))"; - print(T->getResultType(), S); + OS << " __attribute__((noreturn))"; + printAfter(T->getResultType(), OS); } -static void printTypeSpec(const NamedDecl *D, std::string &S) { +void TypePrinter::printTypeSpec(const NamedDecl *D, raw_ostream &OS) { IdentifierInfo *II = D->getIdentifier(); - if (S.empty()) - S = II->getName().str(); - else - S = II->getName().str() + ' ' + S; + OS << II->getName(); + spaceBeforePlaceHolder(OS); } -void TypePrinter::printUnresolvedUsing(const UnresolvedUsingType *T, - std::string &S) { - printTypeSpec(T->getDecl(), S); +void TypePrinter::printUnresolvedUsingBefore(const UnresolvedUsingType *T, + raw_ostream &OS) { + printTypeSpec(T->getDecl(), OS); } +void TypePrinter::printUnresolvedUsingAfter(const UnresolvedUsingType *T, + raw_ostream &OS) { } -void TypePrinter::printTypedef(const TypedefType *T, std::string &S) { - printTypeSpec(T->getDecl(), S); +void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) { + printTypeSpec(T->getDecl(), OS); } +void TypePrinter::printTypedefAfter(const TypedefType *T, raw_ostream &OS) { } -void TypePrinter::printTypeOfExpr(const TypeOfExprType *T, std::string &S) { - if (!S.empty()) // Prefix the basic type, e.g. 'typeof(e) X'. - S = ' ' + S; - std::string Str; - llvm::raw_string_ostream s(Str); - T->getUnderlyingExpr()->printPretty(s, 0, Policy); - S = "typeof " + s.str() + S; +void TypePrinter::printTypeOfExprBefore(const TypeOfExprType *T, + raw_ostream &OS) { + OS << "typeof "; + T->getUnderlyingExpr()->printPretty(OS, 0, Policy); + spaceBeforePlaceHolder(OS); } - -void TypePrinter::printTypeOf(const TypeOfType *T, std::string &S) { - if (!S.empty()) // Prefix the basic type, e.g. 'typeof(t) X'. - S = ' ' + S; - std::string Tmp; - print(T->getUnderlyingType(), Tmp); - S = "typeof(" + Tmp + ")" + S; +void TypePrinter::printTypeOfExprAfter(const TypeOfExprType *T, + raw_ostream &OS) { } + +void TypePrinter::printTypeOfBefore(const TypeOfType *T, raw_ostream &OS) { + OS << "typeof("; + print(T->getUnderlyingType(), OS, StringRef()); + OS << ')'; + spaceBeforePlaceHolder(OS); } +void TypePrinter::printTypeOfAfter(const TypeOfType *T, raw_ostream &OS) { } -void TypePrinter::printDecltype(const DecltypeType *T, std::string &S) { - if (!S.empty()) // Prefix the basic type, e.g. 'decltype(t) X'. - S = ' ' + S; - std::string Str; - llvm::raw_string_ostream s(Str); - T->getUnderlyingExpr()->printPretty(s, 0, Policy); - S = "decltype(" + s.str() + ")" + S; +void TypePrinter::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) { + OS << "decltype("; + T->getUnderlyingExpr()->printPretty(OS, 0, Policy); + OS << ')'; + spaceBeforePlaceHolder(OS); } +void TypePrinter::printDecltypeAfter(const DecltypeType *T, raw_ostream &OS) { } -void TypePrinter::printUnaryTransform(const UnaryTransformType *T, - std::string &S) { - if (!S.empty()) - S = ' ' + S; - std::string Str; +void TypePrinter::printUnaryTransformBefore(const UnaryTransformType *T, + raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - print(T->getBaseType(), Str); switch (T->getUTTKind()) { case UnaryTransformType::EnumUnderlyingType: - S = "__underlying_type(" + Str + ")" + S; - break; + OS << "__underlying_type("; + print(T->getBaseType(), OS, StringRef()); + OS << ')'; + spaceBeforePlaceHolder(OS); + return; + } + + printBefore(T->getBaseType(), OS); +} +void TypePrinter::printUnaryTransformAfter(const UnaryTransformType *T, + raw_ostream &OS) { + IncludeStrongLifetimeRAII Strong(Policy); + + switch (T->getUTTKind()) { + case UnaryTransformType::EnumUnderlyingType: + return; } + + printAfter(T->getBaseType(), OS); } -void TypePrinter::printAuto(const AutoType *T, std::string &S) { +void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) { // If the type has been deduced, do not print 'auto'. if (T->isDeduced()) { - print(T->getDeducedType(), S); + printBefore(T->getDeducedType(), OS); } else { - if (!S.empty()) // Prefix the basic type, e.g. 'auto X'. - S = ' ' + S; - S = "auto" + S; + OS << "auto"; + spaceBeforePlaceHolder(OS); } } +void TypePrinter::printAutoAfter(const AutoType *T, raw_ostream &OS) { + // If the type has been deduced, do not print 'auto'. + if (T->isDeduced()) + printAfter(T->getDeducedType(), OS); +} -void TypePrinter::printAtomic(const AtomicType *T, std::string &S) { - if (!S.empty()) - S = ' ' + S; - std::string Str; +void TypePrinter::printAtomicBefore(const AtomicType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - print(T->getValueType(), Str); - S = "_Atomic(" + Str + ")" + S; + OS << "_Atomic("; + print(T->getValueType(), OS, StringRef()); + OS << ')'; + spaceBeforePlaceHolder(OS); } +void TypePrinter::printAtomicAfter(const AtomicType *T, raw_ostream &OS) { } /// Appends the given scope to the end of a string. -void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) { +void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) { if (DC->isTranslationUnit()) return; - AppendScope(DC->getParent(), Buffer); - - unsigned OldSize = Buffer.size(); + AppendScope(DC->getParent(), OS); if (NamespaceDecl *NS = dyn_cast(DC)) { if (Policy.SuppressUnwrittenScope && (NS->isAnonymousNamespace() || NS->isInline())) return; if (NS->getIdentifier()) - Buffer += NS->getNameAsString(); + OS << NS->getName() << "::"; else - Buffer += ""; + OS << "::"; } else if (ClassTemplateSpecializationDecl *Spec = dyn_cast(DC)) { IncludeStrongLifetimeRAII Strong(Policy); + OS << Spec->getIdentifier()->getName(); const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - std::string TemplateArgsStr - = TemplateSpecializationType::PrintTemplateArgumentList( + TemplateSpecializationType::PrintTemplateArgumentList(OS, TemplateArgs.data(), TemplateArgs.size(), Policy); - Buffer += Spec->getIdentifier()->getName(); - Buffer += TemplateArgsStr; + OS << "::"; } else if (TagDecl *Tag = dyn_cast(DC)) { if (TypedefNameDecl *Typedef = Tag->getTypedefNameForAnonDecl()) - Buffer += Typedef->getIdentifier()->getName(); + OS << Typedef->getIdentifier()->getName() << "::"; else if (Tag->getIdentifier()) - Buffer += Tag->getIdentifier()->getName(); + OS << Tag->getIdentifier()->getName() << "::"; else return; } - - if (Buffer.size() != OldSize) - Buffer += "::"; } -void TypePrinter::printTag(TagDecl *D, std::string &InnerString) { +void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { if (Policy.SuppressTag) return; - std::string Buffer; bool HasKindDecoration = false; // bool SuppressTagKeyword @@ -654,25 +833,24 @@ void TypePrinter::printTag(TagDecl *D, std::string &InnerString) { if (!(Policy.LangOpts.CPlusPlus || Policy.SuppressTagKeyword || D->getTypedefNameForAnonDecl())) { HasKindDecoration = true; - Buffer += D->getKindName(); - Buffer += ' '; + OS << D->getKindName(); + OS << ' '; } // Compute the full nested-name-specifier for this type. // In C, this will always be empty except when the type // being printed is anonymous within other Record. if (!Policy.SuppressScope) - AppendScope(D->getDeclContext(), Buffer); + AppendScope(D->getDeclContext(), OS); if (const IdentifierInfo *II = D->getIdentifier()) - Buffer += II->getNameStart(); + OS << II->getName(); else if (TypedefNameDecl *Typedef = D->getTypedefNameForAnonDecl()) { assert(Typedef->getIdentifier() && "Typedef without identifier?"); - Buffer += Typedef->getIdentifier()->getNameStart(); + OS << Typedef->getIdentifier()->getName(); } else { // Make an unambiguous representation for anonymous types, e.g. // - llvm::raw_string_ostream OS(Buffer); if (isa(D) && cast(D)->isLambda()) { OS << "getDecl(), S); +void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) { + printTag(T->getDecl(), OS); } +void TypePrinter::printRecordAfter(const RecordType *T, raw_ostream &OS) { } -void TypePrinter::printEnum(const EnumType *T, std::string &S) { - printTag(T->getDecl(), S); +void TypePrinter::printEnumBefore(const EnumType *T, raw_ostream &OS) { + printTag(T->getDecl(), OS); } +void TypePrinter::printEnumAfter(const EnumType *T, raw_ostream &OS) { } -void TypePrinter::printTemplateTypeParm(const TemplateTypeParmType *T, - std::string &S) { - if (!S.empty()) // Prefix the basic type, e.g. 'parmname X'. - S = ' ' + S; - +void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T, + raw_ostream &OS) { if (IdentifierInfo *Id = T->getIdentifier()) - S = Id->getName().str() + S; + OS << Id->getName(); else - S = "type-parameter-" + llvm::utostr_32(T->getDepth()) + '-' + - llvm::utostr_32(T->getIndex()) + S; + OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex(); + spaceBeforePlaceHolder(OS); } +void TypePrinter::printTemplateTypeParmAfter(const TemplateTypeParmType *T, + raw_ostream &OS) { } -void TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T, - std::string &S) { +void TypePrinter::printSubstTemplateTypeParmBefore( + const SubstTemplateTypeParmType *T, + raw_ostream &OS) { + IncludeStrongLifetimeRAII Strong(Policy); + printBefore(T->getReplacementType(), OS); +} +void TypePrinter::printSubstTemplateTypeParmAfter( + const SubstTemplateTypeParmType *T, + raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - print(T->getReplacementType(), S); + printAfter(T->getReplacementType(), OS); } -void TypePrinter::printSubstTemplateTypeParmPack( +void TypePrinter::printSubstTemplateTypeParmPackBefore( const SubstTemplateTypeParmPackType *T, - std::string &S) { + raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - printTemplateTypeParm(T->getReplacedParameter(), S); + printTemplateTypeParmBefore(T->getReplacedParameter(), OS); +} +void TypePrinter::printSubstTemplateTypeParmPackAfter( + const SubstTemplateTypeParmPackType *T, + raw_ostream &OS) { + IncludeStrongLifetimeRAII Strong(Policy); + printTemplateTypeParmAfter(T->getReplacedParameter(), OS); } -void TypePrinter::printTemplateSpecialization( +void TypePrinter::printTemplateSpecializationBefore( const TemplateSpecializationType *T, - std::string &S) { + raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - std::string SpecString; - - { - llvm::raw_string_ostream OS(SpecString); - T->getTemplateName().print(OS, Policy); - } + T->getTemplateName().print(OS, Policy); - SpecString += TemplateSpecializationType::PrintTemplateArgumentList( - T->getArgs(), - T->getNumArgs(), - Policy); - if (S.empty()) - S.swap(SpecString); - else - S = SpecString + ' ' + S; + TemplateSpecializationType::PrintTemplateArgumentList(OS, + T->getArgs(), + T->getNumArgs(), + Policy); + spaceBeforePlaceHolder(OS); } +void TypePrinter::printTemplateSpecializationAfter( + const TemplateSpecializationType *T, + raw_ostream &OS) { } -void TypePrinter::printInjectedClassName(const InjectedClassNameType *T, - std::string &S) { - printTemplateSpecialization(T->getInjectedTST(), S); +void TypePrinter::printInjectedClassNameBefore(const InjectedClassNameType *T, + raw_ostream &OS) { + printTemplateSpecializationBefore(T->getInjectedTST(), OS); } - -void TypePrinter::printElaborated(const ElaboratedType *T, std::string &S) { - std::string MyString; +void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T, + raw_ostream &OS) { } + +void TypePrinter::printElaboratedBefore(const ElaboratedType *T, + raw_ostream &OS) { + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ETK_None) + OS << " "; + NestedNameSpecifier* Qualifier = T->getQualifier(); + if (Qualifier) + Qualifier->print(OS, Policy); - { - llvm::raw_string_ostream OS(MyString); - OS << TypeWithKeyword::getKeywordName(T->getKeyword()); - if (T->getKeyword() != ETK_None) - OS << " "; - NestedNameSpecifier* Qualifier = T->getQualifier(); - if (Qualifier) - Qualifier->print(OS, Policy); - } - - std::string TypeStr; - PrintingPolicy InnerPolicy(Policy); - InnerPolicy.SuppressTagKeyword = true; - InnerPolicy.SuppressScope = true; - TypePrinter(InnerPolicy).print(T->getNamedType(), TypeStr); - - MyString += TypeStr; - if (S.empty()) - S.swap(MyString); - else - S = MyString + ' ' + S; + ElaboratedTypePolicyRAII PolicyRAII(Policy); + printBefore(T->getNamedType(), OS); +} +void TypePrinter::printElaboratedAfter(const ElaboratedType *T, + raw_ostream &OS) { + ElaboratedTypePolicyRAII PolicyRAII(Policy); + printAfter(T->getNamedType(), OS); } -void TypePrinter::printParen(const ParenType *T, std::string &S) { - if (!S.empty() && !isa(T->getInnerType())) - S = '(' + S + ')'; - print(T->getInnerType(), S); +void TypePrinter::printParenBefore(const ParenType *T, raw_ostream &OS) { + if (!HasEmptyPlaceHolder && !isa(T->getInnerType())) { + printBefore(T->getInnerType(), OS); + OS << '('; + } else + printBefore(T->getInnerType(), OS); +} +void TypePrinter::printParenAfter(const ParenType *T, raw_ostream &OS) { + if (!HasEmptyPlaceHolder && !isa(T->getInnerType())) { + OS << ')'; + printAfter(T->getInnerType(), OS); + } else + printAfter(T->getInnerType(), OS); } -void TypePrinter::printDependentName(const DependentNameType *T, std::string &S) { - std::string MyString; +void TypePrinter::printDependentNameBefore(const DependentNameType *T, + raw_ostream &OS) { + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ETK_None) + OS << " "; - { - llvm::raw_string_ostream OS(MyString); - OS << TypeWithKeyword::getKeywordName(T->getKeyword()); - if (T->getKeyword() != ETK_None) - OS << " "; - - T->getQualifier()->print(OS, Policy); - - OS << T->getIdentifier()->getName(); - } + T->getQualifier()->print(OS, Policy); - if (S.empty()) - S.swap(MyString); - else - S = MyString + ' ' + S; + OS << T->getIdentifier()->getName(); + spaceBeforePlaceHolder(OS); } +void TypePrinter::printDependentNameAfter(const DependentNameType *T, + raw_ostream &OS) { } -void TypePrinter::printDependentTemplateSpecialization( - const DependentTemplateSpecializationType *T, std::string &S) { +void TypePrinter::printDependentTemplateSpecializationBefore( + const DependentTemplateSpecializationType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - std::string MyString; - { - llvm::raw_string_ostream OS(MyString); - OS << TypeWithKeyword::getKeywordName(T->getKeyword()); - if (T->getKeyword() != ETK_None) - OS << " "; - - if (T->getQualifier()) - T->getQualifier()->print(OS, Policy); - OS << T->getIdentifier()->getName(); - OS << TemplateSpecializationType::PrintTemplateArgumentList( - T->getArgs(), - T->getNumArgs(), - Policy); - } + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ETK_None) + OS << " "; - if (S.empty()) - S.swap(MyString); - else - S = MyString + ' ' + S; + if (T->getQualifier()) + T->getQualifier()->print(OS, Policy); + OS << T->getIdentifier()->getName(); + TemplateSpecializationType::PrintTemplateArgumentList(OS, + T->getArgs(), + T->getNumArgs(), + Policy); + spaceBeforePlaceHolder(OS); } +void TypePrinter::printDependentTemplateSpecializationAfter( + const DependentTemplateSpecializationType *T, raw_ostream &OS) { } -void TypePrinter::printPackExpansion(const PackExpansionType *T, - std::string &S) { - print(T->getPattern(), S); - S += "..."; +void TypePrinter::printPackExpansionBefore(const PackExpansionType *T, + raw_ostream &OS) { + printBefore(T->getPattern(), OS); +} +void TypePrinter::printPackExpansionAfter(const PackExpansionType *T, + raw_ostream &OS) { + printAfter(T->getPattern(), OS); + OS << "..."; } -void TypePrinter::printAttributed(const AttributedType *T, - std::string &S) { +void TypePrinter::printAttributedBefore(const AttributedType *T, + raw_ostream &OS) { // Prefer the macro forms of the GC and ownership qualifiers. if (T->getAttrKind() == AttributedType::attr_objc_gc || T->getAttrKind() == AttributedType::attr_objc_ownership) - return print(T->getEquivalentType(), S); + return printBefore(T->getEquivalentType(), OS); - print(T->getModifiedType(), S); + printBefore(T->getModifiedType(), OS); +} + +void TypePrinter::printAttributedAfter(const AttributedType *T, + raw_ostream &OS) { + // Prefer the macro forms of the GC and ownership qualifiers. + if (T->getAttrKind() == AttributedType::attr_objc_gc || + T->getAttrKind() == AttributedType::attr_objc_ownership) + return printAfter(T->getEquivalentType(), OS); // TODO: not all attributes are GCC-style attributes. - S += " __attribute__(("; + OS << " __attribute__(("; switch (T->getAttrKind()) { case AttributedType::attr_address_space: - S += "address_space("; - S += T->getEquivalentType().getAddressSpace(); - S += ")"; + OS << "address_space("; + OS << T->getEquivalentType().getAddressSpace(); + OS << ')'; break; case AttributedType::attr_vector_size: { - S += "__vector_size__("; + OS << "__vector_size__("; if (const VectorType *vector =T->getEquivalentType()->getAs()) { - S += vector->getNumElements(); - S += " * sizeof("; - - std::string tmp; - print(vector->getElementType(), tmp); - S += tmp; - S += ")"; + OS << vector->getNumElements(); + OS << " * sizeof("; + print(vector->getElementType(), OS, StringRef()); + OS << ')'; } - S += ")"; + OS << ')'; break; } case AttributedType::attr_neon_vector_type: case AttributedType::attr_neon_polyvector_type: { if (T->getAttrKind() == AttributedType::attr_neon_vector_type) - S += "neon_vector_type("; + OS << "neon_vector_type("; else - S += "neon_polyvector_type("; + OS << "neon_polyvector_type("; const VectorType *vector = T->getEquivalentType()->getAs(); - S += llvm::utostr_32(vector->getNumElements()); - S += ")"; + OS << vector->getNumElements(); + OS << ')'; break; } case AttributedType::attr_regparm: { - S += "regparm("; + OS << "regparm("; QualType t = T->getEquivalentType(); while (!t->isFunctionType()) t = t->getPointeeType(); - S += t->getAs()->getRegParmType(); - S += ")"; + OS << t->getAs()->getRegParmType(); + OS << ')'; break; } case AttributedType::attr_objc_gc: { - S += "objc_gc("; + OS << "objc_gc("; QualType tmp = T->getEquivalentType(); while (tmp.getObjCGCAttr() == Qualifiers::GCNone) { @@ -939,116 +1121,225 @@ void TypePrinter::printAttributed(const AttributedType *T, } if (tmp.isObjCGCWeak()) - S += "weak"; + OS << "weak"; else - S += "strong"; - S += ")"; + OS << "strong"; + OS << ')'; break; } case AttributedType::attr_objc_ownership: - S += "objc_ownership("; + OS << "objc_ownership("; switch (T->getEquivalentType().getObjCLifetime()) { case Qualifiers::OCL_None: llvm_unreachable("no ownership!"); - case Qualifiers::OCL_ExplicitNone: S += "none"; break; - case Qualifiers::OCL_Strong: S += "strong"; break; - case Qualifiers::OCL_Weak: S += "weak"; break; - case Qualifiers::OCL_Autoreleasing: S += "autoreleasing"; break; + case Qualifiers::OCL_ExplicitNone: OS << "none"; break; + case Qualifiers::OCL_Strong: OS << "strong"; break; + case Qualifiers::OCL_Weak: OS << "weak"; break; + case Qualifiers::OCL_Autoreleasing: OS << "autoreleasing"; break; } - S += ")"; + OS << ')'; break; - case AttributedType::attr_noreturn: S += "noreturn"; break; - case AttributedType::attr_cdecl: S += "cdecl"; break; - case AttributedType::attr_fastcall: S += "fastcall"; break; - case AttributedType::attr_stdcall: S += "stdcall"; break; - case AttributedType::attr_thiscall: S += "thiscall"; break; - case AttributedType::attr_pascal: S += "pascal"; break; + case AttributedType::attr_noreturn: OS << "noreturn"; break; + case AttributedType::attr_cdecl: OS << "cdecl"; break; + case AttributedType::attr_fastcall: OS << "fastcall"; break; + case AttributedType::attr_stdcall: OS << "stdcall"; break; + case AttributedType::attr_thiscall: OS << "thiscall"; break; + case AttributedType::attr_pascal: OS << "pascal"; break; case AttributedType::attr_pcs: { - S += "pcs("; + OS << "pcs("; QualType t = T->getEquivalentType(); while (!t->isFunctionType()) t = t->getPointeeType(); - S += (t->getAs()->getCallConv() == CC_AAPCS ? + OS << (t->getAs()->getCallConv() == CC_AAPCS ? "\"aapcs\"" : "\"aapcs-vfp\""); - S += ")"; + OS << ')'; break; } } - S += "))"; + OS << "))"; } -void TypePrinter::printObjCInterface(const ObjCInterfaceType *T, - std::string &S) { - if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. - S = ' ' + S; - - std::string ObjCQIString = T->getDecl()->getNameAsString(); - S = ObjCQIString + S; +void TypePrinter::printObjCInterfaceBefore(const ObjCInterfaceType *T, + raw_ostream &OS) { + OS << T->getDecl()->getName(); + spaceBeforePlaceHolder(OS); } +void TypePrinter::printObjCInterfaceAfter(const ObjCInterfaceType *T, + raw_ostream &OS) { } -void TypePrinter::printObjCObject(const ObjCObjectType *T, - std::string &S) { +void TypePrinter::printObjCObjectBefore(const ObjCObjectType *T, + raw_ostream &OS) { if (T->qual_empty()) - return print(T->getBaseType(), S); + return printBefore(T->getBaseType(), OS); - std::string tmp; - print(T->getBaseType(), tmp); - tmp += '<'; + print(T->getBaseType(), OS, StringRef()); + OS << '<'; bool isFirst = true; for (ObjCObjectType::qual_iterator I = T->qual_begin(), E = T->qual_end(); I != E; ++I) { if (isFirst) isFirst = false; else - tmp += ','; - tmp += (*I)->getNameAsString(); - } - tmp += '>'; - - if (!S.empty()) { - tmp += ' '; - tmp += S; + OS << ','; + OS << (*I)->getName(); } - std::swap(tmp, S); + OS << '>'; + spaceBeforePlaceHolder(OS); +} +void TypePrinter::printObjCObjectAfter(const ObjCObjectType *T, + raw_ostream &OS) { + if (T->qual_empty()) + return printAfter(T->getBaseType(), OS); } -void TypePrinter::printObjCObjectPointer(const ObjCObjectPointerType *T, - std::string &S) { - std::string ObjCQIString; - - T->getPointeeType().getLocalQualifiers().getAsStringInternal(ObjCQIString, - Policy); - if (!ObjCQIString.empty()) - ObjCQIString += ' '; - +void TypePrinter::printObjCObjectPointerBefore(const ObjCObjectPointerType *T, + raw_ostream &OS) { + T->getPointeeType().getLocalQualifiers().print(OS, Policy, + /*appendSpaceIfNonEmpty=*/true); + if (T->isObjCIdType() || T->isObjCQualifiedIdType()) - ObjCQIString += "id"; + OS << "id"; else if (T->isObjCClassType() || T->isObjCQualifiedClassType()) - ObjCQIString += "Class"; + OS << "Class"; else if (T->isObjCSelType()) - ObjCQIString += "SEL"; + OS << "SEL"; else - ObjCQIString += T->getInterfaceDecl()->getNameAsString(); + OS << T->getInterfaceDecl()->getName(); if (!T->qual_empty()) { - ObjCQIString += '<'; + OS << '<'; for (ObjCObjectPointerType::qual_iterator I = T->qual_begin(), E = T->qual_end(); I != E; ++I) { - ObjCQIString += (*I)->getNameAsString(); + OS << (*I)->getName(); if (I+1 != E) - ObjCQIString += ','; + OS << ','; } - ObjCQIString += '>'; + OS << '>'; } - if (!T->isObjCIdType() && !T->isObjCQualifiedIdType()) - ObjCQIString += " *"; // Don't forget the implicit pointer. - else if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. - S = ' ' + S; + if (!T->isObjCIdType() && !T->isObjCQualifiedIdType()) { + OS << " *"; // Don't forget the implicit pointer. + } else { + spaceBeforePlaceHolder(OS); + } +} +void TypePrinter::printObjCObjectPointerAfter(const ObjCObjectPointerType *T, + raw_ostream &OS) { } + +void TemplateSpecializationType:: + PrintTemplateArgumentList(raw_ostream &OS, + const TemplateArgumentListInfo &Args, + const PrintingPolicy &Policy) { + return PrintTemplateArgumentList(OS, + Args.getArgumentArray(), + Args.size(), + Policy); +} + +void +TemplateSpecializationType::PrintTemplateArgumentList( + raw_ostream &OS, + const TemplateArgument *Args, + unsigned NumArgs, + const PrintingPolicy &Policy, + bool SkipBrackets) { + if (!SkipBrackets) + OS << '<'; - S = ObjCQIString + S; + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { + if (Arg > 0) + OS << ", "; + + // Print the argument into a string. + SmallString<128> Buf; + llvm::raw_svector_ostream ArgOS(Buf); + if (Args[Arg].getKind() == TemplateArgument::Pack) { + PrintTemplateArgumentList(ArgOS, + Args[Arg].pack_begin(), + Args[Arg].pack_size(), + Policy, true); + } else { + Args[Arg].print(Policy, ArgOS); + } + StringRef ArgString = ArgOS.str(); + + // If this is the first argument and its string representation + // begins with the global scope specifier ('::foo'), add a space + // to avoid printing the diagraph '<:'. + if (!Arg && !ArgString.empty() && ArgString[0] == ':') + OS << ' '; + + OS << ArgString; + } + + if (!SkipBrackets) + OS << '>'; +} + +// Sadly, repeat all that with TemplateArgLoc. +void TemplateSpecializationType:: +PrintTemplateArgumentList(raw_ostream &OS, + const TemplateArgumentLoc *Args, unsigned NumArgs, + const PrintingPolicy &Policy) { + OS << '<'; + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { + if (Arg > 0) + OS << ", "; + + // Print the argument into a string. + SmallString<128> Buf; + llvm::raw_svector_ostream ArgOS(Buf); + if (Args[Arg].getArgument().getKind() == TemplateArgument::Pack) { + PrintTemplateArgumentList(ArgOS, + Args[Arg].getArgument().pack_begin(), + Args[Arg].getArgument().pack_size(), + Policy, true); + } else { + Args[Arg].getArgument().print(Policy, ArgOS); + } + StringRef ArgString = ArgOS.str(); + + // If this is the first argument and its string representation + // begins with the global scope specifier ('::foo'), add a space + // to avoid printing the diagraph '<:'. + if (!Arg && !ArgString.empty() && ArgString[0] == ':') + OS << ' '; + + OS << ArgString; + } + + OS << '>'; +} + +void +FunctionProtoType::printExceptionSpecification(std::string &S, + PrintingPolicy Policy) const { + + if (hasDynamicExceptionSpec()) { + S += " throw("; + if (getExceptionSpecType() == EST_MSAny) + S += "..."; + else + for (unsigned I = 0, N = getNumExceptions(); I != N; ++I) { + if (I) + S += ", "; + + S += getExceptionType(I).getAsString(Policy); + } + S += ")"; + } else if (isNoexceptExceptionSpec(getExceptionSpecType())) { + S += " noexcept"; + if (getExceptionSpecType() == EST_ComputedNoexcept) { + S += "("; + llvm::raw_string_ostream EOut(S); + getNoexceptExpr()->printPretty(EOut, 0, Policy); + EOut.flush(); + S += EOut.str(); + S += ")"; + } + } } std::string TemplateSpecializationType:: @@ -1148,15 +1439,14 @@ PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs, } void QualType::dump(const char *msg) const { - std::string R = "identifier"; - LangOptions LO; - getAsStringInternal(R, PrintingPolicy(LO)); if (msg) llvm::errs() << msg << ": "; - llvm::errs() << R << "\n"; + LangOptions LO; + print(llvm::errs(), PrintingPolicy(LO), "identifier"); + llvm::errs() << '\n'; } void QualType::dump() const { - dump(""); + dump(0); } void Type::dump() const { @@ -1171,51 +1461,99 @@ std::string Qualifiers::getAsString() const { // Appends qualifiers to the given string, separated by spaces. Will // prefix a space if the string is non-empty. Will not append a final // space. -void Qualifiers::getAsStringInternal(std::string &S, - const PrintingPolicy& Policy) const { - AppendTypeQualList(S, getCVRQualifiers()); +std::string Qualifiers::getAsString(const PrintingPolicy &Policy) const { + SmallString<64> Buf; + llvm::raw_svector_ostream StrOS(Buf); + print(StrOS, Policy); + return StrOS.str(); +} + +bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const { + if (getCVRQualifiers()) + return false; + + if (getAddressSpace()) + return false; + + if (getObjCGCAttr()) + return false; + + if (Qualifiers::ObjCLifetime lifetime = getObjCLifetime()) + if (!(lifetime == Qualifiers::OCL_Strong && Policy.SuppressStrongLifetime)) + return false; + + return true; +} + +// Appends qualifiers to the given string, separated by spaces. Will +// prefix a space if the string is non-empty. Will not append a final +// space. +void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy, + bool appendSpaceIfNonEmpty) const { + bool addSpace = false; + + unsigned quals = getCVRQualifiers(); + if (quals) { + AppendTypeQualList(OS, quals); + addSpace = true; + } if (unsigned addrspace = getAddressSpace()) { - if (!S.empty()) S += ' '; + if (addSpace) + OS << ' '; + addSpace = true; switch (addrspace) { case LangAS::opencl_global: - S += "__global"; + OS << "__global"; break; case LangAS::opencl_local: - S += "__local"; + OS << "__local"; break; case LangAS::opencl_constant: - S += "__constant"; + OS << "__constant"; break; default: - S += "__attribute__((address_space("; - S += llvm::utostr_32(addrspace); - S += ")))"; + OS << "__attribute__((address_space("; + OS << addrspace; + OS << ")))"; } } if (Qualifiers::GC gc = getObjCGCAttr()) { - if (!S.empty()) S += ' '; + if (addSpace) + OS << ' '; + addSpace = true; if (gc == Qualifiers::Weak) - S += "__weak"; + OS << "__weak"; else - S += "__strong"; + OS << "__strong"; } if (Qualifiers::ObjCLifetime lifetime = getObjCLifetime()) { - if (!S.empty() && - !(lifetime == Qualifiers::OCL_Strong && Policy.SuppressStrongLifetime)) - S += ' '; + if (!(lifetime == Qualifiers::OCL_Strong && Policy.SuppressStrongLifetime)){ + if (addSpace) + OS << ' '; + addSpace = true; + } switch (lifetime) { case Qualifiers::OCL_None: llvm_unreachable("none but true"); - case Qualifiers::OCL_ExplicitNone: S += "__unsafe_unretained"; break; + case Qualifiers::OCL_ExplicitNone: OS << "__unsafe_unretained"; break; case Qualifiers::OCL_Strong: if (!Policy.SuppressStrongLifetime) - S += "__strong"; + OS << "__strong"; break; - case Qualifiers::OCL_Weak: S += "__weak"; break; - case Qualifiers::OCL_Autoreleasing: S += "__autoreleasing"; break; + case Qualifiers::OCL_Weak: OS << "__weak"; break; + case Qualifiers::OCL_Autoreleasing: OS << "__autoreleasing"; break; } } + + if (appendSpaceIfNonEmpty && addSpace) + OS << ' '; +} + +std::string QualType::getAsString(const PrintingPolicy &Policy) const { + std::string S; + getAsStringInternal(S, Policy); + return S; } std::string QualType::getAsString(const Type *ty, Qualifiers qs) { @@ -1225,8 +1563,25 @@ std::string QualType::getAsString(const Type *ty, Qualifiers qs) { return buffer; } +void QualType::print(const Type *ty, Qualifiers qs, + raw_ostream &OS, const PrintingPolicy &policy, + const Twine &PlaceHolder) { + SmallString<128> PHBuf; + StringRef PH; + if (PlaceHolder.isSingleStringRef()) + PH = PlaceHolder.getSingleStringRef(); + else + PH = PlaceHolder.toStringRef(PHBuf); + + TypePrinter(policy).print(ty, qs, OS, PH); +} + void QualType::getAsStringInternal(const Type *ty, Qualifiers qs, std::string &buffer, const PrintingPolicy &policy) { - TypePrinter(policy).print(ty, qs, buffer); + SmallString<256> Buf; + llvm::raw_svector_ostream StrOS(Buf); + TypePrinter(policy).print(ty, qs, StrOS, buffer); + std::string str = StrOS.str(); + buffer.swap(str); } diff --git a/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp b/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp index 1c13bffa21..0c555b53f9 100644 --- a/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp +++ b/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp @@ -13,9 +13,9 @@ template struct E; eval> eA; eval> eB; -eval> eC; // expected-error{{implicit instantiation of undefined template 'eval >'}} -eval> eD; // expected-error{{implicit instantiation of undefined template 'eval >'}} -eval> eE; // expected-error{{implicit instantiation of undefined template 'eval >}} +eval> eC; // expected-error{{implicit instantiation of undefined template 'eval>'}} +eval> eD; // expected-error{{implicit instantiation of undefined template 'eval>'}} +eval> eE; // expected-error{{implicit instantiation of undefined template 'eval>}} template