1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909 |
- //===- TypePrinter.cpp - Pretty-Print Clang Types -------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This contains code to print types from Clang's type system.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/AST/PrettyPrinter.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/Decl.h"
- #include "clang/AST/DeclBase.h"
- #include "clang/AST/DeclCXX.h"
- #include "clang/AST/DeclObjC.h"
- #include "clang/AST/DeclTemplate.h"
- #include "clang/AST/Expr.h"
- #include "clang/AST/NestedNameSpecifier.h"
- #include "clang/AST/TemplateBase.h"
- #include "clang/AST/TemplateName.h"
- #include "clang/AST/Type.h"
- #include "clang/Basic/AddressSpaces.h"
- #include "clang/Basic/ExceptionSpecificationType.h"
- #include "clang/Basic/IdentifierTable.h"
- #include "clang/Basic/LLVM.h"
- #include "clang/Basic/LangOptions.h"
- #include "clang/Basic/SourceLocation.h"
- #include "clang/Basic/SourceManager.h"
- #include "clang/Basic/Specifiers.h"
- #include "llvm/ADT/ArrayRef.h"
- #include "llvm/ADT/SmallString.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/ADT/Twine.h"
- #include "llvm/Support/Casting.h"
- #include "llvm/Support/Compiler.h"
- #include "llvm/Support/ErrorHandling.h"
- #include "llvm/Support/SaveAndRestore.h"
- #include "llvm/Support/raw_ostream.h"
- #include <cassert>
- #include <string>
- using namespace clang;
- namespace {
- /// RAII object that enables printing of the ARC __strong lifetime
- /// qualifier.
- class IncludeStrongLifetimeRAII {
- PrintingPolicy &Policy;
- bool Old;
- public:
- explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy)
- : Policy(Policy), Old(Policy.SuppressStrongLifetime) {
- if (!Policy.SuppressLifetimeQualifiers)
- Policy.SuppressStrongLifetime = false;
- }
- ~IncludeStrongLifetimeRAII() {
- 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;
- unsigned Indentation;
- bool HasEmptyPlaceHolder = false;
- bool InsideCCAttribute = false;
- public:
- explicit TypePrinter(const PrintingPolicy &Policy, unsigned Indentation = 0)
- : Policy(Policy), Indentation(Indentation) {}
- 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(NamedDecl *D, raw_ostream &OS);
- void printBefore(QualType T, raw_ostream &OS);
- void printAfter(QualType T, raw_ostream &OS);
- void AppendScope(DeclContext *DC, raw_ostream &OS);
- void printTag(TagDecl *T, raw_ostream &OS);
- void printFunctionAfter(const FunctionType::ExtInfo &Info, raw_ostream &OS);
- #define ABSTRACT_TYPE(CLASS, PARENT)
- #define TYPE(CLASS, PARENT) \
- 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.inc"
- private:
- void printBefore(const Type *ty, Qualifiers qs, raw_ostream &OS);
- void printAfter(const Type *ty, Qualifiers qs, raw_ostream &OS);
- };
- } // namespace
- static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals,
- bool HasRestrictKeyword) {
- bool appendSpace = false;
- if (TypeQuals & Qualifiers::Const) {
- OS << "const";
- appendSpace = true;
- }
- if (TypeQuals & Qualifiers::Volatile) {
- if (appendSpace) OS << ' ';
- OS << "volatile";
- appendSpace = true;
- }
- if (TypeQuals & Qualifiers::Restrict) {
- if (appendSpace) OS << ' ';
- if (HasRestrictKeyword) {
- OS << "restrict";
- } else {
- OS << "__restrict";
- }
- }
- }
- void TypePrinter::spaceBeforePlaceHolder(raw_ostream &OS) {
- if (!HasEmptyPlaceHolder)
- OS << ' ';
- }
- static SplitQualType splitAccordingToPolicy(QualType QT,
- const PrintingPolicy &Policy) {
- if (Policy.PrintCanonicalTypes)
- QT = QT.getCanonicalType();
- return QT.split();
- }
- void TypePrinter::print(QualType t, raw_ostream &OS, StringRef PlaceHolder) {
- SplitQualType split = splitAccordingToPolicy(t, Policy);
- print(split.Ty, split.Quals, OS, PlaceHolder);
- }
- void TypePrinter::print(const Type *T, Qualifiers Quals, raw_ostream &OS,
- StringRef PlaceHolder) {
- if (!T) {
- OS << "NULL TYPE";
- return;
- }
- SaveAndRestore<bool> 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;
- NeedARCStrongQualifier = false;
- Type::TypeClass TC = T->getTypeClass();
- if (const auto *AT = dyn_cast<AutoType>(T))
- TC = AT->desugar()->getTypeClass();
- if (const auto *Subst = dyn_cast<SubstTemplateTypeParmType>(T))
- TC = Subst->getReplacementType()->getTypeClass();
- switch (TC) {
- case Type::Auto:
- case Type::Builtin:
- case Type::Complex:
- case Type::UnresolvedUsing:
- case Type::Typedef:
- case Type::TypeOfExpr:
- case Type::TypeOf:
- case Type::Decltype:
- case Type::UnaryTransform:
- case Type::Record:
- case Type::Enum:
- case Type::Elaborated:
- case Type::TemplateTypeParm:
- case Type::SubstTemplateTypeParmPack:
- case Type::DeducedTemplateSpecialization:
- case Type::TemplateSpecialization:
- case Type::InjectedClassName:
- case Type::DependentName:
- case Type::DependentTemplateSpecialization:
- case Type::ObjCObject:
- case Type::ObjCTypeParam:
- case Type::ObjCInterface:
- case Type::Atomic:
- case Type::Pipe:
- CanPrefixQualifiers = true;
- break;
- case Type::ObjCObjectPointer:
- CanPrefixQualifiers = T->isObjCIdType() || T->isObjCClassType() ||
- T->isObjCQualifiedIdType() || T->isObjCQualifiedClassType();
- break;
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- case Type::DependentSizedArray:
- NeedARCStrongQualifier = true;
- LLVM_FALLTHROUGH;
- case Type::Adjusted:
- case Type::Decayed:
- case Type::Pointer:
- case Type::BlockPointer:
- case Type::LValueReference:
- case Type::RValueReference:
- case Type::MemberPointer:
- case Type::DependentAddressSpace:
- case Type::DependentVector:
- case Type::DependentSizedExtVector:
- case Type::Vector:
- case Type::ExtVector:
- case Type::FunctionProto:
- case Type::FunctionNoProto:
- case Type::Paren:
- case Type::PackExpansion:
- case Type::SubstTemplateTypeParm:
- case Type::MacroQualified:
- CanPrefixQualifiers = false;
- break;
- case Type::Attributed: {
- // We still want to print the address_space before the type if it is an
- // address_space attribute.
- const auto *AttrTy = cast<AttributedType>(T);
- CanPrefixQualifiers = AttrTy->getAttrKind() == attr::AddressSpace;
- }
- }
- return CanPrefixQualifiers;
- }
- void TypePrinter::printBefore(QualType T, raw_ostream &OS) {
- SplitQualType Split = splitAccordingToPolicy(T, Policy);
- // If we have cv1 T, where T is substituted for cv2 U, only print cv1 - cv2
- // at this level.
- Qualifiers Quals = Split.Quals;
- if (const auto *Subst = dyn_cast<SubstTemplateTypeParmType>(Split.Ty))
- Quals -= QualType(Subst, 0).getQualifiers();
- printBefore(Split.Ty, Quals, OS);
- }
- /// 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<bool> 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.print(OS, Policy, /*appendSpaceIfNonEmpty=*/true);
- } else {
- 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##Before(cast<CLASS##Type>(T), OS); \
- break;
- #include "clang/AST/TypeNodes.inc"
- }
- if (hasAfterQuals) {
- if (NeedARCStrongQualifier) {
- IncludeStrongLifetimeRAII Strong(Policy);
- Quals.print(OS, Policy, /*appendSpaceIfNonEmpty=*/!PrevPHIsEmpty.get());
- } else {
- Quals.print(OS, Policy, /*appendSpaceIfNonEmpty=*/!PrevPHIsEmpty.get());
- }
- }
- }
- void TypePrinter::printAfter(QualType t, raw_ostream &OS) {
- SplitQualType split = splitAccordingToPolicy(t, Policy);
- printAfter(split.Ty, split.Quals, OS);
- }
- /// 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<CLASS##Type>(T), OS); \
- break;
- #include "clang/AST/TypeNodes.inc"
- }
- }
- 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::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<bool> 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<ArrayType>(T->getPointeeType()))
- OS << '(';
- OS << '*';
- }
- void TypePrinter::printPointerAfter(const PointerType *T, raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
- // Handle things like 'int (*A)[4];' correctly.
- // FIXME: this should include vectors, but vectors use attributes I guess.
- if (isa<ArrayType>(T->getPointeeType()))
- OS << ')';
- printAfter(T->getPointeeType(), OS);
- }
- void TypePrinter::printBlockPointerBefore(const BlockPointerType *T,
- raw_ostream &OS) {
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
- printBefore(T->getPointeeType(), OS);
- OS << '^';
- }
- void TypePrinter::printBlockPointerAfter(const BlockPointerType *T,
- raw_ostream &OS) {
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
- printAfter(T->getPointeeType(), OS);
- }
- // When printing a reference, the referenced type might also be a reference.
- // If so, we want to skip that before printing the inner type.
- static QualType skipTopLevelReferences(QualType T) {
- if (auto *Ref = T->getAs<ReferenceType>())
- return skipTopLevelReferences(Ref->getPointeeTypeAsWritten());
- return T;
- }
- void TypePrinter::printLValueReferenceBefore(const LValueReferenceType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
- QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten());
- printBefore(Inner, OS);
- // Handle things like 'int (&A)[4];' correctly.
- // FIXME: this should include vectors, but vectors use attributes I guess.
- if (isa<ArrayType>(Inner))
- OS << '(';
- OS << '&';
- }
- void TypePrinter::printLValueReferenceAfter(const LValueReferenceType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
- QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten());
- // Handle things like 'int (&A)[4];' correctly.
- // FIXME: this should include vectors, but vectors use attributes I guess.
- if (isa<ArrayType>(Inner))
- OS << ')';
- printAfter(Inner, OS);
- }
- void TypePrinter::printRValueReferenceBefore(const RValueReferenceType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
- QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten());
- printBefore(Inner, OS);
- // Handle things like 'int (&&A)[4];' correctly.
- // FIXME: this should include vectors, but vectors use attributes I guess.
- if (isa<ArrayType>(Inner))
- OS << '(';
- OS << "&&";
- }
- void TypePrinter::printRValueReferenceAfter(const RValueReferenceType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
- QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten());
- // Handle things like 'int (&&A)[4];' correctly.
- // FIXME: this should include vectors, but vectors use attributes I guess.
- if (isa<ArrayType>(Inner))
- OS << ')';
- printAfter(Inner, OS);
- }
- void TypePrinter::printMemberPointerBefore(const MemberPointerType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> 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<ArrayType>(T->getPointeeType()))
- OS << '(';
- PrintingPolicy InnerPolicy(Policy);
- InnerPolicy.IncludeTagDefinition = false;
- TypePrinter(InnerPolicy).print(QualType(T->getClass(), 0), OS, StringRef());
- OS << "::*";
- }
- void TypePrinter::printMemberPointerAfter(const MemberPointerType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
- // Handle things like 'int (Cls::*A)[4];' correctly.
- // FIXME: this should include vectors, but vectors use attributes I guess.
- if (isa<ArrayType>(T->getPointeeType()))
- OS << ')';
- printAfter(T->getPointeeType(), OS);
- }
- void TypePrinter::printConstantArrayBefore(const ConstantArrayType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
- printBefore(T->getElementType(), OS);
- }
- void TypePrinter::printConstantArrayAfter(const ConstantArrayType *T,
- raw_ostream &OS) {
- OS << '[';
- if (T->getIndexTypeQualifiers().hasQualifiers()) {
- AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers(),
- Policy.Restrict);
- OS << ' ';
- }
- if (T->getSizeModifier() == ArrayType::Static)
- OS << "static ";
- OS << T->getSize().getZExtValue() << ']';
- printAfter(T->getElementType(), OS);
- }
- void TypePrinter::printIncompleteArrayBefore(const IncompleteArrayType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
- printBefore(T->getElementType(), OS);
- }
- void TypePrinter::printIncompleteArrayAfter(const IncompleteArrayType *T,
- raw_ostream &OS) {
- OS << "[]";
- printAfter(T->getElementType(), OS);
- }
- void TypePrinter::printVariableArrayBefore(const VariableArrayType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
- printBefore(T->getElementType(), OS);
- }
- void TypePrinter::printVariableArrayAfter(const VariableArrayType *T,
- raw_ostream &OS) {
- OS << '[';
- if (T->getIndexTypeQualifiers().hasQualifiers()) {
- AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers(), Policy.Restrict);
- OS << ' ';
- }
- if (T->getSizeModifier() == VariableArrayType::Static)
- OS << "static ";
- else if (T->getSizeModifier() == VariableArrayType::Star)
- OS << '*';
- if (T->getSizeExpr())
- T->getSizeExpr()->printPretty(OS, nullptr, Policy);
- OS << ']';
- printAfter(T->getElementType(), OS);
- }
- void TypePrinter::printAdjustedBefore(const AdjustedType *T, raw_ostream &OS) {
- // Print the adjusted representation, otherwise the adjustment will be
- // invisible.
- printBefore(T->getAdjustedType(), OS);
- }
- void TypePrinter::printAdjustedAfter(const AdjustedType *T, raw_ostream &OS) {
- printAfter(T->getAdjustedType(), OS);
- }
- void TypePrinter::printDecayedBefore(const DecayedType *T, raw_ostream &OS) {
- // Print as though it's a pointer.
- printAdjustedBefore(T, OS);
- }
- void TypePrinter::printDecayedAfter(const DecayedType *T, raw_ostream &OS) {
- printAdjustedAfter(T, OS);
- }
- void TypePrinter::printDependentSizedArrayBefore(
- const DependentSizedArrayType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
- printBefore(T->getElementType(), OS);
- }
- void TypePrinter::printDependentSizedArrayAfter(
- const DependentSizedArrayType *T,
- raw_ostream &OS) {
- OS << '[';
- if (T->getSizeExpr())
- T->getSizeExpr()->printPretty(OS, nullptr, Policy);
- OS << ']';
- printAfter(T->getElementType(), OS);
- }
- void TypePrinter::printDependentAddressSpaceBefore(
- const DependentAddressSpaceType *T, raw_ostream &OS) {
- printBefore(T->getPointeeType(), OS);
- }
- void TypePrinter::printDependentAddressSpaceAfter(
- const DependentAddressSpaceType *T, raw_ostream &OS) {
- OS << " __attribute__((address_space(";
- if (T->getAddrSpaceExpr())
- T->getAddrSpaceExpr()->printPretty(OS, nullptr, Policy);
- OS << ")))";
- printAfter(T->getPointeeType(), OS);
- }
- void TypePrinter::printDependentSizedExtVectorBefore(
- const DependentSizedExtVectorType *T,
- 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, nullptr, Policy);
- OS << ")))";
- printAfter(T->getElementType(), OS);
- }
- void TypePrinter::printVectorBefore(const VectorType *T, raw_ostream &OS) {
- switch (T->getVectorKind()) {
- case VectorType::AltiVecPixel:
- OS << "__vector __pixel ";
- break;
- case VectorType::AltiVecBool:
- OS << "__vector __bool ";
- printBefore(T->getElementType(), OS);
- break;
- case VectorType::AltiVecVector:
- OS << "__vector ";
- printBefore(T->getElementType(), OS);
- break;
- case VectorType::NeonVector:
- OS << "__attribute__((neon_vector_type("
- << T->getNumElements() << "))) ";
- printBefore(T->getElementType(), OS);
- break;
- case VectorType::NeonPolyVector:
- 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.
- 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::printDependentVectorBefore(
- const DependentVectorType *T, raw_ostream &OS) {
- switch (T->getVectorKind()) {
- case VectorType::AltiVecPixel:
- OS << "__vector __pixel ";
- break;
- case VectorType::AltiVecBool:
- OS << "__vector __bool ";
- printBefore(T->getElementType(), OS);
- break;
- case VectorType::AltiVecVector:
- OS << "__vector ";
- printBefore(T->getElementType(), OS);
- break;
- case VectorType::NeonVector:
- OS << "__attribute__((neon_vector_type(";
- if (T->getSizeExpr())
- T->getSizeExpr()->printPretty(OS, nullptr, Policy);
- OS << "))) ";
- printBefore(T->getElementType(), OS);
- break;
- case VectorType::NeonPolyVector:
- OS << "__attribute__((neon_polyvector_type(";
- if (T->getSizeExpr())
- T->getSizeExpr()->printPretty(OS, nullptr, Policy);
- OS << "))) ";
- 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.
- OS << "__attribute__((__vector_size__(";
- if (T->getSizeExpr())
- T->getSizeExpr()->printPretty(OS, nullptr, Policy);
- OS << " * sizeof(";
- print(T->getElementType(), OS, StringRef());
- OS << ")))) ";
- printBefore(T->getElementType(), OS);
- break;
- }
- }
- }
- void TypePrinter::printDependentVectorAfter(
- const DependentVectorType *T, raw_ostream &OS) {
- printAfter(T->getElementType(), OS);
- }
- 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(raw_ostream &OS,
- const PrintingPolicy &Policy)
- const {
- if (hasDynamicExceptionSpec()) {
- OS << " throw(";
- if (getExceptionSpecType() == EST_MSAny)
- OS << "...";
- else
- for (unsigned I = 0, N = getNumExceptions(); I != N; ++I) {
- if (I)
- OS << ", ";
- OS << getExceptionType(I).stream(Policy);
- }
- OS << ')';
- } else if (EST_NoThrow == getExceptionSpecType()) {
- OS << " __attribute__((nothrow))";
- } else if (isNoexceptExceptionSpec(getExceptionSpecType())) {
- OS << " noexcept";
- // FIXME:Is it useful to print out the expression for a non-dependent
- // noexcept specification?
- if (isComputedNoexcept(getExceptionSpecType())) {
- OS << '(';
- if (getNoexceptExpr())
- getNoexceptExpr()->printPretty(OS, nullptr, Policy);
- OS << ')';
- }
- }
- }
- 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<bool> PrevPHIsEmpty(HasEmptyPlaceHolder, false);
- printBefore(T->getReturnType(), OS);
- if (!PrevPHIsEmpty.get())
- OS << '(';
- }
- }
- StringRef clang::getParameterABISpelling(ParameterABI ABI) {
- switch (ABI) {
- case ParameterABI::Ordinary:
- llvm_unreachable("asking for spelling of ordinary parameter ABI");
- case ParameterABI::SwiftContext:
- return "swift_context";
- case ParameterABI::SwiftErrorResult:
- return "swift_error_result";
- case ParameterABI::SwiftIndirectResult:
- return "swift_indirect_result";
- }
- llvm_unreachable("bad parameter ABI kind");
- }
- void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
- raw_ostream &OS) {
- // If needed for precedence reasons, wrap the inner part in grouping parens.
- if (!HasEmptyPlaceHolder)
- OS << ')';
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
- OS << '(';
- {
- ParamPolicyRAII ParamPolicy(Policy);
- for (unsigned i = 0, e = T->getNumParams(); i != e; ++i) {
- if (i) OS << ", ";
- auto EPI = T->getExtParameterInfo(i);
- if (EPI.isConsumed()) OS << "__attribute__((ns_consumed)) ";
- if (EPI.isNoEscape())
- OS << "__attribute__((noescape)) ";
- auto ABI = EPI.getABI();
- if (ABI != ParameterABI::Ordinary)
- OS << "__attribute__((" << getParameterABISpelling(ABI) << ")) ";
- print(T->getParamType(i), OS, StringRef());
- }
- }
- if (T->isVariadic()) {
- if (T->getNumParams())
- OS << ", ";
- OS << "...";
- } else if (T->getNumParams() == 0 && Policy.UseVoidForZeroParams) {
- // Do not emit int() if we have a proto, emit 'int(void)'.
- OS << "void";
- }
- OS << ')';
- FunctionType::ExtInfo Info = T->getExtInfo();
- printFunctionAfter(Info, OS);
- if (!T->getMethodQuals().empty())
- OS << " " << T->getMethodQuals().getAsString();
- switch (T->getRefQualifier()) {
- case RQ_None:
- break;
- case RQ_LValue:
- OS << " &";
- break;
- case RQ_RValue:
- OS << " &&";
- break;
- }
- T->printExceptionSpecification(OS, Policy);
- if (T->hasTrailingReturn()) {
- OS << " -> ";
- print(T->getReturnType(), OS, StringRef());
- } else
- printAfter(T->getReturnType(), OS);
- }
- void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info,
- raw_ostream &OS) {
- if (!InsideCCAttribute) {
- switch (Info.getCC()) {
- case CC_C:
- // The C calling convention is the default on the vast majority of platforms
- // we support. If the user wrote it explicitly, it will usually be printed
- // while traversing the AttributedType. If the type has been desugared, let
- // the canonical spelling be the implicit calling convention.
- // FIXME: It would be better to be explicit in certain contexts, such as a
- // cdecl function typedef used to declare a member function with the
- // Microsoft C++ ABI.
- break;
- case CC_X86StdCall:
- OS << " __attribute__((stdcall))";
- break;
- case CC_X86FastCall:
- OS << " __attribute__((fastcall))";
- break;
- case CC_X86ThisCall:
- OS << " __attribute__((thiscall))";
- break;
- case CC_X86VectorCall:
- OS << " __attribute__((vectorcall))";
- break;
- case CC_X86Pascal:
- OS << " __attribute__((pascal))";
- break;
- case CC_AAPCS:
- OS << " __attribute__((pcs(\"aapcs\")))";
- break;
- case CC_AAPCS_VFP:
- OS << " __attribute__((pcs(\"aapcs-vfp\")))";
- break;
- case CC_AArch64VectorCall:
- OS << "__attribute__((aarch64_vector_pcs))";
- break;
- case CC_IntelOclBicc:
- OS << " __attribute__((intel_ocl_bicc))";
- break;
- case CC_Win64:
- OS << " __attribute__((ms_abi))";
- break;
- case CC_X86_64SysV:
- OS << " __attribute__((sysv_abi))";
- break;
- case CC_X86RegCall:
- OS << " __attribute__((regcall))";
- break;
- case CC_SpirFunction:
- case CC_OpenCLKernel:
- // Do nothing. These CCs are not available as attributes.
- break;
- case CC_Swift:
- OS << " __attribute__((swiftcall))";
- break;
- case CC_PreserveMost:
- OS << " __attribute__((preserve_most))";
- break;
- case CC_PreserveAll:
- OS << " __attribute__((preserve_all))";
- break;
- }
- }
- if (Info.getNoReturn())
- OS << " __attribute__((noreturn))";
- if (Info.getProducesResult())
- OS << " __attribute__((ns_returns_retained))";
- if (Info.getRegParm())
- OS << " __attribute__((regparm ("
- << Info.getRegParm() << ")))";
- if (Info.getNoCallerSavedRegs())
- OS << " __attribute__((no_caller_saved_registers))";
- if (Info.getNoCfCheck())
- OS << " __attribute__((nocf_check))";
- }
- void TypePrinter::printFunctionNoProtoBefore(const FunctionNoProtoType *T,
- raw_ostream &OS) {
- // If needed for precedence reasons, wrap the inner part in grouping parens.
- SaveAndRestore<bool> PrevPHIsEmpty(HasEmptyPlaceHolder, false);
- printBefore(T->getReturnType(), 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<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
- OS << "()";
- printFunctionAfter(T->getExtInfo(), OS);
- printAfter(T->getReturnType(), OS);
- }
- void TypePrinter::printTypeSpec(NamedDecl *D, raw_ostream &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(), OS);
- IdentifierInfo *II = D->getIdentifier();
- OS << II->getName();
- spaceBeforePlaceHolder(OS);
- }
- void TypePrinter::printUnresolvedUsingBefore(const UnresolvedUsingType *T,
- raw_ostream &OS) {
- printTypeSpec(T->getDecl(), OS);
- }
- void TypePrinter::printUnresolvedUsingAfter(const UnresolvedUsingType *T,
- raw_ostream &OS) {}
- void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) {
- printTypeSpec(T->getDecl(), OS);
- }
- void TypePrinter::printMacroQualifiedBefore(const MacroQualifiedType *T,
- raw_ostream &OS) {
- StringRef MacroName = T->getMacroIdentifier()->getName();
- OS << MacroName << " ";
- // Since this type is meant to print the macro instead of the whole attribute,
- // we trim any attributes and go directly to the original modified type.
- printBefore(T->getModifiedType(), OS);
- }
- void TypePrinter::printMacroQualifiedAfter(const MacroQualifiedType *T,
- raw_ostream &OS) {
- printAfter(T->getModifiedType(), OS);
- }
- void TypePrinter::printTypedefAfter(const TypedefType *T, raw_ostream &OS) {}
- void TypePrinter::printTypeOfExprBefore(const TypeOfExprType *T,
- raw_ostream &OS) {
- OS << "typeof ";
- if (T->getUnderlyingExpr())
- T->getUnderlyingExpr()->printPretty(OS, nullptr, Policy);
- spaceBeforePlaceHolder(OS);
- }
- 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::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) {
- OS << "decltype(";
- if (T->getUnderlyingExpr())
- T->getUnderlyingExpr()->printPretty(OS, nullptr, Policy);
- OS << ')';
- spaceBeforePlaceHolder(OS);
- }
- void TypePrinter::printDecltypeAfter(const DecltypeType *T, raw_ostream &OS) {}
- void TypePrinter::printUnaryTransformBefore(const UnaryTransformType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- switch (T->getUTTKind()) {
- case UnaryTransformType::EnumUnderlyingType:
- 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::printAutoBefore(const AutoType *T, raw_ostream &OS) {
- // If the type has been deduced, do not print 'auto'.
- if (!T->getDeducedType().isNull()) {
- printBefore(T->getDeducedType(), OS);
- } else {
- switch (T->getKeyword()) {
- case AutoTypeKeyword::Auto: OS << "auto"; break;
- case AutoTypeKeyword::DecltypeAuto: OS << "decltype(auto)"; break;
- case AutoTypeKeyword::GNUAutoType: OS << "__auto_type"; break;
- }
- spaceBeforePlaceHolder(OS);
- }
- }
- void TypePrinter::printAutoAfter(const AutoType *T, raw_ostream &OS) {
- // If the type has been deduced, do not print 'auto'.
- if (!T->getDeducedType().isNull())
- printAfter(T->getDeducedType(), OS);
- }
- void TypePrinter::printDeducedTemplateSpecializationBefore(
- const DeducedTemplateSpecializationType *T, raw_ostream &OS) {
- // If the type has been deduced, print the deduced type.
- if (!T->getDeducedType().isNull()) {
- printBefore(T->getDeducedType(), OS);
- } else {
- IncludeStrongLifetimeRAII Strong(Policy);
- T->getTemplateName().print(OS, Policy);
- spaceBeforePlaceHolder(OS);
- }
- }
- void TypePrinter::printDeducedTemplateSpecializationAfter(
- const DeducedTemplateSpecializationType *T, raw_ostream &OS) {
- // If the type has been deduced, print the deduced type.
- if (!T->getDeducedType().isNull())
- printAfter(T->getDeducedType(), OS);
- }
- void TypePrinter::printAtomicBefore(const AtomicType *T, raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- OS << "_Atomic(";
- print(T->getValueType(), OS, StringRef());
- OS << ')';
- spaceBeforePlaceHolder(OS);
- }
- void TypePrinter::printAtomicAfter(const AtomicType *T, raw_ostream &OS) {}
- void TypePrinter::printPipeBefore(const PipeType *T, raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- if (T->isReadOnly())
- OS << "read_only ";
- else
- OS << "write_only ";
- OS << "pipe ";
- print(T->getElementType(), OS, StringRef());
- spaceBeforePlaceHolder(OS);
- }
- void TypePrinter::printPipeAfter(const PipeType *T, raw_ostream &OS) {}
- /// Appends the given scope to the end of a string.
- void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) {
- if (DC->isTranslationUnit()) return;
- if (DC->isFunctionOrMethod()) return;
- AppendScope(DC->getParent(), OS);
- if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
- if (Policy.SuppressUnwrittenScope &&
- (NS->isAnonymousNamespace() || NS->isInline()))
- return;
- if (NS->getIdentifier())
- OS << NS->getName() << "::";
- else
- OS << "(anonymous namespace)::";
- } else if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
- IncludeStrongLifetimeRAII Strong(Policy);
- OS << Spec->getIdentifier()->getName();
- const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- printTemplateArgumentList(OS, TemplateArgs.asArray(), Policy);
- OS << "::";
- } else if (const auto *Tag = dyn_cast<TagDecl>(DC)) {
- if (TypedefNameDecl *Typedef = Tag->getTypedefNameForAnonDecl())
- OS << Typedef->getIdentifier()->getName() << "::";
- else if (Tag->getIdentifier())
- OS << Tag->getIdentifier()->getName() << "::";
- else
- return;
- }
- }
- void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
- if (Policy.IncludeTagDefinition) {
- PrintingPolicy SubPolicy = Policy;
- SubPolicy.IncludeTagDefinition = false;
- D->print(OS, SubPolicy, Indentation);
- spaceBeforePlaceHolder(OS);
- return;
- }
- bool HasKindDecoration = false;
- // We don't print tags unless this is an elaborated type.
- // In C, we just assume every RecordType is an elaborated type.
- if (!Policy.SuppressTagKeyword && !D->getTypedefNameForAnonDecl()) {
- HasKindDecoration = true;
- 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(), OS);
- if (const IdentifierInfo *II = D->getIdentifier())
- OS << II->getName();
- else if (TypedefNameDecl *Typedef = D->getTypedefNameForAnonDecl()) {
- assert(Typedef->getIdentifier() && "Typedef without identifier?");
- OS << Typedef->getIdentifier()->getName();
- } else {
- // Make an unambiguous representation for anonymous types, e.g.
- // (anonymous enum at /usr/include/string.h:120:9)
- OS << (Policy.MSVCFormatting ? '`' : '(');
- if (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda()) {
- OS << "lambda";
- HasKindDecoration = true;
- } else {
- OS << "anonymous";
- }
- if (Policy.AnonymousTagLocations) {
- // Suppress the redundant tag keyword if we just printed one.
- // We don't have to worry about ElaboratedTypes here because you can't
- // refer to an anonymous type with one.
- if (!HasKindDecoration)
- OS << " " << D->getKindName();
- PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc(
- D->getLocation());
- if (PLoc.isValid()) {
- OS << " at ";
- StringRef File = PLoc.getFilename();
- if (Policy.RemapFilePaths)
- OS << Policy.remapPath(File);
- else
- OS << File;
- OS << ':' << PLoc.getLine() << ':' << PLoc.getColumn();
- }
- }
- OS << (Policy.MSVCFormatting ? '\'' : ')');
- }
- // If this is a class template specialization, print the template
- // arguments.
- if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
- ArrayRef<TemplateArgument> Args;
- TypeSourceInfo *TAW = Spec->getTypeAsWritten();
- if (!Policy.PrintCanonicalTypes && TAW) {
- const TemplateSpecializationType *TST =
- cast<TemplateSpecializationType>(TAW->getType());
- Args = TST->template_arguments();
- } else {
- const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- Args = TemplateArgs.asArray();
- }
- IncludeStrongLifetimeRAII Strong(Policy);
- printTemplateArgumentList(OS, Args, Policy);
- }
- spaceBeforePlaceHolder(OS);
- }
- void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) {
- printTag(T->getDecl(), OS);
- }
- void TypePrinter::printRecordAfter(const RecordType *T, raw_ostream &OS) {}
- void TypePrinter::printEnumBefore(const EnumType *T, raw_ostream &OS) {
- printTag(T->getDecl(), OS);
- }
- void TypePrinter::printEnumAfter(const EnumType *T, raw_ostream &OS) {}
- void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T,
- raw_ostream &OS) {
- if (IdentifierInfo *Id = T->getIdentifier())
- OS << Id->getName();
- else {
- bool IsLambdaAutoParam = false;
- if (auto D = T->getDecl()) {
- if (auto M = dyn_cast_or_null<CXXMethodDecl>(D->getDeclContext()))
- IsLambdaAutoParam = D->isImplicit() && M->getParent()->isLambda();
- }
- if (IsLambdaAutoParam)
- OS << "auto";
- else
- OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
- }
- spaceBeforePlaceHolder(OS);
- }
- void TypePrinter::printTemplateTypeParmAfter(const TemplateTypeParmType *T,
- raw_ostream &OS) {}
- 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);
- printAfter(T->getReplacementType(), OS);
- }
- void TypePrinter::printSubstTemplateTypeParmPackBefore(
- const SubstTemplateTypeParmPackType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- printTemplateTypeParmBefore(T->getReplacedParameter(), OS);
- }
- void TypePrinter::printSubstTemplateTypeParmPackAfter(
- const SubstTemplateTypeParmPackType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- printTemplateTypeParmAfter(T->getReplacedParameter(), OS);
- }
- void TypePrinter::printTemplateSpecializationBefore(
- const TemplateSpecializationType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- T->getTemplateName().print(OS, Policy);
- printTemplateArgumentList(OS, T->template_arguments(), Policy);
- spaceBeforePlaceHolder(OS);
- }
- void TypePrinter::printTemplateSpecializationAfter(
- const TemplateSpecializationType *T,
- raw_ostream &OS) {}
- void TypePrinter::printInjectedClassNameBefore(const InjectedClassNameType *T,
- raw_ostream &OS) {
- printTemplateSpecializationBefore(T->getInjectedTST(), OS);
- }
- void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T,
- raw_ostream &OS) {}
- void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
- raw_ostream &OS) {
- if (Policy.IncludeTagDefinition && T->getOwnedTagDecl()) {
- TagDecl *OwnedTagDecl = T->getOwnedTagDecl();
- assert(OwnedTagDecl->getTypeForDecl() == T->getNamedType().getTypePtr() &&
- "OwnedTagDecl expected to be a declaration for the type");
- PrintingPolicy SubPolicy = Policy;
- SubPolicy.IncludeTagDefinition = false;
- OwnedTagDecl->print(OS, SubPolicy, Indentation);
- spaceBeforePlaceHolder(OS);
- return;
- }
- // The tag definition will take care of these.
- if (!Policy.IncludeTagDefinition)
- {
- OS << TypeWithKeyword::getKeywordName(T->getKeyword());
- if (T->getKeyword() != ETK_None)
- OS << " ";
- NestedNameSpecifier *Qualifier = T->getQualifier();
- if (Qualifier)
- Qualifier->print(OS, Policy);
- }
- ElaboratedTypePolicyRAII PolicyRAII(Policy);
- printBefore(T->getNamedType(), OS);
- }
- void TypePrinter::printElaboratedAfter(const ElaboratedType *T,
- raw_ostream &OS) {
- if (Policy.IncludeTagDefinition && T->getOwnedTagDecl())
- return;
- ElaboratedTypePolicyRAII PolicyRAII(Policy);
- printAfter(T->getNamedType(), OS);
- }
- void TypePrinter::printParenBefore(const ParenType *T, raw_ostream &OS) {
- if (!HasEmptyPlaceHolder && !isa<FunctionType>(T->getInnerType())) {
- printBefore(T->getInnerType(), OS);
- OS << '(';
- } else
- printBefore(T->getInnerType(), OS);
- }
- void TypePrinter::printParenAfter(const ParenType *T, raw_ostream &OS) {
- if (!HasEmptyPlaceHolder && !isa<FunctionType>(T->getInnerType())) {
- OS << ')';
- printAfter(T->getInnerType(), OS);
- } else
- printAfter(T->getInnerType(), OS);
- }
- void TypePrinter::printDependentNameBefore(const DependentNameType *T,
- raw_ostream &OS) {
- OS << TypeWithKeyword::getKeywordName(T->getKeyword());
- if (T->getKeyword() != ETK_None)
- OS << " ";
- T->getQualifier()->print(OS, Policy);
- OS << T->getIdentifier()->getName();
- spaceBeforePlaceHolder(OS);
- }
- void TypePrinter::printDependentNameAfter(const DependentNameType *T,
- raw_ostream &OS) {}
- void TypePrinter::printDependentTemplateSpecializationBefore(
- const DependentTemplateSpecializationType *T, raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
- OS << TypeWithKeyword::getKeywordName(T->getKeyword());
- if (T->getKeyword() != ETK_None)
- OS << " ";
- if (T->getQualifier())
- T->getQualifier()->print(OS, Policy);
- OS << T->getIdentifier()->getName();
- printTemplateArgumentList(OS, T->template_arguments(), Policy);
- spaceBeforePlaceHolder(OS);
- }
- void TypePrinter::printDependentTemplateSpecializationAfter(
- const DependentTemplateSpecializationType *T, raw_ostream &OS) {}
- 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::printAttributedBefore(const AttributedType *T,
- raw_ostream &OS) {
- // FIXME: Generate this with TableGen.
- // Prefer the macro forms of the GC and ownership qualifiers.
- if (T->getAttrKind() == attr::ObjCGC ||
- T->getAttrKind() == attr::ObjCOwnership)
- return printBefore(T->getEquivalentType(), OS);
- if (T->getAttrKind() == attr::ObjCKindOf)
- OS << "__kindof ";
- if (T->getAttrKind() == attr::AddressSpace)
- printBefore(T->getEquivalentType(), OS);
- else
- printBefore(T->getModifiedType(), OS);
- if (T->isMSTypeSpec()) {
- switch (T->getAttrKind()) {
- default: return;
- case attr::Ptr32: OS << " __ptr32"; break;
- case attr::Ptr64: OS << " __ptr64"; break;
- case attr::SPtr: OS << " __sptr"; break;
- case attr::UPtr: OS << " __uptr"; break;
- }
- spaceBeforePlaceHolder(OS);
- }
- // Print nullability type specifiers.
- if (T->getImmediateNullability()) {
- if (T->getAttrKind() == attr::TypeNonNull)
- OS << " _Nonnull";
- else if (T->getAttrKind() == attr::TypeNullable)
- OS << " _Nullable";
- else if (T->getAttrKind() == attr::TypeNullUnspecified)
- OS << " _Null_unspecified";
- else
- llvm_unreachable("unhandled nullability");
- spaceBeforePlaceHolder(OS);
- }
- }
- void TypePrinter::printAttributedAfter(const AttributedType *T,
- raw_ostream &OS) {
- // FIXME: Generate this with TableGen.
- // Prefer the macro forms of the GC and ownership qualifiers.
- if (T->getAttrKind() == attr::ObjCGC ||
- T->getAttrKind() == attr::ObjCOwnership)
- return printAfter(T->getEquivalentType(), OS);
- // If this is a calling convention attribute, don't print the implicit CC from
- // the modified type.
- SaveAndRestore<bool> MaybeSuppressCC(InsideCCAttribute, T->isCallingConv());
- printAfter(T->getModifiedType(), OS);
- // Some attributes are printed as qualifiers before the type, so we have
- // nothing left to do.
- if (T->getAttrKind() == attr::ObjCKindOf ||
- T->isMSTypeSpec() || T->getImmediateNullability())
- return;
- // Don't print the inert __unsafe_unretained attribute at all.
- if (T->getAttrKind() == attr::ObjCInertUnsafeUnretained)
- return;
- // Don't print ns_returns_retained unless it had an effect.
- if (T->getAttrKind() == attr::NSReturnsRetained &&
- !T->getEquivalentType()->castAs<FunctionType>()
- ->getExtInfo().getProducesResult())
- return;
- if (T->getAttrKind() == attr::LifetimeBound) {
- OS << " [[clang::lifetimebound]]";
- return;
- }
- // The printing of the address_space attribute is handled by the qualifier
- // since it is still stored in the qualifier. Return early to prevent printing
- // this twice.
- if (T->getAttrKind() == attr::AddressSpace)
- return;
- OS << " __attribute__((";
- switch (T->getAttrKind()) {
- #define TYPE_ATTR(NAME)
- #define DECL_OR_TYPE_ATTR(NAME)
- #define ATTR(NAME) case attr::NAME:
- #include "clang/Basic/AttrList.inc"
- llvm_unreachable("non-type attribute attached to type");
- case attr::OpenCLPrivateAddressSpace:
- case attr::OpenCLGlobalAddressSpace:
- case attr::OpenCLLocalAddressSpace:
- case attr::OpenCLConstantAddressSpace:
- case attr::OpenCLGenericAddressSpace:
- // FIXME: Update printAttributedBefore to print these once we generate
- // AttributedType nodes for them.
- break;
- case attr::LifetimeBound:
- case attr::TypeNonNull:
- case attr::TypeNullable:
- case attr::TypeNullUnspecified:
- case attr::ObjCGC:
- case attr::ObjCInertUnsafeUnretained:
- case attr::ObjCKindOf:
- case attr::ObjCOwnership:
- case attr::Ptr32:
- case attr::Ptr64:
- case attr::SPtr:
- case attr::UPtr:
- case attr::AddressSpace:
- llvm_unreachable("This attribute should have been handled already");
- case attr::NSReturnsRetained:
- OS << "ns_returns_retained";
- break;
- // FIXME: When Sema learns to form this AttributedType, avoid printing the
- // attribute again in printFunctionProtoAfter.
- case attr::AnyX86NoCfCheck: OS << "nocf_check"; break;
- case attr::CDecl: OS << "cdecl"; break;
- case attr::FastCall: OS << "fastcall"; break;
- case attr::StdCall: OS << "stdcall"; break;
- case attr::ThisCall: OS << "thiscall"; break;
- case attr::SwiftCall: OS << "swiftcall"; break;
- case attr::VectorCall: OS << "vectorcall"; break;
- case attr::Pascal: OS << "pascal"; break;
- case attr::MSABI: OS << "ms_abi"; break;
- case attr::SysVABI: OS << "sysv_abi"; break;
- case attr::RegCall: OS << "regcall"; break;
- case attr::Pcs: {
- OS << "pcs(";
- QualType t = T->getEquivalentType();
- while (!t->isFunctionType())
- t = t->getPointeeType();
- OS << (t->castAs<FunctionType>()->getCallConv() == CC_AAPCS ?
- "\"aapcs\"" : "\"aapcs-vfp\"");
- OS << ')';
- break;
- }
- case attr::AArch64VectorPcs: OS << "aarch64_vector_pcs"; break;
- case attr::IntelOclBicc: OS << "inteloclbicc"; break;
- case attr::PreserveMost:
- OS << "preserve_most";
- break;
- case attr::PreserveAll:
- OS << "preserve_all";
- break;
- case attr::NoDeref:
- OS << "noderef";
- break;
- }
- OS << "))";
- }
- 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::printObjCTypeParamBefore(const ObjCTypeParamType *T,
- raw_ostream &OS) {
- OS << T->getDecl()->getName();
- if (!T->qual_empty()) {
- bool isFirst = true;
- OS << '<';
- for (const auto *I : T->quals()) {
- if (isFirst)
- isFirst = false;
- else
- OS << ',';
- OS << I->getName();
- }
- OS << '>';
- }
- spaceBeforePlaceHolder(OS);
- }
- void TypePrinter::printObjCTypeParamAfter(const ObjCTypeParamType *T,
- raw_ostream &OS) {}
- void TypePrinter::printObjCObjectBefore(const ObjCObjectType *T,
- raw_ostream &OS) {
- if (T->qual_empty() && T->isUnspecializedAsWritten() &&
- !T->isKindOfTypeAsWritten())
- return printBefore(T->getBaseType(), OS);
- if (T->isKindOfTypeAsWritten())
- OS << "__kindof ";
- print(T->getBaseType(), OS, StringRef());
- if (T->isSpecializedAsWritten()) {
- bool isFirst = true;
- OS << '<';
- for (auto typeArg : T->getTypeArgsAsWritten()) {
- if (isFirst)
- isFirst = false;
- else
- OS << ",";
- print(typeArg, OS, StringRef());
- }
- OS << '>';
- }
- if (!T->qual_empty()) {
- bool isFirst = true;
- OS << '<';
- for (const auto *I : T->quals()) {
- if (isFirst)
- isFirst = false;
- else
- OS << ',';
- OS << I->getName();
- }
- OS << '>';
- }
- spaceBeforePlaceHolder(OS);
- }
- void TypePrinter::printObjCObjectAfter(const ObjCObjectType *T,
- raw_ostream &OS) {
- if (T->qual_empty() && T->isUnspecializedAsWritten() &&
- !T->isKindOfTypeAsWritten())
- return printAfter(T->getBaseType(), OS);
- }
- void TypePrinter::printObjCObjectPointerBefore(const ObjCObjectPointerType *T,
- raw_ostream &OS) {
- printBefore(T->getPointeeType(), OS);
- // If we need to print the pointer, print it now.
- if (!T->isObjCIdType() && !T->isObjCQualifiedIdType() &&
- !T->isObjCClassType() && !T->isObjCQualifiedClassType()) {
- if (HasEmptyPlaceHolder)
- OS << ' ';
- OS << '*';
- }
- }
- void TypePrinter::printObjCObjectPointerAfter(const ObjCObjectPointerType *T,
- raw_ostream &OS) {}
- static
- const TemplateArgument &getArgument(const TemplateArgument &A) { return A; }
- static const TemplateArgument &getArgument(const TemplateArgumentLoc &A) {
- return A.getArgument();
- }
- static void printArgument(const TemplateArgument &A, const PrintingPolicy &PP,
- llvm::raw_ostream &OS) {
- A.print(PP, OS);
- }
- static void printArgument(const TemplateArgumentLoc &A,
- const PrintingPolicy &PP, llvm::raw_ostream &OS) {
- const TemplateArgument::ArgKind &Kind = A.getArgument().getKind();
- if (Kind == TemplateArgument::ArgKind::Type)
- return A.getTypeSourceInfo()->getType().print(OS, PP);
- return A.getArgument().print(PP, OS);
- }
- template<typename TA>
- static void printTo(raw_ostream &OS, ArrayRef<TA> Args,
- const PrintingPolicy &Policy, bool SkipBrackets) {
- const char *Comma = Policy.MSVCFormatting ? "," : ", ";
- if (!SkipBrackets)
- OS << '<';
- bool NeedSpace = false;
- bool FirstArg = true;
- for (const auto &Arg : Args) {
- // Print the argument into a string.
- SmallString<128> Buf;
- llvm::raw_svector_ostream ArgOS(Buf);
- const TemplateArgument &Argument = getArgument(Arg);
- if (Argument.getKind() == TemplateArgument::Pack) {
- if (Argument.pack_size() && !FirstArg)
- OS << Comma;
- printTo(ArgOS, Argument.getPackAsArray(), Policy, true);
- } else {
- if (!FirstArg)
- OS << Comma;
- // Tries to print the argument with location info if exists.
- printArgument(Arg, 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 (FirstArg && !ArgString.empty() && ArgString[0] == ':')
- OS << ' ';
- OS << ArgString;
- NeedSpace = (!ArgString.empty() && ArgString.back() == '>');
- FirstArg = false;
- }
- // If the last character of our string is '>', add another space to
- // keep the two '>''s separate tokens. We don't *have* to do this in
- // C++0x, but it's still good hygiene.
- if (NeedSpace)
- OS << ' ';
- if (!SkipBrackets)
- OS << '>';
- }
- void clang::printTemplateArgumentList(raw_ostream &OS,
- const TemplateArgumentListInfo &Args,
- const PrintingPolicy &Policy) {
- return printTo(OS, Args.arguments(), Policy, false);
- }
- void clang::printTemplateArgumentList(raw_ostream &OS,
- ArrayRef<TemplateArgument> Args,
- const PrintingPolicy &Policy) {
- printTo(OS, Args, Policy, false);
- }
- void clang::printTemplateArgumentList(raw_ostream &OS,
- ArrayRef<TemplateArgumentLoc> Args,
- const PrintingPolicy &Policy) {
- printTo(OS, Args, Policy, false);
- }
- std::string Qualifiers::getAsString() const {
- LangOptions LO;
- return getAsString(PrintingPolicy(LO));
- }
- // 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.
- 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() != LangAS::Default)
- 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, Policy.Restrict);
- addSpace = true;
- }
- if (hasUnaligned()) {
- if (addSpace)
- OS << ' ';
- OS << "__unaligned";
- addSpace = true;
- }
- LangAS addrspace = getAddressSpace();
- if (addrspace != LangAS::Default) {
- if (addrspace != LangAS::opencl_private) {
- if (addSpace)
- OS << ' ';
- addSpace = true;
- switch (addrspace) {
- case LangAS::opencl_global:
- OS << "__global";
- break;
- case LangAS::opencl_local:
- OS << "__local";
- break;
- case LangAS::opencl_private:
- break;
- case LangAS::opencl_constant:
- OS << "__constant";
- break;
- case LangAS::opencl_generic:
- OS << "__generic";
- break;
- case LangAS::cuda_device:
- OS << "__device__";
- break;
- case LangAS::cuda_constant:
- OS << "__constant__";
- break;
- case LangAS::cuda_shared:
- OS << "__shared__";
- break;
- default:
- OS << "__attribute__((address_space(";
- OS << toTargetAddressSpace(addrspace);
- OS << ")))";
- }
- }
- }
- if (Qualifiers::GC gc = getObjCGCAttr()) {
- if (addSpace)
- OS << ' ';
- addSpace = true;
- if (gc == Qualifiers::Weak)
- OS << "__weak";
- else
- OS << "__strong";
- }
- if (Qualifiers::ObjCLifetime lifetime = getObjCLifetime()) {
- 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: OS << "__unsafe_unretained"; break;
- case Qualifiers::OCL_Strong:
- if (!Policy.SuppressStrongLifetime)
- OS << "__strong";
- break;
- case Qualifiers::OCL_Weak: OS << "__weak"; break;
- case Qualifiers::OCL_Autoreleasing: OS << "__autoreleasing"; break;
- }
- }
- if (appendSpaceIfNonEmpty && addSpace)
- OS << ' ';
- }
- std::string QualType::getAsString() const {
- return getAsString(split(), LangOptions());
- }
- 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,
- const PrintingPolicy &Policy) {
- std::string buffer;
- getAsStringInternal(ty, qs, buffer, Policy);
- return buffer;
- }
- void QualType::print(raw_ostream &OS, const PrintingPolicy &Policy,
- const Twine &PlaceHolder, unsigned Indentation) const {
- print(splitAccordingToPolicy(*this, Policy), OS, Policy, PlaceHolder,
- Indentation);
- }
- void QualType::print(const Type *ty, Qualifiers qs,
- raw_ostream &OS, const PrintingPolicy &policy,
- const Twine &PlaceHolder, unsigned Indentation) {
- SmallString<128> PHBuf;
- StringRef PH = PlaceHolder.toStringRef(PHBuf);
- TypePrinter(policy, Indentation).print(ty, qs, OS, PH);
- }
- void QualType::getAsStringInternal(std::string &Str,
- const PrintingPolicy &Policy) const {
- return getAsStringInternal(splitAccordingToPolicy(*this, Policy), Str,
- Policy);
- }
- void QualType::getAsStringInternal(const Type *ty, Qualifiers qs,
- std::string &buffer,
- const PrintingPolicy &policy) {
- SmallString<256> Buf;
- llvm::raw_svector_ostream StrOS(Buf);
- TypePrinter(policy).print(ty, qs, StrOS, buffer);
- std::string str = StrOS.str();
- buffer.swap(str);
- }
|