1 | //===- MicrosoftDemangle.cpp ----------------------------------------------===// |
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 defines a demangler for MSVC-style mangled symbols. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/Demangle/MicrosoftDemangleNodes.h" |
14 | #include "llvm/Demangle/Utility.h" |
15 | #include <cctype> |
16 | #include <string> |
17 | |
18 | using namespace llvm; |
19 | using namespace ms_demangle; |
20 | |
21 | #define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \ |
22 | case Enum::Value: \ |
23 | OB << Desc; \ |
24 | break; |
25 | |
26 | // Writes a space if the last token does not end with a punctuation. |
27 | static void outputSpaceIfNecessary(OutputBuffer &OB) { |
28 | if (OB.empty()) |
29 | return; |
30 | |
31 | char C = OB.back(); |
32 | if (std::isalnum(C) || C == '>') |
33 | OB << " " ; |
34 | } |
35 | |
36 | static void outputSingleQualifier(OutputBuffer &OB, Qualifiers Q) { |
37 | switch (Q) { |
38 | case Q_Const: |
39 | OB << "const" ; |
40 | break; |
41 | case Q_Volatile: |
42 | OB << "volatile" ; |
43 | break; |
44 | case Q_Restrict: |
45 | OB << "__restrict" ; |
46 | break; |
47 | default: |
48 | break; |
49 | } |
50 | } |
51 | |
52 | static bool outputQualifierIfPresent(OutputBuffer &OB, Qualifiers Q, |
53 | Qualifiers Mask, bool NeedSpace) { |
54 | if (!(Q & Mask)) |
55 | return NeedSpace; |
56 | |
57 | if (NeedSpace) |
58 | OB << " " ; |
59 | |
60 | outputSingleQualifier(OB, Q: Mask); |
61 | return true; |
62 | } |
63 | |
64 | static void outputQualifiers(OutputBuffer &OB, Qualifiers Q, bool SpaceBefore, |
65 | bool SpaceAfter) { |
66 | if (Q == Q_None) |
67 | return; |
68 | |
69 | size_t Pos1 = OB.getCurrentPosition(); |
70 | SpaceBefore = outputQualifierIfPresent(OB, Q, Mask: Q_Const, NeedSpace: SpaceBefore); |
71 | SpaceBefore = outputQualifierIfPresent(OB, Q, Mask: Q_Volatile, NeedSpace: SpaceBefore); |
72 | SpaceBefore = outputQualifierIfPresent(OB, Q, Mask: Q_Restrict, NeedSpace: SpaceBefore); |
73 | size_t Pos2 = OB.getCurrentPosition(); |
74 | if (SpaceAfter && Pos2 > Pos1) |
75 | OB << " " ; |
76 | } |
77 | |
78 | static void outputCallingConvention(OutputBuffer &OB, CallingConv CC) { |
79 | outputSpaceIfNecessary(OB); |
80 | |
81 | switch (CC) { |
82 | case CallingConv::Cdecl: |
83 | OB << "__cdecl" ; |
84 | break; |
85 | case CallingConv::Fastcall: |
86 | OB << "__fastcall" ; |
87 | break; |
88 | case CallingConv::Pascal: |
89 | OB << "__pascal" ; |
90 | break; |
91 | case CallingConv::Regcall: |
92 | OB << "__regcall" ; |
93 | break; |
94 | case CallingConv::Stdcall: |
95 | OB << "__stdcall" ; |
96 | break; |
97 | case CallingConv::Thiscall: |
98 | OB << "__thiscall" ; |
99 | break; |
100 | case CallingConv::Eabi: |
101 | OB << "__eabi" ; |
102 | break; |
103 | case CallingConv::Vectorcall: |
104 | OB << "__vectorcall" ; |
105 | break; |
106 | case CallingConv::Clrcall: |
107 | OB << "__clrcall" ; |
108 | break; |
109 | case CallingConv::Swift: |
110 | OB << "__attribute__((__swiftcall__)) " ; |
111 | break; |
112 | case CallingConv::SwiftAsync: |
113 | OB << "__attribute__((__swiftasynccall__)) " ; |
114 | break; |
115 | default: |
116 | break; |
117 | } |
118 | } |
119 | |
120 | std::string Node::toString(OutputFlags Flags) const { |
121 | OutputBuffer OB; |
122 | this->output(OB, Flags); |
123 | std::string_view SV = OB; |
124 | std::string Owned(SV.begin(), SV.end()); |
125 | std::free(ptr: OB.getBuffer()); |
126 | return Owned; |
127 | } |
128 | |
129 | void PrimitiveTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { |
130 | switch (PrimKind) { |
131 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void" ); |
132 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool" ); |
133 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char" ); |
134 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char" ); |
135 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char" ); |
136 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char8, "char8_t" ); |
137 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, "char16_t" ); |
138 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, "char32_t" ); |
139 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, "short" ); |
140 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short" ); |
141 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, "int" ); |
142 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int" ); |
143 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, "long" ); |
144 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long" ); |
145 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, "__int64" ); |
146 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64" ); |
147 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, "wchar_t" ); |
148 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, "float" ); |
149 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, "double" ); |
150 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double" ); |
151 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t" ); |
152 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Auto, "auto" ); |
153 | OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, DecltypeAuto, "decltype(auto)" ); |
154 | } |
155 | outputQualifiers(OB, Q: Quals, SpaceBefore: true, SpaceAfter: false); |
156 | } |
157 | |
158 | void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
159 | output(OB, Flags, Separator: ", " ); |
160 | } |
161 | |
162 | void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags, |
163 | std::string_view Separator) const { |
164 | if (Count == 0) |
165 | return; |
166 | if (Nodes[0]) |
167 | Nodes[0]->output(OB, Flags); |
168 | for (size_t I = 1; I < Count; ++I) { |
169 | OB << Separator; |
170 | Nodes[I]->output(OB, Flags); |
171 | } |
172 | } |
173 | |
174 | void EncodedStringLiteralNode::output(OutputBuffer &OB, |
175 | OutputFlags Flags) const { |
176 | switch (Char) { |
177 | case CharKind::Wchar: |
178 | OB << "L\"" ; |
179 | break; |
180 | case CharKind::Char: |
181 | OB << "\"" ; |
182 | break; |
183 | case CharKind::Char16: |
184 | OB << "u\"" ; |
185 | break; |
186 | case CharKind::Char32: |
187 | OB << "U\"" ; |
188 | break; |
189 | } |
190 | OB << DecodedString << "\"" ; |
191 | if (IsTruncated) |
192 | OB << "..." ; |
193 | } |
194 | |
195 | void IntegerLiteralNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
196 | if (IsNegative) |
197 | OB << '-'; |
198 | OB << Value; |
199 | } |
200 | |
201 | void TemplateParameterReferenceNode::output(OutputBuffer &OB, |
202 | OutputFlags Flags) const { |
203 | if (ThunkOffsetCount > 0) |
204 | OB << "{" ; |
205 | else if (Affinity == PointerAffinity::Pointer) |
206 | OB << "&" ; |
207 | |
208 | if (Symbol) { |
209 | Symbol->output(OB, Flags); |
210 | if (ThunkOffsetCount > 0) |
211 | OB << ", " ; |
212 | } |
213 | |
214 | if (ThunkOffsetCount > 0) |
215 | OB << ThunkOffsets[0]; |
216 | for (int I = 1; I < ThunkOffsetCount; ++I) { |
217 | OB << ", " << ThunkOffsets[I]; |
218 | } |
219 | if (ThunkOffsetCount > 0) |
220 | OB << "}" ; |
221 | } |
222 | |
223 | void IdentifierNode::outputTemplateParameters(OutputBuffer &OB, |
224 | OutputFlags Flags) const { |
225 | if (!TemplateParams) |
226 | return; |
227 | OB << "<" ; |
228 | TemplateParams->output(OB, Flags); |
229 | OB << ">" ; |
230 | } |
231 | |
232 | void DynamicStructorIdentifierNode::output(OutputBuffer &OB, |
233 | OutputFlags Flags) const { |
234 | if (IsDestructor) |
235 | OB << "`dynamic atexit destructor for " ; |
236 | else |
237 | OB << "`dynamic initializer for " ; |
238 | |
239 | if (Variable) { |
240 | OB << "`" ; |
241 | Variable->output(OB, Flags); |
242 | OB << "''" ; |
243 | } else { |
244 | OB << "'" ; |
245 | Name->output(OB, Flags); |
246 | OB << "''" ; |
247 | } |
248 | } |
249 | |
250 | void NamedIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
251 | OB << Name; |
252 | outputTemplateParameters(OB, Flags); |
253 | } |
254 | |
255 | void IntrinsicFunctionIdentifierNode::output(OutputBuffer &OB, |
256 | OutputFlags Flags) const { |
257 | switch (Operator) { |
258 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new" ); |
259 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete" ); |
260 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator=" ); |
261 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>" ); |
262 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<" ); |
263 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!" ); |
264 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator==" ); |
265 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!=" ); |
266 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript, |
267 | "operator[]" ); |
268 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->" ); |
269 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++" ); |
270 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--" ); |
271 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-" ); |
272 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+" ); |
273 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*" ); |
274 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&" ); |
275 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer, |
276 | "operator->*" ); |
277 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/" ); |
278 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%" ); |
279 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<" ); |
280 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<=" ); |
281 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>" ); |
282 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual, |
283 | "operator>=" ); |
284 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator," ); |
285 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()" ); |
286 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~" ); |
287 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^" ); |
288 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|" ); |
289 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&" ); |
290 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||" ); |
291 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*=" ); |
292 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+=" ); |
293 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-=" ); |
294 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/=" ); |
295 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%=" ); |
296 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>=" ); |
297 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<=" ); |
298 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual, |
299 | "operator&=" ); |
300 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual, |
301 | "operator|=" ); |
302 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual, |
303 | "operator^=" ); |
304 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'" ); |
305 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor, |
306 | "`vector deleting dtor'" ); |
307 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure, |
308 | "`default ctor closure'" ); |
309 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor, |
310 | "`scalar deleting dtor'" ); |
311 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter, |
312 | "`vector ctor iterator'" ); |
313 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter, |
314 | "`vector dtor iterator'" ); |
315 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter, |
316 | "`vector vbase ctor iterator'" ); |
317 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap, |
318 | "`virtual displacement map'" ); |
319 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter, |
320 | "`eh vector ctor iterator'" ); |
321 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter, |
322 | "`eh vector dtor iterator'" ); |
323 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter, |
324 | "`eh vector vbase ctor iterator'" ); |
325 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure, |
326 | "`copy ctor closure'" ); |
327 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure, |
328 | "`local vftable ctor closure'" ); |
329 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]" ); |
330 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete, |
331 | "operator delete[]" ); |
332 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter, |
333 | "`managed vector ctor iterator'" ); |
334 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter, |
335 | "`managed vector dtor iterator'" ); |
336 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter, |
337 | "`EH vector copy ctor iterator'" ); |
338 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter, |
339 | "`EH vector vbase copy ctor iterator'" ); |
340 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter, |
341 | "`vector copy ctor iterator'" ); |
342 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter, |
343 | "`vector vbase copy constructor iterator'" ); |
344 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter, |
345 | "`managed vector vbase copy constructor iterator'" ); |
346 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait, |
347 | "operator co_await" ); |
348 | OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>" ); |
349 | case IntrinsicFunctionKind::MaxIntrinsic: |
350 | case IntrinsicFunctionKind::None: |
351 | break; |
352 | } |
353 | outputTemplateParameters(OB, Flags); |
354 | } |
355 | |
356 | void LocalStaticGuardIdentifierNode::output(OutputBuffer &OB, |
357 | OutputFlags Flags) const { |
358 | if (IsThread) |
359 | OB << "`local static thread guard'" ; |
360 | else |
361 | OB << "`local static guard'" ; |
362 | if (ScopeIndex > 0) |
363 | OB << "{" << ScopeIndex << "}" ; |
364 | } |
365 | |
366 | void ConversionOperatorIdentifierNode::output(OutputBuffer &OB, |
367 | OutputFlags Flags) const { |
368 | OB << "operator" ; |
369 | outputTemplateParameters(OB, Flags); |
370 | OB << " " ; |
371 | TargetType->output(OB, Flags); |
372 | } |
373 | |
374 | void StructorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
375 | if (IsDestructor) |
376 | OB << "~" ; |
377 | Class->output(OB, Flags); |
378 | outputTemplateParameters(OB, Flags); |
379 | } |
380 | |
381 | void LiteralOperatorIdentifierNode::output(OutputBuffer &OB, |
382 | OutputFlags Flags) const { |
383 | OB << "operator \"\"" << Name; |
384 | outputTemplateParameters(OB, Flags); |
385 | } |
386 | |
387 | void FunctionSignatureNode::outputPre(OutputBuffer &OB, |
388 | OutputFlags Flags) const { |
389 | if (!(Flags & OF_NoAccessSpecifier)) { |
390 | if (FunctionClass & FC_Public) |
391 | OB << "public: " ; |
392 | if (FunctionClass & FC_Protected) |
393 | OB << "protected: " ; |
394 | if (FunctionClass & FC_Private) |
395 | OB << "private: " ; |
396 | } |
397 | |
398 | if (!(Flags & OF_NoMemberType)) { |
399 | if (!(FunctionClass & FC_Global)) { |
400 | if (FunctionClass & FC_Static) |
401 | OB << "static " ; |
402 | } |
403 | if (FunctionClass & FC_Virtual) |
404 | OB << "virtual " ; |
405 | |
406 | if (FunctionClass & FC_ExternC) |
407 | OB << "extern \"C\" " ; |
408 | } |
409 | |
410 | if (!(Flags & OF_NoReturnType) && ReturnType) { |
411 | ReturnType->outputPre(OB, Flags); |
412 | OB << " " ; |
413 | } |
414 | |
415 | if (!(Flags & OF_NoCallingConvention)) |
416 | outputCallingConvention(OB, CC: CallConvention); |
417 | } |
418 | |
419 | void FunctionSignatureNode::outputPost(OutputBuffer &OB, |
420 | OutputFlags Flags) const { |
421 | if (!(FunctionClass & FC_NoParameterList)) { |
422 | OB << "(" ; |
423 | if (Params) |
424 | Params->output(OB, Flags); |
425 | else |
426 | OB << "void" ; |
427 | |
428 | if (IsVariadic) { |
429 | if (OB.back() != '(') |
430 | OB << ", " ; |
431 | OB << "..." ; |
432 | } |
433 | OB << ")" ; |
434 | } |
435 | |
436 | if (Quals & Q_Const) |
437 | OB << " const" ; |
438 | if (Quals & Q_Volatile) |
439 | OB << " volatile" ; |
440 | if (Quals & Q_Restrict) |
441 | OB << " __restrict" ; |
442 | if (Quals & Q_Unaligned) |
443 | OB << " __unaligned" ; |
444 | |
445 | if (IsNoexcept) |
446 | OB << " noexcept" ; |
447 | |
448 | if (RefQualifier == FunctionRefQualifier::Reference) |
449 | OB << " &" ; |
450 | else if (RefQualifier == FunctionRefQualifier::RValueReference) |
451 | OB << " &&" ; |
452 | |
453 | if (!(Flags & OF_NoReturnType) && ReturnType) |
454 | ReturnType->outputPost(OB, Flags); |
455 | } |
456 | |
457 | void ThunkSignatureNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { |
458 | OB << "[thunk]: " ; |
459 | |
460 | FunctionSignatureNode::outputPre(OB, Flags); |
461 | } |
462 | |
463 | void ThunkSignatureNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { |
464 | if (FunctionClass & FC_StaticThisAdjust) { |
465 | OB << "`adjustor{" << ThisAdjust.StaticOffset << "}'" ; |
466 | } else if (FunctionClass & FC_VirtualThisAdjust) { |
467 | if (FunctionClass & FC_VirtualThisAdjustEx) { |
468 | OB << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", " |
469 | << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset |
470 | << ", " << ThisAdjust.StaticOffset << "}'" ; |
471 | } else { |
472 | OB << "`vtordisp{" << ThisAdjust.VtordispOffset << ", " |
473 | << ThisAdjust.StaticOffset << "}'" ; |
474 | } |
475 | } |
476 | |
477 | FunctionSignatureNode::outputPost(OB, Flags); |
478 | } |
479 | |
480 | void PointerTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { |
481 | if (Pointee->kind() == NodeKind::FunctionSignature) { |
482 | // If this is a pointer to a function, don't output the calling convention. |
483 | // It needs to go inside the parentheses. |
484 | const FunctionSignatureNode *Sig = |
485 | static_cast<const FunctionSignatureNode *>(Pointee); |
486 | Sig->outputPre(OB, Flags: OF_NoCallingConvention); |
487 | } else |
488 | Pointee->outputPre(OB, Flags); |
489 | |
490 | outputSpaceIfNecessary(OB); |
491 | |
492 | if (Quals & Q_Unaligned) |
493 | OB << "__unaligned " ; |
494 | |
495 | if (Pointee->kind() == NodeKind::ArrayType) { |
496 | OB << "(" ; |
497 | } else if (Pointee->kind() == NodeKind::FunctionSignature) { |
498 | OB << "(" ; |
499 | const FunctionSignatureNode *Sig = |
500 | static_cast<const FunctionSignatureNode *>(Pointee); |
501 | outputCallingConvention(OB, CC: Sig->CallConvention); |
502 | OB << " " ; |
503 | } |
504 | |
505 | if (ClassParent) { |
506 | ClassParent->output(OB, Flags); |
507 | OB << "::" ; |
508 | } |
509 | |
510 | switch (Affinity) { |
511 | case PointerAffinity::Pointer: |
512 | OB << "*" ; |
513 | break; |
514 | case PointerAffinity::Reference: |
515 | OB << "&" ; |
516 | break; |
517 | case PointerAffinity::RValueReference: |
518 | OB << "&&" ; |
519 | break; |
520 | default: |
521 | assert(false); |
522 | } |
523 | outputQualifiers(OB, Q: Quals, SpaceBefore: false, SpaceAfter: false); |
524 | |
525 | if (PointerAuthQualifier) |
526 | PointerAuthQualifier->output(OB, Flags); |
527 | } |
528 | |
529 | void PointerTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { |
530 | if (Pointee->kind() == NodeKind::ArrayType || |
531 | Pointee->kind() == NodeKind::FunctionSignature) |
532 | OB << ")" ; |
533 | |
534 | Pointee->outputPost(OB, Flags); |
535 | } |
536 | |
537 | void TagTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { |
538 | if (!(Flags & OF_NoTagSpecifier)) { |
539 | switch (Tag) { |
540 | OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class" ); |
541 | OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct" ); |
542 | OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union" ); |
543 | OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum" ); |
544 | } |
545 | OB << " " ; |
546 | } |
547 | QualifiedName->output(OB, Flags); |
548 | outputQualifiers(OB, Q: Quals, SpaceBefore: true, SpaceAfter: false); |
549 | } |
550 | |
551 | void TagTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {} |
552 | |
553 | void ArrayTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { |
554 | ElementType->outputPre(OB, Flags); |
555 | outputQualifiers(OB, Q: Quals, SpaceBefore: true, SpaceAfter: false); |
556 | } |
557 | |
558 | void ArrayTypeNode::outputOneDimension(OutputBuffer &OB, OutputFlags Flags, |
559 | Node *N) const { |
560 | assert(N->kind() == NodeKind::IntegerLiteral); |
561 | IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N); |
562 | if (ILN->Value != 0) |
563 | ILN->output(OB, Flags); |
564 | } |
565 | |
566 | void ArrayTypeNode::outputDimensionsImpl(OutputBuffer &OB, |
567 | OutputFlags Flags) const { |
568 | if (Dimensions->Count == 0) |
569 | return; |
570 | |
571 | outputOneDimension(OB, Flags, N: Dimensions->Nodes[0]); |
572 | for (size_t I = 1; I < Dimensions->Count; ++I) { |
573 | OB << "][" ; |
574 | outputOneDimension(OB, Flags, N: Dimensions->Nodes[I]); |
575 | } |
576 | } |
577 | |
578 | void ArrayTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { |
579 | OB << "[" ; |
580 | outputDimensionsImpl(OB, Flags); |
581 | OB << "]" ; |
582 | |
583 | ElementType->outputPost(OB, Flags); |
584 | } |
585 | |
586 | void SymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
587 | Name->output(OB, Flags); |
588 | } |
589 | |
590 | void FunctionSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
591 | Signature->outputPre(OB, Flags); |
592 | outputSpaceIfNecessary(OB); |
593 | Name->output(OB, Flags); |
594 | Signature->outputPost(OB, Flags); |
595 | } |
596 | |
597 | void PointerAuthQualifierNode::output(OutputBuffer &OB, |
598 | OutputFlags Flags) const { |
599 | OB << "__ptrauth(" ; |
600 | Components->output(OB, Flags); |
601 | OB << ")" ; |
602 | } |
603 | |
604 | void VariableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
605 | const char *AccessSpec = nullptr; |
606 | bool IsStatic = true; |
607 | switch (SC) { |
608 | case StorageClass::PrivateStatic: |
609 | AccessSpec = "private" ; |
610 | break; |
611 | case StorageClass::PublicStatic: |
612 | AccessSpec = "public" ; |
613 | break; |
614 | case StorageClass::ProtectedStatic: |
615 | AccessSpec = "protected" ; |
616 | break; |
617 | default: |
618 | IsStatic = false; |
619 | break; |
620 | } |
621 | if (!(Flags & OF_NoAccessSpecifier) && AccessSpec) |
622 | OB << AccessSpec << ": " ; |
623 | if (!(Flags & OF_NoMemberType) && IsStatic) |
624 | OB << "static " ; |
625 | |
626 | if (!(Flags & OF_NoVariableType) && Type) { |
627 | Type->outputPre(OB, Flags); |
628 | outputSpaceIfNecessary(OB); |
629 | } |
630 | Name->output(OB, Flags); |
631 | if (!(Flags & OF_NoVariableType) && Type) |
632 | Type->outputPost(OB, Flags); |
633 | } |
634 | |
635 | void CustomTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { |
636 | Identifier->output(OB, Flags); |
637 | } |
638 | void CustomTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {} |
639 | |
640 | void QualifiedNameNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
641 | Components->output(OB, Flags, Separator: "::" ); |
642 | } |
643 | |
644 | void RttiBaseClassDescriptorNode::output(OutputBuffer &OB, |
645 | OutputFlags Flags) const { |
646 | OB << "`RTTI Base Class Descriptor at (" ; |
647 | OB << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", " |
648 | << this->Flags; |
649 | OB << ")'" ; |
650 | } |
651 | |
652 | void LocalStaticGuardVariableNode::output(OutputBuffer &OB, |
653 | OutputFlags Flags) const { |
654 | Name->output(OB, Flags); |
655 | } |
656 | |
657 | void VcallThunkIdentifierNode::output(OutputBuffer &OB, |
658 | OutputFlags Flags) const { |
659 | OB << "`vcall'{" << OffsetInVTable << ", {flat}}" ; |
660 | } |
661 | |
662 | void SpecialTableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { |
663 | outputQualifiers(OB, Q: Quals, SpaceBefore: false, SpaceAfter: true); |
664 | Name->output(OB, Flags); |
665 | if (TargetName) { |
666 | OB << "{for `" ; |
667 | TargetName->output(OB, Flags); |
668 | OB << "'}" ; |
669 | } |
670 | } |
671 | |