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