106f32e7eSjoerg //===--- DeclPrinter.cpp - Printing implementation for Decl ASTs ----------===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // This file implements the Decl::print method, which pretty prints the
1006f32e7eSjoerg // AST back out to C/Objective-C/C++/Objective-C++ code.
1106f32e7eSjoerg //
1206f32e7eSjoerg //===----------------------------------------------------------------------===//
1306f32e7eSjoerg #include "clang/AST/ASTContext.h"
1406f32e7eSjoerg #include "clang/AST/Attr.h"
1506f32e7eSjoerg #include "clang/AST/Decl.h"
1606f32e7eSjoerg #include "clang/AST/DeclCXX.h"
1706f32e7eSjoerg #include "clang/AST/DeclObjC.h"
1806f32e7eSjoerg #include "clang/AST/DeclTemplate.h"
1906f32e7eSjoerg #include "clang/AST/DeclVisitor.h"
2006f32e7eSjoerg #include "clang/AST/Expr.h"
2106f32e7eSjoerg #include "clang/AST/ExprCXX.h"
2206f32e7eSjoerg #include "clang/AST/PrettyPrinter.h"
2306f32e7eSjoerg #include "clang/Basic/Module.h"
2406f32e7eSjoerg #include "llvm/Support/raw_ostream.h"
2506f32e7eSjoerg using namespace clang;
2606f32e7eSjoerg 
2706f32e7eSjoerg namespace {
2806f32e7eSjoerg   class DeclPrinter : public DeclVisitor<DeclPrinter> {
2906f32e7eSjoerg     raw_ostream &Out;
3006f32e7eSjoerg     PrintingPolicy Policy;
3106f32e7eSjoerg     const ASTContext &Context;
3206f32e7eSjoerg     unsigned Indentation;
3306f32e7eSjoerg     bool PrintInstantiation;
3406f32e7eSjoerg 
Indent()3506f32e7eSjoerg     raw_ostream& Indent() { return Indent(Indentation); }
3606f32e7eSjoerg     raw_ostream& Indent(unsigned Indentation);
3706f32e7eSjoerg     void ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls);
3806f32e7eSjoerg 
3906f32e7eSjoerg     void Print(AccessSpecifier AS);
4006f32e7eSjoerg     void PrintConstructorInitializers(CXXConstructorDecl *CDecl,
4106f32e7eSjoerg                                       std::string &Proto);
4206f32e7eSjoerg 
4306f32e7eSjoerg     /// Print an Objective-C method type in parentheses.
4406f32e7eSjoerg     ///
4506f32e7eSjoerg     /// \param Quals The Objective-C declaration qualifiers.
4606f32e7eSjoerg     /// \param T The type to print.
4706f32e7eSjoerg     void PrintObjCMethodType(ASTContext &Ctx, Decl::ObjCDeclQualifier Quals,
4806f32e7eSjoerg                              QualType T);
4906f32e7eSjoerg 
5006f32e7eSjoerg     void PrintObjCTypeParams(ObjCTypeParamList *Params);
5106f32e7eSjoerg 
5206f32e7eSjoerg   public:
DeclPrinter(raw_ostream & Out,const PrintingPolicy & Policy,const ASTContext & Context,unsigned Indentation=0,bool PrintInstantiation=false)5306f32e7eSjoerg     DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
5406f32e7eSjoerg                 const ASTContext &Context, unsigned Indentation = 0,
5506f32e7eSjoerg                 bool PrintInstantiation = false)
5606f32e7eSjoerg         : Out(Out), Policy(Policy), Context(Context), Indentation(Indentation),
5706f32e7eSjoerg           PrintInstantiation(PrintInstantiation) {}
5806f32e7eSjoerg 
5906f32e7eSjoerg     void VisitDeclContext(DeclContext *DC, bool Indent = true);
6006f32e7eSjoerg 
6106f32e7eSjoerg     void VisitTranslationUnitDecl(TranslationUnitDecl *D);
6206f32e7eSjoerg     void VisitTypedefDecl(TypedefDecl *D);
6306f32e7eSjoerg     void VisitTypeAliasDecl(TypeAliasDecl *D);
6406f32e7eSjoerg     void VisitEnumDecl(EnumDecl *D);
6506f32e7eSjoerg     void VisitRecordDecl(RecordDecl *D);
6606f32e7eSjoerg     void VisitEnumConstantDecl(EnumConstantDecl *D);
6706f32e7eSjoerg     void VisitEmptyDecl(EmptyDecl *D);
6806f32e7eSjoerg     void VisitFunctionDecl(FunctionDecl *D);
6906f32e7eSjoerg     void VisitFriendDecl(FriendDecl *D);
7006f32e7eSjoerg     void VisitFieldDecl(FieldDecl *D);
7106f32e7eSjoerg     void VisitVarDecl(VarDecl *D);
7206f32e7eSjoerg     void VisitLabelDecl(LabelDecl *D);
7306f32e7eSjoerg     void VisitParmVarDecl(ParmVarDecl *D);
7406f32e7eSjoerg     void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
7506f32e7eSjoerg     void VisitImportDecl(ImportDecl *D);
7606f32e7eSjoerg     void VisitStaticAssertDecl(StaticAssertDecl *D);
7706f32e7eSjoerg     void VisitNamespaceDecl(NamespaceDecl *D);
7806f32e7eSjoerg     void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
7906f32e7eSjoerg     void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
8006f32e7eSjoerg     void VisitCXXRecordDecl(CXXRecordDecl *D);
8106f32e7eSjoerg     void VisitLinkageSpecDecl(LinkageSpecDecl *D);
8206f32e7eSjoerg     void VisitTemplateDecl(const TemplateDecl *D);
8306f32e7eSjoerg     void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
8406f32e7eSjoerg     void VisitClassTemplateDecl(ClassTemplateDecl *D);
8506f32e7eSjoerg     void VisitClassTemplateSpecializationDecl(
8606f32e7eSjoerg                                             ClassTemplateSpecializationDecl *D);
8706f32e7eSjoerg     void VisitClassTemplatePartialSpecializationDecl(
8806f32e7eSjoerg                                      ClassTemplatePartialSpecializationDecl *D);
8906f32e7eSjoerg     void VisitObjCMethodDecl(ObjCMethodDecl *D);
9006f32e7eSjoerg     void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
9106f32e7eSjoerg     void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
9206f32e7eSjoerg     void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
9306f32e7eSjoerg     void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
9406f32e7eSjoerg     void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
9506f32e7eSjoerg     void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
9606f32e7eSjoerg     void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
9706f32e7eSjoerg     void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
9806f32e7eSjoerg     void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
9906f32e7eSjoerg     void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
10006f32e7eSjoerg     void VisitUsingDecl(UsingDecl *D);
10106f32e7eSjoerg     void VisitUsingShadowDecl(UsingShadowDecl *D);
10206f32e7eSjoerg     void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
10306f32e7eSjoerg     void VisitOMPAllocateDecl(OMPAllocateDecl *D);
10406f32e7eSjoerg     void VisitOMPRequiresDecl(OMPRequiresDecl *D);
10506f32e7eSjoerg     void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
10606f32e7eSjoerg     void VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D);
10706f32e7eSjoerg     void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
108*13fbcb42Sjoerg     void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *TTP);
109*13fbcb42Sjoerg     void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *NTTP);
11006f32e7eSjoerg 
11106f32e7eSjoerg     void printTemplateParameters(const TemplateParameterList *Params,
11206f32e7eSjoerg                                  bool OmitTemplateKW = false);
113*13fbcb42Sjoerg     void printTemplateArguments(llvm::ArrayRef<TemplateArgument> Args,
114*13fbcb42Sjoerg                                 const TemplateParameterList *Params,
115*13fbcb42Sjoerg                                 bool TemplOverloaded);
116*13fbcb42Sjoerg     void printTemplateArguments(llvm::ArrayRef<TemplateArgumentLoc> Args,
117*13fbcb42Sjoerg                                 const TemplateParameterList *Params,
118*13fbcb42Sjoerg                                 bool TemplOverloaded);
11906f32e7eSjoerg     void prettyPrintAttributes(Decl *D);
12006f32e7eSjoerg     void prettyPrintPragmas(Decl *D);
12106f32e7eSjoerg     void printDeclType(QualType T, StringRef DeclName, bool Pack = false);
12206f32e7eSjoerg   };
12306f32e7eSjoerg }
12406f32e7eSjoerg 
print(raw_ostream & Out,unsigned Indentation,bool PrintInstantiation) const12506f32e7eSjoerg void Decl::print(raw_ostream &Out, unsigned Indentation,
12606f32e7eSjoerg                  bool PrintInstantiation) const {
12706f32e7eSjoerg   print(Out, getASTContext().getPrintingPolicy(), Indentation, PrintInstantiation);
12806f32e7eSjoerg }
12906f32e7eSjoerg 
print(raw_ostream & Out,const PrintingPolicy & Policy,unsigned Indentation,bool PrintInstantiation) const13006f32e7eSjoerg void Decl::print(raw_ostream &Out, const PrintingPolicy &Policy,
13106f32e7eSjoerg                  unsigned Indentation, bool PrintInstantiation) const {
13206f32e7eSjoerg   DeclPrinter Printer(Out, Policy, getASTContext(), Indentation,
13306f32e7eSjoerg                       PrintInstantiation);
13406f32e7eSjoerg   Printer.Visit(const_cast<Decl*>(this));
13506f32e7eSjoerg }
13606f32e7eSjoerg 
print(raw_ostream & Out,const ASTContext & Context,bool OmitTemplateKW) const13706f32e7eSjoerg void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context,
13806f32e7eSjoerg                                   bool OmitTemplateKW) const {
13906f32e7eSjoerg   print(Out, Context, Context.getPrintingPolicy(), OmitTemplateKW);
14006f32e7eSjoerg }
14106f32e7eSjoerg 
print(raw_ostream & Out,const ASTContext & Context,const PrintingPolicy & Policy,bool OmitTemplateKW) const14206f32e7eSjoerg void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context,
14306f32e7eSjoerg                                   const PrintingPolicy &Policy,
14406f32e7eSjoerg                                   bool OmitTemplateKW) const {
14506f32e7eSjoerg   DeclPrinter Printer(Out, Policy, Context);
14606f32e7eSjoerg   Printer.printTemplateParameters(this, OmitTemplateKW);
14706f32e7eSjoerg }
14806f32e7eSjoerg 
GetBaseType(QualType T)14906f32e7eSjoerg static QualType GetBaseType(QualType T) {
15006f32e7eSjoerg   // FIXME: This should be on the Type class!
15106f32e7eSjoerg   QualType BaseType = T;
15206f32e7eSjoerg   while (!BaseType->isSpecifierType()) {
15306f32e7eSjoerg     if (const PointerType *PTy = BaseType->getAs<PointerType>())
15406f32e7eSjoerg       BaseType = PTy->getPointeeType();
15506f32e7eSjoerg     else if (const BlockPointerType *BPy = BaseType->getAs<BlockPointerType>())
15606f32e7eSjoerg       BaseType = BPy->getPointeeType();
15706f32e7eSjoerg     else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType))
15806f32e7eSjoerg       BaseType = ATy->getElementType();
15906f32e7eSjoerg     else if (const FunctionType* FTy = BaseType->getAs<FunctionType>())
16006f32e7eSjoerg       BaseType = FTy->getReturnType();
16106f32e7eSjoerg     else if (const VectorType *VTy = BaseType->getAs<VectorType>())
16206f32e7eSjoerg       BaseType = VTy->getElementType();
16306f32e7eSjoerg     else if (const ReferenceType *RTy = BaseType->getAs<ReferenceType>())
16406f32e7eSjoerg       BaseType = RTy->getPointeeType();
16506f32e7eSjoerg     else if (const AutoType *ATy = BaseType->getAs<AutoType>())
16606f32e7eSjoerg       BaseType = ATy->getDeducedType();
16706f32e7eSjoerg     else if (const ParenType *PTy = BaseType->getAs<ParenType>())
16806f32e7eSjoerg       BaseType = PTy->desugar();
16906f32e7eSjoerg     else
17006f32e7eSjoerg       // This must be a syntax error.
17106f32e7eSjoerg       break;
17206f32e7eSjoerg   }
17306f32e7eSjoerg   return BaseType;
17406f32e7eSjoerg }
17506f32e7eSjoerg 
getDeclType(Decl * D)17606f32e7eSjoerg static QualType getDeclType(Decl* D) {
17706f32e7eSjoerg   if (TypedefNameDecl* TDD = dyn_cast<TypedefNameDecl>(D))
17806f32e7eSjoerg     return TDD->getUnderlyingType();
17906f32e7eSjoerg   if (ValueDecl* VD = dyn_cast<ValueDecl>(D))
18006f32e7eSjoerg     return VD->getType();
18106f32e7eSjoerg   return QualType();
18206f32e7eSjoerg }
18306f32e7eSjoerg 
printGroup(Decl ** Begin,unsigned NumDecls,raw_ostream & Out,const PrintingPolicy & Policy,unsigned Indentation)18406f32e7eSjoerg void Decl::printGroup(Decl** Begin, unsigned NumDecls,
18506f32e7eSjoerg                       raw_ostream &Out, const PrintingPolicy &Policy,
18606f32e7eSjoerg                       unsigned Indentation) {
18706f32e7eSjoerg   if (NumDecls == 1) {
18806f32e7eSjoerg     (*Begin)->print(Out, Policy, Indentation);
18906f32e7eSjoerg     return;
19006f32e7eSjoerg   }
19106f32e7eSjoerg 
19206f32e7eSjoerg   Decl** End = Begin + NumDecls;
19306f32e7eSjoerg   TagDecl* TD = dyn_cast<TagDecl>(*Begin);
19406f32e7eSjoerg   if (TD)
19506f32e7eSjoerg     ++Begin;
19606f32e7eSjoerg 
19706f32e7eSjoerg   PrintingPolicy SubPolicy(Policy);
19806f32e7eSjoerg 
19906f32e7eSjoerg   bool isFirst = true;
20006f32e7eSjoerg   for ( ; Begin != End; ++Begin) {
20106f32e7eSjoerg     if (isFirst) {
20206f32e7eSjoerg       if(TD)
20306f32e7eSjoerg         SubPolicy.IncludeTagDefinition = true;
20406f32e7eSjoerg       SubPolicy.SuppressSpecifiers = false;
20506f32e7eSjoerg       isFirst = false;
20606f32e7eSjoerg     } else {
20706f32e7eSjoerg       if (!isFirst) Out << ", ";
20806f32e7eSjoerg       SubPolicy.IncludeTagDefinition = false;
20906f32e7eSjoerg       SubPolicy.SuppressSpecifiers = true;
21006f32e7eSjoerg     }
21106f32e7eSjoerg 
21206f32e7eSjoerg     (*Begin)->print(Out, SubPolicy, Indentation);
21306f32e7eSjoerg   }
21406f32e7eSjoerg }
21506f32e7eSjoerg 
dumpDeclContext() const21606f32e7eSjoerg LLVM_DUMP_METHOD void DeclContext::dumpDeclContext() const {
21706f32e7eSjoerg   // Get the translation unit
21806f32e7eSjoerg   const DeclContext *DC = this;
21906f32e7eSjoerg   while (!DC->isTranslationUnit())
22006f32e7eSjoerg     DC = DC->getParent();
22106f32e7eSjoerg 
22206f32e7eSjoerg   ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
22306f32e7eSjoerg   DeclPrinter Printer(llvm::errs(), Ctx.getPrintingPolicy(), Ctx, 0);
22406f32e7eSjoerg   Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false);
22506f32e7eSjoerg }
22606f32e7eSjoerg 
Indent(unsigned Indentation)22706f32e7eSjoerg raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
22806f32e7eSjoerg   for (unsigned i = 0; i != Indentation; ++i)
22906f32e7eSjoerg     Out << "  ";
23006f32e7eSjoerg   return Out;
23106f32e7eSjoerg }
23206f32e7eSjoerg 
prettyPrintAttributes(Decl * D)23306f32e7eSjoerg void DeclPrinter::prettyPrintAttributes(Decl *D) {
23406f32e7eSjoerg   if (Policy.PolishForDeclaration)
23506f32e7eSjoerg     return;
23606f32e7eSjoerg 
23706f32e7eSjoerg   if (D->hasAttrs()) {
23806f32e7eSjoerg     AttrVec &Attrs = D->getAttrs();
23906f32e7eSjoerg     for (auto *A : Attrs) {
24006f32e7eSjoerg       if (A->isInherited() || A->isImplicit())
24106f32e7eSjoerg         continue;
24206f32e7eSjoerg       switch (A->getKind()) {
24306f32e7eSjoerg #define ATTR(X)
24406f32e7eSjoerg #define PRAGMA_SPELLING_ATTR(X) case attr::X:
24506f32e7eSjoerg #include "clang/Basic/AttrList.inc"
24606f32e7eSjoerg         break;
24706f32e7eSjoerg       default:
24806f32e7eSjoerg         A->printPretty(Out, Policy);
24906f32e7eSjoerg         break;
25006f32e7eSjoerg       }
25106f32e7eSjoerg     }
25206f32e7eSjoerg   }
25306f32e7eSjoerg }
25406f32e7eSjoerg 
prettyPrintPragmas(Decl * D)25506f32e7eSjoerg void DeclPrinter::prettyPrintPragmas(Decl *D) {
25606f32e7eSjoerg   if (Policy.PolishForDeclaration)
25706f32e7eSjoerg     return;
25806f32e7eSjoerg 
25906f32e7eSjoerg   if (D->hasAttrs()) {
26006f32e7eSjoerg     AttrVec &Attrs = D->getAttrs();
26106f32e7eSjoerg     for (auto *A : Attrs) {
26206f32e7eSjoerg       switch (A->getKind()) {
26306f32e7eSjoerg #define ATTR(X)
26406f32e7eSjoerg #define PRAGMA_SPELLING_ATTR(X) case attr::X:
26506f32e7eSjoerg #include "clang/Basic/AttrList.inc"
26606f32e7eSjoerg         A->printPretty(Out, Policy);
26706f32e7eSjoerg         Indent();
26806f32e7eSjoerg         break;
26906f32e7eSjoerg       default:
27006f32e7eSjoerg         break;
27106f32e7eSjoerg       }
27206f32e7eSjoerg     }
27306f32e7eSjoerg   }
27406f32e7eSjoerg }
27506f32e7eSjoerg 
printDeclType(QualType T,StringRef DeclName,bool Pack)27606f32e7eSjoerg void DeclPrinter::printDeclType(QualType T, StringRef DeclName, bool Pack) {
27706f32e7eSjoerg   // Normally, a PackExpansionType is written as T[3]... (for instance, as a
27806f32e7eSjoerg   // template argument), but if it is the type of a declaration, the ellipsis
27906f32e7eSjoerg   // is placed before the name being declared.
28006f32e7eSjoerg   if (auto *PET = T->getAs<PackExpansionType>()) {
28106f32e7eSjoerg     Pack = true;
28206f32e7eSjoerg     T = PET->getPattern();
28306f32e7eSjoerg   }
28406f32e7eSjoerg   T.print(Out, Policy, (Pack ? "..." : "") + DeclName, Indentation);
28506f32e7eSjoerg }
28606f32e7eSjoerg 
ProcessDeclGroup(SmallVectorImpl<Decl * > & Decls)28706f32e7eSjoerg void DeclPrinter::ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls) {
28806f32e7eSjoerg   this->Indent();
28906f32e7eSjoerg   Decl::printGroup(Decls.data(), Decls.size(), Out, Policy, Indentation);
29006f32e7eSjoerg   Out << ";\n";
29106f32e7eSjoerg   Decls.clear();
29206f32e7eSjoerg 
29306f32e7eSjoerg }
29406f32e7eSjoerg 
Print(AccessSpecifier AS)29506f32e7eSjoerg void DeclPrinter::Print(AccessSpecifier AS) {
296*13fbcb42Sjoerg   const auto AccessSpelling = getAccessSpelling(AS);
297*13fbcb42Sjoerg   if (AccessSpelling.empty())
298*13fbcb42Sjoerg     llvm_unreachable("No access specifier!");
299*13fbcb42Sjoerg   Out << AccessSpelling;
30006f32e7eSjoerg }
30106f32e7eSjoerg 
PrintConstructorInitializers(CXXConstructorDecl * CDecl,std::string & Proto)30206f32e7eSjoerg void DeclPrinter::PrintConstructorInitializers(CXXConstructorDecl *CDecl,
30306f32e7eSjoerg                                                std::string &Proto) {
30406f32e7eSjoerg   bool HasInitializerList = false;
30506f32e7eSjoerg   for (const auto *BMInitializer : CDecl->inits()) {
30606f32e7eSjoerg     if (BMInitializer->isInClassMemberInitializer())
30706f32e7eSjoerg       continue;
30806f32e7eSjoerg 
30906f32e7eSjoerg     if (!HasInitializerList) {
31006f32e7eSjoerg       Proto += " : ";
31106f32e7eSjoerg       Out << Proto;
31206f32e7eSjoerg       Proto.clear();
31306f32e7eSjoerg       HasInitializerList = true;
31406f32e7eSjoerg     } else
31506f32e7eSjoerg       Out << ", ";
31606f32e7eSjoerg 
31706f32e7eSjoerg     if (BMInitializer->isAnyMemberInitializer()) {
31806f32e7eSjoerg       FieldDecl *FD = BMInitializer->getAnyMember();
31906f32e7eSjoerg       Out << *FD;
32006f32e7eSjoerg     } else {
32106f32e7eSjoerg       Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(Policy);
32206f32e7eSjoerg     }
32306f32e7eSjoerg 
32406f32e7eSjoerg     Out << "(";
32506f32e7eSjoerg     if (!BMInitializer->getInit()) {
32606f32e7eSjoerg       // Nothing to print
32706f32e7eSjoerg     } else {
32806f32e7eSjoerg       Expr *Init = BMInitializer->getInit();
32906f32e7eSjoerg       if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init))
33006f32e7eSjoerg         Init = Tmp->getSubExpr();
33106f32e7eSjoerg 
33206f32e7eSjoerg       Init = Init->IgnoreParens();
33306f32e7eSjoerg 
33406f32e7eSjoerg       Expr *SimpleInit = nullptr;
33506f32e7eSjoerg       Expr **Args = nullptr;
33606f32e7eSjoerg       unsigned NumArgs = 0;
33706f32e7eSjoerg       if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
33806f32e7eSjoerg         Args = ParenList->getExprs();
33906f32e7eSjoerg         NumArgs = ParenList->getNumExprs();
34006f32e7eSjoerg       } else if (CXXConstructExpr *Construct =
34106f32e7eSjoerg                      dyn_cast<CXXConstructExpr>(Init)) {
34206f32e7eSjoerg         Args = Construct->getArgs();
34306f32e7eSjoerg         NumArgs = Construct->getNumArgs();
34406f32e7eSjoerg       } else
34506f32e7eSjoerg         SimpleInit = Init;
34606f32e7eSjoerg 
34706f32e7eSjoerg       if (SimpleInit)
348*13fbcb42Sjoerg         SimpleInit->printPretty(Out, nullptr, Policy, Indentation, "\n",
349*13fbcb42Sjoerg                                 &Context);
35006f32e7eSjoerg       else {
35106f32e7eSjoerg         for (unsigned I = 0; I != NumArgs; ++I) {
35206f32e7eSjoerg           assert(Args[I] != nullptr && "Expected non-null Expr");
35306f32e7eSjoerg           if (isa<CXXDefaultArgExpr>(Args[I]))
35406f32e7eSjoerg             break;
35506f32e7eSjoerg 
35606f32e7eSjoerg           if (I)
35706f32e7eSjoerg             Out << ", ";
358*13fbcb42Sjoerg           Args[I]->printPretty(Out, nullptr, Policy, Indentation, "\n",
359*13fbcb42Sjoerg                                &Context);
36006f32e7eSjoerg         }
36106f32e7eSjoerg       }
36206f32e7eSjoerg     }
36306f32e7eSjoerg     Out << ")";
36406f32e7eSjoerg     if (BMInitializer->isPackExpansion())
36506f32e7eSjoerg       Out << "...";
36606f32e7eSjoerg   }
36706f32e7eSjoerg }
36806f32e7eSjoerg 
36906f32e7eSjoerg //----------------------------------------------------------------------------
37006f32e7eSjoerg // Common C declarations
37106f32e7eSjoerg //----------------------------------------------------------------------------
37206f32e7eSjoerg 
VisitDeclContext(DeclContext * DC,bool Indent)37306f32e7eSjoerg void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
37406f32e7eSjoerg   if (Policy.TerseOutput)
37506f32e7eSjoerg     return;
37606f32e7eSjoerg 
37706f32e7eSjoerg   if (Indent)
37806f32e7eSjoerg     Indentation += Policy.Indentation;
37906f32e7eSjoerg 
38006f32e7eSjoerg   SmallVector<Decl*, 2> Decls;
38106f32e7eSjoerg   for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end();
38206f32e7eSjoerg        D != DEnd; ++D) {
38306f32e7eSjoerg 
38406f32e7eSjoerg     // Don't print ObjCIvarDecls, as they are printed when visiting the
38506f32e7eSjoerg     // containing ObjCInterfaceDecl.
38606f32e7eSjoerg     if (isa<ObjCIvarDecl>(*D))
38706f32e7eSjoerg       continue;
38806f32e7eSjoerg 
38906f32e7eSjoerg     // Skip over implicit declarations in pretty-printing mode.
39006f32e7eSjoerg     if (D->isImplicit())
39106f32e7eSjoerg       continue;
39206f32e7eSjoerg 
39306f32e7eSjoerg     // Don't print implicit specializations, as they are printed when visiting
39406f32e7eSjoerg     // corresponding templates.
39506f32e7eSjoerg     if (auto FD = dyn_cast<FunctionDecl>(*D))
39606f32e7eSjoerg       if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation &&
39706f32e7eSjoerg           !isa<ClassTemplateSpecializationDecl>(DC))
39806f32e7eSjoerg         continue;
39906f32e7eSjoerg 
40006f32e7eSjoerg     // The next bits of code handle stuff like "struct {int x;} a,b"; we're
40106f32e7eSjoerg     // forced to merge the declarations because there's no other way to
40206f32e7eSjoerg     // refer to the struct in question.  When that struct is named instead, we
40306f32e7eSjoerg     // also need to merge to avoid splitting off a stand-alone struct
40406f32e7eSjoerg     // declaration that produces the warning ext_no_declarators in some
40506f32e7eSjoerg     // contexts.
40606f32e7eSjoerg     //
40706f32e7eSjoerg     // This limited merging is safe without a bunch of other checks because it
40806f32e7eSjoerg     // only merges declarations directly referring to the tag, not typedefs.
40906f32e7eSjoerg     //
41006f32e7eSjoerg     // Check whether the current declaration should be grouped with a previous
41106f32e7eSjoerg     // non-free-standing tag declaration.
41206f32e7eSjoerg     QualType CurDeclType = getDeclType(*D);
41306f32e7eSjoerg     if (!Decls.empty() && !CurDeclType.isNull()) {
41406f32e7eSjoerg       QualType BaseType = GetBaseType(CurDeclType);
41506f32e7eSjoerg       if (!BaseType.isNull() && isa<ElaboratedType>(BaseType) &&
41606f32e7eSjoerg           cast<ElaboratedType>(BaseType)->getOwnedTagDecl() == Decls[0]) {
41706f32e7eSjoerg         Decls.push_back(*D);
41806f32e7eSjoerg         continue;
41906f32e7eSjoerg       }
42006f32e7eSjoerg     }
42106f32e7eSjoerg 
42206f32e7eSjoerg     // If we have a merged group waiting to be handled, handle it now.
42306f32e7eSjoerg     if (!Decls.empty())
42406f32e7eSjoerg       ProcessDeclGroup(Decls);
42506f32e7eSjoerg 
42606f32e7eSjoerg     // If the current declaration is not a free standing declaration, save it
42706f32e7eSjoerg     // so we can merge it with the subsequent declaration(s) using it.
42806f32e7eSjoerg     if (isa<TagDecl>(*D) && !cast<TagDecl>(*D)->isFreeStanding()) {
42906f32e7eSjoerg       Decls.push_back(*D);
43006f32e7eSjoerg       continue;
43106f32e7eSjoerg     }
43206f32e7eSjoerg 
43306f32e7eSjoerg     if (isa<AccessSpecDecl>(*D)) {
43406f32e7eSjoerg       Indentation -= Policy.Indentation;
43506f32e7eSjoerg       this->Indent();
43606f32e7eSjoerg       Print(D->getAccess());
43706f32e7eSjoerg       Out << ":\n";
43806f32e7eSjoerg       Indentation += Policy.Indentation;
43906f32e7eSjoerg       continue;
44006f32e7eSjoerg     }
44106f32e7eSjoerg 
44206f32e7eSjoerg     this->Indent();
44306f32e7eSjoerg     Visit(*D);
44406f32e7eSjoerg 
44506f32e7eSjoerg     // FIXME: Need to be able to tell the DeclPrinter when
44606f32e7eSjoerg     const char *Terminator = nullptr;
44706f32e7eSjoerg     if (isa<OMPThreadPrivateDecl>(*D) || isa<OMPDeclareReductionDecl>(*D) ||
44806f32e7eSjoerg         isa<OMPDeclareMapperDecl>(*D) || isa<OMPRequiresDecl>(*D) ||
44906f32e7eSjoerg         isa<OMPAllocateDecl>(*D))
45006f32e7eSjoerg       Terminator = nullptr;
45106f32e7eSjoerg     else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->hasBody())
45206f32e7eSjoerg       Terminator = nullptr;
45306f32e7eSjoerg     else if (auto FD = dyn_cast<FunctionDecl>(*D)) {
45406f32e7eSjoerg       if (FD->isThisDeclarationADefinition())
45506f32e7eSjoerg         Terminator = nullptr;
45606f32e7eSjoerg       else
45706f32e7eSjoerg         Terminator = ";";
45806f32e7eSjoerg     } else if (auto TD = dyn_cast<FunctionTemplateDecl>(*D)) {
45906f32e7eSjoerg       if (TD->getTemplatedDecl()->isThisDeclarationADefinition())
46006f32e7eSjoerg         Terminator = nullptr;
46106f32e7eSjoerg       else
46206f32e7eSjoerg         Terminator = ";";
46306f32e7eSjoerg     } else if (isa<NamespaceDecl>(*D) || isa<LinkageSpecDecl>(*D) ||
46406f32e7eSjoerg              isa<ObjCImplementationDecl>(*D) ||
46506f32e7eSjoerg              isa<ObjCInterfaceDecl>(*D) ||
46606f32e7eSjoerg              isa<ObjCProtocolDecl>(*D) ||
46706f32e7eSjoerg              isa<ObjCCategoryImplDecl>(*D) ||
46806f32e7eSjoerg              isa<ObjCCategoryDecl>(*D))
46906f32e7eSjoerg       Terminator = nullptr;
47006f32e7eSjoerg     else if (isa<EnumConstantDecl>(*D)) {
47106f32e7eSjoerg       DeclContext::decl_iterator Next = D;
47206f32e7eSjoerg       ++Next;
47306f32e7eSjoerg       if (Next != DEnd)
47406f32e7eSjoerg         Terminator = ",";
47506f32e7eSjoerg     } else
47606f32e7eSjoerg       Terminator = ";";
47706f32e7eSjoerg 
47806f32e7eSjoerg     if (Terminator)
47906f32e7eSjoerg       Out << Terminator;
48006f32e7eSjoerg     if (!Policy.TerseOutput &&
48106f32e7eSjoerg         ((isa<FunctionDecl>(*D) &&
48206f32e7eSjoerg           cast<FunctionDecl>(*D)->doesThisDeclarationHaveABody()) ||
48306f32e7eSjoerg          (isa<FunctionTemplateDecl>(*D) &&
48406f32e7eSjoerg           cast<FunctionTemplateDecl>(*D)->getTemplatedDecl()->doesThisDeclarationHaveABody())))
48506f32e7eSjoerg       ; // StmtPrinter already added '\n' after CompoundStmt.
48606f32e7eSjoerg     else
48706f32e7eSjoerg       Out << "\n";
48806f32e7eSjoerg 
48906f32e7eSjoerg     // Declare target attribute is special one, natural spelling for the pragma
49006f32e7eSjoerg     // assumes "ending" construct so print it here.
49106f32e7eSjoerg     if (D->hasAttr<OMPDeclareTargetDeclAttr>())
49206f32e7eSjoerg       Out << "#pragma omp end declare target\n";
49306f32e7eSjoerg   }
49406f32e7eSjoerg 
49506f32e7eSjoerg   if (!Decls.empty())
49606f32e7eSjoerg     ProcessDeclGroup(Decls);
49706f32e7eSjoerg 
49806f32e7eSjoerg   if (Indent)
49906f32e7eSjoerg     Indentation -= Policy.Indentation;
50006f32e7eSjoerg }
50106f32e7eSjoerg 
VisitTranslationUnitDecl(TranslationUnitDecl * D)50206f32e7eSjoerg void DeclPrinter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
50306f32e7eSjoerg   VisitDeclContext(D, false);
50406f32e7eSjoerg }
50506f32e7eSjoerg 
VisitTypedefDecl(TypedefDecl * D)50606f32e7eSjoerg void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
50706f32e7eSjoerg   if (!Policy.SuppressSpecifiers) {
50806f32e7eSjoerg     Out << "typedef ";
50906f32e7eSjoerg 
51006f32e7eSjoerg     if (D->isModulePrivate())
51106f32e7eSjoerg       Out << "__module_private__ ";
51206f32e7eSjoerg   }
51306f32e7eSjoerg   QualType Ty = D->getTypeSourceInfo()->getType();
51406f32e7eSjoerg   Ty.print(Out, Policy, D->getName(), Indentation);
51506f32e7eSjoerg   prettyPrintAttributes(D);
51606f32e7eSjoerg }
51706f32e7eSjoerg 
VisitTypeAliasDecl(TypeAliasDecl * D)51806f32e7eSjoerg void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) {
51906f32e7eSjoerg   Out << "using " << *D;
52006f32e7eSjoerg   prettyPrintAttributes(D);
52106f32e7eSjoerg   Out << " = " << D->getTypeSourceInfo()->getType().getAsString(Policy);
52206f32e7eSjoerg }
52306f32e7eSjoerg 
VisitEnumDecl(EnumDecl * D)52406f32e7eSjoerg void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
52506f32e7eSjoerg   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
52606f32e7eSjoerg     Out << "__module_private__ ";
52706f32e7eSjoerg   Out << "enum";
52806f32e7eSjoerg   if (D->isScoped()) {
52906f32e7eSjoerg     if (D->isScopedUsingClassTag())
53006f32e7eSjoerg       Out << " class";
53106f32e7eSjoerg     else
53206f32e7eSjoerg       Out << " struct";
53306f32e7eSjoerg   }
53406f32e7eSjoerg 
53506f32e7eSjoerg   prettyPrintAttributes(D);
53606f32e7eSjoerg 
537*13fbcb42Sjoerg   if (D->getDeclName())
538*13fbcb42Sjoerg     Out << ' ' << D->getDeclName();
53906f32e7eSjoerg 
540*13fbcb42Sjoerg   if (D->isFixed())
54106f32e7eSjoerg     Out << " : " << D->getIntegerType().stream(Policy);
54206f32e7eSjoerg 
54306f32e7eSjoerg   if (D->isCompleteDefinition()) {
54406f32e7eSjoerg     Out << " {\n";
54506f32e7eSjoerg     VisitDeclContext(D);
54606f32e7eSjoerg     Indent() << "}";
54706f32e7eSjoerg   }
54806f32e7eSjoerg }
54906f32e7eSjoerg 
VisitRecordDecl(RecordDecl * D)55006f32e7eSjoerg void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
55106f32e7eSjoerg   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
55206f32e7eSjoerg     Out << "__module_private__ ";
55306f32e7eSjoerg   Out << D->getKindName();
55406f32e7eSjoerg 
55506f32e7eSjoerg   prettyPrintAttributes(D);
55606f32e7eSjoerg 
55706f32e7eSjoerg   if (D->getIdentifier())
55806f32e7eSjoerg     Out << ' ' << *D;
55906f32e7eSjoerg 
56006f32e7eSjoerg   if (D->isCompleteDefinition()) {
56106f32e7eSjoerg     Out << " {\n";
56206f32e7eSjoerg     VisitDeclContext(D);
56306f32e7eSjoerg     Indent() << "}";
56406f32e7eSjoerg   }
56506f32e7eSjoerg }
56606f32e7eSjoerg 
VisitEnumConstantDecl(EnumConstantDecl * D)56706f32e7eSjoerg void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
56806f32e7eSjoerg   Out << *D;
56906f32e7eSjoerg   prettyPrintAttributes(D);
57006f32e7eSjoerg   if (Expr *Init = D->getInitExpr()) {
57106f32e7eSjoerg     Out << " = ";
57206f32e7eSjoerg     Init->printPretty(Out, nullptr, Policy, Indentation, "\n", &Context);
57306f32e7eSjoerg   }
57406f32e7eSjoerg }
57506f32e7eSjoerg 
printExplicitSpecifier(ExplicitSpecifier ES,llvm::raw_ostream & Out,PrintingPolicy & Policy,unsigned Indentation,const ASTContext & Context)57606f32e7eSjoerg static void printExplicitSpecifier(ExplicitSpecifier ES, llvm::raw_ostream &Out,
577*13fbcb42Sjoerg                                    PrintingPolicy &Policy, unsigned Indentation,
578*13fbcb42Sjoerg                                    const ASTContext &Context) {
57906f32e7eSjoerg   std::string Proto = "explicit";
58006f32e7eSjoerg   llvm::raw_string_ostream EOut(Proto);
58106f32e7eSjoerg   if (ES.getExpr()) {
58206f32e7eSjoerg     EOut << "(";
583*13fbcb42Sjoerg     ES.getExpr()->printPretty(EOut, nullptr, Policy, Indentation, "\n",
584*13fbcb42Sjoerg                               &Context);
58506f32e7eSjoerg     EOut << ")";
58606f32e7eSjoerg   }
58706f32e7eSjoerg   EOut << " ";
58806f32e7eSjoerg   EOut.flush();
58906f32e7eSjoerg   Out << EOut.str();
59006f32e7eSjoerg }
59106f32e7eSjoerg 
VisitFunctionDecl(FunctionDecl * D)59206f32e7eSjoerg void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
59306f32e7eSjoerg   if (!D->getDescribedFunctionTemplate() &&
59406f32e7eSjoerg       !D->isFunctionTemplateSpecialization())
59506f32e7eSjoerg     prettyPrintPragmas(D);
59606f32e7eSjoerg 
59706f32e7eSjoerg   if (D->isFunctionTemplateSpecialization())
59806f32e7eSjoerg     Out << "template<> ";
59906f32e7eSjoerg   else if (!D->getDescribedFunctionTemplate()) {
60006f32e7eSjoerg     for (unsigned I = 0, NumTemplateParams = D->getNumTemplateParameterLists();
60106f32e7eSjoerg          I < NumTemplateParams; ++I)
60206f32e7eSjoerg       printTemplateParameters(D->getTemplateParameterList(I));
60306f32e7eSjoerg   }
60406f32e7eSjoerg 
60506f32e7eSjoerg   CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
60606f32e7eSjoerg   CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
60706f32e7eSjoerg   CXXDeductionGuideDecl *GuideDecl = dyn_cast<CXXDeductionGuideDecl>(D);
60806f32e7eSjoerg   if (!Policy.SuppressSpecifiers) {
60906f32e7eSjoerg     switch (D->getStorageClass()) {
61006f32e7eSjoerg     case SC_None: break;
61106f32e7eSjoerg     case SC_Extern: Out << "extern "; break;
61206f32e7eSjoerg     case SC_Static: Out << "static "; break;
61306f32e7eSjoerg     case SC_PrivateExtern: Out << "__private_extern__ "; break;
61406f32e7eSjoerg     case SC_Auto: case SC_Register:
61506f32e7eSjoerg       llvm_unreachable("invalid for functions");
61606f32e7eSjoerg     }
61706f32e7eSjoerg 
61806f32e7eSjoerg     if (D->isInlineSpecified())  Out << "inline ";
61906f32e7eSjoerg     if (D->isVirtualAsWritten()) Out << "virtual ";
62006f32e7eSjoerg     if (D->isModulePrivate())    Out << "__module_private__ ";
62106f32e7eSjoerg     if (D->isConstexprSpecified() && !D->isExplicitlyDefaulted())
62206f32e7eSjoerg       Out << "constexpr ";
62306f32e7eSjoerg     if (D->isConsteval())        Out << "consteval ";
62406f32e7eSjoerg     ExplicitSpecifier ExplicitSpec = ExplicitSpecifier::getFromDecl(D);
62506f32e7eSjoerg     if (ExplicitSpec.isSpecified())
626*13fbcb42Sjoerg       printExplicitSpecifier(ExplicitSpec, Out, Policy, Indentation, Context);
62706f32e7eSjoerg   }
62806f32e7eSjoerg 
62906f32e7eSjoerg   PrintingPolicy SubPolicy(Policy);
63006f32e7eSjoerg   SubPolicy.SuppressSpecifiers = false;
63106f32e7eSjoerg   std::string Proto;
63206f32e7eSjoerg 
63306f32e7eSjoerg   if (Policy.FullyQualifiedName) {
63406f32e7eSjoerg     Proto += D->getQualifiedNameAsString();
63506f32e7eSjoerg   } else {
636*13fbcb42Sjoerg     llvm::raw_string_ostream OS(Proto);
63706f32e7eSjoerg     if (!Policy.SuppressScope) {
63806f32e7eSjoerg       if (const NestedNameSpecifier *NS = D->getQualifier()) {
63906f32e7eSjoerg         NS->print(OS, Policy);
64006f32e7eSjoerg       }
64106f32e7eSjoerg     }
642*13fbcb42Sjoerg     D->getNameInfo().printName(OS, Policy);
64306f32e7eSjoerg   }
64406f32e7eSjoerg 
64506f32e7eSjoerg   if (GuideDecl)
64606f32e7eSjoerg     Proto = GuideDecl->getDeducedTemplate()->getDeclName().getAsString();
647*13fbcb42Sjoerg   if (D->isFunctionTemplateSpecialization()) {
64806f32e7eSjoerg     llvm::raw_string_ostream POut(Proto);
64906f32e7eSjoerg     DeclPrinter TArgPrinter(POut, SubPolicy, Context, Indentation);
650*13fbcb42Sjoerg     const auto *TArgAsWritten = D->getTemplateSpecializationArgsAsWritten();
651*13fbcb42Sjoerg     const TemplateParameterList *TPL = D->getTemplateSpecializationInfo()
652*13fbcb42Sjoerg                                            ->getTemplate()
653*13fbcb42Sjoerg                                            ->getTemplateParameters();
654*13fbcb42Sjoerg     if (TArgAsWritten && !Policy.PrintCanonicalTypes)
655*13fbcb42Sjoerg       TArgPrinter.printTemplateArguments(TArgAsWritten->arguments(), TPL,
656*13fbcb42Sjoerg                                          /*TemplOverloaded*/ true);
657*13fbcb42Sjoerg     else if (const TemplateArgumentList *TArgs =
658*13fbcb42Sjoerg                  D->getTemplateSpecializationArgs())
659*13fbcb42Sjoerg       TArgPrinter.printTemplateArguments(TArgs->asArray(), TPL,
660*13fbcb42Sjoerg                                          /*TemplOverloaded*/ true);
66106f32e7eSjoerg   }
66206f32e7eSjoerg 
66306f32e7eSjoerg   QualType Ty = D->getType();
66406f32e7eSjoerg   while (const ParenType *PT = dyn_cast<ParenType>(Ty)) {
66506f32e7eSjoerg     Proto = '(' + Proto + ')';
66606f32e7eSjoerg     Ty = PT->getInnerType();
66706f32e7eSjoerg   }
66806f32e7eSjoerg 
66906f32e7eSjoerg   if (const FunctionType *AFT = Ty->getAs<FunctionType>()) {
67006f32e7eSjoerg     const FunctionProtoType *FT = nullptr;
67106f32e7eSjoerg     if (D->hasWrittenPrototype())
67206f32e7eSjoerg       FT = dyn_cast<FunctionProtoType>(AFT);
67306f32e7eSjoerg 
67406f32e7eSjoerg     Proto += "(";
67506f32e7eSjoerg     if (FT) {
67606f32e7eSjoerg       llvm::raw_string_ostream POut(Proto);
67706f32e7eSjoerg       DeclPrinter ParamPrinter(POut, SubPolicy, Context, Indentation);
67806f32e7eSjoerg       for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
67906f32e7eSjoerg         if (i) POut << ", ";
68006f32e7eSjoerg         ParamPrinter.VisitParmVarDecl(D->getParamDecl(i));
68106f32e7eSjoerg       }
68206f32e7eSjoerg 
68306f32e7eSjoerg       if (FT->isVariadic()) {
68406f32e7eSjoerg         if (D->getNumParams()) POut << ", ";
68506f32e7eSjoerg         POut << "...";
68606f32e7eSjoerg       }
68706f32e7eSjoerg     } else if (D->doesThisDeclarationHaveABody() && !D->hasPrototype()) {
68806f32e7eSjoerg       for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
68906f32e7eSjoerg         if (i)
69006f32e7eSjoerg           Proto += ", ";
69106f32e7eSjoerg         Proto += D->getParamDecl(i)->getNameAsString();
69206f32e7eSjoerg       }
69306f32e7eSjoerg     }
69406f32e7eSjoerg 
69506f32e7eSjoerg     Proto += ")";
69606f32e7eSjoerg 
69706f32e7eSjoerg     if (FT) {
69806f32e7eSjoerg       if (FT->isConst())
69906f32e7eSjoerg         Proto += " const";
70006f32e7eSjoerg       if (FT->isVolatile())
70106f32e7eSjoerg         Proto += " volatile";
70206f32e7eSjoerg       if (FT->isRestrict())
70306f32e7eSjoerg         Proto += " restrict";
70406f32e7eSjoerg 
70506f32e7eSjoerg       switch (FT->getRefQualifier()) {
70606f32e7eSjoerg       case RQ_None:
70706f32e7eSjoerg         break;
70806f32e7eSjoerg       case RQ_LValue:
70906f32e7eSjoerg         Proto += " &";
71006f32e7eSjoerg         break;
71106f32e7eSjoerg       case RQ_RValue:
71206f32e7eSjoerg         Proto += " &&";
71306f32e7eSjoerg         break;
71406f32e7eSjoerg       }
71506f32e7eSjoerg     }
71606f32e7eSjoerg 
71706f32e7eSjoerg     if (FT && FT->hasDynamicExceptionSpec()) {
71806f32e7eSjoerg       Proto += " throw(";
71906f32e7eSjoerg       if (FT->getExceptionSpecType() == EST_MSAny)
72006f32e7eSjoerg         Proto += "...";
72106f32e7eSjoerg       else
72206f32e7eSjoerg         for (unsigned I = 0, N = FT->getNumExceptions(); I != N; ++I) {
72306f32e7eSjoerg           if (I)
72406f32e7eSjoerg             Proto += ", ";
72506f32e7eSjoerg 
72606f32e7eSjoerg           Proto += FT->getExceptionType(I).getAsString(SubPolicy);
72706f32e7eSjoerg         }
72806f32e7eSjoerg       Proto += ")";
72906f32e7eSjoerg     } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) {
73006f32e7eSjoerg       Proto += " noexcept";
73106f32e7eSjoerg       if (isComputedNoexcept(FT->getExceptionSpecType())) {
73206f32e7eSjoerg         Proto += "(";
73306f32e7eSjoerg         llvm::raw_string_ostream EOut(Proto);
73406f32e7eSjoerg         FT->getNoexceptExpr()->printPretty(EOut, nullptr, SubPolicy,
735*13fbcb42Sjoerg                                            Indentation, "\n", &Context);
73606f32e7eSjoerg         EOut.flush();
73706f32e7eSjoerg         Proto += EOut.str();
73806f32e7eSjoerg         Proto += ")";
73906f32e7eSjoerg       }
74006f32e7eSjoerg     }
74106f32e7eSjoerg 
74206f32e7eSjoerg     if (CDecl) {
74306f32e7eSjoerg       if (!Policy.TerseOutput)
74406f32e7eSjoerg         PrintConstructorInitializers(CDecl, Proto);
74506f32e7eSjoerg     } else if (!ConversionDecl && !isa<CXXDestructorDecl>(D)) {
74606f32e7eSjoerg       if (FT && FT->hasTrailingReturn()) {
74706f32e7eSjoerg         if (!GuideDecl)
74806f32e7eSjoerg           Out << "auto ";
74906f32e7eSjoerg         Out << Proto << " -> ";
75006f32e7eSjoerg         Proto.clear();
75106f32e7eSjoerg       }
75206f32e7eSjoerg       AFT->getReturnType().print(Out, Policy, Proto);
75306f32e7eSjoerg       Proto.clear();
75406f32e7eSjoerg     }
75506f32e7eSjoerg     Out << Proto;
756*13fbcb42Sjoerg 
757*13fbcb42Sjoerg     if (Expr *TrailingRequiresClause = D->getTrailingRequiresClause()) {
758*13fbcb42Sjoerg       Out << " requires ";
759*13fbcb42Sjoerg       TrailingRequiresClause->printPretty(Out, nullptr, SubPolicy, Indentation,
760*13fbcb42Sjoerg                                           "\n", &Context);
761*13fbcb42Sjoerg     }
76206f32e7eSjoerg   } else {
76306f32e7eSjoerg     Ty.print(Out, Policy, Proto);
76406f32e7eSjoerg   }
76506f32e7eSjoerg 
76606f32e7eSjoerg   prettyPrintAttributes(D);
76706f32e7eSjoerg 
76806f32e7eSjoerg   if (D->isPure())
76906f32e7eSjoerg     Out << " = 0";
77006f32e7eSjoerg   else if (D->isDeletedAsWritten())
77106f32e7eSjoerg     Out << " = delete";
77206f32e7eSjoerg   else if (D->isExplicitlyDefaulted())
77306f32e7eSjoerg     Out << " = default";
77406f32e7eSjoerg   else if (D->doesThisDeclarationHaveABody()) {
77506f32e7eSjoerg     if (!Policy.TerseOutput) {
77606f32e7eSjoerg       if (!D->hasPrototype() && D->getNumParams()) {
77706f32e7eSjoerg         // This is a K&R function definition, so we need to print the
77806f32e7eSjoerg         // parameters.
77906f32e7eSjoerg         Out << '\n';
78006f32e7eSjoerg         DeclPrinter ParamPrinter(Out, SubPolicy, Context, Indentation);
78106f32e7eSjoerg         Indentation += Policy.Indentation;
78206f32e7eSjoerg         for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
78306f32e7eSjoerg           Indent();
78406f32e7eSjoerg           ParamPrinter.VisitParmVarDecl(D->getParamDecl(i));
78506f32e7eSjoerg           Out << ";\n";
78606f32e7eSjoerg         }
78706f32e7eSjoerg         Indentation -= Policy.Indentation;
78806f32e7eSjoerg       } else
78906f32e7eSjoerg         Out << ' ';
79006f32e7eSjoerg 
79106f32e7eSjoerg       if (D->getBody())
792*13fbcb42Sjoerg         D->getBody()->printPretty(Out, nullptr, SubPolicy, Indentation, "\n",
793*13fbcb42Sjoerg                                   &Context);
79406f32e7eSjoerg     } else {
79506f32e7eSjoerg       if (!Policy.TerseOutput && isa<CXXConstructorDecl>(*D))
79606f32e7eSjoerg         Out << " {}";
79706f32e7eSjoerg     }
79806f32e7eSjoerg   }
79906f32e7eSjoerg }
80006f32e7eSjoerg 
VisitFriendDecl(FriendDecl * D)80106f32e7eSjoerg void DeclPrinter::VisitFriendDecl(FriendDecl *D) {
80206f32e7eSjoerg   if (TypeSourceInfo *TSI = D->getFriendType()) {
80306f32e7eSjoerg     unsigned NumTPLists = D->getFriendTypeNumTemplateParameterLists();
80406f32e7eSjoerg     for (unsigned i = 0; i < NumTPLists; ++i)
80506f32e7eSjoerg       printTemplateParameters(D->getFriendTypeTemplateParameterList(i));
80606f32e7eSjoerg     Out << "friend ";
80706f32e7eSjoerg     Out << " " << TSI->getType().getAsString(Policy);
80806f32e7eSjoerg   }
80906f32e7eSjoerg   else if (FunctionDecl *FD =
81006f32e7eSjoerg       dyn_cast<FunctionDecl>(D->getFriendDecl())) {
81106f32e7eSjoerg     Out << "friend ";
81206f32e7eSjoerg     VisitFunctionDecl(FD);
81306f32e7eSjoerg   }
81406f32e7eSjoerg   else if (FunctionTemplateDecl *FTD =
81506f32e7eSjoerg            dyn_cast<FunctionTemplateDecl>(D->getFriendDecl())) {
81606f32e7eSjoerg     Out << "friend ";
81706f32e7eSjoerg     VisitFunctionTemplateDecl(FTD);
81806f32e7eSjoerg   }
81906f32e7eSjoerg   else if (ClassTemplateDecl *CTD =
82006f32e7eSjoerg            dyn_cast<ClassTemplateDecl>(D->getFriendDecl())) {
82106f32e7eSjoerg     Out << "friend ";
82206f32e7eSjoerg     VisitRedeclarableTemplateDecl(CTD);
82306f32e7eSjoerg   }
82406f32e7eSjoerg }
82506f32e7eSjoerg 
VisitFieldDecl(FieldDecl * D)82606f32e7eSjoerg void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
82706f32e7eSjoerg   // FIXME: add printing of pragma attributes if required.
82806f32e7eSjoerg   if (!Policy.SuppressSpecifiers && D->isMutable())
82906f32e7eSjoerg     Out << "mutable ";
83006f32e7eSjoerg   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
83106f32e7eSjoerg     Out << "__module_private__ ";
83206f32e7eSjoerg 
83306f32e7eSjoerg   Out << D->getASTContext().getUnqualifiedObjCPointerType(D->getType()).
83406f32e7eSjoerg          stream(Policy, D->getName(), Indentation);
83506f32e7eSjoerg 
83606f32e7eSjoerg   if (D->isBitField()) {
83706f32e7eSjoerg     Out << " : ";
838*13fbcb42Sjoerg     D->getBitWidth()->printPretty(Out, nullptr, Policy, Indentation, "\n",
839*13fbcb42Sjoerg                                   &Context);
84006f32e7eSjoerg   }
84106f32e7eSjoerg 
84206f32e7eSjoerg   Expr *Init = D->getInClassInitializer();
84306f32e7eSjoerg   if (!Policy.SuppressInitializers && Init) {
84406f32e7eSjoerg     if (D->getInClassInitStyle() == ICIS_ListInit)
84506f32e7eSjoerg       Out << " ";
84606f32e7eSjoerg     else
84706f32e7eSjoerg       Out << " = ";
848*13fbcb42Sjoerg     Init->printPretty(Out, nullptr, Policy, Indentation, "\n", &Context);
84906f32e7eSjoerg   }
85006f32e7eSjoerg   prettyPrintAttributes(D);
85106f32e7eSjoerg }
85206f32e7eSjoerg 
VisitLabelDecl(LabelDecl * D)85306f32e7eSjoerg void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
85406f32e7eSjoerg   Out << *D << ":";
85506f32e7eSjoerg }
85606f32e7eSjoerg 
VisitVarDecl(VarDecl * D)85706f32e7eSjoerg void DeclPrinter::VisitVarDecl(VarDecl *D) {
85806f32e7eSjoerg   prettyPrintPragmas(D);
85906f32e7eSjoerg 
86006f32e7eSjoerg   QualType T = D->getTypeSourceInfo()
86106f32e7eSjoerg     ? D->getTypeSourceInfo()->getType()
86206f32e7eSjoerg     : D->getASTContext().getUnqualifiedObjCPointerType(D->getType());
86306f32e7eSjoerg 
86406f32e7eSjoerg   if (!Policy.SuppressSpecifiers) {
86506f32e7eSjoerg     StorageClass SC = D->getStorageClass();
86606f32e7eSjoerg     if (SC != SC_None)
86706f32e7eSjoerg       Out << VarDecl::getStorageClassSpecifierString(SC) << " ";
86806f32e7eSjoerg 
86906f32e7eSjoerg     switch (D->getTSCSpec()) {
87006f32e7eSjoerg     case TSCS_unspecified:
87106f32e7eSjoerg       break;
87206f32e7eSjoerg     case TSCS___thread:
87306f32e7eSjoerg       Out << "__thread ";
87406f32e7eSjoerg       break;
87506f32e7eSjoerg     case TSCS__Thread_local:
87606f32e7eSjoerg       Out << "_Thread_local ";
87706f32e7eSjoerg       break;
87806f32e7eSjoerg     case TSCS_thread_local:
87906f32e7eSjoerg       Out << "thread_local ";
88006f32e7eSjoerg       break;
88106f32e7eSjoerg     }
88206f32e7eSjoerg 
88306f32e7eSjoerg     if (D->isModulePrivate())
88406f32e7eSjoerg       Out << "__module_private__ ";
88506f32e7eSjoerg 
88606f32e7eSjoerg     if (D->isConstexpr()) {
88706f32e7eSjoerg       Out << "constexpr ";
88806f32e7eSjoerg       T.removeLocalConst();
88906f32e7eSjoerg     }
89006f32e7eSjoerg   }
89106f32e7eSjoerg 
89206f32e7eSjoerg   printDeclType(T, D->getName());
89306f32e7eSjoerg   Expr *Init = D->getInit();
89406f32e7eSjoerg   if (!Policy.SuppressInitializers && Init) {
89506f32e7eSjoerg     bool ImplicitInit = false;
89606f32e7eSjoerg     if (CXXConstructExpr *Construct =
89706f32e7eSjoerg             dyn_cast<CXXConstructExpr>(Init->IgnoreImplicit())) {
89806f32e7eSjoerg       if (D->getInitStyle() == VarDecl::CallInit &&
89906f32e7eSjoerg           !Construct->isListInitialization()) {
90006f32e7eSjoerg         ImplicitInit = Construct->getNumArgs() == 0 ||
90106f32e7eSjoerg           Construct->getArg(0)->isDefaultArgument();
90206f32e7eSjoerg       }
90306f32e7eSjoerg     }
90406f32e7eSjoerg     if (!ImplicitInit) {
90506f32e7eSjoerg       if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
90606f32e7eSjoerg         Out << "(";
90706f32e7eSjoerg       else if (D->getInitStyle() == VarDecl::CInit) {
90806f32e7eSjoerg         Out << " = ";
90906f32e7eSjoerg       }
91006f32e7eSjoerg       PrintingPolicy SubPolicy(Policy);
91106f32e7eSjoerg       SubPolicy.SuppressSpecifiers = false;
91206f32e7eSjoerg       SubPolicy.IncludeTagDefinition = false;
913*13fbcb42Sjoerg       Init->printPretty(Out, nullptr, SubPolicy, Indentation, "\n", &Context);
91406f32e7eSjoerg       if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
91506f32e7eSjoerg         Out << ")";
91606f32e7eSjoerg     }
91706f32e7eSjoerg   }
91806f32e7eSjoerg   prettyPrintAttributes(D);
91906f32e7eSjoerg }
92006f32e7eSjoerg 
VisitParmVarDecl(ParmVarDecl * D)92106f32e7eSjoerg void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) {
92206f32e7eSjoerg   VisitVarDecl(D);
92306f32e7eSjoerg }
92406f32e7eSjoerg 
VisitFileScopeAsmDecl(FileScopeAsmDecl * D)92506f32e7eSjoerg void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
92606f32e7eSjoerg   Out << "__asm (";
927*13fbcb42Sjoerg   D->getAsmString()->printPretty(Out, nullptr, Policy, Indentation, "\n",
928*13fbcb42Sjoerg                                  &Context);
92906f32e7eSjoerg   Out << ")";
93006f32e7eSjoerg }
93106f32e7eSjoerg 
VisitImportDecl(ImportDecl * D)93206f32e7eSjoerg void DeclPrinter::VisitImportDecl(ImportDecl *D) {
93306f32e7eSjoerg   Out << "@import " << D->getImportedModule()->getFullModuleName()
93406f32e7eSjoerg       << ";\n";
93506f32e7eSjoerg }
93606f32e7eSjoerg 
VisitStaticAssertDecl(StaticAssertDecl * D)93706f32e7eSjoerg void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) {
93806f32e7eSjoerg   Out << "static_assert(";
939*13fbcb42Sjoerg   D->getAssertExpr()->printPretty(Out, nullptr, Policy, Indentation, "\n",
940*13fbcb42Sjoerg                                   &Context);
94106f32e7eSjoerg   if (StringLiteral *SL = D->getMessage()) {
94206f32e7eSjoerg     Out << ", ";
943*13fbcb42Sjoerg     SL->printPretty(Out, nullptr, Policy, Indentation, "\n", &Context);
94406f32e7eSjoerg   }
94506f32e7eSjoerg   Out << ")";
94606f32e7eSjoerg }
94706f32e7eSjoerg 
94806f32e7eSjoerg //----------------------------------------------------------------------------
94906f32e7eSjoerg // C++ declarations
95006f32e7eSjoerg //----------------------------------------------------------------------------
VisitNamespaceDecl(NamespaceDecl * D)95106f32e7eSjoerg void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) {
95206f32e7eSjoerg   if (D->isInline())
95306f32e7eSjoerg     Out << "inline ";
954*13fbcb42Sjoerg 
955*13fbcb42Sjoerg   Out << "namespace ";
956*13fbcb42Sjoerg   if (D->getDeclName())
957*13fbcb42Sjoerg     Out << D->getDeclName() << ' ';
958*13fbcb42Sjoerg   Out << "{\n";
959*13fbcb42Sjoerg 
96006f32e7eSjoerg   VisitDeclContext(D);
96106f32e7eSjoerg   Indent() << "}";
96206f32e7eSjoerg }
96306f32e7eSjoerg 
VisitUsingDirectiveDecl(UsingDirectiveDecl * D)96406f32e7eSjoerg void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
96506f32e7eSjoerg   Out << "using namespace ";
96606f32e7eSjoerg   if (D->getQualifier())
96706f32e7eSjoerg     D->getQualifier()->print(Out, Policy);
96806f32e7eSjoerg   Out << *D->getNominatedNamespaceAsWritten();
96906f32e7eSjoerg }
97006f32e7eSjoerg 
VisitNamespaceAliasDecl(NamespaceAliasDecl * D)97106f32e7eSjoerg void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
97206f32e7eSjoerg   Out << "namespace " << *D << " = ";
97306f32e7eSjoerg   if (D->getQualifier())
97406f32e7eSjoerg     D->getQualifier()->print(Out, Policy);
97506f32e7eSjoerg   Out << *D->getAliasedNamespace();
97606f32e7eSjoerg }
97706f32e7eSjoerg 
VisitEmptyDecl(EmptyDecl * D)97806f32e7eSjoerg void DeclPrinter::VisitEmptyDecl(EmptyDecl *D) {
97906f32e7eSjoerg   prettyPrintAttributes(D);
98006f32e7eSjoerg }
98106f32e7eSjoerg 
VisitCXXRecordDecl(CXXRecordDecl * D)98206f32e7eSjoerg void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
98306f32e7eSjoerg   // FIXME: add printing of pragma attributes if required.
98406f32e7eSjoerg   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
98506f32e7eSjoerg     Out << "__module_private__ ";
98606f32e7eSjoerg   Out << D->getKindName();
98706f32e7eSjoerg 
98806f32e7eSjoerg   prettyPrintAttributes(D);
98906f32e7eSjoerg 
99006f32e7eSjoerg   if (D->getIdentifier()) {
99106f32e7eSjoerg     Out << ' ' << *D;
99206f32e7eSjoerg 
993*13fbcb42Sjoerg     if (auto S = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
994*13fbcb42Sjoerg       ArrayRef<TemplateArgument> Args = S->getTemplateArgs().asArray();
995*13fbcb42Sjoerg       if (!Policy.PrintCanonicalTypes)
996*13fbcb42Sjoerg         if (const auto* TSI = S->getTypeAsWritten())
997*13fbcb42Sjoerg           if (const auto *TST =
998*13fbcb42Sjoerg                   dyn_cast<TemplateSpecializationType>(TSI->getType()))
999*13fbcb42Sjoerg             Args = TST->template_arguments();
1000*13fbcb42Sjoerg       printTemplateArguments(
1001*13fbcb42Sjoerg           Args, S->getSpecializedTemplate()->getTemplateParameters(),
1002*13fbcb42Sjoerg           /*TemplOverloaded*/ false);
1003*13fbcb42Sjoerg     }
100406f32e7eSjoerg   }
100506f32e7eSjoerg 
100606f32e7eSjoerg   if (D->isCompleteDefinition()) {
100706f32e7eSjoerg     // Print the base classes
100806f32e7eSjoerg     if (D->getNumBases()) {
100906f32e7eSjoerg       Out << " : ";
101006f32e7eSjoerg       for (CXXRecordDecl::base_class_iterator Base = D->bases_begin(),
101106f32e7eSjoerg              BaseEnd = D->bases_end(); Base != BaseEnd; ++Base) {
101206f32e7eSjoerg         if (Base != D->bases_begin())
101306f32e7eSjoerg           Out << ", ";
101406f32e7eSjoerg 
101506f32e7eSjoerg         if (Base->isVirtual())
101606f32e7eSjoerg           Out << "virtual ";
101706f32e7eSjoerg 
101806f32e7eSjoerg         AccessSpecifier AS = Base->getAccessSpecifierAsWritten();
101906f32e7eSjoerg         if (AS != AS_none) {
102006f32e7eSjoerg           Print(AS);
102106f32e7eSjoerg           Out << " ";
102206f32e7eSjoerg         }
102306f32e7eSjoerg         Out << Base->getType().getAsString(Policy);
102406f32e7eSjoerg 
102506f32e7eSjoerg         if (Base->isPackExpansion())
102606f32e7eSjoerg           Out << "...";
102706f32e7eSjoerg       }
102806f32e7eSjoerg     }
102906f32e7eSjoerg 
103006f32e7eSjoerg     // Print the class definition
103106f32e7eSjoerg     // FIXME: Doesn't print access specifiers, e.g., "public:"
103206f32e7eSjoerg     if (Policy.TerseOutput) {
103306f32e7eSjoerg       Out << " {}";
103406f32e7eSjoerg     } else {
103506f32e7eSjoerg       Out << " {\n";
103606f32e7eSjoerg       VisitDeclContext(D);
103706f32e7eSjoerg       Indent() << "}";
103806f32e7eSjoerg     }
103906f32e7eSjoerg   }
104006f32e7eSjoerg }
104106f32e7eSjoerg 
VisitLinkageSpecDecl(LinkageSpecDecl * D)104206f32e7eSjoerg void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
104306f32e7eSjoerg   const char *l;
1044*13fbcb42Sjoerg   if (D->getLanguage() == LinkageSpecDecl::lang_c)
104506f32e7eSjoerg     l = "C";
1046*13fbcb42Sjoerg   else {
1047*13fbcb42Sjoerg     assert(D->getLanguage() == LinkageSpecDecl::lang_cxx &&
1048*13fbcb42Sjoerg            "unknown language in linkage specification");
104906f32e7eSjoerg     l = "C++";
105006f32e7eSjoerg   }
105106f32e7eSjoerg 
105206f32e7eSjoerg   Out << "extern \"" << l << "\" ";
105306f32e7eSjoerg   if (D->hasBraces()) {
105406f32e7eSjoerg     Out << "{\n";
105506f32e7eSjoerg     VisitDeclContext(D);
105606f32e7eSjoerg     Indent() << "}";
105706f32e7eSjoerg   } else
105806f32e7eSjoerg     Visit(*D->decls_begin());
105906f32e7eSjoerg }
106006f32e7eSjoerg 
printTemplateParameters(const TemplateParameterList * Params,bool OmitTemplateKW)106106f32e7eSjoerg void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params,
106206f32e7eSjoerg                                           bool OmitTemplateKW) {
106306f32e7eSjoerg   assert(Params);
106406f32e7eSjoerg 
106506f32e7eSjoerg   if (!OmitTemplateKW)
106606f32e7eSjoerg     Out << "template ";
106706f32e7eSjoerg   Out << '<';
106806f32e7eSjoerg 
106906f32e7eSjoerg   bool NeedComma = false;
107006f32e7eSjoerg   for (const Decl *Param : *Params) {
107106f32e7eSjoerg     if (Param->isImplicit())
107206f32e7eSjoerg       continue;
107306f32e7eSjoerg 
107406f32e7eSjoerg     if (NeedComma)
107506f32e7eSjoerg       Out << ", ";
107606f32e7eSjoerg     else
107706f32e7eSjoerg       NeedComma = true;
107806f32e7eSjoerg 
1079*13fbcb42Sjoerg     if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
1080*13fbcb42Sjoerg       VisitTemplateTypeParmDecl(TTP);
108106f32e7eSjoerg     } else if (auto NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
1082*13fbcb42Sjoerg       VisitNonTypeTemplateParmDecl(NTTP);
108306f32e7eSjoerg     } else if (auto TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
108406f32e7eSjoerg       VisitTemplateDecl(TTPD);
108506f32e7eSjoerg       // FIXME: print the default argument, if present.
108606f32e7eSjoerg     }
108706f32e7eSjoerg   }
108806f32e7eSjoerg 
108906f32e7eSjoerg   Out << '>';
109006f32e7eSjoerg   if (!OmitTemplateKW)
109106f32e7eSjoerg     Out << ' ';
109206f32e7eSjoerg }
109306f32e7eSjoerg 
printTemplateArguments(ArrayRef<TemplateArgument> Args,const TemplateParameterList * Params,bool TemplOverloaded)1094*13fbcb42Sjoerg void DeclPrinter::printTemplateArguments(ArrayRef<TemplateArgument> Args,
1095*13fbcb42Sjoerg                                          const TemplateParameterList *Params,
1096*13fbcb42Sjoerg                                          bool TemplOverloaded) {
109706f32e7eSjoerg   Out << "<";
109806f32e7eSjoerg   for (size_t I = 0, E = Args.size(); I < E; ++I) {
109906f32e7eSjoerg     if (I)
110006f32e7eSjoerg       Out << ", ";
1101*13fbcb42Sjoerg     if (TemplOverloaded || !Params)
1102*13fbcb42Sjoerg       Args[I].print(Policy, Out, /*IncludeType*/ true);
1103*13fbcb42Sjoerg     else
1104*13fbcb42Sjoerg       Args[I].print(
1105*13fbcb42Sjoerg           Policy, Out,
1106*13fbcb42Sjoerg           TemplateParameterList::shouldIncludeTypeForArgument(Params, I));
110706f32e7eSjoerg   }
1108*13fbcb42Sjoerg   Out << ">";
110906f32e7eSjoerg }
1110*13fbcb42Sjoerg 
printTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,const TemplateParameterList * Params,bool TemplOverloaded)1111*13fbcb42Sjoerg void DeclPrinter::printTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
1112*13fbcb42Sjoerg                                          const TemplateParameterList *Params,
1113*13fbcb42Sjoerg                                          bool TemplOverloaded) {
1114*13fbcb42Sjoerg   Out << "<";
1115*13fbcb42Sjoerg   for (size_t I = 0, E = Args.size(); I < E; ++I) {
1116*13fbcb42Sjoerg     if (I)
1117*13fbcb42Sjoerg       Out << ", ";
1118*13fbcb42Sjoerg     if (TemplOverloaded)
1119*13fbcb42Sjoerg       Args[I].getArgument().print(Policy, Out, /*IncludeType*/ true);
1120*13fbcb42Sjoerg     else
1121*13fbcb42Sjoerg       Args[I].getArgument().print(
1122*13fbcb42Sjoerg           Policy, Out,
1123*13fbcb42Sjoerg           TemplateParameterList::shouldIncludeTypeForArgument(Params, I));
112406f32e7eSjoerg   }
112506f32e7eSjoerg   Out << ">";
112606f32e7eSjoerg }
112706f32e7eSjoerg 
VisitTemplateDecl(const TemplateDecl * D)112806f32e7eSjoerg void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
112906f32e7eSjoerg   printTemplateParameters(D->getTemplateParameters());
113006f32e7eSjoerg 
113106f32e7eSjoerg   if (const TemplateTemplateParmDecl *TTP =
113206f32e7eSjoerg         dyn_cast<TemplateTemplateParmDecl>(D)) {
113306f32e7eSjoerg     Out << "class";
1134*13fbcb42Sjoerg 
113506f32e7eSjoerg     if (TTP->isParameterPack())
113606f32e7eSjoerg       Out << " ...";
1137*13fbcb42Sjoerg     else if (TTP->getDeclName())
1138*13fbcb42Sjoerg       Out << ' ';
1139*13fbcb42Sjoerg 
1140*13fbcb42Sjoerg     if (TTP->getDeclName())
1141*13fbcb42Sjoerg       Out << TTP->getDeclName();
114206f32e7eSjoerg   } else if (auto *TD = D->getTemplatedDecl())
114306f32e7eSjoerg     Visit(TD);
114406f32e7eSjoerg   else if (const auto *Concept = dyn_cast<ConceptDecl>(D)) {
114506f32e7eSjoerg     Out << "concept " << Concept->getName() << " = " ;
1146*13fbcb42Sjoerg     Concept->getConstraintExpr()->printPretty(Out, nullptr, Policy, Indentation,
1147*13fbcb42Sjoerg                                               "\n", &Context);
114806f32e7eSjoerg     Out << ";";
114906f32e7eSjoerg   }
115006f32e7eSjoerg }
115106f32e7eSjoerg 
VisitFunctionTemplateDecl(FunctionTemplateDecl * D)115206f32e7eSjoerg void DeclPrinter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
115306f32e7eSjoerg   prettyPrintPragmas(D->getTemplatedDecl());
115406f32e7eSjoerg   // Print any leading template parameter lists.
115506f32e7eSjoerg   if (const FunctionDecl *FD = D->getTemplatedDecl()) {
115606f32e7eSjoerg     for (unsigned I = 0, NumTemplateParams = FD->getNumTemplateParameterLists();
115706f32e7eSjoerg          I < NumTemplateParams; ++I)
115806f32e7eSjoerg       printTemplateParameters(FD->getTemplateParameterList(I));
115906f32e7eSjoerg   }
116006f32e7eSjoerg   VisitRedeclarableTemplateDecl(D);
116106f32e7eSjoerg   // Declare target attribute is special one, natural spelling for the pragma
116206f32e7eSjoerg   // assumes "ending" construct so print it here.
116306f32e7eSjoerg   if (D->getTemplatedDecl()->hasAttr<OMPDeclareTargetDeclAttr>())
116406f32e7eSjoerg     Out << "#pragma omp end declare target\n";
116506f32e7eSjoerg 
116606f32e7eSjoerg   // Never print "instantiations" for deduction guides (they don't really
116706f32e7eSjoerg   // have them).
116806f32e7eSjoerg   if (PrintInstantiation &&
116906f32e7eSjoerg       !isa<CXXDeductionGuideDecl>(D->getTemplatedDecl())) {
117006f32e7eSjoerg     FunctionDecl *PrevDecl = D->getTemplatedDecl();
117106f32e7eSjoerg     const FunctionDecl *Def;
117206f32e7eSjoerg     if (PrevDecl->isDefined(Def) && Def != PrevDecl)
117306f32e7eSjoerg       return;
117406f32e7eSjoerg     for (auto *I : D->specializations())
117506f32e7eSjoerg       if (I->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) {
117606f32e7eSjoerg         if (!PrevDecl->isThisDeclarationADefinition())
117706f32e7eSjoerg           Out << ";\n";
117806f32e7eSjoerg         Indent();
117906f32e7eSjoerg         prettyPrintPragmas(I);
118006f32e7eSjoerg         Visit(I);
118106f32e7eSjoerg       }
118206f32e7eSjoerg   }
118306f32e7eSjoerg }
118406f32e7eSjoerg 
VisitClassTemplateDecl(ClassTemplateDecl * D)118506f32e7eSjoerg void DeclPrinter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
118606f32e7eSjoerg   VisitRedeclarableTemplateDecl(D);
118706f32e7eSjoerg 
118806f32e7eSjoerg   if (PrintInstantiation) {
118906f32e7eSjoerg     for (auto *I : D->specializations())
119006f32e7eSjoerg       if (I->getSpecializationKind() == TSK_ImplicitInstantiation) {
119106f32e7eSjoerg         if (D->isThisDeclarationADefinition())
119206f32e7eSjoerg           Out << ";";
119306f32e7eSjoerg         Out << "\n";
119406f32e7eSjoerg         Visit(I);
119506f32e7eSjoerg       }
119606f32e7eSjoerg   }
119706f32e7eSjoerg }
119806f32e7eSjoerg 
VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl * D)119906f32e7eSjoerg void DeclPrinter::VisitClassTemplateSpecializationDecl(
120006f32e7eSjoerg                                            ClassTemplateSpecializationDecl *D) {
120106f32e7eSjoerg   Out << "template<> ";
120206f32e7eSjoerg   VisitCXXRecordDecl(D);
120306f32e7eSjoerg }
120406f32e7eSjoerg 
VisitClassTemplatePartialSpecializationDecl(ClassTemplatePartialSpecializationDecl * D)120506f32e7eSjoerg void DeclPrinter::VisitClassTemplatePartialSpecializationDecl(
120606f32e7eSjoerg                                     ClassTemplatePartialSpecializationDecl *D) {
120706f32e7eSjoerg   printTemplateParameters(D->getTemplateParameters());
120806f32e7eSjoerg   VisitCXXRecordDecl(D);
120906f32e7eSjoerg }
121006f32e7eSjoerg 
121106f32e7eSjoerg //----------------------------------------------------------------------------
121206f32e7eSjoerg // Objective-C declarations
121306f32e7eSjoerg //----------------------------------------------------------------------------
121406f32e7eSjoerg 
PrintObjCMethodType(ASTContext & Ctx,Decl::ObjCDeclQualifier Quals,QualType T)121506f32e7eSjoerg void DeclPrinter::PrintObjCMethodType(ASTContext &Ctx,
121606f32e7eSjoerg                                       Decl::ObjCDeclQualifier Quals,
121706f32e7eSjoerg                                       QualType T) {
121806f32e7eSjoerg   Out << '(';
121906f32e7eSjoerg   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_In)
122006f32e7eSjoerg     Out << "in ";
122106f32e7eSjoerg   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Inout)
122206f32e7eSjoerg     Out << "inout ";
122306f32e7eSjoerg   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Out)
122406f32e7eSjoerg     Out << "out ";
122506f32e7eSjoerg   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Bycopy)
122606f32e7eSjoerg     Out << "bycopy ";
122706f32e7eSjoerg   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Byref)
122806f32e7eSjoerg     Out << "byref ";
122906f32e7eSjoerg   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Oneway)
123006f32e7eSjoerg     Out << "oneway ";
123106f32e7eSjoerg   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_CSNullability) {
123206f32e7eSjoerg     if (auto nullability = AttributedType::stripOuterNullability(T))
123306f32e7eSjoerg       Out << getNullabilitySpelling(*nullability, true) << ' ';
123406f32e7eSjoerg   }
123506f32e7eSjoerg 
123606f32e7eSjoerg   Out << Ctx.getUnqualifiedObjCPointerType(T).getAsString(Policy);
123706f32e7eSjoerg   Out << ')';
123806f32e7eSjoerg }
123906f32e7eSjoerg 
PrintObjCTypeParams(ObjCTypeParamList * Params)124006f32e7eSjoerg void DeclPrinter::PrintObjCTypeParams(ObjCTypeParamList *Params) {
124106f32e7eSjoerg   Out << "<";
124206f32e7eSjoerg   unsigned First = true;
124306f32e7eSjoerg   for (auto *Param : *Params) {
124406f32e7eSjoerg     if (First) {
124506f32e7eSjoerg       First = false;
124606f32e7eSjoerg     } else {
124706f32e7eSjoerg       Out << ", ";
124806f32e7eSjoerg     }
124906f32e7eSjoerg 
125006f32e7eSjoerg     switch (Param->getVariance()) {
125106f32e7eSjoerg     case ObjCTypeParamVariance::Invariant:
125206f32e7eSjoerg       break;
125306f32e7eSjoerg 
125406f32e7eSjoerg     case ObjCTypeParamVariance::Covariant:
125506f32e7eSjoerg       Out << "__covariant ";
125606f32e7eSjoerg       break;
125706f32e7eSjoerg 
125806f32e7eSjoerg     case ObjCTypeParamVariance::Contravariant:
125906f32e7eSjoerg       Out << "__contravariant ";
126006f32e7eSjoerg       break;
126106f32e7eSjoerg     }
126206f32e7eSjoerg 
1263*13fbcb42Sjoerg     Out << Param->getDeclName();
126406f32e7eSjoerg 
126506f32e7eSjoerg     if (Param->hasExplicitBound()) {
126606f32e7eSjoerg       Out << " : " << Param->getUnderlyingType().getAsString(Policy);
126706f32e7eSjoerg     }
126806f32e7eSjoerg   }
126906f32e7eSjoerg   Out << ">";
127006f32e7eSjoerg }
127106f32e7eSjoerg 
VisitObjCMethodDecl(ObjCMethodDecl * OMD)127206f32e7eSjoerg void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
127306f32e7eSjoerg   if (OMD->isInstanceMethod())
127406f32e7eSjoerg     Out << "- ";
127506f32e7eSjoerg   else
127606f32e7eSjoerg     Out << "+ ";
127706f32e7eSjoerg   if (!OMD->getReturnType().isNull()) {
127806f32e7eSjoerg     PrintObjCMethodType(OMD->getASTContext(), OMD->getObjCDeclQualifier(),
127906f32e7eSjoerg                         OMD->getReturnType());
128006f32e7eSjoerg   }
128106f32e7eSjoerg 
128206f32e7eSjoerg   std::string name = OMD->getSelector().getAsString();
128306f32e7eSjoerg   std::string::size_type pos, lastPos = 0;
128406f32e7eSjoerg   for (const auto *PI : OMD->parameters()) {
128506f32e7eSjoerg     // FIXME: selector is missing here!
128606f32e7eSjoerg     pos = name.find_first_of(':', lastPos);
128706f32e7eSjoerg     if (lastPos != 0)
128806f32e7eSjoerg       Out << " ";
128906f32e7eSjoerg     Out << name.substr(lastPos, pos - lastPos) << ':';
129006f32e7eSjoerg     PrintObjCMethodType(OMD->getASTContext(),
129106f32e7eSjoerg                         PI->getObjCDeclQualifier(),
129206f32e7eSjoerg                         PI->getType());
129306f32e7eSjoerg     Out << *PI;
129406f32e7eSjoerg     lastPos = pos + 1;
129506f32e7eSjoerg   }
129606f32e7eSjoerg 
129706f32e7eSjoerg   if (OMD->param_begin() == OMD->param_end())
129806f32e7eSjoerg     Out << name;
129906f32e7eSjoerg 
130006f32e7eSjoerg   if (OMD->isVariadic())
130106f32e7eSjoerg       Out << ", ...";
130206f32e7eSjoerg 
130306f32e7eSjoerg   prettyPrintAttributes(OMD);
130406f32e7eSjoerg 
130506f32e7eSjoerg   if (OMD->getBody() && !Policy.TerseOutput) {
130606f32e7eSjoerg     Out << ' ';
1307*13fbcb42Sjoerg     OMD->getBody()->printPretty(Out, nullptr, Policy, Indentation, "\n",
1308*13fbcb42Sjoerg                                 &Context);
130906f32e7eSjoerg   }
131006f32e7eSjoerg   else if (Policy.PolishForDeclaration)
131106f32e7eSjoerg     Out << ';';
131206f32e7eSjoerg }
131306f32e7eSjoerg 
VisitObjCImplementationDecl(ObjCImplementationDecl * OID)131406f32e7eSjoerg void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
131506f32e7eSjoerg   std::string I = OID->getNameAsString();
131606f32e7eSjoerg   ObjCInterfaceDecl *SID = OID->getSuperClass();
131706f32e7eSjoerg 
131806f32e7eSjoerg   bool eolnOut = false;
131906f32e7eSjoerg   if (SID)
132006f32e7eSjoerg     Out << "@implementation " << I << " : " << *SID;
132106f32e7eSjoerg   else
132206f32e7eSjoerg     Out << "@implementation " << I;
132306f32e7eSjoerg 
132406f32e7eSjoerg   if (OID->ivar_size() > 0) {
132506f32e7eSjoerg     Out << "{\n";
132606f32e7eSjoerg     eolnOut = true;
132706f32e7eSjoerg     Indentation += Policy.Indentation;
132806f32e7eSjoerg     for (const auto *I : OID->ivars()) {
132906f32e7eSjoerg       Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()).
133006f32e7eSjoerg                     getAsString(Policy) << ' ' << *I << ";\n";
133106f32e7eSjoerg     }
133206f32e7eSjoerg     Indentation -= Policy.Indentation;
133306f32e7eSjoerg     Out << "}\n";
133406f32e7eSjoerg   }
133506f32e7eSjoerg   else if (SID || (OID->decls_begin() != OID->decls_end())) {
133606f32e7eSjoerg     Out << "\n";
133706f32e7eSjoerg     eolnOut = true;
133806f32e7eSjoerg   }
133906f32e7eSjoerg   VisitDeclContext(OID, false);
134006f32e7eSjoerg   if (!eolnOut)
134106f32e7eSjoerg     Out << "\n";
134206f32e7eSjoerg   Out << "@end";
134306f32e7eSjoerg }
134406f32e7eSjoerg 
VisitObjCInterfaceDecl(ObjCInterfaceDecl * OID)134506f32e7eSjoerg void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
134606f32e7eSjoerg   std::string I = OID->getNameAsString();
134706f32e7eSjoerg   ObjCInterfaceDecl *SID = OID->getSuperClass();
134806f32e7eSjoerg 
134906f32e7eSjoerg   if (!OID->isThisDeclarationADefinition()) {
135006f32e7eSjoerg     Out << "@class " << I;
135106f32e7eSjoerg 
135206f32e7eSjoerg     if (auto TypeParams = OID->getTypeParamListAsWritten()) {
135306f32e7eSjoerg       PrintObjCTypeParams(TypeParams);
135406f32e7eSjoerg     }
135506f32e7eSjoerg 
135606f32e7eSjoerg     Out << ";";
135706f32e7eSjoerg     return;
135806f32e7eSjoerg   }
135906f32e7eSjoerg   bool eolnOut = false;
136006f32e7eSjoerg   Out << "@interface " << I;
136106f32e7eSjoerg 
136206f32e7eSjoerg   if (auto TypeParams = OID->getTypeParamListAsWritten()) {
136306f32e7eSjoerg     PrintObjCTypeParams(TypeParams);
136406f32e7eSjoerg   }
136506f32e7eSjoerg 
136606f32e7eSjoerg   if (SID)
136706f32e7eSjoerg     Out << " : " << QualType(OID->getSuperClassType(), 0).getAsString(Policy);
136806f32e7eSjoerg 
136906f32e7eSjoerg   // Protocols?
137006f32e7eSjoerg   const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
137106f32e7eSjoerg   if (!Protocols.empty()) {
137206f32e7eSjoerg     for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
137306f32e7eSjoerg          E = Protocols.end(); I != E; ++I)
137406f32e7eSjoerg       Out << (I == Protocols.begin() ? '<' : ',') << **I;
137506f32e7eSjoerg     Out << "> ";
137606f32e7eSjoerg   }
137706f32e7eSjoerg 
137806f32e7eSjoerg   if (OID->ivar_size() > 0) {
137906f32e7eSjoerg     Out << "{\n";
138006f32e7eSjoerg     eolnOut = true;
138106f32e7eSjoerg     Indentation += Policy.Indentation;
138206f32e7eSjoerg     for (const auto *I : OID->ivars()) {
138306f32e7eSjoerg       Indent() << I->getASTContext()
138406f32e7eSjoerg                       .getUnqualifiedObjCPointerType(I->getType())
138506f32e7eSjoerg                       .getAsString(Policy) << ' ' << *I << ";\n";
138606f32e7eSjoerg     }
138706f32e7eSjoerg     Indentation -= Policy.Indentation;
138806f32e7eSjoerg     Out << "}\n";
138906f32e7eSjoerg   }
139006f32e7eSjoerg   else if (SID || (OID->decls_begin() != OID->decls_end())) {
139106f32e7eSjoerg     Out << "\n";
139206f32e7eSjoerg     eolnOut = true;
139306f32e7eSjoerg   }
139406f32e7eSjoerg 
139506f32e7eSjoerg   VisitDeclContext(OID, false);
139606f32e7eSjoerg   if (!eolnOut)
139706f32e7eSjoerg     Out << "\n";
139806f32e7eSjoerg   Out << "@end";
139906f32e7eSjoerg   // FIXME: implement the rest...
140006f32e7eSjoerg }
140106f32e7eSjoerg 
VisitObjCProtocolDecl(ObjCProtocolDecl * PID)140206f32e7eSjoerg void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
140306f32e7eSjoerg   if (!PID->isThisDeclarationADefinition()) {
140406f32e7eSjoerg     Out << "@protocol " << *PID << ";\n";
140506f32e7eSjoerg     return;
140606f32e7eSjoerg   }
140706f32e7eSjoerg   // Protocols?
140806f32e7eSjoerg   const ObjCList<ObjCProtocolDecl> &Protocols = PID->getReferencedProtocols();
140906f32e7eSjoerg   if (!Protocols.empty()) {
141006f32e7eSjoerg     Out << "@protocol " << *PID;
141106f32e7eSjoerg     for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
141206f32e7eSjoerg          E = Protocols.end(); I != E; ++I)
141306f32e7eSjoerg       Out << (I == Protocols.begin() ? '<' : ',') << **I;
141406f32e7eSjoerg     Out << ">\n";
141506f32e7eSjoerg   } else
141606f32e7eSjoerg     Out << "@protocol " << *PID << '\n';
141706f32e7eSjoerg   VisitDeclContext(PID, false);
141806f32e7eSjoerg   Out << "@end";
141906f32e7eSjoerg }
142006f32e7eSjoerg 
VisitObjCCategoryImplDecl(ObjCCategoryImplDecl * PID)142106f32e7eSjoerg void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
1422*13fbcb42Sjoerg   Out << "@implementation ";
1423*13fbcb42Sjoerg   if (const auto *CID = PID->getClassInterface())
1424*13fbcb42Sjoerg     Out << *CID;
1425*13fbcb42Sjoerg   else
1426*13fbcb42Sjoerg     Out << "<<error-type>>";
1427*13fbcb42Sjoerg   Out << '(' << *PID << ")\n";
142806f32e7eSjoerg 
142906f32e7eSjoerg   VisitDeclContext(PID, false);
143006f32e7eSjoerg   Out << "@end";
143106f32e7eSjoerg   // FIXME: implement the rest...
143206f32e7eSjoerg }
143306f32e7eSjoerg 
VisitObjCCategoryDecl(ObjCCategoryDecl * PID)143406f32e7eSjoerg void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
1435*13fbcb42Sjoerg   Out << "@interface ";
1436*13fbcb42Sjoerg   if (const auto *CID = PID->getClassInterface())
1437*13fbcb42Sjoerg     Out << *CID;
1438*13fbcb42Sjoerg   else
1439*13fbcb42Sjoerg     Out << "<<error-type>>";
144006f32e7eSjoerg   if (auto TypeParams = PID->getTypeParamList()) {
144106f32e7eSjoerg     PrintObjCTypeParams(TypeParams);
144206f32e7eSjoerg   }
144306f32e7eSjoerg   Out << "(" << *PID << ")\n";
144406f32e7eSjoerg   if (PID->ivar_size() > 0) {
144506f32e7eSjoerg     Out << "{\n";
144606f32e7eSjoerg     Indentation += Policy.Indentation;
144706f32e7eSjoerg     for (const auto *I : PID->ivars())
144806f32e7eSjoerg       Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()).
144906f32e7eSjoerg                     getAsString(Policy) << ' ' << *I << ";\n";
145006f32e7eSjoerg     Indentation -= Policy.Indentation;
145106f32e7eSjoerg     Out << "}\n";
145206f32e7eSjoerg   }
145306f32e7eSjoerg 
145406f32e7eSjoerg   VisitDeclContext(PID, false);
145506f32e7eSjoerg   Out << "@end";
145606f32e7eSjoerg 
145706f32e7eSjoerg   // FIXME: implement the rest...
145806f32e7eSjoerg }
145906f32e7eSjoerg 
VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl * AID)146006f32e7eSjoerg void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) {
146106f32e7eSjoerg   Out << "@compatibility_alias " << *AID
146206f32e7eSjoerg       << ' ' << *AID->getClassInterface() << ";\n";
146306f32e7eSjoerg }
146406f32e7eSjoerg 
146506f32e7eSjoerg /// PrintObjCPropertyDecl - print a property declaration.
146606f32e7eSjoerg ///
146706f32e7eSjoerg /// Print attributes in the following order:
146806f32e7eSjoerg /// - class
146906f32e7eSjoerg /// - nonatomic | atomic
147006f32e7eSjoerg /// - assign | retain | strong | copy | weak | unsafe_unretained
147106f32e7eSjoerg /// - readwrite | readonly
147206f32e7eSjoerg /// - getter & setter
147306f32e7eSjoerg /// - nullability
VisitObjCPropertyDecl(ObjCPropertyDecl * PDecl)147406f32e7eSjoerg void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
147506f32e7eSjoerg   if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Required)
147606f32e7eSjoerg     Out << "@required\n";
147706f32e7eSjoerg   else if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Optional)
147806f32e7eSjoerg     Out << "@optional\n";
147906f32e7eSjoerg 
148006f32e7eSjoerg   QualType T = PDecl->getType();
148106f32e7eSjoerg 
148206f32e7eSjoerg   Out << "@property";
1483*13fbcb42Sjoerg   if (PDecl->getPropertyAttributes() != ObjCPropertyAttribute::kind_noattr) {
148406f32e7eSjoerg     bool first = true;
148506f32e7eSjoerg     Out << "(";
1486*13fbcb42Sjoerg     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_class) {
148706f32e7eSjoerg       Out << (first ? "" : ", ") << "class";
148806f32e7eSjoerg       first = false;
148906f32e7eSjoerg     }
149006f32e7eSjoerg 
1491*13fbcb42Sjoerg     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_direct) {
1492*13fbcb42Sjoerg       Out << (first ? "" : ", ") << "direct";
1493*13fbcb42Sjoerg       first = false;
1494*13fbcb42Sjoerg     }
1495*13fbcb42Sjoerg 
149606f32e7eSjoerg     if (PDecl->getPropertyAttributes() &
1497*13fbcb42Sjoerg         ObjCPropertyAttribute::kind_nonatomic) {
149806f32e7eSjoerg       Out << (first ? "" : ", ") << "nonatomic";
149906f32e7eSjoerg       first = false;
150006f32e7eSjoerg     }
1501*13fbcb42Sjoerg     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_atomic) {
150206f32e7eSjoerg       Out << (first ? "" : ", ") << "atomic";
150306f32e7eSjoerg       first = false;
150406f32e7eSjoerg     }
150506f32e7eSjoerg 
1506*13fbcb42Sjoerg     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_assign) {
150706f32e7eSjoerg       Out << (first ? "" : ", ") << "assign";
150806f32e7eSjoerg       first = false;
150906f32e7eSjoerg     }
1510*13fbcb42Sjoerg     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_retain) {
151106f32e7eSjoerg       Out << (first ? "" : ", ") << "retain";
151206f32e7eSjoerg       first = false;
151306f32e7eSjoerg     }
151406f32e7eSjoerg 
1515*13fbcb42Sjoerg     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_strong) {
151606f32e7eSjoerg       Out << (first ? "" : ", ") << "strong";
151706f32e7eSjoerg       first = false;
151806f32e7eSjoerg     }
1519*13fbcb42Sjoerg     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_copy) {
152006f32e7eSjoerg       Out << (first ? "" : ", ") << "copy";
152106f32e7eSjoerg       first = false;
152206f32e7eSjoerg     }
1523*13fbcb42Sjoerg     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak) {
152406f32e7eSjoerg       Out << (first ? "" : ", ") << "weak";
152506f32e7eSjoerg       first = false;
152606f32e7eSjoerg     }
1527*13fbcb42Sjoerg     if (PDecl->getPropertyAttributes() &
1528*13fbcb42Sjoerg         ObjCPropertyAttribute::kind_unsafe_unretained) {
152906f32e7eSjoerg       Out << (first ? "" : ", ") << "unsafe_unretained";
153006f32e7eSjoerg       first = false;
153106f32e7eSjoerg     }
153206f32e7eSjoerg 
153306f32e7eSjoerg     if (PDecl->getPropertyAttributes() &
1534*13fbcb42Sjoerg         ObjCPropertyAttribute::kind_readwrite) {
153506f32e7eSjoerg       Out << (first ? "" : ", ") << "readwrite";
153606f32e7eSjoerg       first = false;
153706f32e7eSjoerg     }
1538*13fbcb42Sjoerg     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly) {
153906f32e7eSjoerg       Out << (first ? "" : ", ") << "readonly";
154006f32e7eSjoerg       first = false;
154106f32e7eSjoerg     }
154206f32e7eSjoerg 
1543*13fbcb42Sjoerg     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_getter) {
154406f32e7eSjoerg       Out << (first ? "" : ", ") << "getter = ";
154506f32e7eSjoerg       PDecl->getGetterName().print(Out);
154606f32e7eSjoerg       first = false;
154706f32e7eSjoerg     }
1548*13fbcb42Sjoerg     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_setter) {
154906f32e7eSjoerg       Out << (first ? "" : ", ") << "setter = ";
155006f32e7eSjoerg       PDecl->getSetterName().print(Out);
155106f32e7eSjoerg       first = false;
155206f32e7eSjoerg     }
155306f32e7eSjoerg 
155406f32e7eSjoerg     if (PDecl->getPropertyAttributes() &
1555*13fbcb42Sjoerg         ObjCPropertyAttribute::kind_nullability) {
155606f32e7eSjoerg       if (auto nullability = AttributedType::stripOuterNullability(T)) {
155706f32e7eSjoerg         if (*nullability == NullabilityKind::Unspecified &&
155806f32e7eSjoerg             (PDecl->getPropertyAttributes() &
1559*13fbcb42Sjoerg              ObjCPropertyAttribute::kind_null_resettable)) {
156006f32e7eSjoerg           Out << (first ? "" : ", ") << "null_resettable";
156106f32e7eSjoerg         } else {
156206f32e7eSjoerg           Out << (first ? "" : ", ")
156306f32e7eSjoerg               << getNullabilitySpelling(*nullability, true);
156406f32e7eSjoerg         }
156506f32e7eSjoerg         first = false;
156606f32e7eSjoerg       }
156706f32e7eSjoerg     }
156806f32e7eSjoerg 
156906f32e7eSjoerg     (void) first; // Silence dead store warning due to idiomatic code.
157006f32e7eSjoerg     Out << ")";
157106f32e7eSjoerg   }
157206f32e7eSjoerg   std::string TypeStr = PDecl->getASTContext().getUnqualifiedObjCPointerType(T).
157306f32e7eSjoerg       getAsString(Policy);
157406f32e7eSjoerg   Out << ' ' << TypeStr;
157506f32e7eSjoerg   if (!StringRef(TypeStr).endswith("*"))
157606f32e7eSjoerg     Out << ' ';
157706f32e7eSjoerg   Out << *PDecl;
157806f32e7eSjoerg   if (Policy.PolishForDeclaration)
157906f32e7eSjoerg     Out << ';';
158006f32e7eSjoerg }
158106f32e7eSjoerg 
VisitObjCPropertyImplDecl(ObjCPropertyImplDecl * PID)158206f32e7eSjoerg void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
158306f32e7eSjoerg   if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize)
158406f32e7eSjoerg     Out << "@synthesize ";
158506f32e7eSjoerg   else
158606f32e7eSjoerg     Out << "@dynamic ";
158706f32e7eSjoerg   Out << *PID->getPropertyDecl();
158806f32e7eSjoerg   if (PID->getPropertyIvarDecl())
158906f32e7eSjoerg     Out << '=' << *PID->getPropertyIvarDecl();
159006f32e7eSjoerg }
159106f32e7eSjoerg 
VisitUsingDecl(UsingDecl * D)159206f32e7eSjoerg void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
159306f32e7eSjoerg   if (!D->isAccessDeclaration())
159406f32e7eSjoerg     Out << "using ";
159506f32e7eSjoerg   if (D->hasTypename())
159606f32e7eSjoerg     Out << "typename ";
159706f32e7eSjoerg   D->getQualifier()->print(Out, Policy);
159806f32e7eSjoerg 
159906f32e7eSjoerg   // Use the correct record name when the using declaration is used for
160006f32e7eSjoerg   // inheriting constructors.
160106f32e7eSjoerg   for (const auto *Shadow : D->shadows()) {
160206f32e7eSjoerg     if (const auto *ConstructorShadow =
160306f32e7eSjoerg             dyn_cast<ConstructorUsingShadowDecl>(Shadow)) {
160406f32e7eSjoerg       assert(Shadow->getDeclContext() == ConstructorShadow->getDeclContext());
160506f32e7eSjoerg       Out << *ConstructorShadow->getNominatedBaseClass();
160606f32e7eSjoerg       return;
160706f32e7eSjoerg     }
160806f32e7eSjoerg   }
160906f32e7eSjoerg   Out << *D;
161006f32e7eSjoerg }
161106f32e7eSjoerg 
161206f32e7eSjoerg void
VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl * D)161306f32e7eSjoerg DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
161406f32e7eSjoerg   Out << "using typename ";
161506f32e7eSjoerg   D->getQualifier()->print(Out, Policy);
161606f32e7eSjoerg   Out << D->getDeclName();
161706f32e7eSjoerg }
161806f32e7eSjoerg 
VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl * D)161906f32e7eSjoerg void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
162006f32e7eSjoerg   if (!D->isAccessDeclaration())
162106f32e7eSjoerg     Out << "using ";
162206f32e7eSjoerg   D->getQualifier()->print(Out, Policy);
162306f32e7eSjoerg   Out << D->getDeclName();
162406f32e7eSjoerg }
162506f32e7eSjoerg 
VisitUsingShadowDecl(UsingShadowDecl * D)162606f32e7eSjoerg void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) {
162706f32e7eSjoerg   // ignore
162806f32e7eSjoerg }
162906f32e7eSjoerg 
VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl * D)163006f32e7eSjoerg void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
163106f32e7eSjoerg   Out << "#pragma omp threadprivate";
163206f32e7eSjoerg   if (!D->varlist_empty()) {
163306f32e7eSjoerg     for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
163406f32e7eSjoerg                                                 E = D->varlist_end();
163506f32e7eSjoerg                                                 I != E; ++I) {
163606f32e7eSjoerg       Out << (I == D->varlist_begin() ? '(' : ',');
163706f32e7eSjoerg       NamedDecl *ND = cast<DeclRefExpr>(*I)->getDecl();
163806f32e7eSjoerg       ND->printQualifiedName(Out);
163906f32e7eSjoerg     }
164006f32e7eSjoerg     Out << ")";
164106f32e7eSjoerg   }
164206f32e7eSjoerg }
164306f32e7eSjoerg 
VisitOMPAllocateDecl(OMPAllocateDecl * D)164406f32e7eSjoerg void DeclPrinter::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
164506f32e7eSjoerg   Out << "#pragma omp allocate";
164606f32e7eSjoerg   if (!D->varlist_empty()) {
164706f32e7eSjoerg     for (OMPAllocateDecl::varlist_iterator I = D->varlist_begin(),
164806f32e7eSjoerg                                            E = D->varlist_end();
164906f32e7eSjoerg          I != E; ++I) {
165006f32e7eSjoerg       Out << (I == D->varlist_begin() ? '(' : ',');
165106f32e7eSjoerg       NamedDecl *ND = cast<DeclRefExpr>(*I)->getDecl();
165206f32e7eSjoerg       ND->printQualifiedName(Out);
165306f32e7eSjoerg     }
165406f32e7eSjoerg     Out << ")";
165506f32e7eSjoerg   }
165606f32e7eSjoerg   if (!D->clauselist_empty()) {
165706f32e7eSjoerg     Out << " ";
165806f32e7eSjoerg     OMPClausePrinter Printer(Out, Policy);
165906f32e7eSjoerg     for (OMPClause *C : D->clauselists())
166006f32e7eSjoerg       Printer.Visit(C);
166106f32e7eSjoerg   }
166206f32e7eSjoerg }
166306f32e7eSjoerg 
VisitOMPRequiresDecl(OMPRequiresDecl * D)166406f32e7eSjoerg void DeclPrinter::VisitOMPRequiresDecl(OMPRequiresDecl *D) {
166506f32e7eSjoerg   Out << "#pragma omp requires ";
166606f32e7eSjoerg   if (!D->clauselist_empty()) {
166706f32e7eSjoerg     OMPClausePrinter Printer(Out, Policy);
166806f32e7eSjoerg     for (auto I = D->clauselist_begin(), E = D->clauselist_end(); I != E; ++I)
166906f32e7eSjoerg       Printer.Visit(*I);
167006f32e7eSjoerg   }
167106f32e7eSjoerg }
167206f32e7eSjoerg 
VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl * D)167306f32e7eSjoerg void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
167406f32e7eSjoerg   if (!D->isInvalidDecl()) {
167506f32e7eSjoerg     Out << "#pragma omp declare reduction (";
167606f32e7eSjoerg     if (D->getDeclName().getNameKind() == DeclarationName::CXXOperatorName) {
167706f32e7eSjoerg       const char *OpName =
167806f32e7eSjoerg           getOperatorSpelling(D->getDeclName().getCXXOverloadedOperator());
167906f32e7eSjoerg       assert(OpName && "not an overloaded operator");
168006f32e7eSjoerg       Out << OpName;
168106f32e7eSjoerg     } else {
168206f32e7eSjoerg       assert(D->getDeclName().isIdentifier());
168306f32e7eSjoerg       D->printName(Out);
168406f32e7eSjoerg     }
168506f32e7eSjoerg     Out << " : ";
168606f32e7eSjoerg     D->getType().print(Out, Policy);
168706f32e7eSjoerg     Out << " : ";
1688*13fbcb42Sjoerg     D->getCombiner()->printPretty(Out, nullptr, Policy, 0, "\n", &Context);
168906f32e7eSjoerg     Out << ")";
169006f32e7eSjoerg     if (auto *Init = D->getInitializer()) {
169106f32e7eSjoerg       Out << " initializer(";
169206f32e7eSjoerg       switch (D->getInitializerKind()) {
169306f32e7eSjoerg       case OMPDeclareReductionDecl::DirectInit:
169406f32e7eSjoerg         Out << "omp_priv(";
169506f32e7eSjoerg         break;
169606f32e7eSjoerg       case OMPDeclareReductionDecl::CopyInit:
169706f32e7eSjoerg         Out << "omp_priv = ";
169806f32e7eSjoerg         break;
169906f32e7eSjoerg       case OMPDeclareReductionDecl::CallInit:
170006f32e7eSjoerg         break;
170106f32e7eSjoerg       }
1702*13fbcb42Sjoerg       Init->printPretty(Out, nullptr, Policy, 0, "\n", &Context);
170306f32e7eSjoerg       if (D->getInitializerKind() == OMPDeclareReductionDecl::DirectInit)
170406f32e7eSjoerg         Out << ")";
170506f32e7eSjoerg       Out << ")";
170606f32e7eSjoerg     }
170706f32e7eSjoerg   }
170806f32e7eSjoerg }
170906f32e7eSjoerg 
VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl * D)171006f32e7eSjoerg void DeclPrinter::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
171106f32e7eSjoerg   if (!D->isInvalidDecl()) {
171206f32e7eSjoerg     Out << "#pragma omp declare mapper (";
171306f32e7eSjoerg     D->printName(Out);
171406f32e7eSjoerg     Out << " : ";
171506f32e7eSjoerg     D->getType().print(Out, Policy);
171606f32e7eSjoerg     Out << " ";
171706f32e7eSjoerg     Out << D->getVarName();
171806f32e7eSjoerg     Out << ")";
171906f32e7eSjoerg     if (!D->clauselist_empty()) {
172006f32e7eSjoerg       OMPClausePrinter Printer(Out, Policy);
172106f32e7eSjoerg       for (auto *C : D->clauselists()) {
172206f32e7eSjoerg         Out << " ";
172306f32e7eSjoerg         Printer.Visit(C);
172406f32e7eSjoerg       }
172506f32e7eSjoerg     }
172606f32e7eSjoerg   }
172706f32e7eSjoerg }
172806f32e7eSjoerg 
VisitOMPCapturedExprDecl(OMPCapturedExprDecl * D)172906f32e7eSjoerg void DeclPrinter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
1730*13fbcb42Sjoerg   D->getInit()->printPretty(Out, nullptr, Policy, Indentation, "\n", &Context);
173106f32e7eSjoerg }
173206f32e7eSjoerg 
VisitTemplateTypeParmDecl(const TemplateTypeParmDecl * TTP)1733*13fbcb42Sjoerg void DeclPrinter::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *TTP) {
1734*13fbcb42Sjoerg   if (const TypeConstraint *TC = TTP->getTypeConstraint())
1735*13fbcb42Sjoerg     TC->print(Out, Policy);
1736*13fbcb42Sjoerg   else if (TTP->wasDeclaredWithTypename())
1737*13fbcb42Sjoerg     Out << "typename";
1738*13fbcb42Sjoerg   else
1739*13fbcb42Sjoerg     Out << "class";
1740*13fbcb42Sjoerg 
1741*13fbcb42Sjoerg   if (TTP->isParameterPack())
1742*13fbcb42Sjoerg     Out << " ...";
1743*13fbcb42Sjoerg   else if (TTP->getDeclName())
1744*13fbcb42Sjoerg     Out << ' ';
1745*13fbcb42Sjoerg 
1746*13fbcb42Sjoerg   if (TTP->getDeclName())
1747*13fbcb42Sjoerg     Out << TTP->getDeclName();
1748*13fbcb42Sjoerg 
1749*13fbcb42Sjoerg   if (TTP->hasDefaultArgument()) {
1750*13fbcb42Sjoerg     Out << " = ";
1751*13fbcb42Sjoerg     Out << TTP->getDefaultArgument().getAsString(Policy);
1752*13fbcb42Sjoerg   }
1753*13fbcb42Sjoerg }
1754*13fbcb42Sjoerg 
VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl * NTTP)1755*13fbcb42Sjoerg void DeclPrinter::VisitNonTypeTemplateParmDecl(
1756*13fbcb42Sjoerg     const NonTypeTemplateParmDecl *NTTP) {
1757*13fbcb42Sjoerg   StringRef Name;
1758*13fbcb42Sjoerg   if (IdentifierInfo *II = NTTP->getIdentifier())
1759*13fbcb42Sjoerg     Name = II->getName();
1760*13fbcb42Sjoerg   printDeclType(NTTP->getType(), Name, NTTP->isParameterPack());
1761*13fbcb42Sjoerg 
1762*13fbcb42Sjoerg   if (NTTP->hasDefaultArgument()) {
1763*13fbcb42Sjoerg     Out << " = ";
1764*13fbcb42Sjoerg     NTTP->getDefaultArgument()->printPretty(Out, nullptr, Policy, Indentation,
1765*13fbcb42Sjoerg                                             "\n", &Context);
1766*13fbcb42Sjoerg   }
1767*13fbcb42Sjoerg }
1768