1f4a2713aSLionel Sambuc //===--- DeclPrinter.cpp - Printing implementation for Decl ASTs ----------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This file implements the Decl::print method, which pretty prints the
11f4a2713aSLionel Sambuc // AST back out to C/Objective-C/C++/Objective-C++ code.
12f4a2713aSLionel Sambuc //
13f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
14f4a2713aSLionel Sambuc #include "clang/AST/ASTContext.h"
15f4a2713aSLionel Sambuc #include "clang/AST/Attr.h"
16f4a2713aSLionel Sambuc #include "clang/AST/Decl.h"
17f4a2713aSLionel Sambuc #include "clang/AST/DeclCXX.h"
18f4a2713aSLionel Sambuc #include "clang/AST/DeclObjC.h"
19f4a2713aSLionel Sambuc #include "clang/AST/DeclVisitor.h"
20f4a2713aSLionel Sambuc #include "clang/AST/Expr.h"
21f4a2713aSLionel Sambuc #include "clang/AST/ExprCXX.h"
22f4a2713aSLionel Sambuc #include "clang/AST/PrettyPrinter.h"
23f4a2713aSLionel Sambuc #include "clang/Basic/Module.h"
24f4a2713aSLionel Sambuc #include "llvm/Support/raw_ostream.h"
25f4a2713aSLionel Sambuc using namespace clang;
26f4a2713aSLionel Sambuc 
27f4a2713aSLionel Sambuc namespace {
28f4a2713aSLionel Sambuc   class DeclPrinter : public DeclVisitor<DeclPrinter> {
29f4a2713aSLionel Sambuc     raw_ostream &Out;
30f4a2713aSLionel Sambuc     PrintingPolicy Policy;
31f4a2713aSLionel Sambuc     unsigned Indentation;
32f4a2713aSLionel Sambuc     bool PrintInstantiation;
33f4a2713aSLionel Sambuc 
Indent()34f4a2713aSLionel Sambuc     raw_ostream& Indent() { return Indent(Indentation); }
35f4a2713aSLionel Sambuc     raw_ostream& Indent(unsigned Indentation);
36f4a2713aSLionel Sambuc     void ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls);
37f4a2713aSLionel Sambuc 
38f4a2713aSLionel Sambuc     void Print(AccessSpecifier AS);
39f4a2713aSLionel Sambuc 
40f4a2713aSLionel Sambuc   public:
DeclPrinter(raw_ostream & Out,const PrintingPolicy & Policy,unsigned Indentation=0,bool PrintInstantiation=false)41f4a2713aSLionel Sambuc     DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
42f4a2713aSLionel Sambuc                 unsigned Indentation = 0, bool PrintInstantiation = false)
43f4a2713aSLionel Sambuc       : Out(Out), Policy(Policy), Indentation(Indentation),
44f4a2713aSLionel Sambuc         PrintInstantiation(PrintInstantiation) { }
45f4a2713aSLionel Sambuc 
46f4a2713aSLionel Sambuc     void VisitDeclContext(DeclContext *DC, bool Indent = true);
47f4a2713aSLionel Sambuc 
48f4a2713aSLionel Sambuc     void VisitTranslationUnitDecl(TranslationUnitDecl *D);
49f4a2713aSLionel Sambuc     void VisitTypedefDecl(TypedefDecl *D);
50f4a2713aSLionel Sambuc     void VisitTypeAliasDecl(TypeAliasDecl *D);
51f4a2713aSLionel Sambuc     void VisitEnumDecl(EnumDecl *D);
52f4a2713aSLionel Sambuc     void VisitRecordDecl(RecordDecl *D);
53f4a2713aSLionel Sambuc     void VisitEnumConstantDecl(EnumConstantDecl *D);
54f4a2713aSLionel Sambuc     void VisitEmptyDecl(EmptyDecl *D);
55f4a2713aSLionel Sambuc     void VisitFunctionDecl(FunctionDecl *D);
56f4a2713aSLionel Sambuc     void VisitFriendDecl(FriendDecl *D);
57f4a2713aSLionel Sambuc     void VisitFieldDecl(FieldDecl *D);
58f4a2713aSLionel Sambuc     void VisitVarDecl(VarDecl *D);
59f4a2713aSLionel Sambuc     void VisitLabelDecl(LabelDecl *D);
60f4a2713aSLionel Sambuc     void VisitParmVarDecl(ParmVarDecl *D);
61f4a2713aSLionel Sambuc     void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
62f4a2713aSLionel Sambuc     void VisitImportDecl(ImportDecl *D);
63f4a2713aSLionel Sambuc     void VisitStaticAssertDecl(StaticAssertDecl *D);
64f4a2713aSLionel Sambuc     void VisitNamespaceDecl(NamespaceDecl *D);
65f4a2713aSLionel Sambuc     void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
66f4a2713aSLionel Sambuc     void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
67f4a2713aSLionel Sambuc     void VisitCXXRecordDecl(CXXRecordDecl *D);
68f4a2713aSLionel Sambuc     void VisitLinkageSpecDecl(LinkageSpecDecl *D);
69f4a2713aSLionel Sambuc     void VisitTemplateDecl(const TemplateDecl *D);
70f4a2713aSLionel Sambuc     void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
71f4a2713aSLionel Sambuc     void VisitClassTemplateDecl(ClassTemplateDecl *D);
72f4a2713aSLionel Sambuc     void VisitObjCMethodDecl(ObjCMethodDecl *D);
73f4a2713aSLionel Sambuc     void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
74f4a2713aSLionel Sambuc     void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
75f4a2713aSLionel Sambuc     void VisitObjCProtocolDecl(ObjCProtocolDecl *D);
76f4a2713aSLionel Sambuc     void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
77f4a2713aSLionel Sambuc     void VisitObjCCategoryDecl(ObjCCategoryDecl *D);
78f4a2713aSLionel Sambuc     void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
79f4a2713aSLionel Sambuc     void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
80f4a2713aSLionel Sambuc     void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
81f4a2713aSLionel Sambuc     void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
82f4a2713aSLionel Sambuc     void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
83f4a2713aSLionel Sambuc     void VisitUsingDecl(UsingDecl *D);
84f4a2713aSLionel Sambuc     void VisitUsingShadowDecl(UsingShadowDecl *D);
85f4a2713aSLionel Sambuc     void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
86f4a2713aSLionel Sambuc 
87f4a2713aSLionel Sambuc     void PrintTemplateParameters(const TemplateParameterList *Params,
88*0a6a1f1dSLionel Sambuc                                  const TemplateArgumentList *Args = nullptr);
89f4a2713aSLionel Sambuc     void prettyPrintAttributes(Decl *D);
90*0a6a1f1dSLionel Sambuc     void printDeclType(QualType T, StringRef DeclName, bool Pack = false);
91f4a2713aSLionel Sambuc   };
92f4a2713aSLionel Sambuc }
93f4a2713aSLionel Sambuc 
print(raw_ostream & Out,unsigned Indentation,bool PrintInstantiation) const94f4a2713aSLionel Sambuc void Decl::print(raw_ostream &Out, unsigned Indentation,
95f4a2713aSLionel Sambuc                  bool PrintInstantiation) const {
96f4a2713aSLionel Sambuc   print(Out, getASTContext().getPrintingPolicy(), Indentation, PrintInstantiation);
97f4a2713aSLionel Sambuc }
98f4a2713aSLionel Sambuc 
print(raw_ostream & Out,const PrintingPolicy & Policy,unsigned Indentation,bool PrintInstantiation) const99f4a2713aSLionel Sambuc void Decl::print(raw_ostream &Out, const PrintingPolicy &Policy,
100f4a2713aSLionel Sambuc                  unsigned Indentation, bool PrintInstantiation) const {
101f4a2713aSLionel Sambuc   DeclPrinter Printer(Out, Policy, Indentation, PrintInstantiation);
102f4a2713aSLionel Sambuc   Printer.Visit(const_cast<Decl*>(this));
103f4a2713aSLionel Sambuc }
104f4a2713aSLionel Sambuc 
GetBaseType(QualType T)105f4a2713aSLionel Sambuc static QualType GetBaseType(QualType T) {
106f4a2713aSLionel Sambuc   // FIXME: This should be on the Type class!
107f4a2713aSLionel Sambuc   QualType BaseType = T;
108f4a2713aSLionel Sambuc   while (!BaseType->isSpecifierType()) {
109f4a2713aSLionel Sambuc     if (isa<TypedefType>(BaseType))
110f4a2713aSLionel Sambuc       break;
111f4a2713aSLionel Sambuc     else if (const PointerType* PTy = BaseType->getAs<PointerType>())
112f4a2713aSLionel Sambuc       BaseType = PTy->getPointeeType();
113f4a2713aSLionel Sambuc     else if (const BlockPointerType *BPy = BaseType->getAs<BlockPointerType>())
114f4a2713aSLionel Sambuc       BaseType = BPy->getPointeeType();
115f4a2713aSLionel Sambuc     else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType))
116f4a2713aSLionel Sambuc       BaseType = ATy->getElementType();
117f4a2713aSLionel Sambuc     else if (const FunctionType* FTy = BaseType->getAs<FunctionType>())
118*0a6a1f1dSLionel Sambuc       BaseType = FTy->getReturnType();
119f4a2713aSLionel Sambuc     else if (const VectorType *VTy = BaseType->getAs<VectorType>())
120f4a2713aSLionel Sambuc       BaseType = VTy->getElementType();
121f4a2713aSLionel Sambuc     else if (const ReferenceType *RTy = BaseType->getAs<ReferenceType>())
122f4a2713aSLionel Sambuc       BaseType = RTy->getPointeeType();
123f4a2713aSLionel Sambuc     else
124f4a2713aSLionel Sambuc       llvm_unreachable("Unknown declarator!");
125f4a2713aSLionel Sambuc   }
126f4a2713aSLionel Sambuc   return BaseType;
127f4a2713aSLionel Sambuc }
128f4a2713aSLionel Sambuc 
getDeclType(Decl * D)129f4a2713aSLionel Sambuc static QualType getDeclType(Decl* D) {
130f4a2713aSLionel Sambuc   if (TypedefNameDecl* TDD = dyn_cast<TypedefNameDecl>(D))
131f4a2713aSLionel Sambuc     return TDD->getUnderlyingType();
132f4a2713aSLionel Sambuc   if (ValueDecl* VD = dyn_cast<ValueDecl>(D))
133f4a2713aSLionel Sambuc     return VD->getType();
134f4a2713aSLionel Sambuc   return QualType();
135f4a2713aSLionel Sambuc }
136f4a2713aSLionel Sambuc 
printGroup(Decl ** Begin,unsigned NumDecls,raw_ostream & Out,const PrintingPolicy & Policy,unsigned Indentation)137f4a2713aSLionel Sambuc void Decl::printGroup(Decl** Begin, unsigned NumDecls,
138f4a2713aSLionel Sambuc                       raw_ostream &Out, const PrintingPolicy &Policy,
139f4a2713aSLionel Sambuc                       unsigned Indentation) {
140f4a2713aSLionel Sambuc   if (NumDecls == 1) {
141f4a2713aSLionel Sambuc     (*Begin)->print(Out, Policy, Indentation);
142f4a2713aSLionel Sambuc     return;
143f4a2713aSLionel Sambuc   }
144f4a2713aSLionel Sambuc 
145f4a2713aSLionel Sambuc   Decl** End = Begin + NumDecls;
146f4a2713aSLionel Sambuc   TagDecl* TD = dyn_cast<TagDecl>(*Begin);
147f4a2713aSLionel Sambuc   if (TD)
148f4a2713aSLionel Sambuc     ++Begin;
149f4a2713aSLionel Sambuc 
150f4a2713aSLionel Sambuc   PrintingPolicy SubPolicy(Policy);
151f4a2713aSLionel Sambuc   if (TD && TD->isCompleteDefinition()) {
152f4a2713aSLionel Sambuc     TD->print(Out, Policy, Indentation);
153f4a2713aSLionel Sambuc     Out << " ";
154f4a2713aSLionel Sambuc     SubPolicy.SuppressTag = true;
155f4a2713aSLionel Sambuc   }
156f4a2713aSLionel Sambuc 
157f4a2713aSLionel Sambuc   bool isFirst = true;
158f4a2713aSLionel Sambuc   for ( ; Begin != End; ++Begin) {
159f4a2713aSLionel Sambuc     if (isFirst) {
160f4a2713aSLionel Sambuc       SubPolicy.SuppressSpecifiers = false;
161f4a2713aSLionel Sambuc       isFirst = false;
162f4a2713aSLionel Sambuc     } else {
163f4a2713aSLionel Sambuc       if (!isFirst) Out << ", ";
164f4a2713aSLionel Sambuc       SubPolicy.SuppressSpecifiers = true;
165f4a2713aSLionel Sambuc     }
166f4a2713aSLionel Sambuc 
167f4a2713aSLionel Sambuc     (*Begin)->print(Out, SubPolicy, Indentation);
168f4a2713aSLionel Sambuc   }
169f4a2713aSLionel Sambuc }
170f4a2713aSLionel Sambuc 
dumpDeclContext() const171*0a6a1f1dSLionel Sambuc LLVM_DUMP_METHOD void DeclContext::dumpDeclContext() const {
172f4a2713aSLionel Sambuc   // Get the translation unit
173f4a2713aSLionel Sambuc   const DeclContext *DC = this;
174f4a2713aSLionel Sambuc   while (!DC->isTranslationUnit())
175f4a2713aSLionel Sambuc     DC = DC->getParent();
176f4a2713aSLionel Sambuc 
177f4a2713aSLionel Sambuc   ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
178f4a2713aSLionel Sambuc   DeclPrinter Printer(llvm::errs(), Ctx.getPrintingPolicy(), 0);
179f4a2713aSLionel Sambuc   Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false);
180f4a2713aSLionel Sambuc }
181f4a2713aSLionel Sambuc 
Indent(unsigned Indentation)182f4a2713aSLionel Sambuc raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
183f4a2713aSLionel Sambuc   for (unsigned i = 0; i != Indentation; ++i)
184f4a2713aSLionel Sambuc     Out << "  ";
185f4a2713aSLionel Sambuc   return Out;
186f4a2713aSLionel Sambuc }
187f4a2713aSLionel Sambuc 
prettyPrintAttributes(Decl * D)188f4a2713aSLionel Sambuc void DeclPrinter::prettyPrintAttributes(Decl *D) {
189f4a2713aSLionel Sambuc   if (Policy.PolishForDeclaration)
190f4a2713aSLionel Sambuc     return;
191f4a2713aSLionel Sambuc 
192f4a2713aSLionel Sambuc   if (D->hasAttrs()) {
193f4a2713aSLionel Sambuc     AttrVec &Attrs = D->getAttrs();
194f4a2713aSLionel Sambuc     for (AttrVec::const_iterator i=Attrs.begin(), e=Attrs.end(); i!=e; ++i) {
195f4a2713aSLionel Sambuc       Attr *A = *i;
196f4a2713aSLionel Sambuc       A->printPretty(Out, Policy);
197f4a2713aSLionel Sambuc     }
198f4a2713aSLionel Sambuc   }
199f4a2713aSLionel Sambuc }
200f4a2713aSLionel Sambuc 
printDeclType(QualType T,StringRef DeclName,bool Pack)201*0a6a1f1dSLionel Sambuc void DeclPrinter::printDeclType(QualType T, StringRef DeclName, bool Pack) {
202*0a6a1f1dSLionel Sambuc   // Normally, a PackExpansionType is written as T[3]... (for instance, as a
203*0a6a1f1dSLionel Sambuc   // template argument), but if it is the type of a declaration, the ellipsis
204*0a6a1f1dSLionel Sambuc   // is placed before the name being declared.
205*0a6a1f1dSLionel Sambuc   if (auto *PET = T->getAs<PackExpansionType>()) {
206*0a6a1f1dSLionel Sambuc     Pack = true;
207*0a6a1f1dSLionel Sambuc     T = PET->getPattern();
208*0a6a1f1dSLionel Sambuc   }
209*0a6a1f1dSLionel Sambuc   T.print(Out, Policy, (Pack ? "..." : "") + DeclName);
210*0a6a1f1dSLionel Sambuc }
211*0a6a1f1dSLionel Sambuc 
ProcessDeclGroup(SmallVectorImpl<Decl * > & Decls)212f4a2713aSLionel Sambuc void DeclPrinter::ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls) {
213f4a2713aSLionel Sambuc   this->Indent();
214f4a2713aSLionel Sambuc   Decl::printGroup(Decls.data(), Decls.size(), Out, Policy, Indentation);
215f4a2713aSLionel Sambuc   Out << ";\n";
216f4a2713aSLionel Sambuc   Decls.clear();
217f4a2713aSLionel Sambuc 
218f4a2713aSLionel Sambuc }
219f4a2713aSLionel Sambuc 
Print(AccessSpecifier AS)220f4a2713aSLionel Sambuc void DeclPrinter::Print(AccessSpecifier AS) {
221f4a2713aSLionel Sambuc   switch(AS) {
222f4a2713aSLionel Sambuc   case AS_none:      llvm_unreachable("No access specifier!");
223f4a2713aSLionel Sambuc   case AS_public:    Out << "public"; break;
224f4a2713aSLionel Sambuc   case AS_protected: Out << "protected"; break;
225f4a2713aSLionel Sambuc   case AS_private:   Out << "private"; break;
226f4a2713aSLionel Sambuc   }
227f4a2713aSLionel Sambuc }
228f4a2713aSLionel Sambuc 
229f4a2713aSLionel Sambuc //----------------------------------------------------------------------------
230f4a2713aSLionel Sambuc // Common C declarations
231f4a2713aSLionel Sambuc //----------------------------------------------------------------------------
232f4a2713aSLionel Sambuc 
VisitDeclContext(DeclContext * DC,bool Indent)233f4a2713aSLionel Sambuc void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
234f4a2713aSLionel Sambuc   if (Policy.TerseOutput)
235f4a2713aSLionel Sambuc     return;
236f4a2713aSLionel Sambuc 
237f4a2713aSLionel Sambuc   if (Indent)
238f4a2713aSLionel Sambuc     Indentation += Policy.Indentation;
239f4a2713aSLionel Sambuc 
240f4a2713aSLionel Sambuc   SmallVector<Decl*, 2> Decls;
241f4a2713aSLionel Sambuc   for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end();
242f4a2713aSLionel Sambuc        D != DEnd; ++D) {
243f4a2713aSLionel Sambuc 
244f4a2713aSLionel Sambuc     // Don't print ObjCIvarDecls, as they are printed when visiting the
245f4a2713aSLionel Sambuc     // containing ObjCInterfaceDecl.
246f4a2713aSLionel Sambuc     if (isa<ObjCIvarDecl>(*D))
247f4a2713aSLionel Sambuc       continue;
248f4a2713aSLionel Sambuc 
249f4a2713aSLionel Sambuc     // Skip over implicit declarations in pretty-printing mode.
250f4a2713aSLionel Sambuc     if (D->isImplicit())
251f4a2713aSLionel Sambuc       continue;
252f4a2713aSLionel Sambuc 
253f4a2713aSLionel Sambuc     // The next bits of code handles stuff like "struct {int x;} a,b"; we're
254f4a2713aSLionel Sambuc     // forced to merge the declarations because there's no other way to
255f4a2713aSLionel Sambuc     // refer to the struct in question.  This limited merging is safe without
256f4a2713aSLionel Sambuc     // a bunch of other checks because it only merges declarations directly
257f4a2713aSLionel Sambuc     // referring to the tag, not typedefs.
258f4a2713aSLionel Sambuc     //
259f4a2713aSLionel Sambuc     // Check whether the current declaration should be grouped with a previous
260f4a2713aSLionel Sambuc     // unnamed struct.
261f4a2713aSLionel Sambuc     QualType CurDeclType = getDeclType(*D);
262f4a2713aSLionel Sambuc     if (!Decls.empty() && !CurDeclType.isNull()) {
263f4a2713aSLionel Sambuc       QualType BaseType = GetBaseType(CurDeclType);
264f4a2713aSLionel Sambuc       if (!BaseType.isNull() && isa<ElaboratedType>(BaseType))
265f4a2713aSLionel Sambuc         BaseType = cast<ElaboratedType>(BaseType)->getNamedType();
266f4a2713aSLionel Sambuc       if (!BaseType.isNull() && isa<TagType>(BaseType) &&
267f4a2713aSLionel Sambuc           cast<TagType>(BaseType)->getDecl() == Decls[0]) {
268f4a2713aSLionel Sambuc         Decls.push_back(*D);
269f4a2713aSLionel Sambuc         continue;
270f4a2713aSLionel Sambuc       }
271f4a2713aSLionel Sambuc     }
272f4a2713aSLionel Sambuc 
273f4a2713aSLionel Sambuc     // If we have a merged group waiting to be handled, handle it now.
274f4a2713aSLionel Sambuc     if (!Decls.empty())
275f4a2713aSLionel Sambuc       ProcessDeclGroup(Decls);
276f4a2713aSLionel Sambuc 
277f4a2713aSLionel Sambuc     // If the current declaration is an unnamed tag type, save it
278f4a2713aSLionel Sambuc     // so we can merge it with the subsequent declaration(s) using it.
279f4a2713aSLionel Sambuc     if (isa<TagDecl>(*D) && !cast<TagDecl>(*D)->getIdentifier()) {
280f4a2713aSLionel Sambuc       Decls.push_back(*D);
281f4a2713aSLionel Sambuc       continue;
282f4a2713aSLionel Sambuc     }
283f4a2713aSLionel Sambuc 
284f4a2713aSLionel Sambuc     if (isa<AccessSpecDecl>(*D)) {
285f4a2713aSLionel Sambuc       Indentation -= Policy.Indentation;
286f4a2713aSLionel Sambuc       this->Indent();
287f4a2713aSLionel Sambuc       Print(D->getAccess());
288f4a2713aSLionel Sambuc       Out << ":\n";
289f4a2713aSLionel Sambuc       Indentation += Policy.Indentation;
290f4a2713aSLionel Sambuc       continue;
291f4a2713aSLionel Sambuc     }
292f4a2713aSLionel Sambuc 
293f4a2713aSLionel Sambuc     this->Indent();
294f4a2713aSLionel Sambuc     Visit(*D);
295f4a2713aSLionel Sambuc 
296f4a2713aSLionel Sambuc     // FIXME: Need to be able to tell the DeclPrinter when
297*0a6a1f1dSLionel Sambuc     const char *Terminator = nullptr;
298f4a2713aSLionel Sambuc     if (isa<OMPThreadPrivateDecl>(*D))
299*0a6a1f1dSLionel Sambuc       Terminator = nullptr;
300f4a2713aSLionel Sambuc     else if (isa<FunctionDecl>(*D) &&
301f4a2713aSLionel Sambuc              cast<FunctionDecl>(*D)->isThisDeclarationADefinition())
302*0a6a1f1dSLionel Sambuc       Terminator = nullptr;
303f4a2713aSLionel Sambuc     else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->getBody())
304*0a6a1f1dSLionel Sambuc       Terminator = nullptr;
305f4a2713aSLionel Sambuc     else if (isa<NamespaceDecl>(*D) || isa<LinkageSpecDecl>(*D) ||
306f4a2713aSLionel Sambuc              isa<ObjCImplementationDecl>(*D) ||
307f4a2713aSLionel Sambuc              isa<ObjCInterfaceDecl>(*D) ||
308f4a2713aSLionel Sambuc              isa<ObjCProtocolDecl>(*D) ||
309f4a2713aSLionel Sambuc              isa<ObjCCategoryImplDecl>(*D) ||
310f4a2713aSLionel Sambuc              isa<ObjCCategoryDecl>(*D))
311*0a6a1f1dSLionel Sambuc       Terminator = nullptr;
312f4a2713aSLionel Sambuc     else if (isa<EnumConstantDecl>(*D)) {
313f4a2713aSLionel Sambuc       DeclContext::decl_iterator Next = D;
314f4a2713aSLionel Sambuc       ++Next;
315f4a2713aSLionel Sambuc       if (Next != DEnd)
316f4a2713aSLionel Sambuc         Terminator = ",";
317f4a2713aSLionel Sambuc     } else
318f4a2713aSLionel Sambuc       Terminator = ";";
319f4a2713aSLionel Sambuc 
320f4a2713aSLionel Sambuc     if (Terminator)
321f4a2713aSLionel Sambuc       Out << Terminator;
322f4a2713aSLionel Sambuc     Out << "\n";
323f4a2713aSLionel Sambuc   }
324f4a2713aSLionel Sambuc 
325f4a2713aSLionel Sambuc   if (!Decls.empty())
326f4a2713aSLionel Sambuc     ProcessDeclGroup(Decls);
327f4a2713aSLionel Sambuc 
328f4a2713aSLionel Sambuc   if (Indent)
329f4a2713aSLionel Sambuc     Indentation -= Policy.Indentation;
330f4a2713aSLionel Sambuc }
331f4a2713aSLionel Sambuc 
VisitTranslationUnitDecl(TranslationUnitDecl * D)332f4a2713aSLionel Sambuc void DeclPrinter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
333f4a2713aSLionel Sambuc   VisitDeclContext(D, false);
334f4a2713aSLionel Sambuc }
335f4a2713aSLionel Sambuc 
VisitTypedefDecl(TypedefDecl * D)336f4a2713aSLionel Sambuc void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
337f4a2713aSLionel Sambuc   if (!Policy.SuppressSpecifiers) {
338f4a2713aSLionel Sambuc     Out << "typedef ";
339f4a2713aSLionel Sambuc 
340f4a2713aSLionel Sambuc     if (D->isModulePrivate())
341f4a2713aSLionel Sambuc       Out << "__module_private__ ";
342f4a2713aSLionel Sambuc   }
343f4a2713aSLionel Sambuc   D->getTypeSourceInfo()->getType().print(Out, Policy, D->getName());
344f4a2713aSLionel Sambuc   prettyPrintAttributes(D);
345f4a2713aSLionel Sambuc }
346f4a2713aSLionel Sambuc 
VisitTypeAliasDecl(TypeAliasDecl * D)347f4a2713aSLionel Sambuc void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) {
348f4a2713aSLionel Sambuc   Out << "using " << *D;
349f4a2713aSLionel Sambuc   prettyPrintAttributes(D);
350f4a2713aSLionel Sambuc   Out << " = " << D->getTypeSourceInfo()->getType().getAsString(Policy);
351f4a2713aSLionel Sambuc }
352f4a2713aSLionel Sambuc 
VisitEnumDecl(EnumDecl * D)353f4a2713aSLionel Sambuc void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
354f4a2713aSLionel Sambuc   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
355f4a2713aSLionel Sambuc     Out << "__module_private__ ";
356f4a2713aSLionel Sambuc   Out << "enum ";
357f4a2713aSLionel Sambuc   if (D->isScoped()) {
358f4a2713aSLionel Sambuc     if (D->isScopedUsingClassTag())
359f4a2713aSLionel Sambuc       Out << "class ";
360f4a2713aSLionel Sambuc     else
361f4a2713aSLionel Sambuc       Out << "struct ";
362f4a2713aSLionel Sambuc   }
363f4a2713aSLionel Sambuc   Out << *D;
364f4a2713aSLionel Sambuc 
365f4a2713aSLionel Sambuc   if (D->isFixed())
366f4a2713aSLionel Sambuc     Out << " : " << D->getIntegerType().stream(Policy);
367f4a2713aSLionel Sambuc 
368f4a2713aSLionel Sambuc   if (D->isCompleteDefinition()) {
369f4a2713aSLionel Sambuc     Out << " {\n";
370f4a2713aSLionel Sambuc     VisitDeclContext(D);
371f4a2713aSLionel Sambuc     Indent() << "}";
372f4a2713aSLionel Sambuc   }
373f4a2713aSLionel Sambuc   prettyPrintAttributes(D);
374f4a2713aSLionel Sambuc }
375f4a2713aSLionel Sambuc 
VisitRecordDecl(RecordDecl * D)376f4a2713aSLionel Sambuc void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
377f4a2713aSLionel Sambuc   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
378f4a2713aSLionel Sambuc     Out << "__module_private__ ";
379f4a2713aSLionel Sambuc   Out << D->getKindName();
380*0a6a1f1dSLionel Sambuc 
381*0a6a1f1dSLionel Sambuc   prettyPrintAttributes(D);
382*0a6a1f1dSLionel Sambuc 
383f4a2713aSLionel Sambuc   if (D->getIdentifier())
384f4a2713aSLionel Sambuc     Out << ' ' << *D;
385f4a2713aSLionel Sambuc 
386f4a2713aSLionel Sambuc   if (D->isCompleteDefinition()) {
387f4a2713aSLionel Sambuc     Out << " {\n";
388f4a2713aSLionel Sambuc     VisitDeclContext(D);
389f4a2713aSLionel Sambuc     Indent() << "}";
390f4a2713aSLionel Sambuc   }
391f4a2713aSLionel Sambuc }
392f4a2713aSLionel Sambuc 
VisitEnumConstantDecl(EnumConstantDecl * D)393f4a2713aSLionel Sambuc void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
394f4a2713aSLionel Sambuc   Out << *D;
395f4a2713aSLionel Sambuc   if (Expr *Init = D->getInitExpr()) {
396f4a2713aSLionel Sambuc     Out << " = ";
397*0a6a1f1dSLionel Sambuc     Init->printPretty(Out, nullptr, Policy, Indentation);
398f4a2713aSLionel Sambuc   }
399f4a2713aSLionel Sambuc }
400f4a2713aSLionel Sambuc 
VisitFunctionDecl(FunctionDecl * D)401f4a2713aSLionel Sambuc void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
402f4a2713aSLionel Sambuc   CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
403*0a6a1f1dSLionel Sambuc   CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
404f4a2713aSLionel Sambuc   if (!Policy.SuppressSpecifiers) {
405f4a2713aSLionel Sambuc     switch (D->getStorageClass()) {
406f4a2713aSLionel Sambuc     case SC_None: break;
407f4a2713aSLionel Sambuc     case SC_Extern: Out << "extern "; break;
408f4a2713aSLionel Sambuc     case SC_Static: Out << "static "; break;
409f4a2713aSLionel Sambuc     case SC_PrivateExtern: Out << "__private_extern__ "; break;
410f4a2713aSLionel Sambuc     case SC_Auto: case SC_Register: case SC_OpenCLWorkGroupLocal:
411f4a2713aSLionel Sambuc       llvm_unreachable("invalid for functions");
412f4a2713aSLionel Sambuc     }
413f4a2713aSLionel Sambuc 
414f4a2713aSLionel Sambuc     if (D->isInlineSpecified())  Out << "inline ";
415f4a2713aSLionel Sambuc     if (D->isVirtualAsWritten()) Out << "virtual ";
416f4a2713aSLionel Sambuc     if (D->isModulePrivate())    Out << "__module_private__ ";
417*0a6a1f1dSLionel Sambuc     if (D->isConstexpr() && !D->isExplicitlyDefaulted()) Out << "constexpr ";
418*0a6a1f1dSLionel Sambuc     if ((CDecl && CDecl->isExplicitSpecified()) ||
419*0a6a1f1dSLionel Sambuc         (ConversionDecl && ConversionDecl->isExplicit()))
420f4a2713aSLionel Sambuc       Out << "explicit ";
421f4a2713aSLionel Sambuc   }
422f4a2713aSLionel Sambuc 
423f4a2713aSLionel Sambuc   PrintingPolicy SubPolicy(Policy);
424f4a2713aSLionel Sambuc   SubPolicy.SuppressSpecifiers = false;
425f4a2713aSLionel Sambuc   std::string Proto = D->getNameInfo().getAsString();
426f4a2713aSLionel Sambuc 
427f4a2713aSLionel Sambuc   QualType Ty = D->getType();
428f4a2713aSLionel Sambuc   while (const ParenType *PT = dyn_cast<ParenType>(Ty)) {
429f4a2713aSLionel Sambuc     Proto = '(' + Proto + ')';
430f4a2713aSLionel Sambuc     Ty = PT->getInnerType();
431f4a2713aSLionel Sambuc   }
432f4a2713aSLionel Sambuc 
433*0a6a1f1dSLionel Sambuc   if (const FunctionType *AFT = Ty->getAs<FunctionType>()) {
434*0a6a1f1dSLionel Sambuc     const FunctionProtoType *FT = nullptr;
435f4a2713aSLionel Sambuc     if (D->hasWrittenPrototype())
436f4a2713aSLionel Sambuc       FT = dyn_cast<FunctionProtoType>(AFT);
437f4a2713aSLionel Sambuc 
438f4a2713aSLionel Sambuc     Proto += "(";
439f4a2713aSLionel Sambuc     if (FT) {
440f4a2713aSLionel Sambuc       llvm::raw_string_ostream POut(Proto);
441f4a2713aSLionel Sambuc       DeclPrinter ParamPrinter(POut, SubPolicy, Indentation);
442f4a2713aSLionel Sambuc       for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
443f4a2713aSLionel Sambuc         if (i) POut << ", ";
444f4a2713aSLionel Sambuc         ParamPrinter.VisitParmVarDecl(D->getParamDecl(i));
445f4a2713aSLionel Sambuc       }
446f4a2713aSLionel Sambuc 
447f4a2713aSLionel Sambuc       if (FT->isVariadic()) {
448f4a2713aSLionel Sambuc         if (D->getNumParams()) POut << ", ";
449f4a2713aSLionel Sambuc         POut << "...";
450f4a2713aSLionel Sambuc       }
451f4a2713aSLionel Sambuc     } else if (D->doesThisDeclarationHaveABody() && !D->hasPrototype()) {
452f4a2713aSLionel Sambuc       for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
453f4a2713aSLionel Sambuc         if (i)
454f4a2713aSLionel Sambuc           Proto += ", ";
455f4a2713aSLionel Sambuc         Proto += D->getParamDecl(i)->getNameAsString();
456f4a2713aSLionel Sambuc       }
457f4a2713aSLionel Sambuc     }
458f4a2713aSLionel Sambuc 
459f4a2713aSLionel Sambuc     Proto += ")";
460f4a2713aSLionel Sambuc 
461f4a2713aSLionel Sambuc     if (FT) {
462f4a2713aSLionel Sambuc       if (FT->isConst())
463f4a2713aSLionel Sambuc         Proto += " const";
464f4a2713aSLionel Sambuc       if (FT->isVolatile())
465f4a2713aSLionel Sambuc         Proto += " volatile";
466f4a2713aSLionel Sambuc       if (FT->isRestrict())
467f4a2713aSLionel Sambuc         Proto += " restrict";
468*0a6a1f1dSLionel Sambuc 
469*0a6a1f1dSLionel Sambuc       switch (FT->getRefQualifier()) {
470*0a6a1f1dSLionel Sambuc       case RQ_None:
471*0a6a1f1dSLionel Sambuc         break;
472*0a6a1f1dSLionel Sambuc       case RQ_LValue:
473*0a6a1f1dSLionel Sambuc         Proto += " &";
474*0a6a1f1dSLionel Sambuc         break;
475*0a6a1f1dSLionel Sambuc       case RQ_RValue:
476*0a6a1f1dSLionel Sambuc         Proto += " &&";
477*0a6a1f1dSLionel Sambuc         break;
478*0a6a1f1dSLionel Sambuc       }
479f4a2713aSLionel Sambuc     }
480f4a2713aSLionel Sambuc 
481f4a2713aSLionel Sambuc     if (FT && FT->hasDynamicExceptionSpec()) {
482f4a2713aSLionel Sambuc       Proto += " throw(";
483f4a2713aSLionel Sambuc       if (FT->getExceptionSpecType() == EST_MSAny)
484f4a2713aSLionel Sambuc         Proto += "...";
485f4a2713aSLionel Sambuc       else
486f4a2713aSLionel Sambuc         for (unsigned I = 0, N = FT->getNumExceptions(); I != N; ++I) {
487f4a2713aSLionel Sambuc           if (I)
488f4a2713aSLionel Sambuc             Proto += ", ";
489f4a2713aSLionel Sambuc 
490f4a2713aSLionel Sambuc           Proto += FT->getExceptionType(I).getAsString(SubPolicy);
491f4a2713aSLionel Sambuc         }
492f4a2713aSLionel Sambuc       Proto += ")";
493f4a2713aSLionel Sambuc     } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) {
494f4a2713aSLionel Sambuc       Proto += " noexcept";
495f4a2713aSLionel Sambuc       if (FT->getExceptionSpecType() == EST_ComputedNoexcept) {
496f4a2713aSLionel Sambuc         Proto += "(";
497f4a2713aSLionel Sambuc         llvm::raw_string_ostream EOut(Proto);
498*0a6a1f1dSLionel Sambuc         FT->getNoexceptExpr()->printPretty(EOut, nullptr, SubPolicy,
499f4a2713aSLionel Sambuc                                            Indentation);
500f4a2713aSLionel Sambuc         EOut.flush();
501f4a2713aSLionel Sambuc         Proto += EOut.str();
502f4a2713aSLionel Sambuc         Proto += ")";
503f4a2713aSLionel Sambuc       }
504f4a2713aSLionel Sambuc     }
505f4a2713aSLionel Sambuc 
506f4a2713aSLionel Sambuc     if (CDecl) {
507f4a2713aSLionel Sambuc       bool HasInitializerList = false;
508*0a6a1f1dSLionel Sambuc       for (const auto *BMInitializer : CDecl->inits()) {
509f4a2713aSLionel Sambuc         if (BMInitializer->isInClassMemberInitializer())
510f4a2713aSLionel Sambuc           continue;
511f4a2713aSLionel Sambuc 
512f4a2713aSLionel Sambuc         if (!HasInitializerList) {
513f4a2713aSLionel Sambuc           Proto += " : ";
514f4a2713aSLionel Sambuc           Out << Proto;
515f4a2713aSLionel Sambuc           Proto.clear();
516f4a2713aSLionel Sambuc           HasInitializerList = true;
517f4a2713aSLionel Sambuc         } else
518f4a2713aSLionel Sambuc           Out << ", ";
519f4a2713aSLionel Sambuc 
520f4a2713aSLionel Sambuc         if (BMInitializer->isAnyMemberInitializer()) {
521f4a2713aSLionel Sambuc           FieldDecl *FD = BMInitializer->getAnyMember();
522f4a2713aSLionel Sambuc           Out << *FD;
523f4a2713aSLionel Sambuc         } else {
524f4a2713aSLionel Sambuc           Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(Policy);
525f4a2713aSLionel Sambuc         }
526f4a2713aSLionel Sambuc 
527f4a2713aSLionel Sambuc         Out << "(";
528f4a2713aSLionel Sambuc         if (!BMInitializer->getInit()) {
529f4a2713aSLionel Sambuc           // Nothing to print
530f4a2713aSLionel Sambuc         } else {
531f4a2713aSLionel Sambuc           Expr *Init = BMInitializer->getInit();
532f4a2713aSLionel Sambuc           if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init))
533f4a2713aSLionel Sambuc             Init = Tmp->getSubExpr();
534f4a2713aSLionel Sambuc 
535f4a2713aSLionel Sambuc           Init = Init->IgnoreParens();
536f4a2713aSLionel Sambuc 
537*0a6a1f1dSLionel Sambuc           Expr *SimpleInit = nullptr;
538*0a6a1f1dSLionel Sambuc           Expr **Args = nullptr;
539f4a2713aSLionel Sambuc           unsigned NumArgs = 0;
540f4a2713aSLionel Sambuc           if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
541f4a2713aSLionel Sambuc             Args = ParenList->getExprs();
542f4a2713aSLionel Sambuc             NumArgs = ParenList->getNumExprs();
543f4a2713aSLionel Sambuc           } else if (CXXConstructExpr *Construct
544f4a2713aSLionel Sambuc                                         = dyn_cast<CXXConstructExpr>(Init)) {
545f4a2713aSLionel Sambuc             Args = Construct->getArgs();
546f4a2713aSLionel Sambuc             NumArgs = Construct->getNumArgs();
547f4a2713aSLionel Sambuc           } else
548f4a2713aSLionel Sambuc             SimpleInit = Init;
549f4a2713aSLionel Sambuc 
550f4a2713aSLionel Sambuc           if (SimpleInit)
551*0a6a1f1dSLionel Sambuc             SimpleInit->printPretty(Out, nullptr, Policy, Indentation);
552f4a2713aSLionel Sambuc           else {
553f4a2713aSLionel Sambuc             for (unsigned I = 0; I != NumArgs; ++I) {
554*0a6a1f1dSLionel Sambuc               assert(Args[I] != nullptr && "Expected non-null Expr");
555f4a2713aSLionel Sambuc               if (isa<CXXDefaultArgExpr>(Args[I]))
556f4a2713aSLionel Sambuc                 break;
557f4a2713aSLionel Sambuc 
558f4a2713aSLionel Sambuc               if (I)
559f4a2713aSLionel Sambuc                 Out << ", ";
560*0a6a1f1dSLionel Sambuc               Args[I]->printPretty(Out, nullptr, Policy, Indentation);
561f4a2713aSLionel Sambuc             }
562f4a2713aSLionel Sambuc           }
563f4a2713aSLionel Sambuc         }
564f4a2713aSLionel Sambuc         Out << ")";
565*0a6a1f1dSLionel Sambuc         if (BMInitializer->isPackExpansion())
566*0a6a1f1dSLionel Sambuc           Out << "...";
567f4a2713aSLionel Sambuc       }
568*0a6a1f1dSLionel Sambuc     } else if (!ConversionDecl && !isa<CXXDestructorDecl>(D)) {
569f4a2713aSLionel Sambuc       if (FT && FT->hasTrailingReturn()) {
570f4a2713aSLionel Sambuc         Out << "auto " << Proto << " -> ";
571f4a2713aSLionel Sambuc         Proto.clear();
572f4a2713aSLionel Sambuc       }
573*0a6a1f1dSLionel Sambuc       AFT->getReturnType().print(Out, Policy, Proto);
574*0a6a1f1dSLionel Sambuc       Proto.clear();
575f4a2713aSLionel Sambuc     }
576*0a6a1f1dSLionel Sambuc     Out << Proto;
577f4a2713aSLionel Sambuc   } else {
578f4a2713aSLionel Sambuc     Ty.print(Out, Policy, Proto);
579f4a2713aSLionel Sambuc   }
580f4a2713aSLionel Sambuc 
581f4a2713aSLionel Sambuc   prettyPrintAttributes(D);
582f4a2713aSLionel Sambuc 
583f4a2713aSLionel Sambuc   if (D->isPure())
584f4a2713aSLionel Sambuc     Out << " = 0";
585f4a2713aSLionel Sambuc   else if (D->isDeletedAsWritten())
586f4a2713aSLionel Sambuc     Out << " = delete";
587f4a2713aSLionel Sambuc   else if (D->isExplicitlyDefaulted())
588f4a2713aSLionel Sambuc     Out << " = default";
589f4a2713aSLionel Sambuc   else if (D->doesThisDeclarationHaveABody() && !Policy.TerseOutput) {
590f4a2713aSLionel Sambuc     if (!D->hasPrototype() && D->getNumParams()) {
591f4a2713aSLionel Sambuc       // This is a K&R function definition, so we need to print the
592f4a2713aSLionel Sambuc       // parameters.
593f4a2713aSLionel Sambuc       Out << '\n';
594f4a2713aSLionel Sambuc       DeclPrinter ParamPrinter(Out, SubPolicy, Indentation);
595f4a2713aSLionel Sambuc       Indentation += Policy.Indentation;
596f4a2713aSLionel Sambuc       for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
597f4a2713aSLionel Sambuc         Indent();
598f4a2713aSLionel Sambuc         ParamPrinter.VisitParmVarDecl(D->getParamDecl(i));
599f4a2713aSLionel Sambuc         Out << ";\n";
600f4a2713aSLionel Sambuc       }
601f4a2713aSLionel Sambuc       Indentation -= Policy.Indentation;
602f4a2713aSLionel Sambuc     } else
603f4a2713aSLionel Sambuc       Out << ' ';
604f4a2713aSLionel Sambuc 
605*0a6a1f1dSLionel Sambuc     if (D->getBody())
606*0a6a1f1dSLionel Sambuc       D->getBody()->printPretty(Out, nullptr, SubPolicy, Indentation);
607f4a2713aSLionel Sambuc     Out << '\n';
608f4a2713aSLionel Sambuc   }
609f4a2713aSLionel Sambuc }
610f4a2713aSLionel Sambuc 
VisitFriendDecl(FriendDecl * D)611f4a2713aSLionel Sambuc void DeclPrinter::VisitFriendDecl(FriendDecl *D) {
612f4a2713aSLionel Sambuc   if (TypeSourceInfo *TSI = D->getFriendType()) {
613f4a2713aSLionel Sambuc     unsigned NumTPLists = D->getFriendTypeNumTemplateParameterLists();
614f4a2713aSLionel Sambuc     for (unsigned i = 0; i < NumTPLists; ++i)
615f4a2713aSLionel Sambuc       PrintTemplateParameters(D->getFriendTypeTemplateParameterList(i));
616f4a2713aSLionel Sambuc     Out << "friend ";
617f4a2713aSLionel Sambuc     Out << " " << TSI->getType().getAsString(Policy);
618f4a2713aSLionel Sambuc   }
619f4a2713aSLionel Sambuc   else if (FunctionDecl *FD =
620f4a2713aSLionel Sambuc       dyn_cast<FunctionDecl>(D->getFriendDecl())) {
621f4a2713aSLionel Sambuc     Out << "friend ";
622f4a2713aSLionel Sambuc     VisitFunctionDecl(FD);
623f4a2713aSLionel Sambuc   }
624f4a2713aSLionel Sambuc   else if (FunctionTemplateDecl *FTD =
625f4a2713aSLionel Sambuc            dyn_cast<FunctionTemplateDecl>(D->getFriendDecl())) {
626f4a2713aSLionel Sambuc     Out << "friend ";
627f4a2713aSLionel Sambuc     VisitFunctionTemplateDecl(FTD);
628f4a2713aSLionel Sambuc   }
629f4a2713aSLionel Sambuc   else if (ClassTemplateDecl *CTD =
630f4a2713aSLionel Sambuc            dyn_cast<ClassTemplateDecl>(D->getFriendDecl())) {
631f4a2713aSLionel Sambuc     Out << "friend ";
632f4a2713aSLionel Sambuc     VisitRedeclarableTemplateDecl(CTD);
633f4a2713aSLionel Sambuc   }
634f4a2713aSLionel Sambuc }
635f4a2713aSLionel Sambuc 
VisitFieldDecl(FieldDecl * D)636f4a2713aSLionel Sambuc void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
637f4a2713aSLionel Sambuc   if (!Policy.SuppressSpecifiers && D->isMutable())
638f4a2713aSLionel Sambuc     Out << "mutable ";
639f4a2713aSLionel Sambuc   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
640f4a2713aSLionel Sambuc     Out << "__module_private__ ";
641f4a2713aSLionel Sambuc 
642f4a2713aSLionel Sambuc   Out << D->getASTContext().getUnqualifiedObjCPointerType(D->getType()).
643f4a2713aSLionel Sambuc             stream(Policy, D->getName());
644f4a2713aSLionel Sambuc 
645f4a2713aSLionel Sambuc   if (D->isBitField()) {
646f4a2713aSLionel Sambuc     Out << " : ";
647*0a6a1f1dSLionel Sambuc     D->getBitWidth()->printPretty(Out, nullptr, Policy, Indentation);
648f4a2713aSLionel Sambuc   }
649f4a2713aSLionel Sambuc 
650f4a2713aSLionel Sambuc   Expr *Init = D->getInClassInitializer();
651f4a2713aSLionel Sambuc   if (!Policy.SuppressInitializers && Init) {
652f4a2713aSLionel Sambuc     if (D->getInClassInitStyle() == ICIS_ListInit)
653f4a2713aSLionel Sambuc       Out << " ";
654f4a2713aSLionel Sambuc     else
655f4a2713aSLionel Sambuc       Out << " = ";
656*0a6a1f1dSLionel Sambuc     Init->printPretty(Out, nullptr, Policy, Indentation);
657f4a2713aSLionel Sambuc   }
658f4a2713aSLionel Sambuc   prettyPrintAttributes(D);
659f4a2713aSLionel Sambuc }
660f4a2713aSLionel Sambuc 
VisitLabelDecl(LabelDecl * D)661f4a2713aSLionel Sambuc void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
662f4a2713aSLionel Sambuc   Out << *D << ":";
663f4a2713aSLionel Sambuc }
664f4a2713aSLionel Sambuc 
VisitVarDecl(VarDecl * D)665f4a2713aSLionel Sambuc void DeclPrinter::VisitVarDecl(VarDecl *D) {
666f4a2713aSLionel Sambuc   if (!Policy.SuppressSpecifiers) {
667f4a2713aSLionel Sambuc     StorageClass SC = D->getStorageClass();
668f4a2713aSLionel Sambuc     if (SC != SC_None)
669f4a2713aSLionel Sambuc       Out << VarDecl::getStorageClassSpecifierString(SC) << " ";
670f4a2713aSLionel Sambuc 
671f4a2713aSLionel Sambuc     switch (D->getTSCSpec()) {
672f4a2713aSLionel Sambuc     case TSCS_unspecified:
673f4a2713aSLionel Sambuc       break;
674f4a2713aSLionel Sambuc     case TSCS___thread:
675f4a2713aSLionel Sambuc       Out << "__thread ";
676f4a2713aSLionel Sambuc       break;
677f4a2713aSLionel Sambuc     case TSCS__Thread_local:
678f4a2713aSLionel Sambuc       Out << "_Thread_local ";
679f4a2713aSLionel Sambuc       break;
680f4a2713aSLionel Sambuc     case TSCS_thread_local:
681f4a2713aSLionel Sambuc       Out << "thread_local ";
682f4a2713aSLionel Sambuc       break;
683f4a2713aSLionel Sambuc     }
684f4a2713aSLionel Sambuc 
685f4a2713aSLionel Sambuc     if (D->isModulePrivate())
686f4a2713aSLionel Sambuc       Out << "__module_private__ ";
687f4a2713aSLionel Sambuc   }
688f4a2713aSLionel Sambuc 
689f4a2713aSLionel Sambuc   QualType T = D->getTypeSourceInfo()
690f4a2713aSLionel Sambuc     ? D->getTypeSourceInfo()->getType()
691f4a2713aSLionel Sambuc     : D->getASTContext().getUnqualifiedObjCPointerType(D->getType());
692*0a6a1f1dSLionel Sambuc   printDeclType(T, D->getName());
693f4a2713aSLionel Sambuc   Expr *Init = D->getInit();
694f4a2713aSLionel Sambuc   if (!Policy.SuppressInitializers && Init) {
695f4a2713aSLionel Sambuc     bool ImplicitInit = false;
696f4a2713aSLionel Sambuc     if (CXXConstructExpr *Construct =
697f4a2713aSLionel Sambuc             dyn_cast<CXXConstructExpr>(Init->IgnoreImplicit())) {
698f4a2713aSLionel Sambuc       if (D->getInitStyle() == VarDecl::CallInit &&
699f4a2713aSLionel Sambuc           !Construct->isListInitialization()) {
700f4a2713aSLionel Sambuc         ImplicitInit = Construct->getNumArgs() == 0 ||
701f4a2713aSLionel Sambuc           Construct->getArg(0)->isDefaultArgument();
702f4a2713aSLionel Sambuc       }
703f4a2713aSLionel Sambuc     }
704f4a2713aSLionel Sambuc     if (!ImplicitInit) {
705f4a2713aSLionel Sambuc       if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
706f4a2713aSLionel Sambuc         Out << "(";
707f4a2713aSLionel Sambuc       else if (D->getInitStyle() == VarDecl::CInit) {
708f4a2713aSLionel Sambuc         Out << " = ";
709f4a2713aSLionel Sambuc       }
710*0a6a1f1dSLionel Sambuc       Init->printPretty(Out, nullptr, Policy, Indentation);
711f4a2713aSLionel Sambuc       if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
712f4a2713aSLionel Sambuc         Out << ")";
713f4a2713aSLionel Sambuc     }
714f4a2713aSLionel Sambuc   }
715f4a2713aSLionel Sambuc   prettyPrintAttributes(D);
716f4a2713aSLionel Sambuc }
717f4a2713aSLionel Sambuc 
VisitParmVarDecl(ParmVarDecl * D)718f4a2713aSLionel Sambuc void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) {
719f4a2713aSLionel Sambuc   VisitVarDecl(D);
720f4a2713aSLionel Sambuc }
721f4a2713aSLionel Sambuc 
VisitFileScopeAsmDecl(FileScopeAsmDecl * D)722f4a2713aSLionel Sambuc void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
723f4a2713aSLionel Sambuc   Out << "__asm (";
724*0a6a1f1dSLionel Sambuc   D->getAsmString()->printPretty(Out, nullptr, Policy, Indentation);
725f4a2713aSLionel Sambuc   Out << ")";
726f4a2713aSLionel Sambuc }
727f4a2713aSLionel Sambuc 
VisitImportDecl(ImportDecl * D)728f4a2713aSLionel Sambuc void DeclPrinter::VisitImportDecl(ImportDecl *D) {
729f4a2713aSLionel Sambuc   Out << "@import " << D->getImportedModule()->getFullModuleName()
730f4a2713aSLionel Sambuc       << ";\n";
731f4a2713aSLionel Sambuc }
732f4a2713aSLionel Sambuc 
VisitStaticAssertDecl(StaticAssertDecl * D)733f4a2713aSLionel Sambuc void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) {
734f4a2713aSLionel Sambuc   Out << "static_assert(";
735*0a6a1f1dSLionel Sambuc   D->getAssertExpr()->printPretty(Out, nullptr, Policy, Indentation);
736f4a2713aSLionel Sambuc   Out << ", ";
737*0a6a1f1dSLionel Sambuc   D->getMessage()->printPretty(Out, nullptr, Policy, Indentation);
738f4a2713aSLionel Sambuc   Out << ")";
739f4a2713aSLionel Sambuc }
740f4a2713aSLionel Sambuc 
741f4a2713aSLionel Sambuc //----------------------------------------------------------------------------
742f4a2713aSLionel Sambuc // C++ declarations
743f4a2713aSLionel Sambuc //----------------------------------------------------------------------------
VisitNamespaceDecl(NamespaceDecl * D)744f4a2713aSLionel Sambuc void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) {
745f4a2713aSLionel Sambuc   if (D->isInline())
746f4a2713aSLionel Sambuc     Out << "inline ";
747f4a2713aSLionel Sambuc   Out << "namespace " << *D << " {\n";
748f4a2713aSLionel Sambuc   VisitDeclContext(D);
749f4a2713aSLionel Sambuc   Indent() << "}";
750f4a2713aSLionel Sambuc }
751f4a2713aSLionel Sambuc 
VisitUsingDirectiveDecl(UsingDirectiveDecl * D)752f4a2713aSLionel Sambuc void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
753f4a2713aSLionel Sambuc   Out << "using namespace ";
754f4a2713aSLionel Sambuc   if (D->getQualifier())
755f4a2713aSLionel Sambuc     D->getQualifier()->print(Out, Policy);
756f4a2713aSLionel Sambuc   Out << *D->getNominatedNamespaceAsWritten();
757f4a2713aSLionel Sambuc }
758f4a2713aSLionel Sambuc 
VisitNamespaceAliasDecl(NamespaceAliasDecl * D)759f4a2713aSLionel Sambuc void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
760f4a2713aSLionel Sambuc   Out << "namespace " << *D << " = ";
761f4a2713aSLionel Sambuc   if (D->getQualifier())
762f4a2713aSLionel Sambuc     D->getQualifier()->print(Out, Policy);
763f4a2713aSLionel Sambuc   Out << *D->getAliasedNamespace();
764f4a2713aSLionel Sambuc }
765f4a2713aSLionel Sambuc 
VisitEmptyDecl(EmptyDecl * D)766f4a2713aSLionel Sambuc void DeclPrinter::VisitEmptyDecl(EmptyDecl *D) {
767f4a2713aSLionel Sambuc   prettyPrintAttributes(D);
768f4a2713aSLionel Sambuc }
769f4a2713aSLionel Sambuc 
VisitCXXRecordDecl(CXXRecordDecl * D)770f4a2713aSLionel Sambuc void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
771f4a2713aSLionel Sambuc   if (!Policy.SuppressSpecifiers && D->isModulePrivate())
772f4a2713aSLionel Sambuc     Out << "__module_private__ ";
773f4a2713aSLionel Sambuc   Out << D->getKindName();
774*0a6a1f1dSLionel Sambuc 
775*0a6a1f1dSLionel Sambuc   prettyPrintAttributes(D);
776*0a6a1f1dSLionel Sambuc 
777f4a2713aSLionel Sambuc   if (D->getIdentifier())
778f4a2713aSLionel Sambuc     Out << ' ' << *D;
779f4a2713aSLionel Sambuc 
780f4a2713aSLionel Sambuc   if (D->isCompleteDefinition()) {
781f4a2713aSLionel Sambuc     // Print the base classes
782f4a2713aSLionel Sambuc     if (D->getNumBases()) {
783f4a2713aSLionel Sambuc       Out << " : ";
784f4a2713aSLionel Sambuc       for (CXXRecordDecl::base_class_iterator Base = D->bases_begin(),
785f4a2713aSLionel Sambuc              BaseEnd = D->bases_end(); Base != BaseEnd; ++Base) {
786f4a2713aSLionel Sambuc         if (Base != D->bases_begin())
787f4a2713aSLionel Sambuc           Out << ", ";
788f4a2713aSLionel Sambuc 
789f4a2713aSLionel Sambuc         if (Base->isVirtual())
790f4a2713aSLionel Sambuc           Out << "virtual ";
791f4a2713aSLionel Sambuc 
792f4a2713aSLionel Sambuc         AccessSpecifier AS = Base->getAccessSpecifierAsWritten();
793*0a6a1f1dSLionel Sambuc         if (AS != AS_none) {
794f4a2713aSLionel Sambuc           Print(AS);
795*0a6a1f1dSLionel Sambuc           Out << " ";
796*0a6a1f1dSLionel Sambuc         }
797*0a6a1f1dSLionel Sambuc         Out << Base->getType().getAsString(Policy);
798f4a2713aSLionel Sambuc 
799f4a2713aSLionel Sambuc         if (Base->isPackExpansion())
800f4a2713aSLionel Sambuc           Out << "...";
801f4a2713aSLionel Sambuc       }
802f4a2713aSLionel Sambuc     }
803f4a2713aSLionel Sambuc 
804f4a2713aSLionel Sambuc     // Print the class definition
805f4a2713aSLionel Sambuc     // FIXME: Doesn't print access specifiers, e.g., "public:"
806f4a2713aSLionel Sambuc     Out << " {\n";
807f4a2713aSLionel Sambuc     VisitDeclContext(D);
808f4a2713aSLionel Sambuc     Indent() << "}";
809f4a2713aSLionel Sambuc   }
810f4a2713aSLionel Sambuc }
811f4a2713aSLionel Sambuc 
VisitLinkageSpecDecl(LinkageSpecDecl * D)812f4a2713aSLionel Sambuc void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
813f4a2713aSLionel Sambuc   const char *l;
814f4a2713aSLionel Sambuc   if (D->getLanguage() == LinkageSpecDecl::lang_c)
815f4a2713aSLionel Sambuc     l = "C";
816f4a2713aSLionel Sambuc   else {
817f4a2713aSLionel Sambuc     assert(D->getLanguage() == LinkageSpecDecl::lang_cxx &&
818f4a2713aSLionel Sambuc            "unknown language in linkage specification");
819f4a2713aSLionel Sambuc     l = "C++";
820f4a2713aSLionel Sambuc   }
821f4a2713aSLionel Sambuc 
822f4a2713aSLionel Sambuc   Out << "extern \"" << l << "\" ";
823f4a2713aSLionel Sambuc   if (D->hasBraces()) {
824f4a2713aSLionel Sambuc     Out << "{\n";
825f4a2713aSLionel Sambuc     VisitDeclContext(D);
826f4a2713aSLionel Sambuc     Indent() << "}";
827f4a2713aSLionel Sambuc   } else
828f4a2713aSLionel Sambuc     Visit(*D->decls_begin());
829f4a2713aSLionel Sambuc }
830f4a2713aSLionel Sambuc 
PrintTemplateParameters(const TemplateParameterList * Params,const TemplateArgumentList * Args)831f4a2713aSLionel Sambuc void DeclPrinter::PrintTemplateParameters(const TemplateParameterList *Params,
832f4a2713aSLionel Sambuc                                           const TemplateArgumentList *Args) {
833f4a2713aSLionel Sambuc   assert(Params);
834f4a2713aSLionel Sambuc   assert(!Args || Params->size() == Args->size());
835f4a2713aSLionel Sambuc 
836f4a2713aSLionel Sambuc   Out << "template <";
837f4a2713aSLionel Sambuc 
838f4a2713aSLionel Sambuc   for (unsigned i = 0, e = Params->size(); i != e; ++i) {
839f4a2713aSLionel Sambuc     if (i != 0)
840f4a2713aSLionel Sambuc       Out << ", ";
841f4a2713aSLionel Sambuc 
842f4a2713aSLionel Sambuc     const Decl *Param = Params->getParam(i);
843f4a2713aSLionel Sambuc     if (const TemplateTypeParmDecl *TTP =
844f4a2713aSLionel Sambuc           dyn_cast<TemplateTypeParmDecl>(Param)) {
845f4a2713aSLionel Sambuc 
846f4a2713aSLionel Sambuc       if (TTP->wasDeclaredWithTypename())
847f4a2713aSLionel Sambuc         Out << "typename ";
848f4a2713aSLionel Sambuc       else
849f4a2713aSLionel Sambuc         Out << "class ";
850f4a2713aSLionel Sambuc 
851f4a2713aSLionel Sambuc       if (TTP->isParameterPack())
852f4a2713aSLionel Sambuc         Out << "...";
853f4a2713aSLionel Sambuc 
854f4a2713aSLionel Sambuc       Out << *TTP;
855f4a2713aSLionel Sambuc 
856f4a2713aSLionel Sambuc       if (Args) {
857f4a2713aSLionel Sambuc         Out << " = ";
858f4a2713aSLionel Sambuc         Args->get(i).print(Policy, Out);
859f4a2713aSLionel Sambuc       } else if (TTP->hasDefaultArgument()) {
860f4a2713aSLionel Sambuc         Out << " = ";
861f4a2713aSLionel Sambuc         Out << TTP->getDefaultArgument().getAsString(Policy);
862f4a2713aSLionel Sambuc       };
863f4a2713aSLionel Sambuc     } else if (const NonTypeTemplateParmDecl *NTTP =
864f4a2713aSLionel Sambuc                  dyn_cast<NonTypeTemplateParmDecl>(Param)) {
865*0a6a1f1dSLionel Sambuc       StringRef Name;
866*0a6a1f1dSLionel Sambuc       if (IdentifierInfo *II = NTTP->getIdentifier())
867*0a6a1f1dSLionel Sambuc         Name = II->getName();
868*0a6a1f1dSLionel Sambuc       printDeclType(NTTP->getType(), Name, NTTP->isParameterPack());
869f4a2713aSLionel Sambuc 
870f4a2713aSLionel Sambuc       if (Args) {
871f4a2713aSLionel Sambuc         Out << " = ";
872f4a2713aSLionel Sambuc         Args->get(i).print(Policy, Out);
873f4a2713aSLionel Sambuc       } else if (NTTP->hasDefaultArgument()) {
874f4a2713aSLionel Sambuc         Out << " = ";
875*0a6a1f1dSLionel Sambuc         NTTP->getDefaultArgument()->printPretty(Out, nullptr, Policy,
876*0a6a1f1dSLionel Sambuc                                                 Indentation);
877f4a2713aSLionel Sambuc       }
878f4a2713aSLionel Sambuc     } else if (const TemplateTemplateParmDecl *TTPD =
879f4a2713aSLionel Sambuc                  dyn_cast<TemplateTemplateParmDecl>(Param)) {
880f4a2713aSLionel Sambuc       VisitTemplateDecl(TTPD);
881f4a2713aSLionel Sambuc       // FIXME: print the default argument, if present.
882f4a2713aSLionel Sambuc     }
883f4a2713aSLionel Sambuc   }
884f4a2713aSLionel Sambuc 
885f4a2713aSLionel Sambuc   Out << "> ";
886f4a2713aSLionel Sambuc }
887f4a2713aSLionel Sambuc 
VisitTemplateDecl(const TemplateDecl * D)888f4a2713aSLionel Sambuc void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
889f4a2713aSLionel Sambuc   PrintTemplateParameters(D->getTemplateParameters());
890f4a2713aSLionel Sambuc 
891f4a2713aSLionel Sambuc   if (const TemplateTemplateParmDecl *TTP =
892f4a2713aSLionel Sambuc         dyn_cast<TemplateTemplateParmDecl>(D)) {
893f4a2713aSLionel Sambuc     Out << "class ";
894f4a2713aSLionel Sambuc     if (TTP->isParameterPack())
895f4a2713aSLionel Sambuc       Out << "...";
896f4a2713aSLionel Sambuc     Out << D->getName();
897f4a2713aSLionel Sambuc   } else {
898f4a2713aSLionel Sambuc     Visit(D->getTemplatedDecl());
899f4a2713aSLionel Sambuc   }
900f4a2713aSLionel Sambuc }
901f4a2713aSLionel Sambuc 
VisitFunctionTemplateDecl(FunctionTemplateDecl * D)902f4a2713aSLionel Sambuc void DeclPrinter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
903f4a2713aSLionel Sambuc   if (PrintInstantiation) {
904f4a2713aSLionel Sambuc     TemplateParameterList *Params = D->getTemplateParameters();
905*0a6a1f1dSLionel Sambuc     for (auto *I : D->specializations()) {
906*0a6a1f1dSLionel Sambuc       PrintTemplateParameters(Params, I->getTemplateSpecializationArgs());
907*0a6a1f1dSLionel Sambuc       Visit(I);
908f4a2713aSLionel Sambuc     }
909f4a2713aSLionel Sambuc   }
910f4a2713aSLionel Sambuc 
911f4a2713aSLionel Sambuc   return VisitRedeclarableTemplateDecl(D);
912f4a2713aSLionel Sambuc }
913f4a2713aSLionel Sambuc 
VisitClassTemplateDecl(ClassTemplateDecl * D)914f4a2713aSLionel Sambuc void DeclPrinter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
915f4a2713aSLionel Sambuc   if (PrintInstantiation) {
916f4a2713aSLionel Sambuc     TemplateParameterList *Params = D->getTemplateParameters();
917*0a6a1f1dSLionel Sambuc     for (auto *I : D->specializations()) {
918*0a6a1f1dSLionel Sambuc       PrintTemplateParameters(Params, &I->getTemplateArgs());
919*0a6a1f1dSLionel Sambuc       Visit(I);
920f4a2713aSLionel Sambuc       Out << '\n';
921f4a2713aSLionel Sambuc     }
922f4a2713aSLionel Sambuc   }
923f4a2713aSLionel Sambuc 
924f4a2713aSLionel Sambuc   return VisitRedeclarableTemplateDecl(D);
925f4a2713aSLionel Sambuc }
926f4a2713aSLionel Sambuc 
927f4a2713aSLionel Sambuc //----------------------------------------------------------------------------
928f4a2713aSLionel Sambuc // Objective-C declarations
929f4a2713aSLionel Sambuc //----------------------------------------------------------------------------
930f4a2713aSLionel Sambuc 
VisitObjCMethodDecl(ObjCMethodDecl * OMD)931f4a2713aSLionel Sambuc void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
932f4a2713aSLionel Sambuc   if (OMD->isInstanceMethod())
933f4a2713aSLionel Sambuc     Out << "- ";
934f4a2713aSLionel Sambuc   else
935f4a2713aSLionel Sambuc     Out << "+ ";
936*0a6a1f1dSLionel Sambuc   if (!OMD->getReturnType().isNull())
937*0a6a1f1dSLionel Sambuc     Out << '(' << OMD->getASTContext()
938*0a6a1f1dSLionel Sambuc                       .getUnqualifiedObjCPointerType(OMD->getReturnType())
939*0a6a1f1dSLionel Sambuc                       .getAsString(Policy) << ")";
940f4a2713aSLionel Sambuc 
941f4a2713aSLionel Sambuc   std::string name = OMD->getSelector().getAsString();
942f4a2713aSLionel Sambuc   std::string::size_type pos, lastPos = 0;
943*0a6a1f1dSLionel Sambuc   for (const auto *PI : OMD->params()) {
944f4a2713aSLionel Sambuc     // FIXME: selector is missing here!
945f4a2713aSLionel Sambuc     pos = name.find_first_of(':', lastPos);
946f4a2713aSLionel Sambuc     Out << " " << name.substr(lastPos, pos - lastPos);
947*0a6a1f1dSLionel Sambuc     Out << ":(" << PI->getASTContext().getUnqualifiedObjCPointerType(PI->getType()).
948*0a6a1f1dSLionel Sambuc                       getAsString(Policy) << ')' << *PI;
949f4a2713aSLionel Sambuc     lastPos = pos + 1;
950f4a2713aSLionel Sambuc   }
951f4a2713aSLionel Sambuc 
952f4a2713aSLionel Sambuc   if (OMD->param_begin() == OMD->param_end())
953f4a2713aSLionel Sambuc     Out << " " << name;
954f4a2713aSLionel Sambuc 
955f4a2713aSLionel Sambuc   if (OMD->isVariadic())
956f4a2713aSLionel Sambuc       Out << ", ...";
957f4a2713aSLionel Sambuc 
958*0a6a1f1dSLionel Sambuc   prettyPrintAttributes(OMD);
959*0a6a1f1dSLionel Sambuc 
960f4a2713aSLionel Sambuc   if (OMD->getBody() && !Policy.TerseOutput) {
961f4a2713aSLionel Sambuc     Out << ' ';
962*0a6a1f1dSLionel Sambuc     OMD->getBody()->printPretty(Out, nullptr, Policy);
963f4a2713aSLionel Sambuc   }
964f4a2713aSLionel Sambuc   else if (Policy.PolishForDeclaration)
965f4a2713aSLionel Sambuc     Out << ';';
966f4a2713aSLionel Sambuc }
967f4a2713aSLionel Sambuc 
VisitObjCImplementationDecl(ObjCImplementationDecl * OID)968f4a2713aSLionel Sambuc void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
969f4a2713aSLionel Sambuc   std::string I = OID->getNameAsString();
970f4a2713aSLionel Sambuc   ObjCInterfaceDecl *SID = OID->getSuperClass();
971f4a2713aSLionel Sambuc 
972*0a6a1f1dSLionel Sambuc   bool eolnOut = false;
973f4a2713aSLionel Sambuc   if (SID)
974f4a2713aSLionel Sambuc     Out << "@implementation " << I << " : " << *SID;
975f4a2713aSLionel Sambuc   else
976f4a2713aSLionel Sambuc     Out << "@implementation " << I;
977f4a2713aSLionel Sambuc 
978f4a2713aSLionel Sambuc   if (OID->ivar_size() > 0) {
979f4a2713aSLionel Sambuc     Out << "{\n";
980*0a6a1f1dSLionel Sambuc     eolnOut = true;
981f4a2713aSLionel Sambuc     Indentation += Policy.Indentation;
982*0a6a1f1dSLionel Sambuc     for (const auto *I : OID->ivars()) {
983f4a2713aSLionel Sambuc       Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()).
984*0a6a1f1dSLionel Sambuc                     getAsString(Policy) << ' ' << *I << ";\n";
985f4a2713aSLionel Sambuc     }
986f4a2713aSLionel Sambuc     Indentation -= Policy.Indentation;
987f4a2713aSLionel Sambuc     Out << "}\n";
988f4a2713aSLionel Sambuc   }
989*0a6a1f1dSLionel Sambuc   else if (SID || (OID->decls_begin() != OID->decls_end())) {
990*0a6a1f1dSLionel Sambuc     Out << "\n";
991*0a6a1f1dSLionel Sambuc     eolnOut = true;
992*0a6a1f1dSLionel Sambuc   }
993f4a2713aSLionel Sambuc   VisitDeclContext(OID, false);
994*0a6a1f1dSLionel Sambuc   if (!eolnOut)
995*0a6a1f1dSLionel Sambuc     Out << "\n";
996f4a2713aSLionel Sambuc   Out << "@end";
997f4a2713aSLionel Sambuc }
998f4a2713aSLionel Sambuc 
VisitObjCInterfaceDecl(ObjCInterfaceDecl * OID)999f4a2713aSLionel Sambuc void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
1000f4a2713aSLionel Sambuc   std::string I = OID->getNameAsString();
1001f4a2713aSLionel Sambuc   ObjCInterfaceDecl *SID = OID->getSuperClass();
1002f4a2713aSLionel Sambuc 
1003f4a2713aSLionel Sambuc   if (!OID->isThisDeclarationADefinition()) {
1004f4a2713aSLionel Sambuc     Out << "@class " << I << ";";
1005f4a2713aSLionel Sambuc     return;
1006f4a2713aSLionel Sambuc   }
1007f4a2713aSLionel Sambuc   bool eolnOut = false;
1008f4a2713aSLionel Sambuc   if (SID)
1009f4a2713aSLionel Sambuc     Out << "@interface " << I << " : " << *SID;
1010f4a2713aSLionel Sambuc   else
1011f4a2713aSLionel Sambuc     Out << "@interface " << I;
1012f4a2713aSLionel Sambuc 
1013f4a2713aSLionel Sambuc   // Protocols?
1014f4a2713aSLionel Sambuc   const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
1015f4a2713aSLionel Sambuc   if (!Protocols.empty()) {
1016f4a2713aSLionel Sambuc     for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
1017f4a2713aSLionel Sambuc          E = Protocols.end(); I != E; ++I)
1018f4a2713aSLionel Sambuc       Out << (I == Protocols.begin() ? '<' : ',') << **I;
1019f4a2713aSLionel Sambuc     Out << "> ";
1020f4a2713aSLionel Sambuc   }
1021f4a2713aSLionel Sambuc 
1022f4a2713aSLionel Sambuc   if (OID->ivar_size() > 0) {
1023f4a2713aSLionel Sambuc     Out << "{\n";
1024f4a2713aSLionel Sambuc     eolnOut = true;
1025f4a2713aSLionel Sambuc     Indentation += Policy.Indentation;
1026*0a6a1f1dSLionel Sambuc     for (const auto *I : OID->ivars()) {
1027*0a6a1f1dSLionel Sambuc       Indent() << I->getASTContext()
1028*0a6a1f1dSLionel Sambuc                       .getUnqualifiedObjCPointerType(I->getType())
1029*0a6a1f1dSLionel Sambuc                       .getAsString(Policy) << ' ' << *I << ";\n";
1030f4a2713aSLionel Sambuc     }
1031f4a2713aSLionel Sambuc     Indentation -= Policy.Indentation;
1032f4a2713aSLionel Sambuc     Out << "}\n";
1033f4a2713aSLionel Sambuc   }
1034*0a6a1f1dSLionel Sambuc   else if (SID || (OID->decls_begin() != OID->decls_end())) {
1035f4a2713aSLionel Sambuc     Out << "\n";
1036f4a2713aSLionel Sambuc     eolnOut = true;
1037f4a2713aSLionel Sambuc   }
1038f4a2713aSLionel Sambuc 
1039f4a2713aSLionel Sambuc   VisitDeclContext(OID, false);
1040f4a2713aSLionel Sambuc   if (!eolnOut)
1041*0a6a1f1dSLionel Sambuc     Out << "\n";
1042f4a2713aSLionel Sambuc   Out << "@end";
1043f4a2713aSLionel Sambuc   // FIXME: implement the rest...
1044f4a2713aSLionel Sambuc }
1045f4a2713aSLionel Sambuc 
VisitObjCProtocolDecl(ObjCProtocolDecl * PID)1046f4a2713aSLionel Sambuc void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
1047f4a2713aSLionel Sambuc   if (!PID->isThisDeclarationADefinition()) {
1048f4a2713aSLionel Sambuc     Out << "@protocol " << *PID << ";\n";
1049f4a2713aSLionel Sambuc     return;
1050f4a2713aSLionel Sambuc   }
1051f4a2713aSLionel Sambuc   // Protocols?
1052f4a2713aSLionel Sambuc   const ObjCList<ObjCProtocolDecl> &Protocols = PID->getReferencedProtocols();
1053f4a2713aSLionel Sambuc   if (!Protocols.empty()) {
1054f4a2713aSLionel Sambuc     Out << "@protocol " << *PID;
1055f4a2713aSLionel Sambuc     for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
1056f4a2713aSLionel Sambuc          E = Protocols.end(); I != E; ++I)
1057f4a2713aSLionel Sambuc       Out << (I == Protocols.begin() ? '<' : ',') << **I;
1058f4a2713aSLionel Sambuc     Out << ">\n";
1059f4a2713aSLionel Sambuc   } else
1060f4a2713aSLionel Sambuc     Out << "@protocol " << *PID << '\n';
1061f4a2713aSLionel Sambuc   VisitDeclContext(PID, false);
1062f4a2713aSLionel Sambuc   Out << "@end";
1063f4a2713aSLionel Sambuc }
1064f4a2713aSLionel Sambuc 
VisitObjCCategoryImplDecl(ObjCCategoryImplDecl * PID)1065f4a2713aSLionel Sambuc void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
1066f4a2713aSLionel Sambuc   Out << "@implementation " << *PID->getClassInterface() << '(' << *PID <<")\n";
1067f4a2713aSLionel Sambuc 
1068f4a2713aSLionel Sambuc   VisitDeclContext(PID, false);
1069f4a2713aSLionel Sambuc   Out << "@end";
1070f4a2713aSLionel Sambuc   // FIXME: implement the rest...
1071f4a2713aSLionel Sambuc }
1072f4a2713aSLionel Sambuc 
VisitObjCCategoryDecl(ObjCCategoryDecl * PID)1073f4a2713aSLionel Sambuc void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
1074f4a2713aSLionel Sambuc   Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n";
1075f4a2713aSLionel Sambuc   if (PID->ivar_size() > 0) {
1076f4a2713aSLionel Sambuc     Out << "{\n";
1077f4a2713aSLionel Sambuc     Indentation += Policy.Indentation;
1078*0a6a1f1dSLionel Sambuc     for (const auto *I : PID->ivars())
1079f4a2713aSLionel Sambuc       Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()).
1080*0a6a1f1dSLionel Sambuc                     getAsString(Policy) << ' ' << *I << ";\n";
1081f4a2713aSLionel Sambuc     Indentation -= Policy.Indentation;
1082f4a2713aSLionel Sambuc     Out << "}\n";
1083f4a2713aSLionel Sambuc   }
1084f4a2713aSLionel Sambuc 
1085f4a2713aSLionel Sambuc   VisitDeclContext(PID, false);
1086f4a2713aSLionel Sambuc   Out << "@end";
1087f4a2713aSLionel Sambuc 
1088f4a2713aSLionel Sambuc   // FIXME: implement the rest...
1089f4a2713aSLionel Sambuc }
1090f4a2713aSLionel Sambuc 
VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl * AID)1091f4a2713aSLionel Sambuc void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) {
1092f4a2713aSLionel Sambuc   Out << "@compatibility_alias " << *AID
1093f4a2713aSLionel Sambuc       << ' ' << *AID->getClassInterface() << ";\n";
1094f4a2713aSLionel Sambuc }
1095f4a2713aSLionel Sambuc 
1096f4a2713aSLionel Sambuc /// PrintObjCPropertyDecl - print a property declaration.
1097f4a2713aSLionel Sambuc ///
VisitObjCPropertyDecl(ObjCPropertyDecl * PDecl)1098f4a2713aSLionel Sambuc void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
1099f4a2713aSLionel Sambuc   if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Required)
1100f4a2713aSLionel Sambuc     Out << "@required\n";
1101f4a2713aSLionel Sambuc   else if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Optional)
1102f4a2713aSLionel Sambuc     Out << "@optional\n";
1103f4a2713aSLionel Sambuc 
1104f4a2713aSLionel Sambuc   Out << "@property";
1105f4a2713aSLionel Sambuc   if (PDecl->getPropertyAttributes() != ObjCPropertyDecl::OBJC_PR_noattr) {
1106f4a2713aSLionel Sambuc     bool first = true;
1107f4a2713aSLionel Sambuc     Out << " (";
1108f4a2713aSLionel Sambuc     if (PDecl->getPropertyAttributes() &
1109f4a2713aSLionel Sambuc         ObjCPropertyDecl::OBJC_PR_readonly) {
1110f4a2713aSLionel Sambuc       Out << (first ? ' ' : ',') << "readonly";
1111f4a2713aSLionel Sambuc       first = false;
1112f4a2713aSLionel Sambuc     }
1113f4a2713aSLionel Sambuc 
1114f4a2713aSLionel Sambuc     if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) {
1115*0a6a1f1dSLionel Sambuc       Out << (first ? ' ' : ',') << "getter = ";
1116*0a6a1f1dSLionel Sambuc       PDecl->getGetterName().print(Out);
1117f4a2713aSLionel Sambuc       first = false;
1118f4a2713aSLionel Sambuc     }
1119f4a2713aSLionel Sambuc     if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) {
1120*0a6a1f1dSLionel Sambuc       Out << (first ? ' ' : ',') << "setter = ";
1121*0a6a1f1dSLionel Sambuc       PDecl->getSetterName().print(Out);
1122f4a2713aSLionel Sambuc       first = false;
1123f4a2713aSLionel Sambuc     }
1124f4a2713aSLionel Sambuc 
1125f4a2713aSLionel Sambuc     if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) {
1126f4a2713aSLionel Sambuc       Out << (first ? ' ' : ',') << "assign";
1127f4a2713aSLionel Sambuc       first = false;
1128f4a2713aSLionel Sambuc     }
1129f4a2713aSLionel Sambuc 
1130f4a2713aSLionel Sambuc     if (PDecl->getPropertyAttributes() &
1131f4a2713aSLionel Sambuc         ObjCPropertyDecl::OBJC_PR_readwrite) {
1132f4a2713aSLionel Sambuc       Out << (first ? ' ' : ',') << "readwrite";
1133f4a2713aSLionel Sambuc       first = false;
1134f4a2713aSLionel Sambuc     }
1135f4a2713aSLionel Sambuc 
1136f4a2713aSLionel Sambuc     if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) {
1137f4a2713aSLionel Sambuc       Out << (first ? ' ' : ',') << "retain";
1138f4a2713aSLionel Sambuc       first = false;
1139f4a2713aSLionel Sambuc     }
1140f4a2713aSLionel Sambuc 
1141f4a2713aSLionel Sambuc     if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_strong) {
1142f4a2713aSLionel Sambuc       Out << (first ? ' ' : ',') << "strong";
1143f4a2713aSLionel Sambuc       first = false;
1144f4a2713aSLionel Sambuc     }
1145f4a2713aSLionel Sambuc 
1146f4a2713aSLionel Sambuc     if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) {
1147f4a2713aSLionel Sambuc       Out << (first ? ' ' : ',') << "copy";
1148f4a2713aSLionel Sambuc       first = false;
1149f4a2713aSLionel Sambuc     }
1150f4a2713aSLionel Sambuc 
1151f4a2713aSLionel Sambuc     if (PDecl->getPropertyAttributes() &
1152f4a2713aSLionel Sambuc         ObjCPropertyDecl::OBJC_PR_nonatomic) {
1153f4a2713aSLionel Sambuc       Out << (first ? ' ' : ',') << "nonatomic";
1154f4a2713aSLionel Sambuc       first = false;
1155f4a2713aSLionel Sambuc     }
1156f4a2713aSLionel Sambuc     if (PDecl->getPropertyAttributes() &
1157f4a2713aSLionel Sambuc         ObjCPropertyDecl::OBJC_PR_atomic) {
1158f4a2713aSLionel Sambuc       Out << (first ? ' ' : ',') << "atomic";
1159f4a2713aSLionel Sambuc       first = false;
1160f4a2713aSLionel Sambuc     }
1161f4a2713aSLionel Sambuc 
1162f4a2713aSLionel Sambuc     (void) first; // Silence dead store warning due to idiomatic code.
1163f4a2713aSLionel Sambuc     Out << " )";
1164f4a2713aSLionel Sambuc   }
1165f4a2713aSLionel Sambuc   Out << ' ' << PDecl->getASTContext().getUnqualifiedObjCPointerType(PDecl->getType()).
1166f4a2713aSLionel Sambuc                   getAsString(Policy) << ' ' << *PDecl;
1167f4a2713aSLionel Sambuc   if (Policy.PolishForDeclaration)
1168f4a2713aSLionel Sambuc     Out << ';';
1169f4a2713aSLionel Sambuc }
1170f4a2713aSLionel Sambuc 
VisitObjCPropertyImplDecl(ObjCPropertyImplDecl * PID)1171f4a2713aSLionel Sambuc void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
1172f4a2713aSLionel Sambuc   if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize)
1173f4a2713aSLionel Sambuc     Out << "@synthesize ";
1174f4a2713aSLionel Sambuc   else
1175f4a2713aSLionel Sambuc     Out << "@dynamic ";
1176f4a2713aSLionel Sambuc   Out << *PID->getPropertyDecl();
1177f4a2713aSLionel Sambuc   if (PID->getPropertyIvarDecl())
1178f4a2713aSLionel Sambuc     Out << '=' << *PID->getPropertyIvarDecl();
1179f4a2713aSLionel Sambuc }
1180f4a2713aSLionel Sambuc 
VisitUsingDecl(UsingDecl * D)1181f4a2713aSLionel Sambuc void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
1182f4a2713aSLionel Sambuc   if (!D->isAccessDeclaration())
1183f4a2713aSLionel Sambuc     Out << "using ";
1184f4a2713aSLionel Sambuc   if (D->hasTypename())
1185f4a2713aSLionel Sambuc     Out << "typename ";
1186f4a2713aSLionel Sambuc   D->getQualifier()->print(Out, Policy);
1187f4a2713aSLionel Sambuc   Out << *D;
1188f4a2713aSLionel Sambuc }
1189f4a2713aSLionel Sambuc 
1190f4a2713aSLionel Sambuc void
VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl * D)1191f4a2713aSLionel Sambuc DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
1192f4a2713aSLionel Sambuc   Out << "using typename ";
1193f4a2713aSLionel Sambuc   D->getQualifier()->print(Out, Policy);
1194f4a2713aSLionel Sambuc   Out << D->getDeclName();
1195f4a2713aSLionel Sambuc }
1196f4a2713aSLionel Sambuc 
VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl * D)1197f4a2713aSLionel Sambuc void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
1198f4a2713aSLionel Sambuc   if (!D->isAccessDeclaration())
1199f4a2713aSLionel Sambuc     Out << "using ";
1200f4a2713aSLionel Sambuc   D->getQualifier()->print(Out, Policy);
1201f4a2713aSLionel Sambuc   Out << D->getName();
1202f4a2713aSLionel Sambuc }
1203f4a2713aSLionel Sambuc 
VisitUsingShadowDecl(UsingShadowDecl * D)1204f4a2713aSLionel Sambuc void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) {
1205f4a2713aSLionel Sambuc   // ignore
1206f4a2713aSLionel Sambuc }
1207f4a2713aSLionel Sambuc 
VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl * D)1208f4a2713aSLionel Sambuc void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
1209f4a2713aSLionel Sambuc   Out << "#pragma omp threadprivate";
1210f4a2713aSLionel Sambuc   if (!D->varlist_empty()) {
1211f4a2713aSLionel Sambuc     for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
1212f4a2713aSLionel Sambuc                                                 E = D->varlist_end();
1213f4a2713aSLionel Sambuc                                                 I != E; ++I) {
1214f4a2713aSLionel Sambuc       Out << (I == D->varlist_begin() ? '(' : ',');
1215f4a2713aSLionel Sambuc       NamedDecl *ND = cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl());
1216f4a2713aSLionel Sambuc       ND->printQualifiedName(Out);
1217f4a2713aSLionel Sambuc     }
1218f4a2713aSLionel Sambuc     Out << ")";
1219f4a2713aSLionel Sambuc   }
1220f4a2713aSLionel Sambuc }
1221f4a2713aSLionel Sambuc 
1222