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