xref: /openbsd-src/gnu/llvm/clang/lib/AST/DeclPrinter.cpp (revision a9ac8606c53d55cee9c3a39778b249c51df111ef)
1e5dd7070Spatrick //===--- DeclPrinter.cpp - Printing implementation for Decl ASTs ----------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file implements the Decl::print method, which pretty prints the
10e5dd7070Spatrick // AST back out to C/Objective-C/C++/Objective-C++ code.
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick #include "clang/AST/ASTContext.h"
14e5dd7070Spatrick #include "clang/AST/Attr.h"
15e5dd7070Spatrick #include "clang/AST/Decl.h"
16e5dd7070Spatrick #include "clang/AST/DeclCXX.h"
17e5dd7070Spatrick #include "clang/AST/DeclObjC.h"
18e5dd7070Spatrick #include "clang/AST/DeclTemplate.h"
19e5dd7070Spatrick #include "clang/AST/DeclVisitor.h"
20e5dd7070Spatrick #include "clang/AST/Expr.h"
21e5dd7070Spatrick #include "clang/AST/ExprCXX.h"
22e5dd7070Spatrick #include "clang/AST/PrettyPrinter.h"
23e5dd7070Spatrick #include "clang/Basic/Module.h"
24e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
25e5dd7070Spatrick using namespace clang;
26e5dd7070Spatrick 
27e5dd7070Spatrick namespace {
28e5dd7070Spatrick   class DeclPrinter : public DeclVisitor<DeclPrinter> {
29e5dd7070Spatrick     raw_ostream &Out;
30e5dd7070Spatrick     PrintingPolicy Policy;
31e5dd7070Spatrick     const ASTContext &Context;
32e5dd7070Spatrick     unsigned Indentation;
33e5dd7070Spatrick     bool PrintInstantiation;
34e5dd7070Spatrick 
35e5dd7070Spatrick     raw_ostream& Indent() { return Indent(Indentation); }
36e5dd7070Spatrick     raw_ostream& Indent(unsigned Indentation);
37e5dd7070Spatrick     void ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls);
38e5dd7070Spatrick 
39e5dd7070Spatrick     void Print(AccessSpecifier AS);
40e5dd7070Spatrick     void PrintConstructorInitializers(CXXConstructorDecl *CDecl,
41e5dd7070Spatrick                                       std::string &Proto);
42e5dd7070Spatrick 
43e5dd7070Spatrick     /// Print an Objective-C method type in parentheses.
44e5dd7070Spatrick     ///
45e5dd7070Spatrick     /// \param Quals The Objective-C declaration qualifiers.
46e5dd7070Spatrick     /// \param T The type to print.
47e5dd7070Spatrick     void PrintObjCMethodType(ASTContext &Ctx, Decl::ObjCDeclQualifier Quals,
48e5dd7070Spatrick                              QualType T);
49e5dd7070Spatrick 
50e5dd7070Spatrick     void PrintObjCTypeParams(ObjCTypeParamList *Params);
51e5dd7070Spatrick 
52e5dd7070Spatrick   public:
53e5dd7070Spatrick     DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
54e5dd7070Spatrick                 const ASTContext &Context, unsigned Indentation = 0,
55e5dd7070Spatrick                 bool PrintInstantiation = false)
56e5dd7070Spatrick         : Out(Out), Policy(Policy), Context(Context), Indentation(Indentation),
57e5dd7070Spatrick           PrintInstantiation(PrintInstantiation) {}
58e5dd7070Spatrick 
59e5dd7070Spatrick     void VisitDeclContext(DeclContext *DC, bool Indent = true);
60e5dd7070Spatrick 
61e5dd7070Spatrick     void VisitTranslationUnitDecl(TranslationUnitDecl *D);
62e5dd7070Spatrick     void VisitTypedefDecl(TypedefDecl *D);
63e5dd7070Spatrick     void VisitTypeAliasDecl(TypeAliasDecl *D);
64e5dd7070Spatrick     void VisitEnumDecl(EnumDecl *D);
65e5dd7070Spatrick     void VisitRecordDecl(RecordDecl *D);
66e5dd7070Spatrick     void VisitEnumConstantDecl(EnumConstantDecl *D);
67e5dd7070Spatrick     void VisitEmptyDecl(EmptyDecl *D);
68e5dd7070Spatrick     void VisitFunctionDecl(FunctionDecl *D);
69e5dd7070Spatrick     void VisitFriendDecl(FriendDecl *D);
70e5dd7070Spatrick     void VisitFieldDecl(FieldDecl *D);
71e5dd7070Spatrick     void VisitVarDecl(VarDecl *D);
72e5dd7070Spatrick     void VisitLabelDecl(LabelDecl *D);
73e5dd7070Spatrick     void VisitParmVarDecl(ParmVarDecl *D);
74e5dd7070Spatrick     void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
75e5dd7070Spatrick     void VisitImportDecl(ImportDecl *D);
76e5dd7070Spatrick     void VisitStaticAssertDecl(StaticAssertDecl *D);
77e5dd7070Spatrick     void VisitNamespaceDecl(NamespaceDecl *D);
78e5dd7070Spatrick     void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
79e5dd7070Spatrick     void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
80e5dd7070Spatrick     void VisitCXXRecordDecl(CXXRecordDecl *D);
81e5dd7070Spatrick     void VisitLinkageSpecDecl(LinkageSpecDecl *D);
82e5dd7070Spatrick     void VisitTemplateDecl(const TemplateDecl *D);
83e5dd7070Spatrick     void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
84e5dd7070Spatrick     void VisitClassTemplateDecl(ClassTemplateDecl *D);
85e5dd7070Spatrick     void VisitClassTemplateSpecializationDecl(
86e5dd7070Spatrick                                             ClassTemplateSpecializationDecl *D);
87e5dd7070Spatrick     void VisitClassTemplatePartialSpecializationDecl(
88e5dd7070Spatrick                                      ClassTemplatePartialSpecializationDecl *D);
89e5dd7070Spatrick     void VisitObjCMethodDecl(ObjCMethodDecl *D);
90e5dd7070Spatrick     void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
91e5dd7070Spatrick     void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
92e5dd7070Spatrick     void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
93e5dd7070Spatrick     void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
94e5dd7070Spatrick     void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
95e5dd7070Spatrick     void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
96e5dd7070Spatrick     void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
97e5dd7070Spatrick     void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
98e5dd7070Spatrick     void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
99e5dd7070Spatrick     void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
100e5dd7070Spatrick     void VisitUsingDecl(UsingDecl *D);
101*a9ac8606Spatrick     void VisitUsingEnumDecl(UsingEnumDecl *D);
102e5dd7070Spatrick     void VisitUsingShadowDecl(UsingShadowDecl *D);
103e5dd7070Spatrick     void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
104e5dd7070Spatrick     void VisitOMPAllocateDecl(OMPAllocateDecl *D);
105e5dd7070Spatrick     void VisitOMPRequiresDecl(OMPRequiresDecl *D);
106e5dd7070Spatrick     void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
107e5dd7070Spatrick     void VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D);
108e5dd7070Spatrick     void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
109ec727ea7Spatrick     void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *TTP);
110ec727ea7Spatrick     void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *NTTP);
111e5dd7070Spatrick 
112e5dd7070Spatrick     void printTemplateParameters(const TemplateParameterList *Params,
113e5dd7070Spatrick                                  bool OmitTemplateKW = false);
114*a9ac8606Spatrick     void printTemplateArguments(llvm::ArrayRef<TemplateArgument> Args,
115*a9ac8606Spatrick                                 const TemplateParameterList *Params,
116*a9ac8606Spatrick                                 bool TemplOverloaded);
117*a9ac8606Spatrick     void printTemplateArguments(llvm::ArrayRef<TemplateArgumentLoc> Args,
118*a9ac8606Spatrick                                 const TemplateParameterList *Params,
119*a9ac8606Spatrick                                 bool TemplOverloaded);
120e5dd7070Spatrick     void prettyPrintAttributes(Decl *D);
121e5dd7070Spatrick     void prettyPrintPragmas(Decl *D);
122e5dd7070Spatrick     void printDeclType(QualType T, StringRef DeclName, bool Pack = false);
123e5dd7070Spatrick   };
124e5dd7070Spatrick }
125e5dd7070Spatrick 
126e5dd7070Spatrick void Decl::print(raw_ostream &Out, unsigned Indentation,
127e5dd7070Spatrick                  bool PrintInstantiation) const {
128e5dd7070Spatrick   print(Out, getASTContext().getPrintingPolicy(), Indentation, PrintInstantiation);
129e5dd7070Spatrick }
130e5dd7070Spatrick 
131e5dd7070Spatrick void Decl::print(raw_ostream &Out, const PrintingPolicy &Policy,
132e5dd7070Spatrick                  unsigned Indentation, bool PrintInstantiation) const {
133e5dd7070Spatrick   DeclPrinter Printer(Out, Policy, getASTContext(), Indentation,
134e5dd7070Spatrick                       PrintInstantiation);
135e5dd7070Spatrick   Printer.Visit(const_cast<Decl*>(this));
136e5dd7070Spatrick }
137e5dd7070Spatrick 
138e5dd7070Spatrick void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context,
139e5dd7070Spatrick                                   bool OmitTemplateKW) const {
140e5dd7070Spatrick   print(Out, Context, Context.getPrintingPolicy(), OmitTemplateKW);
141e5dd7070Spatrick }
142e5dd7070Spatrick 
143e5dd7070Spatrick void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context,
144e5dd7070Spatrick                                   const PrintingPolicy &Policy,
145e5dd7070Spatrick                                   bool OmitTemplateKW) const {
146e5dd7070Spatrick   DeclPrinter Printer(Out, Policy, Context);
147e5dd7070Spatrick   Printer.printTemplateParameters(this, OmitTemplateKW);
148e5dd7070Spatrick }
149e5dd7070Spatrick 
150e5dd7070Spatrick static QualType GetBaseType(QualType T) {
151e5dd7070Spatrick   // FIXME: This should be on the Type class!
152e5dd7070Spatrick   QualType BaseType = T;
153e5dd7070Spatrick   while (!BaseType->isSpecifierType()) {
154e5dd7070Spatrick     if (const PointerType *PTy = BaseType->getAs<PointerType>())
155e5dd7070Spatrick       BaseType = PTy->getPointeeType();
156e5dd7070Spatrick     else if (const BlockPointerType *BPy = BaseType->getAs<BlockPointerType>())
157e5dd7070Spatrick       BaseType = BPy->getPointeeType();
158e5dd7070Spatrick     else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType))
159e5dd7070Spatrick       BaseType = ATy->getElementType();
160e5dd7070Spatrick     else if (const FunctionType* FTy = BaseType->getAs<FunctionType>())
161e5dd7070Spatrick       BaseType = FTy->getReturnType();
162e5dd7070Spatrick     else if (const VectorType *VTy = BaseType->getAs<VectorType>())
163e5dd7070Spatrick       BaseType = VTy->getElementType();
164e5dd7070Spatrick     else if (const ReferenceType *RTy = BaseType->getAs<ReferenceType>())
165e5dd7070Spatrick       BaseType = RTy->getPointeeType();
166e5dd7070Spatrick     else if (const AutoType *ATy = BaseType->getAs<AutoType>())
167e5dd7070Spatrick       BaseType = ATy->getDeducedType();
168e5dd7070Spatrick     else if (const ParenType *PTy = BaseType->getAs<ParenType>())
169e5dd7070Spatrick       BaseType = PTy->desugar();
170e5dd7070Spatrick     else
171e5dd7070Spatrick       // This must be a syntax error.
172e5dd7070Spatrick       break;
173e5dd7070Spatrick   }
174e5dd7070Spatrick   return BaseType;
175e5dd7070Spatrick }
176e5dd7070Spatrick 
177e5dd7070Spatrick static QualType getDeclType(Decl* D) {
178e5dd7070Spatrick   if (TypedefNameDecl* TDD = dyn_cast<TypedefNameDecl>(D))
179e5dd7070Spatrick     return TDD->getUnderlyingType();
180e5dd7070Spatrick   if (ValueDecl* VD = dyn_cast<ValueDecl>(D))
181e5dd7070Spatrick     return VD->getType();
182e5dd7070Spatrick   return QualType();
183e5dd7070Spatrick }
184e5dd7070Spatrick 
185e5dd7070Spatrick void Decl::printGroup(Decl** Begin, unsigned NumDecls,
186e5dd7070Spatrick                       raw_ostream &Out, const PrintingPolicy &Policy,
187e5dd7070Spatrick                       unsigned Indentation) {
188e5dd7070Spatrick   if (NumDecls == 1) {
189e5dd7070Spatrick     (*Begin)->print(Out, Policy, Indentation);
190e5dd7070Spatrick     return;
191e5dd7070Spatrick   }
192e5dd7070Spatrick 
193e5dd7070Spatrick   Decl** End = Begin + NumDecls;
194e5dd7070Spatrick   TagDecl* TD = dyn_cast<TagDecl>(*Begin);
195e5dd7070Spatrick   if (TD)
196e5dd7070Spatrick     ++Begin;
197e5dd7070Spatrick 
198e5dd7070Spatrick   PrintingPolicy SubPolicy(Policy);
199e5dd7070Spatrick 
200e5dd7070Spatrick   bool isFirst = true;
201e5dd7070Spatrick   for ( ; Begin != End; ++Begin) {
202e5dd7070Spatrick     if (isFirst) {
203e5dd7070Spatrick       if(TD)
204e5dd7070Spatrick         SubPolicy.IncludeTagDefinition = true;
205e5dd7070Spatrick       SubPolicy.SuppressSpecifiers = false;
206e5dd7070Spatrick       isFirst = false;
207e5dd7070Spatrick     } else {
208e5dd7070Spatrick       if (!isFirst) Out << ", ";
209e5dd7070Spatrick       SubPolicy.IncludeTagDefinition = false;
210e5dd7070Spatrick       SubPolicy.SuppressSpecifiers = true;
211e5dd7070Spatrick     }
212e5dd7070Spatrick 
213e5dd7070Spatrick     (*Begin)->print(Out, SubPolicy, Indentation);
214e5dd7070Spatrick   }
215e5dd7070Spatrick }
216e5dd7070Spatrick 
217e5dd7070Spatrick LLVM_DUMP_METHOD void DeclContext::dumpDeclContext() const {
218e5dd7070Spatrick   // Get the translation unit
219e5dd7070Spatrick   const DeclContext *DC = this;
220e5dd7070Spatrick   while (!DC->isTranslationUnit())
221e5dd7070Spatrick     DC = DC->getParent();
222e5dd7070Spatrick 
223e5dd7070Spatrick   ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
224e5dd7070Spatrick   DeclPrinter Printer(llvm::errs(), Ctx.getPrintingPolicy(), Ctx, 0);
225e5dd7070Spatrick   Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false);
226e5dd7070Spatrick }
227e5dd7070Spatrick 
228e5dd7070Spatrick raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
229e5dd7070Spatrick   for (unsigned i = 0; i != Indentation; ++i)
230e5dd7070Spatrick     Out << "  ";
231e5dd7070Spatrick   return Out;
232e5dd7070Spatrick }
233e5dd7070Spatrick 
234e5dd7070Spatrick void DeclPrinter::prettyPrintAttributes(Decl *D) {
235e5dd7070Spatrick   if (Policy.PolishForDeclaration)
236e5dd7070Spatrick     return;
237e5dd7070Spatrick 
238e5dd7070Spatrick   if (D->hasAttrs()) {
239e5dd7070Spatrick     AttrVec &Attrs = D->getAttrs();
240e5dd7070Spatrick     for (auto *A : Attrs) {
241e5dd7070Spatrick       if (A->isInherited() || A->isImplicit())
242e5dd7070Spatrick         continue;
243e5dd7070Spatrick       switch (A->getKind()) {
244e5dd7070Spatrick #define ATTR(X)
245e5dd7070Spatrick #define PRAGMA_SPELLING_ATTR(X) case attr::X:
246e5dd7070Spatrick #include "clang/Basic/AttrList.inc"
247e5dd7070Spatrick         break;
248e5dd7070Spatrick       default:
249e5dd7070Spatrick         A->printPretty(Out, Policy);
250e5dd7070Spatrick         break;
251e5dd7070Spatrick       }
252e5dd7070Spatrick     }
253e5dd7070Spatrick   }
254e5dd7070Spatrick }
255e5dd7070Spatrick 
256e5dd7070Spatrick void DeclPrinter::prettyPrintPragmas(Decl *D) {
257e5dd7070Spatrick   if (Policy.PolishForDeclaration)
258e5dd7070Spatrick     return;
259e5dd7070Spatrick 
260e5dd7070Spatrick   if (D->hasAttrs()) {
261e5dd7070Spatrick     AttrVec &Attrs = D->getAttrs();
262e5dd7070Spatrick     for (auto *A : Attrs) {
263e5dd7070Spatrick       switch (A->getKind()) {
264e5dd7070Spatrick #define ATTR(X)
265e5dd7070Spatrick #define PRAGMA_SPELLING_ATTR(X) case attr::X:
266e5dd7070Spatrick #include "clang/Basic/AttrList.inc"
267e5dd7070Spatrick         A->printPretty(Out, Policy);
268e5dd7070Spatrick         Indent();
269e5dd7070Spatrick         break;
270e5dd7070Spatrick       default:
271e5dd7070Spatrick         break;
272e5dd7070Spatrick       }
273e5dd7070Spatrick     }
274e5dd7070Spatrick   }
275e5dd7070Spatrick }
276e5dd7070Spatrick 
277e5dd7070Spatrick void DeclPrinter::printDeclType(QualType T, StringRef DeclName, bool Pack) {
278e5dd7070Spatrick   // Normally, a PackExpansionType is written as T[3]... (for instance, as a
279e5dd7070Spatrick   // template argument), but if it is the type of a declaration, the ellipsis
280e5dd7070Spatrick   // is placed before the name being declared.
281e5dd7070Spatrick   if (auto *PET = T->getAs<PackExpansionType>()) {
282e5dd7070Spatrick     Pack = true;
283e5dd7070Spatrick     T = PET->getPattern();
284e5dd7070Spatrick   }
285e5dd7070Spatrick   T.print(Out, Policy, (Pack ? "..." : "") + DeclName, Indentation);
286e5dd7070Spatrick }
287e5dd7070Spatrick 
288e5dd7070Spatrick void DeclPrinter::ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls) {
289e5dd7070Spatrick   this->Indent();
290e5dd7070Spatrick   Decl::printGroup(Decls.data(), Decls.size(), Out, Policy, Indentation);
291e5dd7070Spatrick   Out << ";\n";
292e5dd7070Spatrick   Decls.clear();
293e5dd7070Spatrick 
294e5dd7070Spatrick }
295e5dd7070Spatrick 
296e5dd7070Spatrick void DeclPrinter::Print(AccessSpecifier AS) {
297ec727ea7Spatrick   const auto AccessSpelling = getAccessSpelling(AS);
298ec727ea7Spatrick   if (AccessSpelling.empty())
299ec727ea7Spatrick     llvm_unreachable("No access specifier!");
300ec727ea7Spatrick   Out << AccessSpelling;
301e5dd7070Spatrick }
302e5dd7070Spatrick 
303e5dd7070Spatrick void DeclPrinter::PrintConstructorInitializers(CXXConstructorDecl *CDecl,
304e5dd7070Spatrick                                                std::string &Proto) {
305e5dd7070Spatrick   bool HasInitializerList = false;
306e5dd7070Spatrick   for (const auto *BMInitializer : CDecl->inits()) {
307e5dd7070Spatrick     if (BMInitializer->isInClassMemberInitializer())
308e5dd7070Spatrick       continue;
309e5dd7070Spatrick 
310e5dd7070Spatrick     if (!HasInitializerList) {
311e5dd7070Spatrick       Proto += " : ";
312e5dd7070Spatrick       Out << Proto;
313e5dd7070Spatrick       Proto.clear();
314e5dd7070Spatrick       HasInitializerList = true;
315e5dd7070Spatrick     } else
316e5dd7070Spatrick       Out << ", ";
317e5dd7070Spatrick 
318e5dd7070Spatrick     if (BMInitializer->isAnyMemberInitializer()) {
319e5dd7070Spatrick       FieldDecl *FD = BMInitializer->getAnyMember();
320e5dd7070Spatrick       Out << *FD;
321e5dd7070Spatrick     } else {
322e5dd7070Spatrick       Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(Policy);
323e5dd7070Spatrick     }
324e5dd7070Spatrick 
325e5dd7070Spatrick     Out << "(";
326e5dd7070Spatrick     if (!BMInitializer->getInit()) {
327e5dd7070Spatrick       // Nothing to print
328e5dd7070Spatrick     } else {
329e5dd7070Spatrick       Expr *Init = BMInitializer->getInit();
330e5dd7070Spatrick       if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init))
331e5dd7070Spatrick         Init = Tmp->getSubExpr();
332e5dd7070Spatrick 
333e5dd7070Spatrick       Init = Init->IgnoreParens();
334e5dd7070Spatrick 
335e5dd7070Spatrick       Expr *SimpleInit = nullptr;
336e5dd7070Spatrick       Expr **Args = nullptr;
337e5dd7070Spatrick       unsigned NumArgs = 0;
338e5dd7070Spatrick       if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
339e5dd7070Spatrick         Args = ParenList->getExprs();
340e5dd7070Spatrick         NumArgs = ParenList->getNumExprs();
341e5dd7070Spatrick       } else if (CXXConstructExpr *Construct =
342e5dd7070Spatrick                      dyn_cast<CXXConstructExpr>(Init)) {
343e5dd7070Spatrick         Args = Construct->getArgs();
344e5dd7070Spatrick         NumArgs = Construct->getNumArgs();
345e5dd7070Spatrick       } else
346e5dd7070Spatrick         SimpleInit = Init;
347e5dd7070Spatrick 
348e5dd7070Spatrick       if (SimpleInit)
349*a9ac8606Spatrick         SimpleInit->printPretty(Out, nullptr, Policy, Indentation, "\n",
350*a9ac8606Spatrick                                 &Context);
351e5dd7070Spatrick       else {
352e5dd7070Spatrick         for (unsigned I = 0; I != NumArgs; ++I) {
353e5dd7070Spatrick           assert(Args[I] != nullptr && "Expected non-null Expr");
354e5dd7070Spatrick           if (isa<CXXDefaultArgExpr>(Args[I]))
355e5dd7070Spatrick             break;
356e5dd7070Spatrick 
357e5dd7070Spatrick           if (I)
358e5dd7070Spatrick             Out << ", ";
359*a9ac8606Spatrick           Args[I]->printPretty(Out, nullptr, Policy, Indentation, "\n",
360*a9ac8606Spatrick                                &Context);
361e5dd7070Spatrick         }
362e5dd7070Spatrick       }
363e5dd7070Spatrick     }
364e5dd7070Spatrick     Out << ")";
365e5dd7070Spatrick     if (BMInitializer->isPackExpansion())
366e5dd7070Spatrick       Out << "...";
367e5dd7070Spatrick   }
368e5dd7070Spatrick }
369e5dd7070Spatrick 
370e5dd7070Spatrick //----------------------------------------------------------------------------
371e5dd7070Spatrick // Common C declarations
372e5dd7070Spatrick //----------------------------------------------------------------------------
373e5dd7070Spatrick 
374e5dd7070Spatrick void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
375e5dd7070Spatrick   if (Policy.TerseOutput)
376e5dd7070Spatrick     return;
377e5dd7070Spatrick 
378e5dd7070Spatrick   if (Indent)
379e5dd7070Spatrick     Indentation += Policy.Indentation;
380e5dd7070Spatrick 
381e5dd7070Spatrick   SmallVector<Decl*, 2> Decls;
382e5dd7070Spatrick   for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end();
383e5dd7070Spatrick        D != DEnd; ++D) {
384e5dd7070Spatrick 
385e5dd7070Spatrick     // Don't print ObjCIvarDecls, as they are printed when visiting the
386e5dd7070Spatrick     // containing ObjCInterfaceDecl.
387e5dd7070Spatrick     if (isa<ObjCIvarDecl>(*D))
388e5dd7070Spatrick       continue;
389e5dd7070Spatrick 
390e5dd7070Spatrick     // Skip over implicit declarations in pretty-printing mode.
391e5dd7070Spatrick     if (D->isImplicit())
392e5dd7070Spatrick       continue;
393e5dd7070Spatrick 
394e5dd7070Spatrick     // Don't print implicit specializations, as they are printed when visiting
395e5dd7070Spatrick     // corresponding templates.
396e5dd7070Spatrick     if (auto FD = dyn_cast<FunctionDecl>(*D))
397e5dd7070Spatrick       if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation &&
398e5dd7070Spatrick           !isa<ClassTemplateSpecializationDecl>(DC))
399e5dd7070Spatrick         continue;
400e5dd7070Spatrick 
401e5dd7070Spatrick     // The next bits of code handle stuff like "struct {int x;} a,b"; we're
402e5dd7070Spatrick     // forced to merge the declarations because there's no other way to
403e5dd7070Spatrick     // refer to the struct in question.  When that struct is named instead, we
404e5dd7070Spatrick     // also need to merge to avoid splitting off a stand-alone struct
405e5dd7070Spatrick     // declaration that produces the warning ext_no_declarators in some
406e5dd7070Spatrick     // contexts.
407e5dd7070Spatrick     //
408e5dd7070Spatrick     // This limited merging is safe without a bunch of other checks because it
409e5dd7070Spatrick     // only merges declarations directly referring to the tag, not typedefs.
410e5dd7070Spatrick     //
411e5dd7070Spatrick     // Check whether the current declaration should be grouped with a previous
412e5dd7070Spatrick     // non-free-standing tag declaration.
413e5dd7070Spatrick     QualType CurDeclType = getDeclType(*D);
414e5dd7070Spatrick     if (!Decls.empty() && !CurDeclType.isNull()) {
415e5dd7070Spatrick       QualType BaseType = GetBaseType(CurDeclType);
416e5dd7070Spatrick       if (!BaseType.isNull() && isa<ElaboratedType>(BaseType) &&
417e5dd7070Spatrick           cast<ElaboratedType>(BaseType)->getOwnedTagDecl() == Decls[0]) {
418e5dd7070Spatrick         Decls.push_back(*D);
419e5dd7070Spatrick         continue;
420e5dd7070Spatrick       }
421e5dd7070Spatrick     }
422e5dd7070Spatrick 
423e5dd7070Spatrick     // If we have a merged group waiting to be handled, handle it now.
424e5dd7070Spatrick     if (!Decls.empty())
425e5dd7070Spatrick       ProcessDeclGroup(Decls);
426e5dd7070Spatrick 
427e5dd7070Spatrick     // If the current declaration is not a free standing declaration, save it
428e5dd7070Spatrick     // so we can merge it with the subsequent declaration(s) using it.
429e5dd7070Spatrick     if (isa<TagDecl>(*D) && !cast<TagDecl>(*D)->isFreeStanding()) {
430e5dd7070Spatrick       Decls.push_back(*D);
431e5dd7070Spatrick       continue;
432e5dd7070Spatrick     }
433e5dd7070Spatrick 
434e5dd7070Spatrick     if (isa<AccessSpecDecl>(*D)) {
435e5dd7070Spatrick       Indentation -= Policy.Indentation;
436e5dd7070Spatrick       this->Indent();
437e5dd7070Spatrick       Print(D->getAccess());
438e5dd7070Spatrick       Out << ":\n";
439e5dd7070Spatrick       Indentation += Policy.Indentation;
440e5dd7070Spatrick       continue;
441e5dd7070Spatrick     }
442e5dd7070Spatrick 
443e5dd7070Spatrick     this->Indent();
444e5dd7070Spatrick     Visit(*D);
445e5dd7070Spatrick 
446e5dd7070Spatrick     // FIXME: Need to be able to tell the DeclPrinter when
447e5dd7070Spatrick     const char *Terminator = nullptr;
448e5dd7070Spatrick     if (isa<OMPThreadPrivateDecl>(*D) || isa<OMPDeclareReductionDecl>(*D) ||
449e5dd7070Spatrick         isa<OMPDeclareMapperDecl>(*D) || isa<OMPRequiresDecl>(*D) ||
450e5dd7070Spatrick         isa<OMPAllocateDecl>(*D))
451e5dd7070Spatrick       Terminator = nullptr;
452e5dd7070Spatrick     else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->hasBody())
453e5dd7070Spatrick       Terminator = nullptr;
454e5dd7070Spatrick     else if (auto FD = dyn_cast<FunctionDecl>(*D)) {
455e5dd7070Spatrick       if (FD->isThisDeclarationADefinition())
456e5dd7070Spatrick         Terminator = nullptr;
457e5dd7070Spatrick       else
458e5dd7070Spatrick         Terminator = ";";
459e5dd7070Spatrick     } else if (auto TD = dyn_cast<FunctionTemplateDecl>(*D)) {
460e5dd7070Spatrick       if (TD->getTemplatedDecl()->isThisDeclarationADefinition())
461e5dd7070Spatrick         Terminator = nullptr;
462e5dd7070Spatrick       else
463e5dd7070Spatrick         Terminator = ";";
464e5dd7070Spatrick     } else if (isa<NamespaceDecl>(*D) || isa<LinkageSpecDecl>(*D) ||
465e5dd7070Spatrick              isa<ObjCImplementationDecl>(*D) ||
466e5dd7070Spatrick              isa<ObjCInterfaceDecl>(*D) ||
467e5dd7070Spatrick              isa<ObjCProtocolDecl>(*D) ||
468e5dd7070Spatrick              isa<ObjCCategoryImplDecl>(*D) ||
469e5dd7070Spatrick              isa<ObjCCategoryDecl>(*D))
470e5dd7070Spatrick       Terminator = nullptr;
471e5dd7070Spatrick     else if (isa<EnumConstantDecl>(*D)) {
472e5dd7070Spatrick       DeclContext::decl_iterator Next = D;
473e5dd7070Spatrick       ++Next;
474e5dd7070Spatrick       if (Next != DEnd)
475e5dd7070Spatrick         Terminator = ",";
476e5dd7070Spatrick     } else
477e5dd7070Spatrick       Terminator = ";";
478e5dd7070Spatrick 
479e5dd7070Spatrick     if (Terminator)
480e5dd7070Spatrick       Out << Terminator;
481e5dd7070Spatrick     if (!Policy.TerseOutput &&
482e5dd7070Spatrick         ((isa<FunctionDecl>(*D) &&
483e5dd7070Spatrick           cast<FunctionDecl>(*D)->doesThisDeclarationHaveABody()) ||
484e5dd7070Spatrick          (isa<FunctionTemplateDecl>(*D) &&
485e5dd7070Spatrick           cast<FunctionTemplateDecl>(*D)->getTemplatedDecl()->doesThisDeclarationHaveABody())))
486e5dd7070Spatrick       ; // StmtPrinter already added '\n' after CompoundStmt.
487e5dd7070Spatrick     else
488e5dd7070Spatrick       Out << "\n";
489e5dd7070Spatrick 
490e5dd7070Spatrick     // Declare target attribute is special one, natural spelling for the pragma
491e5dd7070Spatrick     // assumes "ending" construct so print it here.
492e5dd7070Spatrick     if (D->hasAttr<OMPDeclareTargetDeclAttr>())
493e5dd7070Spatrick       Out << "#pragma omp end declare target\n";
494e5dd7070Spatrick   }
495e5dd7070Spatrick 
496e5dd7070Spatrick   if (!Decls.empty())
497e5dd7070Spatrick     ProcessDeclGroup(Decls);
498e5dd7070Spatrick 
499e5dd7070Spatrick   if (Indent)
500e5dd7070Spatrick     Indentation -= Policy.Indentation;
501e5dd7070Spatrick }
502e5dd7070Spatrick 
503e5dd7070Spatrick void DeclPrinter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
504e5dd7070Spatrick   VisitDeclContext(D, false);
505e5dd7070Spatrick }
506e5dd7070Spatrick 
507e5dd7070Spatrick void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
508e5dd7070Spatrick   if (!Policy.SuppressSpecifiers) {
509e5dd7070Spatrick     Out << "typedef ";
510e5dd7070Spatrick 
511e5dd7070Spatrick     if (D->isModulePrivate())
512e5dd7070Spatrick       Out << "__module_private__ ";
513e5dd7070Spatrick   }
514e5dd7070Spatrick   QualType Ty = D->getTypeSourceInfo()->getType();
515e5dd7070Spatrick   Ty.print(Out, Policy, D->getName(), Indentation);
516e5dd7070Spatrick   prettyPrintAttributes(D);
517e5dd7070Spatrick }
518e5dd7070Spatrick 
519e5dd7070Spatrick void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) {
520e5dd7070Spatrick   Out << "using " << *D;
521e5dd7070Spatrick   prettyPrintAttributes(D);
522e5dd7070Spatrick   Out << " = " << D->getTypeSourceInfo()->getType().getAsString(Policy);
523e5dd7070Spatrick }
524e5dd7070Spatrick 
525e5dd7070Spatrick void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
526e5dd7070Spatrick   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
527e5dd7070Spatrick     Out << "__module_private__ ";
528e5dd7070Spatrick   Out << "enum";
529e5dd7070Spatrick   if (D->isScoped()) {
530e5dd7070Spatrick     if (D->isScopedUsingClassTag())
531e5dd7070Spatrick       Out << " class";
532e5dd7070Spatrick     else
533e5dd7070Spatrick       Out << " struct";
534e5dd7070Spatrick   }
535e5dd7070Spatrick 
536e5dd7070Spatrick   prettyPrintAttributes(D);
537e5dd7070Spatrick 
538*a9ac8606Spatrick   if (D->getDeclName())
539*a9ac8606Spatrick     Out << ' ' << D->getDeclName();
540e5dd7070Spatrick 
541ec727ea7Spatrick   if (D->isFixed())
542e5dd7070Spatrick     Out << " : " << D->getIntegerType().stream(Policy);
543e5dd7070Spatrick 
544e5dd7070Spatrick   if (D->isCompleteDefinition()) {
545e5dd7070Spatrick     Out << " {\n";
546e5dd7070Spatrick     VisitDeclContext(D);
547e5dd7070Spatrick     Indent() << "}";
548e5dd7070Spatrick   }
549e5dd7070Spatrick }
550e5dd7070Spatrick 
551e5dd7070Spatrick void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
552e5dd7070Spatrick   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
553e5dd7070Spatrick     Out << "__module_private__ ";
554e5dd7070Spatrick   Out << D->getKindName();
555e5dd7070Spatrick 
556e5dd7070Spatrick   prettyPrintAttributes(D);
557e5dd7070Spatrick 
558e5dd7070Spatrick   if (D->getIdentifier())
559e5dd7070Spatrick     Out << ' ' << *D;
560e5dd7070Spatrick 
561e5dd7070Spatrick   if (D->isCompleteDefinition()) {
562e5dd7070Spatrick     Out << " {\n";
563e5dd7070Spatrick     VisitDeclContext(D);
564e5dd7070Spatrick     Indent() << "}";
565e5dd7070Spatrick   }
566e5dd7070Spatrick }
567e5dd7070Spatrick 
568e5dd7070Spatrick void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
569e5dd7070Spatrick   Out << *D;
570e5dd7070Spatrick   prettyPrintAttributes(D);
571e5dd7070Spatrick   if (Expr *Init = D->getInitExpr()) {
572e5dd7070Spatrick     Out << " = ";
573e5dd7070Spatrick     Init->printPretty(Out, nullptr, Policy, Indentation, "\n", &Context);
574e5dd7070Spatrick   }
575e5dd7070Spatrick }
576e5dd7070Spatrick 
577e5dd7070Spatrick static void printExplicitSpecifier(ExplicitSpecifier ES, llvm::raw_ostream &Out,
578*a9ac8606Spatrick                                    PrintingPolicy &Policy, unsigned Indentation,
579*a9ac8606Spatrick                                    const ASTContext &Context) {
580e5dd7070Spatrick   std::string Proto = "explicit";
581e5dd7070Spatrick   llvm::raw_string_ostream EOut(Proto);
582e5dd7070Spatrick   if (ES.getExpr()) {
583e5dd7070Spatrick     EOut << "(";
584*a9ac8606Spatrick     ES.getExpr()->printPretty(EOut, nullptr, Policy, Indentation, "\n",
585*a9ac8606Spatrick                               &Context);
586e5dd7070Spatrick     EOut << ")";
587e5dd7070Spatrick   }
588e5dd7070Spatrick   EOut << " ";
589e5dd7070Spatrick   EOut.flush();
590e5dd7070Spatrick   Out << EOut.str();
591e5dd7070Spatrick }
592e5dd7070Spatrick 
593e5dd7070Spatrick void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
594e5dd7070Spatrick   if (!D->getDescribedFunctionTemplate() &&
595e5dd7070Spatrick       !D->isFunctionTemplateSpecialization())
596e5dd7070Spatrick     prettyPrintPragmas(D);
597e5dd7070Spatrick 
598e5dd7070Spatrick   if (D->isFunctionTemplateSpecialization())
599e5dd7070Spatrick     Out << "template<> ";
600e5dd7070Spatrick   else if (!D->getDescribedFunctionTemplate()) {
601e5dd7070Spatrick     for (unsigned I = 0, NumTemplateParams = D->getNumTemplateParameterLists();
602e5dd7070Spatrick          I < NumTemplateParams; ++I)
603e5dd7070Spatrick       printTemplateParameters(D->getTemplateParameterList(I));
604e5dd7070Spatrick   }
605e5dd7070Spatrick 
606e5dd7070Spatrick   CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
607e5dd7070Spatrick   CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
608e5dd7070Spatrick   CXXDeductionGuideDecl *GuideDecl = dyn_cast<CXXDeductionGuideDecl>(D);
609e5dd7070Spatrick   if (!Policy.SuppressSpecifiers) {
610e5dd7070Spatrick     switch (D->getStorageClass()) {
611e5dd7070Spatrick     case SC_None: break;
612e5dd7070Spatrick     case SC_Extern: Out << "extern "; break;
613e5dd7070Spatrick     case SC_Static: Out << "static "; break;
614e5dd7070Spatrick     case SC_PrivateExtern: Out << "__private_extern__ "; break;
615e5dd7070Spatrick     case SC_Auto: case SC_Register:
616e5dd7070Spatrick       llvm_unreachable("invalid for functions");
617e5dd7070Spatrick     }
618e5dd7070Spatrick 
619e5dd7070Spatrick     if (D->isInlineSpecified())  Out << "inline ";
620e5dd7070Spatrick     if (D->isVirtualAsWritten()) Out << "virtual ";
621e5dd7070Spatrick     if (D->isModulePrivate())    Out << "__module_private__ ";
622e5dd7070Spatrick     if (D->isConstexprSpecified() && !D->isExplicitlyDefaulted())
623e5dd7070Spatrick       Out << "constexpr ";
624e5dd7070Spatrick     if (D->isConsteval())        Out << "consteval ";
625e5dd7070Spatrick     ExplicitSpecifier ExplicitSpec = ExplicitSpecifier::getFromDecl(D);
626e5dd7070Spatrick     if (ExplicitSpec.isSpecified())
627*a9ac8606Spatrick       printExplicitSpecifier(ExplicitSpec, Out, Policy, Indentation, Context);
628e5dd7070Spatrick   }
629e5dd7070Spatrick 
630e5dd7070Spatrick   PrintingPolicy SubPolicy(Policy);
631e5dd7070Spatrick   SubPolicy.SuppressSpecifiers = false;
632e5dd7070Spatrick   std::string Proto;
633e5dd7070Spatrick 
634e5dd7070Spatrick   if (Policy.FullyQualifiedName) {
635e5dd7070Spatrick     Proto += D->getQualifiedNameAsString();
636e5dd7070Spatrick   } else {
637e5dd7070Spatrick     llvm::raw_string_ostream OS(Proto);
638e5dd7070Spatrick     if (!Policy.SuppressScope) {
639e5dd7070Spatrick       if (const NestedNameSpecifier *NS = D->getQualifier()) {
640e5dd7070Spatrick         NS->print(OS, Policy);
641e5dd7070Spatrick       }
642e5dd7070Spatrick     }
643e5dd7070Spatrick     D->getNameInfo().printName(OS, Policy);
644e5dd7070Spatrick   }
645e5dd7070Spatrick 
646e5dd7070Spatrick   if (GuideDecl)
647e5dd7070Spatrick     Proto = GuideDecl->getDeducedTemplate()->getDeclName().getAsString();
648e5dd7070Spatrick   if (D->isFunctionTemplateSpecialization()) {
649e5dd7070Spatrick     llvm::raw_string_ostream POut(Proto);
650e5dd7070Spatrick     DeclPrinter TArgPrinter(POut, SubPolicy, Context, Indentation);
651e5dd7070Spatrick     const auto *TArgAsWritten = D->getTemplateSpecializationArgsAsWritten();
652*a9ac8606Spatrick     const TemplateParameterList *TPL = D->getTemplateSpecializationInfo()
653*a9ac8606Spatrick                                            ->getTemplate()
654*a9ac8606Spatrick                                            ->getTemplateParameters();
655e5dd7070Spatrick     if (TArgAsWritten && !Policy.PrintCanonicalTypes)
656*a9ac8606Spatrick       TArgPrinter.printTemplateArguments(TArgAsWritten->arguments(), TPL,
657*a9ac8606Spatrick                                          /*TemplOverloaded*/ true);
658e5dd7070Spatrick     else if (const TemplateArgumentList *TArgs =
659e5dd7070Spatrick                  D->getTemplateSpecializationArgs())
660*a9ac8606Spatrick       TArgPrinter.printTemplateArguments(TArgs->asArray(), TPL,
661*a9ac8606Spatrick                                          /*TemplOverloaded*/ true);
662e5dd7070Spatrick   }
663e5dd7070Spatrick 
664e5dd7070Spatrick   QualType Ty = D->getType();
665e5dd7070Spatrick   while (const ParenType *PT = dyn_cast<ParenType>(Ty)) {
666e5dd7070Spatrick     Proto = '(' + Proto + ')';
667e5dd7070Spatrick     Ty = PT->getInnerType();
668e5dd7070Spatrick   }
669e5dd7070Spatrick 
670e5dd7070Spatrick   if (const FunctionType *AFT = Ty->getAs<FunctionType>()) {
671e5dd7070Spatrick     const FunctionProtoType *FT = nullptr;
672e5dd7070Spatrick     if (D->hasWrittenPrototype())
673e5dd7070Spatrick       FT = dyn_cast<FunctionProtoType>(AFT);
674e5dd7070Spatrick 
675e5dd7070Spatrick     Proto += "(";
676e5dd7070Spatrick     if (FT) {
677e5dd7070Spatrick       llvm::raw_string_ostream POut(Proto);
678e5dd7070Spatrick       DeclPrinter ParamPrinter(POut, SubPolicy, Context, Indentation);
679e5dd7070Spatrick       for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
680e5dd7070Spatrick         if (i) POut << ", ";
681e5dd7070Spatrick         ParamPrinter.VisitParmVarDecl(D->getParamDecl(i));
682e5dd7070Spatrick       }
683e5dd7070Spatrick 
684e5dd7070Spatrick       if (FT->isVariadic()) {
685e5dd7070Spatrick         if (D->getNumParams()) POut << ", ";
686e5dd7070Spatrick         POut << "...";
687e5dd7070Spatrick       }
688e5dd7070Spatrick     } else if (D->doesThisDeclarationHaveABody() && !D->hasPrototype()) {
689e5dd7070Spatrick       for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
690e5dd7070Spatrick         if (i)
691e5dd7070Spatrick           Proto += ", ";
692e5dd7070Spatrick         Proto += D->getParamDecl(i)->getNameAsString();
693e5dd7070Spatrick       }
694e5dd7070Spatrick     }
695e5dd7070Spatrick 
696e5dd7070Spatrick     Proto += ")";
697e5dd7070Spatrick 
698e5dd7070Spatrick     if (FT) {
699e5dd7070Spatrick       if (FT->isConst())
700e5dd7070Spatrick         Proto += " const";
701e5dd7070Spatrick       if (FT->isVolatile())
702e5dd7070Spatrick         Proto += " volatile";
703e5dd7070Spatrick       if (FT->isRestrict())
704e5dd7070Spatrick         Proto += " restrict";
705e5dd7070Spatrick 
706e5dd7070Spatrick       switch (FT->getRefQualifier()) {
707e5dd7070Spatrick       case RQ_None:
708e5dd7070Spatrick         break;
709e5dd7070Spatrick       case RQ_LValue:
710e5dd7070Spatrick         Proto += " &";
711e5dd7070Spatrick         break;
712e5dd7070Spatrick       case RQ_RValue:
713e5dd7070Spatrick         Proto += " &&";
714e5dd7070Spatrick         break;
715e5dd7070Spatrick       }
716e5dd7070Spatrick     }
717e5dd7070Spatrick 
718e5dd7070Spatrick     if (FT && FT->hasDynamicExceptionSpec()) {
719e5dd7070Spatrick       Proto += " throw(";
720e5dd7070Spatrick       if (FT->getExceptionSpecType() == EST_MSAny)
721e5dd7070Spatrick         Proto += "...";
722e5dd7070Spatrick       else
723e5dd7070Spatrick         for (unsigned I = 0, N = FT->getNumExceptions(); I != N; ++I) {
724e5dd7070Spatrick           if (I)
725e5dd7070Spatrick             Proto += ", ";
726e5dd7070Spatrick 
727e5dd7070Spatrick           Proto += FT->getExceptionType(I).getAsString(SubPolicy);
728e5dd7070Spatrick         }
729e5dd7070Spatrick       Proto += ")";
730e5dd7070Spatrick     } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) {
731e5dd7070Spatrick       Proto += " noexcept";
732e5dd7070Spatrick       if (isComputedNoexcept(FT->getExceptionSpecType())) {
733e5dd7070Spatrick         Proto += "(";
734e5dd7070Spatrick         llvm::raw_string_ostream EOut(Proto);
735e5dd7070Spatrick         FT->getNoexceptExpr()->printPretty(EOut, nullptr, SubPolicy,
736*a9ac8606Spatrick                                            Indentation, "\n", &Context);
737e5dd7070Spatrick         EOut.flush();
738e5dd7070Spatrick         Proto += EOut.str();
739e5dd7070Spatrick         Proto += ")";
740e5dd7070Spatrick       }
741e5dd7070Spatrick     }
742e5dd7070Spatrick 
743e5dd7070Spatrick     if (CDecl) {
744e5dd7070Spatrick       if (!Policy.TerseOutput)
745e5dd7070Spatrick         PrintConstructorInitializers(CDecl, Proto);
746e5dd7070Spatrick     } else if (!ConversionDecl && !isa<CXXDestructorDecl>(D)) {
747e5dd7070Spatrick       if (FT && FT->hasTrailingReturn()) {
748e5dd7070Spatrick         if (!GuideDecl)
749e5dd7070Spatrick           Out << "auto ";
750e5dd7070Spatrick         Out << Proto << " -> ";
751e5dd7070Spatrick         Proto.clear();
752e5dd7070Spatrick       }
753e5dd7070Spatrick       AFT->getReturnType().print(Out, Policy, Proto);
754e5dd7070Spatrick       Proto.clear();
755e5dd7070Spatrick     }
756e5dd7070Spatrick     Out << Proto;
757e5dd7070Spatrick 
758e5dd7070Spatrick     if (Expr *TrailingRequiresClause = D->getTrailingRequiresClause()) {
759e5dd7070Spatrick       Out << " requires ";
760*a9ac8606Spatrick       TrailingRequiresClause->printPretty(Out, nullptr, SubPolicy, Indentation,
761*a9ac8606Spatrick                                           "\n", &Context);
762e5dd7070Spatrick     }
763e5dd7070Spatrick   } else {
764e5dd7070Spatrick     Ty.print(Out, Policy, Proto);
765e5dd7070Spatrick   }
766e5dd7070Spatrick 
767e5dd7070Spatrick   prettyPrintAttributes(D);
768e5dd7070Spatrick 
769e5dd7070Spatrick   if (D->isPure())
770e5dd7070Spatrick     Out << " = 0";
771e5dd7070Spatrick   else if (D->isDeletedAsWritten())
772e5dd7070Spatrick     Out << " = delete";
773e5dd7070Spatrick   else if (D->isExplicitlyDefaulted())
774e5dd7070Spatrick     Out << " = default";
775e5dd7070Spatrick   else if (D->doesThisDeclarationHaveABody()) {
776e5dd7070Spatrick     if (!Policy.TerseOutput) {
777e5dd7070Spatrick       if (!D->hasPrototype() && D->getNumParams()) {
778e5dd7070Spatrick         // This is a K&R function definition, so we need to print the
779e5dd7070Spatrick         // parameters.
780e5dd7070Spatrick         Out << '\n';
781e5dd7070Spatrick         DeclPrinter ParamPrinter(Out, SubPolicy, Context, Indentation);
782e5dd7070Spatrick         Indentation += Policy.Indentation;
783e5dd7070Spatrick         for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
784e5dd7070Spatrick           Indent();
785e5dd7070Spatrick           ParamPrinter.VisitParmVarDecl(D->getParamDecl(i));
786e5dd7070Spatrick           Out << ";\n";
787e5dd7070Spatrick         }
788e5dd7070Spatrick         Indentation -= Policy.Indentation;
789e5dd7070Spatrick       } else
790e5dd7070Spatrick         Out << ' ';
791e5dd7070Spatrick 
792e5dd7070Spatrick       if (D->getBody())
793*a9ac8606Spatrick         D->getBody()->printPretty(Out, nullptr, SubPolicy, Indentation, "\n",
794*a9ac8606Spatrick                                   &Context);
795e5dd7070Spatrick     } else {
796e5dd7070Spatrick       if (!Policy.TerseOutput && isa<CXXConstructorDecl>(*D))
797e5dd7070Spatrick         Out << " {}";
798e5dd7070Spatrick     }
799e5dd7070Spatrick   }
800e5dd7070Spatrick }
801e5dd7070Spatrick 
802e5dd7070Spatrick void DeclPrinter::VisitFriendDecl(FriendDecl *D) {
803e5dd7070Spatrick   if (TypeSourceInfo *TSI = D->getFriendType()) {
804e5dd7070Spatrick     unsigned NumTPLists = D->getFriendTypeNumTemplateParameterLists();
805e5dd7070Spatrick     for (unsigned i = 0; i < NumTPLists; ++i)
806e5dd7070Spatrick       printTemplateParameters(D->getFriendTypeTemplateParameterList(i));
807e5dd7070Spatrick     Out << "friend ";
808e5dd7070Spatrick     Out << " " << TSI->getType().getAsString(Policy);
809e5dd7070Spatrick   }
810e5dd7070Spatrick   else if (FunctionDecl *FD =
811e5dd7070Spatrick       dyn_cast<FunctionDecl>(D->getFriendDecl())) {
812e5dd7070Spatrick     Out << "friend ";
813e5dd7070Spatrick     VisitFunctionDecl(FD);
814e5dd7070Spatrick   }
815e5dd7070Spatrick   else if (FunctionTemplateDecl *FTD =
816e5dd7070Spatrick            dyn_cast<FunctionTemplateDecl>(D->getFriendDecl())) {
817e5dd7070Spatrick     Out << "friend ";
818e5dd7070Spatrick     VisitFunctionTemplateDecl(FTD);
819e5dd7070Spatrick   }
820e5dd7070Spatrick   else if (ClassTemplateDecl *CTD =
821e5dd7070Spatrick            dyn_cast<ClassTemplateDecl>(D->getFriendDecl())) {
822e5dd7070Spatrick     Out << "friend ";
823e5dd7070Spatrick     VisitRedeclarableTemplateDecl(CTD);
824e5dd7070Spatrick   }
825e5dd7070Spatrick }
826e5dd7070Spatrick 
827e5dd7070Spatrick void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
828e5dd7070Spatrick   // FIXME: add printing of pragma attributes if required.
829e5dd7070Spatrick   if (!Policy.SuppressSpecifiers && D->isMutable())
830e5dd7070Spatrick     Out << "mutable ";
831e5dd7070Spatrick   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
832e5dd7070Spatrick     Out << "__module_private__ ";
833e5dd7070Spatrick 
834e5dd7070Spatrick   Out << D->getASTContext().getUnqualifiedObjCPointerType(D->getType()).
835e5dd7070Spatrick          stream(Policy, D->getName(), Indentation);
836e5dd7070Spatrick 
837e5dd7070Spatrick   if (D->isBitField()) {
838e5dd7070Spatrick     Out << " : ";
839*a9ac8606Spatrick     D->getBitWidth()->printPretty(Out, nullptr, Policy, Indentation, "\n",
840*a9ac8606Spatrick                                   &Context);
841e5dd7070Spatrick   }
842e5dd7070Spatrick 
843e5dd7070Spatrick   Expr *Init = D->getInClassInitializer();
844e5dd7070Spatrick   if (!Policy.SuppressInitializers && Init) {
845e5dd7070Spatrick     if (D->getInClassInitStyle() == ICIS_ListInit)
846e5dd7070Spatrick       Out << " ";
847e5dd7070Spatrick     else
848e5dd7070Spatrick       Out << " = ";
849*a9ac8606Spatrick     Init->printPretty(Out, nullptr, Policy, Indentation, "\n", &Context);
850e5dd7070Spatrick   }
851e5dd7070Spatrick   prettyPrintAttributes(D);
852e5dd7070Spatrick }
853e5dd7070Spatrick 
854e5dd7070Spatrick void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
855e5dd7070Spatrick   Out << *D << ":";
856e5dd7070Spatrick }
857e5dd7070Spatrick 
858e5dd7070Spatrick void DeclPrinter::VisitVarDecl(VarDecl *D) {
859e5dd7070Spatrick   prettyPrintPragmas(D);
860e5dd7070Spatrick 
861e5dd7070Spatrick   QualType T = D->getTypeSourceInfo()
862e5dd7070Spatrick     ? D->getTypeSourceInfo()->getType()
863e5dd7070Spatrick     : D->getASTContext().getUnqualifiedObjCPointerType(D->getType());
864e5dd7070Spatrick 
865e5dd7070Spatrick   if (!Policy.SuppressSpecifiers) {
866e5dd7070Spatrick     StorageClass SC = D->getStorageClass();
867e5dd7070Spatrick     if (SC != SC_None)
868e5dd7070Spatrick       Out << VarDecl::getStorageClassSpecifierString(SC) << " ";
869e5dd7070Spatrick 
870e5dd7070Spatrick     switch (D->getTSCSpec()) {
871e5dd7070Spatrick     case TSCS_unspecified:
872e5dd7070Spatrick       break;
873e5dd7070Spatrick     case TSCS___thread:
874e5dd7070Spatrick       Out << "__thread ";
875e5dd7070Spatrick       break;
876e5dd7070Spatrick     case TSCS__Thread_local:
877e5dd7070Spatrick       Out << "_Thread_local ";
878e5dd7070Spatrick       break;
879e5dd7070Spatrick     case TSCS_thread_local:
880e5dd7070Spatrick       Out << "thread_local ";
881e5dd7070Spatrick       break;
882e5dd7070Spatrick     }
883e5dd7070Spatrick 
884e5dd7070Spatrick     if (D->isModulePrivate())
885e5dd7070Spatrick       Out << "__module_private__ ";
886e5dd7070Spatrick 
887e5dd7070Spatrick     if (D->isConstexpr()) {
888e5dd7070Spatrick       Out << "constexpr ";
889e5dd7070Spatrick       T.removeLocalConst();
890e5dd7070Spatrick     }
891e5dd7070Spatrick   }
892e5dd7070Spatrick 
893e5dd7070Spatrick   printDeclType(T, D->getName());
894e5dd7070Spatrick   Expr *Init = D->getInit();
895e5dd7070Spatrick   if (!Policy.SuppressInitializers && Init) {
896e5dd7070Spatrick     bool ImplicitInit = false;
897e5dd7070Spatrick     if (CXXConstructExpr *Construct =
898e5dd7070Spatrick             dyn_cast<CXXConstructExpr>(Init->IgnoreImplicit())) {
899e5dd7070Spatrick       if (D->getInitStyle() == VarDecl::CallInit &&
900e5dd7070Spatrick           !Construct->isListInitialization()) {
901e5dd7070Spatrick         ImplicitInit = Construct->getNumArgs() == 0 ||
902e5dd7070Spatrick           Construct->getArg(0)->isDefaultArgument();
903e5dd7070Spatrick       }
904e5dd7070Spatrick     }
905e5dd7070Spatrick     if (!ImplicitInit) {
906e5dd7070Spatrick       if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
907e5dd7070Spatrick         Out << "(";
908e5dd7070Spatrick       else if (D->getInitStyle() == VarDecl::CInit) {
909e5dd7070Spatrick         Out << " = ";
910e5dd7070Spatrick       }
911e5dd7070Spatrick       PrintingPolicy SubPolicy(Policy);
912e5dd7070Spatrick       SubPolicy.SuppressSpecifiers = false;
913e5dd7070Spatrick       SubPolicy.IncludeTagDefinition = false;
914*a9ac8606Spatrick       Init->printPretty(Out, nullptr, SubPolicy, Indentation, "\n", &Context);
915e5dd7070Spatrick       if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
916e5dd7070Spatrick         Out << ")";
917e5dd7070Spatrick     }
918e5dd7070Spatrick   }
919e5dd7070Spatrick   prettyPrintAttributes(D);
920e5dd7070Spatrick }
921e5dd7070Spatrick 
922e5dd7070Spatrick void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) {
923e5dd7070Spatrick   VisitVarDecl(D);
924e5dd7070Spatrick }
925e5dd7070Spatrick 
926e5dd7070Spatrick void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
927e5dd7070Spatrick   Out << "__asm (";
928*a9ac8606Spatrick   D->getAsmString()->printPretty(Out, nullptr, Policy, Indentation, "\n",
929*a9ac8606Spatrick                                  &Context);
930e5dd7070Spatrick   Out << ")";
931e5dd7070Spatrick }
932e5dd7070Spatrick 
933e5dd7070Spatrick void DeclPrinter::VisitImportDecl(ImportDecl *D) {
934e5dd7070Spatrick   Out << "@import " << D->getImportedModule()->getFullModuleName()
935e5dd7070Spatrick       << ";\n";
936e5dd7070Spatrick }
937e5dd7070Spatrick 
938e5dd7070Spatrick void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) {
939e5dd7070Spatrick   Out << "static_assert(";
940*a9ac8606Spatrick   D->getAssertExpr()->printPretty(Out, nullptr, Policy, Indentation, "\n",
941*a9ac8606Spatrick                                   &Context);
942e5dd7070Spatrick   if (StringLiteral *SL = D->getMessage()) {
943e5dd7070Spatrick     Out << ", ";
944*a9ac8606Spatrick     SL->printPretty(Out, nullptr, Policy, Indentation, "\n", &Context);
945e5dd7070Spatrick   }
946e5dd7070Spatrick   Out << ")";
947e5dd7070Spatrick }
948e5dd7070Spatrick 
949e5dd7070Spatrick //----------------------------------------------------------------------------
950e5dd7070Spatrick // C++ declarations
951e5dd7070Spatrick //----------------------------------------------------------------------------
952e5dd7070Spatrick void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) {
953e5dd7070Spatrick   if (D->isInline())
954e5dd7070Spatrick     Out << "inline ";
955*a9ac8606Spatrick 
956*a9ac8606Spatrick   Out << "namespace ";
957*a9ac8606Spatrick   if (D->getDeclName())
958*a9ac8606Spatrick     Out << D->getDeclName() << ' ';
959*a9ac8606Spatrick   Out << "{\n";
960*a9ac8606Spatrick 
961e5dd7070Spatrick   VisitDeclContext(D);
962e5dd7070Spatrick   Indent() << "}";
963e5dd7070Spatrick }
964e5dd7070Spatrick 
965e5dd7070Spatrick void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
966e5dd7070Spatrick   Out << "using namespace ";
967e5dd7070Spatrick   if (D->getQualifier())
968e5dd7070Spatrick     D->getQualifier()->print(Out, Policy);
969e5dd7070Spatrick   Out << *D->getNominatedNamespaceAsWritten();
970e5dd7070Spatrick }
971e5dd7070Spatrick 
972e5dd7070Spatrick void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
973e5dd7070Spatrick   Out << "namespace " << *D << " = ";
974e5dd7070Spatrick   if (D->getQualifier())
975e5dd7070Spatrick     D->getQualifier()->print(Out, Policy);
976e5dd7070Spatrick   Out << *D->getAliasedNamespace();
977e5dd7070Spatrick }
978e5dd7070Spatrick 
979e5dd7070Spatrick void DeclPrinter::VisitEmptyDecl(EmptyDecl *D) {
980e5dd7070Spatrick   prettyPrintAttributes(D);
981e5dd7070Spatrick }
982e5dd7070Spatrick 
983e5dd7070Spatrick void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
984e5dd7070Spatrick   // FIXME: add printing of pragma attributes if required.
985e5dd7070Spatrick   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
986e5dd7070Spatrick     Out << "__module_private__ ";
987e5dd7070Spatrick   Out << D->getKindName();
988e5dd7070Spatrick 
989e5dd7070Spatrick   prettyPrintAttributes(D);
990e5dd7070Spatrick 
991e5dd7070Spatrick   if (D->getIdentifier()) {
992e5dd7070Spatrick     Out << ' ' << *D;
993e5dd7070Spatrick 
994e5dd7070Spatrick     if (auto S = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
995e5dd7070Spatrick       ArrayRef<TemplateArgument> Args = S->getTemplateArgs().asArray();
996e5dd7070Spatrick       if (!Policy.PrintCanonicalTypes)
997e5dd7070Spatrick         if (const auto* TSI = S->getTypeAsWritten())
998e5dd7070Spatrick           if (const auto *TST =
999e5dd7070Spatrick                   dyn_cast<TemplateSpecializationType>(TSI->getType()))
1000e5dd7070Spatrick             Args = TST->template_arguments();
1001*a9ac8606Spatrick       printTemplateArguments(
1002*a9ac8606Spatrick           Args, S->getSpecializedTemplate()->getTemplateParameters(),
1003*a9ac8606Spatrick           /*TemplOverloaded*/ false);
1004e5dd7070Spatrick     }
1005e5dd7070Spatrick   }
1006e5dd7070Spatrick 
1007e5dd7070Spatrick   if (D->isCompleteDefinition()) {
1008e5dd7070Spatrick     // Print the base classes
1009e5dd7070Spatrick     if (D->getNumBases()) {
1010e5dd7070Spatrick       Out << " : ";
1011e5dd7070Spatrick       for (CXXRecordDecl::base_class_iterator Base = D->bases_begin(),
1012e5dd7070Spatrick              BaseEnd = D->bases_end(); Base != BaseEnd; ++Base) {
1013e5dd7070Spatrick         if (Base != D->bases_begin())
1014e5dd7070Spatrick           Out << ", ";
1015e5dd7070Spatrick 
1016e5dd7070Spatrick         if (Base->isVirtual())
1017e5dd7070Spatrick           Out << "virtual ";
1018e5dd7070Spatrick 
1019e5dd7070Spatrick         AccessSpecifier AS = Base->getAccessSpecifierAsWritten();
1020e5dd7070Spatrick         if (AS != AS_none) {
1021e5dd7070Spatrick           Print(AS);
1022e5dd7070Spatrick           Out << " ";
1023e5dd7070Spatrick         }
1024e5dd7070Spatrick         Out << Base->getType().getAsString(Policy);
1025e5dd7070Spatrick 
1026e5dd7070Spatrick         if (Base->isPackExpansion())
1027e5dd7070Spatrick           Out << "...";
1028e5dd7070Spatrick       }
1029e5dd7070Spatrick     }
1030e5dd7070Spatrick 
1031e5dd7070Spatrick     // Print the class definition
1032e5dd7070Spatrick     // FIXME: Doesn't print access specifiers, e.g., "public:"
1033e5dd7070Spatrick     if (Policy.TerseOutput) {
1034e5dd7070Spatrick       Out << " {}";
1035e5dd7070Spatrick     } else {
1036e5dd7070Spatrick       Out << " {\n";
1037e5dd7070Spatrick       VisitDeclContext(D);
1038e5dd7070Spatrick       Indent() << "}";
1039e5dd7070Spatrick     }
1040e5dd7070Spatrick   }
1041e5dd7070Spatrick }
1042e5dd7070Spatrick 
1043e5dd7070Spatrick void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
1044e5dd7070Spatrick   const char *l;
1045e5dd7070Spatrick   if (D->getLanguage() == LinkageSpecDecl::lang_c)
1046e5dd7070Spatrick     l = "C";
1047e5dd7070Spatrick   else {
1048e5dd7070Spatrick     assert(D->getLanguage() == LinkageSpecDecl::lang_cxx &&
1049e5dd7070Spatrick            "unknown language in linkage specification");
1050e5dd7070Spatrick     l = "C++";
1051e5dd7070Spatrick   }
1052e5dd7070Spatrick 
1053e5dd7070Spatrick   Out << "extern \"" << l << "\" ";
1054e5dd7070Spatrick   if (D->hasBraces()) {
1055e5dd7070Spatrick     Out << "{\n";
1056e5dd7070Spatrick     VisitDeclContext(D);
1057e5dd7070Spatrick     Indent() << "}";
1058e5dd7070Spatrick   } else
1059e5dd7070Spatrick     Visit(*D->decls_begin());
1060e5dd7070Spatrick }
1061e5dd7070Spatrick 
1062e5dd7070Spatrick void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params,
1063e5dd7070Spatrick                                           bool OmitTemplateKW) {
1064e5dd7070Spatrick   assert(Params);
1065e5dd7070Spatrick 
1066e5dd7070Spatrick   if (!OmitTemplateKW)
1067e5dd7070Spatrick     Out << "template ";
1068e5dd7070Spatrick   Out << '<';
1069e5dd7070Spatrick 
1070e5dd7070Spatrick   bool NeedComma = false;
1071e5dd7070Spatrick   for (const Decl *Param : *Params) {
1072e5dd7070Spatrick     if (Param->isImplicit())
1073e5dd7070Spatrick       continue;
1074e5dd7070Spatrick 
1075e5dd7070Spatrick     if (NeedComma)
1076e5dd7070Spatrick       Out << ", ";
1077e5dd7070Spatrick     else
1078e5dd7070Spatrick       NeedComma = true;
1079e5dd7070Spatrick 
1080ec727ea7Spatrick     if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
1081ec727ea7Spatrick       VisitTemplateTypeParmDecl(TTP);
1082e5dd7070Spatrick     } else if (auto NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
1083ec727ea7Spatrick       VisitNonTypeTemplateParmDecl(NTTP);
1084e5dd7070Spatrick     } else if (auto TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
1085e5dd7070Spatrick       VisitTemplateDecl(TTPD);
1086e5dd7070Spatrick       // FIXME: print the default argument, if present.
1087e5dd7070Spatrick     }
1088e5dd7070Spatrick   }
1089e5dd7070Spatrick 
1090e5dd7070Spatrick   Out << '>';
1091e5dd7070Spatrick   if (!OmitTemplateKW)
1092e5dd7070Spatrick     Out << ' ';
1093e5dd7070Spatrick }
1094e5dd7070Spatrick 
1095*a9ac8606Spatrick void DeclPrinter::printTemplateArguments(ArrayRef<TemplateArgument> Args,
1096*a9ac8606Spatrick                                          const TemplateParameterList *Params,
1097*a9ac8606Spatrick                                          bool TemplOverloaded) {
1098e5dd7070Spatrick   Out << "<";
1099e5dd7070Spatrick   for (size_t I = 0, E = Args.size(); I < E; ++I) {
1100e5dd7070Spatrick     if (I)
1101e5dd7070Spatrick       Out << ", ";
1102*a9ac8606Spatrick     if (TemplOverloaded || !Params)
1103*a9ac8606Spatrick       Args[I].print(Policy, Out, /*IncludeType*/ true);
1104*a9ac8606Spatrick     else
1105*a9ac8606Spatrick       Args[I].print(
1106*a9ac8606Spatrick           Policy, Out,
1107*a9ac8606Spatrick           TemplateParameterList::shouldIncludeTypeForArgument(Params, I));
1108e5dd7070Spatrick   }
1109e5dd7070Spatrick   Out << ">";
1110e5dd7070Spatrick }
1111e5dd7070Spatrick 
1112*a9ac8606Spatrick void DeclPrinter::printTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
1113*a9ac8606Spatrick                                          const TemplateParameterList *Params,
1114*a9ac8606Spatrick                                          bool TemplOverloaded) {
1115e5dd7070Spatrick   Out << "<";
1116e5dd7070Spatrick   for (size_t I = 0, E = Args.size(); I < E; ++I) {
1117e5dd7070Spatrick     if (I)
1118e5dd7070Spatrick       Out << ", ";
1119*a9ac8606Spatrick     if (TemplOverloaded)
1120*a9ac8606Spatrick       Args[I].getArgument().print(Policy, Out, /*IncludeType*/ true);
1121*a9ac8606Spatrick     else
1122*a9ac8606Spatrick       Args[I].getArgument().print(
1123*a9ac8606Spatrick           Policy, Out,
1124*a9ac8606Spatrick           TemplateParameterList::shouldIncludeTypeForArgument(Params, I));
1125e5dd7070Spatrick   }
1126e5dd7070Spatrick   Out << ">";
1127e5dd7070Spatrick }
1128e5dd7070Spatrick 
1129e5dd7070Spatrick void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
1130e5dd7070Spatrick   printTemplateParameters(D->getTemplateParameters());
1131e5dd7070Spatrick 
1132e5dd7070Spatrick   if (const TemplateTemplateParmDecl *TTP =
1133e5dd7070Spatrick         dyn_cast<TemplateTemplateParmDecl>(D)) {
1134e5dd7070Spatrick     Out << "class";
1135*a9ac8606Spatrick 
1136e5dd7070Spatrick     if (TTP->isParameterPack())
1137e5dd7070Spatrick       Out << " ...";
1138*a9ac8606Spatrick     else if (TTP->getDeclName())
1139*a9ac8606Spatrick       Out << ' ';
1140*a9ac8606Spatrick 
1141*a9ac8606Spatrick     if (TTP->getDeclName())
1142*a9ac8606Spatrick       Out << TTP->getDeclName();
1143e5dd7070Spatrick   } else if (auto *TD = D->getTemplatedDecl())
1144e5dd7070Spatrick     Visit(TD);
1145e5dd7070Spatrick   else if (const auto *Concept = dyn_cast<ConceptDecl>(D)) {
1146e5dd7070Spatrick     Out << "concept " << Concept->getName() << " = " ;
1147*a9ac8606Spatrick     Concept->getConstraintExpr()->printPretty(Out, nullptr, Policy, Indentation,
1148*a9ac8606Spatrick                                               "\n", &Context);
1149e5dd7070Spatrick   }
1150e5dd7070Spatrick }
1151e5dd7070Spatrick 
1152e5dd7070Spatrick void DeclPrinter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
1153e5dd7070Spatrick   prettyPrintPragmas(D->getTemplatedDecl());
1154e5dd7070Spatrick   // Print any leading template parameter lists.
1155e5dd7070Spatrick   if (const FunctionDecl *FD = D->getTemplatedDecl()) {
1156e5dd7070Spatrick     for (unsigned I = 0, NumTemplateParams = FD->getNumTemplateParameterLists();
1157e5dd7070Spatrick          I < NumTemplateParams; ++I)
1158e5dd7070Spatrick       printTemplateParameters(FD->getTemplateParameterList(I));
1159e5dd7070Spatrick   }
1160e5dd7070Spatrick   VisitRedeclarableTemplateDecl(D);
1161e5dd7070Spatrick   // Declare target attribute is special one, natural spelling for the pragma
1162e5dd7070Spatrick   // assumes "ending" construct so print it here.
1163e5dd7070Spatrick   if (D->getTemplatedDecl()->hasAttr<OMPDeclareTargetDeclAttr>())
1164e5dd7070Spatrick     Out << "#pragma omp end declare target\n";
1165e5dd7070Spatrick 
1166e5dd7070Spatrick   // Never print "instantiations" for deduction guides (they don't really
1167e5dd7070Spatrick   // have them).
1168e5dd7070Spatrick   if (PrintInstantiation &&
1169e5dd7070Spatrick       !isa<CXXDeductionGuideDecl>(D->getTemplatedDecl())) {
1170e5dd7070Spatrick     FunctionDecl *PrevDecl = D->getTemplatedDecl();
1171e5dd7070Spatrick     const FunctionDecl *Def;
1172e5dd7070Spatrick     if (PrevDecl->isDefined(Def) && Def != PrevDecl)
1173e5dd7070Spatrick       return;
1174e5dd7070Spatrick     for (auto *I : D->specializations())
1175e5dd7070Spatrick       if (I->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) {
1176e5dd7070Spatrick         if (!PrevDecl->isThisDeclarationADefinition())
1177e5dd7070Spatrick           Out << ";\n";
1178e5dd7070Spatrick         Indent();
1179e5dd7070Spatrick         prettyPrintPragmas(I);
1180e5dd7070Spatrick         Visit(I);
1181e5dd7070Spatrick       }
1182e5dd7070Spatrick   }
1183e5dd7070Spatrick }
1184e5dd7070Spatrick 
1185e5dd7070Spatrick void DeclPrinter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
1186e5dd7070Spatrick   VisitRedeclarableTemplateDecl(D);
1187e5dd7070Spatrick 
1188e5dd7070Spatrick   if (PrintInstantiation) {
1189e5dd7070Spatrick     for (auto *I : D->specializations())
1190e5dd7070Spatrick       if (I->getSpecializationKind() == TSK_ImplicitInstantiation) {
1191e5dd7070Spatrick         if (D->isThisDeclarationADefinition())
1192e5dd7070Spatrick           Out << ";";
1193e5dd7070Spatrick         Out << "\n";
1194e5dd7070Spatrick         Visit(I);
1195e5dd7070Spatrick       }
1196e5dd7070Spatrick   }
1197e5dd7070Spatrick }
1198e5dd7070Spatrick 
1199e5dd7070Spatrick void DeclPrinter::VisitClassTemplateSpecializationDecl(
1200e5dd7070Spatrick                                            ClassTemplateSpecializationDecl *D) {
1201e5dd7070Spatrick   Out << "template<> ";
1202e5dd7070Spatrick   VisitCXXRecordDecl(D);
1203e5dd7070Spatrick }
1204e5dd7070Spatrick 
1205e5dd7070Spatrick void DeclPrinter::VisitClassTemplatePartialSpecializationDecl(
1206e5dd7070Spatrick                                     ClassTemplatePartialSpecializationDecl *D) {
1207e5dd7070Spatrick   printTemplateParameters(D->getTemplateParameters());
1208e5dd7070Spatrick   VisitCXXRecordDecl(D);
1209e5dd7070Spatrick }
1210e5dd7070Spatrick 
1211e5dd7070Spatrick //----------------------------------------------------------------------------
1212e5dd7070Spatrick // Objective-C declarations
1213e5dd7070Spatrick //----------------------------------------------------------------------------
1214e5dd7070Spatrick 
1215e5dd7070Spatrick void DeclPrinter::PrintObjCMethodType(ASTContext &Ctx,
1216e5dd7070Spatrick                                       Decl::ObjCDeclQualifier Quals,
1217e5dd7070Spatrick                                       QualType T) {
1218e5dd7070Spatrick   Out << '(';
1219e5dd7070Spatrick   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_In)
1220e5dd7070Spatrick     Out << "in ";
1221e5dd7070Spatrick   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Inout)
1222e5dd7070Spatrick     Out << "inout ";
1223e5dd7070Spatrick   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Out)
1224e5dd7070Spatrick     Out << "out ";
1225e5dd7070Spatrick   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Bycopy)
1226e5dd7070Spatrick     Out << "bycopy ";
1227e5dd7070Spatrick   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Byref)
1228e5dd7070Spatrick     Out << "byref ";
1229e5dd7070Spatrick   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Oneway)
1230e5dd7070Spatrick     Out << "oneway ";
1231e5dd7070Spatrick   if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_CSNullability) {
1232e5dd7070Spatrick     if (auto nullability = AttributedType::stripOuterNullability(T))
1233e5dd7070Spatrick       Out << getNullabilitySpelling(*nullability, true) << ' ';
1234e5dd7070Spatrick   }
1235e5dd7070Spatrick 
1236e5dd7070Spatrick   Out << Ctx.getUnqualifiedObjCPointerType(T).getAsString(Policy);
1237e5dd7070Spatrick   Out << ')';
1238e5dd7070Spatrick }
1239e5dd7070Spatrick 
1240e5dd7070Spatrick void DeclPrinter::PrintObjCTypeParams(ObjCTypeParamList *Params) {
1241e5dd7070Spatrick   Out << "<";
1242e5dd7070Spatrick   unsigned First = true;
1243e5dd7070Spatrick   for (auto *Param : *Params) {
1244e5dd7070Spatrick     if (First) {
1245e5dd7070Spatrick       First = false;
1246e5dd7070Spatrick     } else {
1247e5dd7070Spatrick       Out << ", ";
1248e5dd7070Spatrick     }
1249e5dd7070Spatrick 
1250e5dd7070Spatrick     switch (Param->getVariance()) {
1251e5dd7070Spatrick     case ObjCTypeParamVariance::Invariant:
1252e5dd7070Spatrick       break;
1253e5dd7070Spatrick 
1254e5dd7070Spatrick     case ObjCTypeParamVariance::Covariant:
1255e5dd7070Spatrick       Out << "__covariant ";
1256e5dd7070Spatrick       break;
1257e5dd7070Spatrick 
1258e5dd7070Spatrick     case ObjCTypeParamVariance::Contravariant:
1259e5dd7070Spatrick       Out << "__contravariant ";
1260e5dd7070Spatrick       break;
1261e5dd7070Spatrick     }
1262e5dd7070Spatrick 
1263*a9ac8606Spatrick     Out << Param->getDeclName();
1264e5dd7070Spatrick 
1265e5dd7070Spatrick     if (Param->hasExplicitBound()) {
1266e5dd7070Spatrick       Out << " : " << Param->getUnderlyingType().getAsString(Policy);
1267e5dd7070Spatrick     }
1268e5dd7070Spatrick   }
1269e5dd7070Spatrick   Out << ">";
1270e5dd7070Spatrick }
1271e5dd7070Spatrick 
1272e5dd7070Spatrick void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
1273e5dd7070Spatrick   if (OMD->isInstanceMethod())
1274e5dd7070Spatrick     Out << "- ";
1275e5dd7070Spatrick   else
1276e5dd7070Spatrick     Out << "+ ";
1277e5dd7070Spatrick   if (!OMD->getReturnType().isNull()) {
1278e5dd7070Spatrick     PrintObjCMethodType(OMD->getASTContext(), OMD->getObjCDeclQualifier(),
1279e5dd7070Spatrick                         OMD->getReturnType());
1280e5dd7070Spatrick   }
1281e5dd7070Spatrick 
1282e5dd7070Spatrick   std::string name = OMD->getSelector().getAsString();
1283e5dd7070Spatrick   std::string::size_type pos, lastPos = 0;
1284e5dd7070Spatrick   for (const auto *PI : OMD->parameters()) {
1285e5dd7070Spatrick     // FIXME: selector is missing here!
1286e5dd7070Spatrick     pos = name.find_first_of(':', lastPos);
1287e5dd7070Spatrick     if (lastPos != 0)
1288e5dd7070Spatrick       Out << " ";
1289e5dd7070Spatrick     Out << name.substr(lastPos, pos - lastPos) << ':';
1290e5dd7070Spatrick     PrintObjCMethodType(OMD->getASTContext(),
1291e5dd7070Spatrick                         PI->getObjCDeclQualifier(),
1292e5dd7070Spatrick                         PI->getType());
1293e5dd7070Spatrick     Out << *PI;
1294e5dd7070Spatrick     lastPos = pos + 1;
1295e5dd7070Spatrick   }
1296e5dd7070Spatrick 
1297e5dd7070Spatrick   if (OMD->param_begin() == OMD->param_end())
1298e5dd7070Spatrick     Out << name;
1299e5dd7070Spatrick 
1300e5dd7070Spatrick   if (OMD->isVariadic())
1301e5dd7070Spatrick       Out << ", ...";
1302e5dd7070Spatrick 
1303e5dd7070Spatrick   prettyPrintAttributes(OMD);
1304e5dd7070Spatrick 
1305e5dd7070Spatrick   if (OMD->getBody() && !Policy.TerseOutput) {
1306e5dd7070Spatrick     Out << ' ';
1307*a9ac8606Spatrick     OMD->getBody()->printPretty(Out, nullptr, Policy, Indentation, "\n",
1308*a9ac8606Spatrick                                 &Context);
1309e5dd7070Spatrick   }
1310e5dd7070Spatrick   else if (Policy.PolishForDeclaration)
1311e5dd7070Spatrick     Out << ';';
1312e5dd7070Spatrick }
1313e5dd7070Spatrick 
1314e5dd7070Spatrick void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
1315e5dd7070Spatrick   std::string I = OID->getNameAsString();
1316e5dd7070Spatrick   ObjCInterfaceDecl *SID = OID->getSuperClass();
1317e5dd7070Spatrick 
1318e5dd7070Spatrick   bool eolnOut = false;
1319e5dd7070Spatrick   if (SID)
1320e5dd7070Spatrick     Out << "@implementation " << I << " : " << *SID;
1321e5dd7070Spatrick   else
1322e5dd7070Spatrick     Out << "@implementation " << I;
1323e5dd7070Spatrick 
1324e5dd7070Spatrick   if (OID->ivar_size() > 0) {
1325e5dd7070Spatrick     Out << "{\n";
1326e5dd7070Spatrick     eolnOut = true;
1327e5dd7070Spatrick     Indentation += Policy.Indentation;
1328e5dd7070Spatrick     for (const auto *I : OID->ivars()) {
1329e5dd7070Spatrick       Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()).
1330e5dd7070Spatrick                     getAsString(Policy) << ' ' << *I << ";\n";
1331e5dd7070Spatrick     }
1332e5dd7070Spatrick     Indentation -= Policy.Indentation;
1333e5dd7070Spatrick     Out << "}\n";
1334e5dd7070Spatrick   }
1335e5dd7070Spatrick   else if (SID || (OID->decls_begin() != OID->decls_end())) {
1336e5dd7070Spatrick     Out << "\n";
1337e5dd7070Spatrick     eolnOut = true;
1338e5dd7070Spatrick   }
1339e5dd7070Spatrick   VisitDeclContext(OID, false);
1340e5dd7070Spatrick   if (!eolnOut)
1341e5dd7070Spatrick     Out << "\n";
1342e5dd7070Spatrick   Out << "@end";
1343e5dd7070Spatrick }
1344e5dd7070Spatrick 
1345e5dd7070Spatrick void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
1346e5dd7070Spatrick   std::string I = OID->getNameAsString();
1347e5dd7070Spatrick   ObjCInterfaceDecl *SID = OID->getSuperClass();
1348e5dd7070Spatrick 
1349e5dd7070Spatrick   if (!OID->isThisDeclarationADefinition()) {
1350e5dd7070Spatrick     Out << "@class " << I;
1351e5dd7070Spatrick 
1352e5dd7070Spatrick     if (auto TypeParams = OID->getTypeParamListAsWritten()) {
1353e5dd7070Spatrick       PrintObjCTypeParams(TypeParams);
1354e5dd7070Spatrick     }
1355e5dd7070Spatrick 
1356e5dd7070Spatrick     Out << ";";
1357e5dd7070Spatrick     return;
1358e5dd7070Spatrick   }
1359e5dd7070Spatrick   bool eolnOut = false;
1360e5dd7070Spatrick   Out << "@interface " << I;
1361e5dd7070Spatrick 
1362e5dd7070Spatrick   if (auto TypeParams = OID->getTypeParamListAsWritten()) {
1363e5dd7070Spatrick     PrintObjCTypeParams(TypeParams);
1364e5dd7070Spatrick   }
1365e5dd7070Spatrick 
1366e5dd7070Spatrick   if (SID)
1367e5dd7070Spatrick     Out << " : " << QualType(OID->getSuperClassType(), 0).getAsString(Policy);
1368e5dd7070Spatrick 
1369e5dd7070Spatrick   // Protocols?
1370e5dd7070Spatrick   const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
1371e5dd7070Spatrick   if (!Protocols.empty()) {
1372e5dd7070Spatrick     for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
1373e5dd7070Spatrick          E = Protocols.end(); I != E; ++I)
1374e5dd7070Spatrick       Out << (I == Protocols.begin() ? '<' : ',') << **I;
1375e5dd7070Spatrick     Out << "> ";
1376e5dd7070Spatrick   }
1377e5dd7070Spatrick 
1378e5dd7070Spatrick   if (OID->ivar_size() > 0) {
1379e5dd7070Spatrick     Out << "{\n";
1380e5dd7070Spatrick     eolnOut = true;
1381e5dd7070Spatrick     Indentation += Policy.Indentation;
1382e5dd7070Spatrick     for (const auto *I : OID->ivars()) {
1383e5dd7070Spatrick       Indent() << I->getASTContext()
1384e5dd7070Spatrick                       .getUnqualifiedObjCPointerType(I->getType())
1385e5dd7070Spatrick                       .getAsString(Policy) << ' ' << *I << ";\n";
1386e5dd7070Spatrick     }
1387e5dd7070Spatrick     Indentation -= Policy.Indentation;
1388e5dd7070Spatrick     Out << "}\n";
1389e5dd7070Spatrick   }
1390e5dd7070Spatrick   else if (SID || (OID->decls_begin() != OID->decls_end())) {
1391e5dd7070Spatrick     Out << "\n";
1392e5dd7070Spatrick     eolnOut = true;
1393e5dd7070Spatrick   }
1394e5dd7070Spatrick 
1395e5dd7070Spatrick   VisitDeclContext(OID, false);
1396e5dd7070Spatrick   if (!eolnOut)
1397e5dd7070Spatrick     Out << "\n";
1398e5dd7070Spatrick   Out << "@end";
1399e5dd7070Spatrick   // FIXME: implement the rest...
1400e5dd7070Spatrick }
1401e5dd7070Spatrick 
1402e5dd7070Spatrick void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
1403e5dd7070Spatrick   if (!PID->isThisDeclarationADefinition()) {
1404e5dd7070Spatrick     Out << "@protocol " << *PID << ";\n";
1405e5dd7070Spatrick     return;
1406e5dd7070Spatrick   }
1407e5dd7070Spatrick   // Protocols?
1408e5dd7070Spatrick   const ObjCList<ObjCProtocolDecl> &Protocols = PID->getReferencedProtocols();
1409e5dd7070Spatrick   if (!Protocols.empty()) {
1410e5dd7070Spatrick     Out << "@protocol " << *PID;
1411e5dd7070Spatrick     for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
1412e5dd7070Spatrick          E = Protocols.end(); I != E; ++I)
1413e5dd7070Spatrick       Out << (I == Protocols.begin() ? '<' : ',') << **I;
1414e5dd7070Spatrick     Out << ">\n";
1415e5dd7070Spatrick   } else
1416e5dd7070Spatrick     Out << "@protocol " << *PID << '\n';
1417e5dd7070Spatrick   VisitDeclContext(PID, false);
1418e5dd7070Spatrick   Out << "@end";
1419e5dd7070Spatrick }
1420e5dd7070Spatrick 
1421e5dd7070Spatrick void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
1422ec727ea7Spatrick   Out << "@implementation ";
1423ec727ea7Spatrick   if (const auto *CID = PID->getClassInterface())
1424ec727ea7Spatrick     Out << *CID;
1425ec727ea7Spatrick   else
1426ec727ea7Spatrick     Out << "<<error-type>>";
1427ec727ea7Spatrick   Out << '(' << *PID << ")\n";
1428e5dd7070Spatrick 
1429e5dd7070Spatrick   VisitDeclContext(PID, false);
1430e5dd7070Spatrick   Out << "@end";
1431e5dd7070Spatrick   // FIXME: implement the rest...
1432e5dd7070Spatrick }
1433e5dd7070Spatrick 
1434e5dd7070Spatrick void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
1435ec727ea7Spatrick   Out << "@interface ";
1436ec727ea7Spatrick   if (const auto *CID = PID->getClassInterface())
1437ec727ea7Spatrick     Out << *CID;
1438ec727ea7Spatrick   else
1439ec727ea7Spatrick     Out << "<<error-type>>";
1440e5dd7070Spatrick   if (auto TypeParams = PID->getTypeParamList()) {
1441e5dd7070Spatrick     PrintObjCTypeParams(TypeParams);
1442e5dd7070Spatrick   }
1443e5dd7070Spatrick   Out << "(" << *PID << ")\n";
1444e5dd7070Spatrick   if (PID->ivar_size() > 0) {
1445e5dd7070Spatrick     Out << "{\n";
1446e5dd7070Spatrick     Indentation += Policy.Indentation;
1447e5dd7070Spatrick     for (const auto *I : PID->ivars())
1448e5dd7070Spatrick       Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()).
1449e5dd7070Spatrick                     getAsString(Policy) << ' ' << *I << ";\n";
1450e5dd7070Spatrick     Indentation -= Policy.Indentation;
1451e5dd7070Spatrick     Out << "}\n";
1452e5dd7070Spatrick   }
1453e5dd7070Spatrick 
1454e5dd7070Spatrick   VisitDeclContext(PID, false);
1455e5dd7070Spatrick   Out << "@end";
1456e5dd7070Spatrick 
1457e5dd7070Spatrick   // FIXME: implement the rest...
1458e5dd7070Spatrick }
1459e5dd7070Spatrick 
1460e5dd7070Spatrick void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) {
1461e5dd7070Spatrick   Out << "@compatibility_alias " << *AID
1462e5dd7070Spatrick       << ' ' << *AID->getClassInterface() << ";\n";
1463e5dd7070Spatrick }
1464e5dd7070Spatrick 
1465e5dd7070Spatrick /// PrintObjCPropertyDecl - print a property declaration.
1466e5dd7070Spatrick ///
1467e5dd7070Spatrick /// Print attributes in the following order:
1468e5dd7070Spatrick /// - class
1469e5dd7070Spatrick /// - nonatomic | atomic
1470e5dd7070Spatrick /// - assign | retain | strong | copy | weak | unsafe_unretained
1471e5dd7070Spatrick /// - readwrite | readonly
1472e5dd7070Spatrick /// - getter & setter
1473e5dd7070Spatrick /// - nullability
1474e5dd7070Spatrick void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
1475e5dd7070Spatrick   if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Required)
1476e5dd7070Spatrick     Out << "@required\n";
1477e5dd7070Spatrick   else if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Optional)
1478e5dd7070Spatrick     Out << "@optional\n";
1479e5dd7070Spatrick 
1480e5dd7070Spatrick   QualType T = PDecl->getType();
1481e5dd7070Spatrick 
1482e5dd7070Spatrick   Out << "@property";
1483ec727ea7Spatrick   if (PDecl->getPropertyAttributes() != ObjCPropertyAttribute::kind_noattr) {
1484e5dd7070Spatrick     bool first = true;
1485e5dd7070Spatrick     Out << "(";
1486ec727ea7Spatrick     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_class) {
1487e5dd7070Spatrick       Out << (first ? "" : ", ") << "class";
1488e5dd7070Spatrick       first = false;
1489e5dd7070Spatrick     }
1490e5dd7070Spatrick 
1491ec727ea7Spatrick     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_direct) {
1492e5dd7070Spatrick       Out << (first ? "" : ", ") << "direct";
1493e5dd7070Spatrick       first = false;
1494e5dd7070Spatrick     }
1495e5dd7070Spatrick 
1496e5dd7070Spatrick     if (PDecl->getPropertyAttributes() &
1497ec727ea7Spatrick         ObjCPropertyAttribute::kind_nonatomic) {
1498e5dd7070Spatrick       Out << (first ? "" : ", ") << "nonatomic";
1499e5dd7070Spatrick       first = false;
1500e5dd7070Spatrick     }
1501ec727ea7Spatrick     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_atomic) {
1502e5dd7070Spatrick       Out << (first ? "" : ", ") << "atomic";
1503e5dd7070Spatrick       first = false;
1504e5dd7070Spatrick     }
1505e5dd7070Spatrick 
1506ec727ea7Spatrick     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_assign) {
1507e5dd7070Spatrick       Out << (first ? "" : ", ") << "assign";
1508e5dd7070Spatrick       first = false;
1509e5dd7070Spatrick     }
1510ec727ea7Spatrick     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_retain) {
1511e5dd7070Spatrick       Out << (first ? "" : ", ") << "retain";
1512e5dd7070Spatrick       first = false;
1513e5dd7070Spatrick     }
1514e5dd7070Spatrick 
1515ec727ea7Spatrick     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_strong) {
1516e5dd7070Spatrick       Out << (first ? "" : ", ") << "strong";
1517e5dd7070Spatrick       first = false;
1518e5dd7070Spatrick     }
1519ec727ea7Spatrick     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_copy) {
1520e5dd7070Spatrick       Out << (first ? "" : ", ") << "copy";
1521e5dd7070Spatrick       first = false;
1522e5dd7070Spatrick     }
1523ec727ea7Spatrick     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak) {
1524e5dd7070Spatrick       Out << (first ? "" : ", ") << "weak";
1525e5dd7070Spatrick       first = false;
1526e5dd7070Spatrick     }
1527ec727ea7Spatrick     if (PDecl->getPropertyAttributes() &
1528ec727ea7Spatrick         ObjCPropertyAttribute::kind_unsafe_unretained) {
1529e5dd7070Spatrick       Out << (first ? "" : ", ") << "unsafe_unretained";
1530e5dd7070Spatrick       first = false;
1531e5dd7070Spatrick     }
1532e5dd7070Spatrick 
1533e5dd7070Spatrick     if (PDecl->getPropertyAttributes() &
1534ec727ea7Spatrick         ObjCPropertyAttribute::kind_readwrite) {
1535e5dd7070Spatrick       Out << (first ? "" : ", ") << "readwrite";
1536e5dd7070Spatrick       first = false;
1537e5dd7070Spatrick     }
1538ec727ea7Spatrick     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly) {
1539e5dd7070Spatrick       Out << (first ? "" : ", ") << "readonly";
1540e5dd7070Spatrick       first = false;
1541e5dd7070Spatrick     }
1542e5dd7070Spatrick 
1543ec727ea7Spatrick     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_getter) {
1544e5dd7070Spatrick       Out << (first ? "" : ", ") << "getter = ";
1545e5dd7070Spatrick       PDecl->getGetterName().print(Out);
1546e5dd7070Spatrick       first = false;
1547e5dd7070Spatrick     }
1548ec727ea7Spatrick     if (PDecl->getPropertyAttributes() & ObjCPropertyAttribute::kind_setter) {
1549e5dd7070Spatrick       Out << (first ? "" : ", ") << "setter = ";
1550e5dd7070Spatrick       PDecl->getSetterName().print(Out);
1551e5dd7070Spatrick       first = false;
1552e5dd7070Spatrick     }
1553e5dd7070Spatrick 
1554e5dd7070Spatrick     if (PDecl->getPropertyAttributes() &
1555ec727ea7Spatrick         ObjCPropertyAttribute::kind_nullability) {
1556e5dd7070Spatrick       if (auto nullability = AttributedType::stripOuterNullability(T)) {
1557e5dd7070Spatrick         if (*nullability == NullabilityKind::Unspecified &&
1558e5dd7070Spatrick             (PDecl->getPropertyAttributes() &
1559ec727ea7Spatrick              ObjCPropertyAttribute::kind_null_resettable)) {
1560e5dd7070Spatrick           Out << (first ? "" : ", ") << "null_resettable";
1561e5dd7070Spatrick         } else {
1562e5dd7070Spatrick           Out << (first ? "" : ", ")
1563e5dd7070Spatrick               << getNullabilitySpelling(*nullability, true);
1564e5dd7070Spatrick         }
1565e5dd7070Spatrick         first = false;
1566e5dd7070Spatrick       }
1567e5dd7070Spatrick     }
1568e5dd7070Spatrick 
1569e5dd7070Spatrick     (void) first; // Silence dead store warning due to idiomatic code.
1570e5dd7070Spatrick     Out << ")";
1571e5dd7070Spatrick   }
1572e5dd7070Spatrick   std::string TypeStr = PDecl->getASTContext().getUnqualifiedObjCPointerType(T).
1573e5dd7070Spatrick       getAsString(Policy);
1574e5dd7070Spatrick   Out << ' ' << TypeStr;
1575e5dd7070Spatrick   if (!StringRef(TypeStr).endswith("*"))
1576e5dd7070Spatrick     Out << ' ';
1577e5dd7070Spatrick   Out << *PDecl;
1578e5dd7070Spatrick   if (Policy.PolishForDeclaration)
1579e5dd7070Spatrick     Out << ';';
1580e5dd7070Spatrick }
1581e5dd7070Spatrick 
1582e5dd7070Spatrick void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
1583e5dd7070Spatrick   if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize)
1584e5dd7070Spatrick     Out << "@synthesize ";
1585e5dd7070Spatrick   else
1586e5dd7070Spatrick     Out << "@dynamic ";
1587e5dd7070Spatrick   Out << *PID->getPropertyDecl();
1588e5dd7070Spatrick   if (PID->getPropertyIvarDecl())
1589e5dd7070Spatrick     Out << '=' << *PID->getPropertyIvarDecl();
1590e5dd7070Spatrick }
1591e5dd7070Spatrick 
1592e5dd7070Spatrick void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
1593e5dd7070Spatrick   if (!D->isAccessDeclaration())
1594e5dd7070Spatrick     Out << "using ";
1595e5dd7070Spatrick   if (D->hasTypename())
1596e5dd7070Spatrick     Out << "typename ";
1597e5dd7070Spatrick   D->getQualifier()->print(Out, Policy);
1598e5dd7070Spatrick 
1599e5dd7070Spatrick   // Use the correct record name when the using declaration is used for
1600e5dd7070Spatrick   // inheriting constructors.
1601e5dd7070Spatrick   for (const auto *Shadow : D->shadows()) {
1602e5dd7070Spatrick     if (const auto *ConstructorShadow =
1603e5dd7070Spatrick             dyn_cast<ConstructorUsingShadowDecl>(Shadow)) {
1604e5dd7070Spatrick       assert(Shadow->getDeclContext() == ConstructorShadow->getDeclContext());
1605e5dd7070Spatrick       Out << *ConstructorShadow->getNominatedBaseClass();
1606e5dd7070Spatrick       return;
1607e5dd7070Spatrick     }
1608e5dd7070Spatrick   }
1609e5dd7070Spatrick   Out << *D;
1610e5dd7070Spatrick }
1611e5dd7070Spatrick 
1612*a9ac8606Spatrick void DeclPrinter::VisitUsingEnumDecl(UsingEnumDecl *D) {
1613*a9ac8606Spatrick   Out << "using enum " << D->getEnumDecl();
1614*a9ac8606Spatrick }
1615*a9ac8606Spatrick 
1616e5dd7070Spatrick void
1617e5dd7070Spatrick DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
1618e5dd7070Spatrick   Out << "using typename ";
1619e5dd7070Spatrick   D->getQualifier()->print(Out, Policy);
1620e5dd7070Spatrick   Out << D->getDeclName();
1621e5dd7070Spatrick }
1622e5dd7070Spatrick 
1623e5dd7070Spatrick void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
1624e5dd7070Spatrick   if (!D->isAccessDeclaration())
1625e5dd7070Spatrick     Out << "using ";
1626e5dd7070Spatrick   D->getQualifier()->print(Out, Policy);
1627e5dd7070Spatrick   Out << D->getDeclName();
1628e5dd7070Spatrick }
1629e5dd7070Spatrick 
1630e5dd7070Spatrick void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) {
1631e5dd7070Spatrick   // ignore
1632e5dd7070Spatrick }
1633e5dd7070Spatrick 
1634e5dd7070Spatrick void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
1635e5dd7070Spatrick   Out << "#pragma omp threadprivate";
1636e5dd7070Spatrick   if (!D->varlist_empty()) {
1637e5dd7070Spatrick     for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
1638e5dd7070Spatrick                                                 E = D->varlist_end();
1639e5dd7070Spatrick                                                 I != E; ++I) {
1640e5dd7070Spatrick       Out << (I == D->varlist_begin() ? '(' : ',');
1641e5dd7070Spatrick       NamedDecl *ND = cast<DeclRefExpr>(*I)->getDecl();
1642e5dd7070Spatrick       ND->printQualifiedName(Out);
1643e5dd7070Spatrick     }
1644e5dd7070Spatrick     Out << ")";
1645e5dd7070Spatrick   }
1646e5dd7070Spatrick }
1647e5dd7070Spatrick 
1648e5dd7070Spatrick void DeclPrinter::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
1649e5dd7070Spatrick   Out << "#pragma omp allocate";
1650e5dd7070Spatrick   if (!D->varlist_empty()) {
1651e5dd7070Spatrick     for (OMPAllocateDecl::varlist_iterator I = D->varlist_begin(),
1652e5dd7070Spatrick                                            E = D->varlist_end();
1653e5dd7070Spatrick          I != E; ++I) {
1654e5dd7070Spatrick       Out << (I == D->varlist_begin() ? '(' : ',');
1655e5dd7070Spatrick       NamedDecl *ND = cast<DeclRefExpr>(*I)->getDecl();
1656e5dd7070Spatrick       ND->printQualifiedName(Out);
1657e5dd7070Spatrick     }
1658e5dd7070Spatrick     Out << ")";
1659e5dd7070Spatrick   }
1660e5dd7070Spatrick   if (!D->clauselist_empty()) {
1661e5dd7070Spatrick     Out << " ";
1662e5dd7070Spatrick     OMPClausePrinter Printer(Out, Policy);
1663e5dd7070Spatrick     for (OMPClause *C : D->clauselists())
1664e5dd7070Spatrick       Printer.Visit(C);
1665e5dd7070Spatrick   }
1666e5dd7070Spatrick }
1667e5dd7070Spatrick 
1668e5dd7070Spatrick void DeclPrinter::VisitOMPRequiresDecl(OMPRequiresDecl *D) {
1669e5dd7070Spatrick   Out << "#pragma omp requires ";
1670e5dd7070Spatrick   if (!D->clauselist_empty()) {
1671e5dd7070Spatrick     OMPClausePrinter Printer(Out, Policy);
1672e5dd7070Spatrick     for (auto I = D->clauselist_begin(), E = D->clauselist_end(); I != E; ++I)
1673e5dd7070Spatrick       Printer.Visit(*I);
1674e5dd7070Spatrick   }
1675e5dd7070Spatrick }
1676e5dd7070Spatrick 
1677e5dd7070Spatrick void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
1678e5dd7070Spatrick   if (!D->isInvalidDecl()) {
1679e5dd7070Spatrick     Out << "#pragma omp declare reduction (";
1680e5dd7070Spatrick     if (D->getDeclName().getNameKind() == DeclarationName::CXXOperatorName) {
1681e5dd7070Spatrick       const char *OpName =
1682e5dd7070Spatrick           getOperatorSpelling(D->getDeclName().getCXXOverloadedOperator());
1683e5dd7070Spatrick       assert(OpName && "not an overloaded operator");
1684e5dd7070Spatrick       Out << OpName;
1685e5dd7070Spatrick     } else {
1686e5dd7070Spatrick       assert(D->getDeclName().isIdentifier());
1687e5dd7070Spatrick       D->printName(Out);
1688e5dd7070Spatrick     }
1689e5dd7070Spatrick     Out << " : ";
1690e5dd7070Spatrick     D->getType().print(Out, Policy);
1691e5dd7070Spatrick     Out << " : ";
1692*a9ac8606Spatrick     D->getCombiner()->printPretty(Out, nullptr, Policy, 0, "\n", &Context);
1693e5dd7070Spatrick     Out << ")";
1694e5dd7070Spatrick     if (auto *Init = D->getInitializer()) {
1695e5dd7070Spatrick       Out << " initializer(";
1696e5dd7070Spatrick       switch (D->getInitializerKind()) {
1697e5dd7070Spatrick       case OMPDeclareReductionDecl::DirectInit:
1698e5dd7070Spatrick         Out << "omp_priv(";
1699e5dd7070Spatrick         break;
1700e5dd7070Spatrick       case OMPDeclareReductionDecl::CopyInit:
1701e5dd7070Spatrick         Out << "omp_priv = ";
1702e5dd7070Spatrick         break;
1703e5dd7070Spatrick       case OMPDeclareReductionDecl::CallInit:
1704e5dd7070Spatrick         break;
1705e5dd7070Spatrick       }
1706*a9ac8606Spatrick       Init->printPretty(Out, nullptr, Policy, 0, "\n", &Context);
1707e5dd7070Spatrick       if (D->getInitializerKind() == OMPDeclareReductionDecl::DirectInit)
1708e5dd7070Spatrick         Out << ")";
1709e5dd7070Spatrick       Out << ")";
1710e5dd7070Spatrick     }
1711e5dd7070Spatrick   }
1712e5dd7070Spatrick }
1713e5dd7070Spatrick 
1714e5dd7070Spatrick void DeclPrinter::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
1715e5dd7070Spatrick   if (!D->isInvalidDecl()) {
1716e5dd7070Spatrick     Out << "#pragma omp declare mapper (";
1717e5dd7070Spatrick     D->printName(Out);
1718e5dd7070Spatrick     Out << " : ";
1719e5dd7070Spatrick     D->getType().print(Out, Policy);
1720e5dd7070Spatrick     Out << " ";
1721e5dd7070Spatrick     Out << D->getVarName();
1722e5dd7070Spatrick     Out << ")";
1723e5dd7070Spatrick     if (!D->clauselist_empty()) {
1724e5dd7070Spatrick       OMPClausePrinter Printer(Out, Policy);
1725e5dd7070Spatrick       for (auto *C : D->clauselists()) {
1726e5dd7070Spatrick         Out << " ";
1727e5dd7070Spatrick         Printer.Visit(C);
1728e5dd7070Spatrick       }
1729e5dd7070Spatrick     }
1730e5dd7070Spatrick   }
1731e5dd7070Spatrick }
1732e5dd7070Spatrick 
1733e5dd7070Spatrick void DeclPrinter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
1734*a9ac8606Spatrick   D->getInit()->printPretty(Out, nullptr, Policy, Indentation, "\n", &Context);
1735e5dd7070Spatrick }
1736e5dd7070Spatrick 
1737ec727ea7Spatrick void DeclPrinter::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *TTP) {
1738ec727ea7Spatrick   if (const TypeConstraint *TC = TTP->getTypeConstraint())
1739ec727ea7Spatrick     TC->print(Out, Policy);
1740ec727ea7Spatrick   else if (TTP->wasDeclaredWithTypename())
1741ec727ea7Spatrick     Out << "typename";
1742ec727ea7Spatrick   else
1743ec727ea7Spatrick     Out << "class";
1744ec727ea7Spatrick 
1745ec727ea7Spatrick   if (TTP->isParameterPack())
1746ec727ea7Spatrick     Out << " ...";
1747*a9ac8606Spatrick   else if (TTP->getDeclName())
1748ec727ea7Spatrick     Out << ' ';
1749ec727ea7Spatrick 
1750*a9ac8606Spatrick   if (TTP->getDeclName())
1751*a9ac8606Spatrick     Out << TTP->getDeclName();
1752ec727ea7Spatrick 
1753ec727ea7Spatrick   if (TTP->hasDefaultArgument()) {
1754ec727ea7Spatrick     Out << " = ";
1755ec727ea7Spatrick     Out << TTP->getDefaultArgument().getAsString(Policy);
1756ec727ea7Spatrick   }
1757ec727ea7Spatrick }
1758ec727ea7Spatrick 
1759ec727ea7Spatrick void DeclPrinter::VisitNonTypeTemplateParmDecl(
1760ec727ea7Spatrick     const NonTypeTemplateParmDecl *NTTP) {
1761ec727ea7Spatrick   StringRef Name;
1762ec727ea7Spatrick   if (IdentifierInfo *II = NTTP->getIdentifier())
1763ec727ea7Spatrick     Name = II->getName();
1764ec727ea7Spatrick   printDeclType(NTTP->getType(), Name, NTTP->isParameterPack());
1765ec727ea7Spatrick 
1766ec727ea7Spatrick   if (NTTP->hasDefaultArgument()) {
1767ec727ea7Spatrick     Out << " = ";
1768*a9ac8606Spatrick     NTTP->getDefaultArgument()->printPretty(Out, nullptr, Policy, Indentation,
1769*a9ac8606Spatrick                                             "\n", &Context);
1770ec727ea7Spatrick   }
1771ec727ea7Spatrick }
1772