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