blob: 9cee975231a2a073c5d5cada489825684e900566 [file] [log] [blame]
Zachary Turner03312862018-08-27 03:48:03 +00001//===- MicrosoftDemangle.cpp ----------------------------------------------===//
2//
Chandler Carruth57b08b02019-01-19 10:56:40 +00003// 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
Zachary Turner03312862018-08-27 03:48:03 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This file defines a demangler for MSVC-style mangled symbols.
10//
11//===----------------------------------------------------------------------===//
12
Zachary Turner7ba90562018-11-01 15:07:32 +000013#include "llvm/Demangle/MicrosoftDemangleNodes.h"
Erik Pilkington5094e5e2019-01-17 20:37:51 +000014#include "llvm/Demangle/DemangleConfig.h"
Zachary Turner03312862018-08-27 03:48:03 +000015#include "llvm/Demangle/Utility.h"
Chandler Carruthbe4a5492018-08-27 06:52:14 +000016#include <cctype>
Zachary Turner1b9a9382018-12-17 16:42:26 +000017#include <string>
Zachary Turner03312862018-08-27 03:48:03 +000018
19using namespace llvm;
20using namespace ms_demangle;
21
22#define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \
23 case Enum::Value: \
24 OS << Desc; \
25 break;
26
27// Writes a space if the last token does not end with a punctuation.
28static void outputSpaceIfNecessary(OutputStream &OS) {
29 if (OS.empty())
30 return;
31
32 char C = OS.back();
Chandler Carruthbe4a5492018-08-27 06:52:14 +000033 if (std::isalnum(C) || C == '>')
Zachary Turner03312862018-08-27 03:48:03 +000034 OS << " ";
35}
36
Nico Weber880d21d2019-06-04 15:13:30 +000037static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) {
Zachary Turner03312862018-08-27 03:48:03 +000038 switch (Q) {
39 case Q_Const:
40 OS << "const";
Nico Weber880d21d2019-06-04 15:13:30 +000041 break;
Zachary Turner03312862018-08-27 03:48:03 +000042 case Q_Volatile:
43 OS << "volatile";
Nico Weber880d21d2019-06-04 15:13:30 +000044 break;
Zachary Turner03312862018-08-27 03:48:03 +000045 case Q_Restrict:
46 OS << "__restrict";
Nico Weber880d21d2019-06-04 15:13:30 +000047 break;
Zachary Turner03312862018-08-27 03:48:03 +000048 default:
49 break;
50 }
Zachary Turner03312862018-08-27 03:48:03 +000051}
52
53static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q,
54 Qualifiers Mask, bool NeedSpace) {
55 if (!(Q & Mask))
56 return NeedSpace;
57
58 if (NeedSpace)
59 OS << " ";
60
61 outputSingleQualifier(OS, Mask);
62 return true;
63}
64
65static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore,
66 bool SpaceAfter) {
67 if (Q == Q_None)
68 return;
69
70 size_t Pos1 = OS.getCurrentPosition();
71 SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore);
72 SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore);
73 SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore);
74 size_t Pos2 = OS.getCurrentPosition();
75 if (SpaceAfter && Pos2 > Pos1)
76 OS << " ";
77}
78
79static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
80 outputSpaceIfNecessary(OS);
81
82 switch (CC) {
83 case CallingConv::Cdecl:
84 OS << "__cdecl";
85 break;
86 case CallingConv::Fastcall:
87 OS << "__fastcall";
88 break;
89 case CallingConv::Pascal:
90 OS << "__pascal";
91 break;
92 case CallingConv::Regcall:
93 OS << "__regcall";
94 break;
95 case CallingConv::Stdcall:
96 OS << "__stdcall";
97 break;
98 case CallingConv::Thiscall:
99 OS << "__thiscall";
100 break;
101 case CallingConv::Eabi:
102 OS << "__eabi";
103 break;
104 case CallingConv::Vectorcall:
105 OS << "__vectorcall";
106 break;
107 case CallingConv::Clrcall:
108 OS << "__clrcall";
109 break;
110 default:
111 break;
112 }
113}
114
Zachary Turnerba797b62019-01-02 18:33:12 +0000115std::string Node::toString(OutputFlags Flags) const {
Zachary Turnerb4725122018-12-17 16:14:50 +0000116 OutputStream OS;
117 initializeOutputStream(nullptr, nullptr, OS, 1024);
Zachary Turnerba797b62019-01-02 18:33:12 +0000118 this->output(OS, Flags);
Zachary Turnerb4725122018-12-17 16:14:50 +0000119 OS << '\0';
120 return {OS.getBuffer()};
121}
122
Zachary Turner38d2edd2018-08-29 03:59:17 +0000123void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000124 switch (PrimKind) {
125 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void");
126 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool");
127 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char");
128 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char");
129 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char");
Nico Webera2ca6e72019-05-28 15:30:04 +0000130 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char8, "char8_t");
Zachary Turner03312862018-08-27 03:48:03 +0000131 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, "char16_t");
132 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, "char32_t");
133 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, "short");
134 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short");
135 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, "int");
136 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int");
137 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, "long");
138 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long");
139 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, "__int64");
140 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64");
141 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, "wchar_t");
142 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, "float");
143 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, "double");
144 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double");
145 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t");
146 }
147 outputQualifiers(OS, Quals, true, false);
148}
149
Zachary Turner38d2edd2018-08-29 03:59:17 +0000150void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const {
151 output(OS, Flags, ", ");
152}
Zachary Turner03312862018-08-27 03:48:03 +0000153
Zachary Turner38d2edd2018-08-29 03:59:17 +0000154void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags,
155 StringView Separator) const {
Zachary Turner03312862018-08-27 03:48:03 +0000156 if (Count == 0)
157 return;
158 if (Nodes[0])
Zachary Turner38d2edd2018-08-29 03:59:17 +0000159 Nodes[0]->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000160 for (size_t I = 1; I < Count; ++I) {
161 OS << Separator;
Zachary Turner38d2edd2018-08-29 03:59:17 +0000162 Nodes[I]->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000163 }
164}
165
Zachary Turner38d2edd2018-08-29 03:59:17 +0000166void EncodedStringLiteralNode::output(OutputStream &OS,
167 OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000168 switch (Char) {
169 case CharKind::Wchar:
Nico Weberdfc08ba2018-11-09 19:28:50 +0000170 OS << "L\"";
Zachary Turner03312862018-08-27 03:48:03 +0000171 break;
172 case CharKind::Char:
Nico Weberdfc08ba2018-11-09 19:28:50 +0000173 OS << "\"";
Zachary Turner03312862018-08-27 03:48:03 +0000174 break;
175 case CharKind::Char16:
Nico Weberdfc08ba2018-11-09 19:28:50 +0000176 OS << "u\"";
Zachary Turner03312862018-08-27 03:48:03 +0000177 break;
178 case CharKind::Char32:
Nico Weberdfc08ba2018-11-09 19:28:50 +0000179 OS << "U\"";
Zachary Turner03312862018-08-27 03:48:03 +0000180 break;
181 }
182 OS << DecodedString << "\"";
183 if (IsTruncated)
184 OS << "...";
Zachary Turner03312862018-08-27 03:48:03 +0000185}
186
Zachary Turner38d2edd2018-08-29 03:59:17 +0000187void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000188 if (IsNegative)
189 OS << '-';
190 OS << Value;
191}
192
Zachary Turner38d2edd2018-08-29 03:59:17 +0000193void TemplateParameterReferenceNode::output(OutputStream &OS,
194 OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000195 if (ThunkOffsetCount > 0)
196 OS << "{";
197 else if (Affinity == PointerAffinity::Pointer)
198 OS << "&";
199
200 if (Symbol) {
Zachary Turner38d2edd2018-08-29 03:59:17 +0000201 Symbol->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000202 if (ThunkOffsetCount > 0)
203 OS << ", ";
204 }
205
206 if (ThunkOffsetCount > 0)
207 OS << ThunkOffsets[0];
208 for (int I = 1; I < ThunkOffsetCount; ++I) {
209 OS << ", " << ThunkOffsets[I];
210 }
211 if (ThunkOffsetCount > 0)
212 OS << "}";
213}
214
Zachary Turner38d2edd2018-08-29 03:59:17 +0000215void IdentifierNode::outputTemplateParameters(OutputStream &OS,
216 OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000217 if (!TemplateParams)
218 return;
219 OS << "<";
Zachary Turner38d2edd2018-08-29 03:59:17 +0000220 TemplateParams->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000221 OS << ">";
222}
223
Zachary Turner38d2edd2018-08-29 03:59:17 +0000224void DynamicStructorIdentifierNode::output(OutputStream &OS,
225 OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000226 if (IsDestructor)
227 OS << "`dynamic atexit destructor for ";
228 else
229 OS << "`dynamic initializer for ";
230
Zachary Turner32a8a202018-08-29 23:56:09 +0000231 if (Variable) {
232 OS << "`";
233 Variable->output(OS, Flags);
234 OS << "''";
235 } else {
236 OS << "'";
237 Name->output(OS, Flags);
238 OS << "''";
239 }
Zachary Turner03312862018-08-27 03:48:03 +0000240}
241
Zachary Turner38d2edd2018-08-29 03:59:17 +0000242void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000243 OS << Name;
Zachary Turner38d2edd2018-08-29 03:59:17 +0000244 outputTemplateParameters(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000245}
246
Zachary Turner38d2edd2018-08-29 03:59:17 +0000247void IntrinsicFunctionIdentifierNode::output(OutputStream &OS,
248 OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000249 switch (Operator) {
250 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new");
251 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete");
252 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator=");
253 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>");
254 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<");
255 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!");
256 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator==");
257 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!=");
258 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript,
259 "operator[]");
260 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->");
261 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++");
262 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--");
263 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-");
264 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+");
265 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*");
266 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&");
267 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer,
268 "operator->*");
269 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/");
270 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%");
271 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<");
272 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<=");
273 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>");
274 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual,
275 "operator>=");
276 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,");
277 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()");
278 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~");
279 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^");
280 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|");
281 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&");
282 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||");
283 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*=");
284 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+=");
285 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-=");
286 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/=");
287 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%=");
288 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>=");
289 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<=");
290 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual,
291 "operator&=");
292 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual,
293 "operator|=");
294 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual,
295 "operator^=");
296 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'");
297 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor,
298 "`vector deleting dtor'");
299 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure,
300 "`default ctor closure'");
301 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor,
302 "`scalar deleting dtor'");
303 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter,
304 "`vector ctor iterator'");
305 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter,
306 "`vector dtor iterator'");
307 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter,
308 "`vector vbase ctor iterator'");
309 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap,
310 "`virtual displacement map'");
311 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter,
312 "`eh vector ctor iterator'");
313 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter,
314 "`eh vector dtor iterator'");
315 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter,
316 "`eh vector vbase ctor iterator'");
317 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure,
318 "`copy ctor closure'");
319 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure,
320 "`local vftable ctor closure'");
321 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]");
322 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete,
323 "operator delete[]");
324 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter,
325 "`managed vector ctor iterator'");
326 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter,
327 "`managed vector dtor iterator'");
328 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter,
329 "`EH vector copy ctor iterator'");
330 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter,
331 "`EH vector vbase copy ctor iterator'");
332 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter,
333 "`vector copy ctor iterator'");
334 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter,
335 "`vector vbase copy constructor iterator'");
336 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter,
337 "`managed vector vbase copy constructor iterator'");
Nico Webere8f21b12019-04-23 16:20:27 +0000338 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait,
339 "operator co_await");
340 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>");
Zachary Turner03312862018-08-27 03:48:03 +0000341 case IntrinsicFunctionKind::MaxIntrinsic:
342 case IntrinsicFunctionKind::None:
343 break;
344 }
Zachary Turner38d2edd2018-08-29 03:59:17 +0000345 outputTemplateParameters(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000346}
347
Zachary Turner38d2edd2018-08-29 03:59:17 +0000348void LocalStaticGuardIdentifierNode::output(OutputStream &OS,
349 OutputFlags Flags) const {
Nico Weber88ab2812019-05-28 14:54:49 +0000350 if (IsThread)
351 OS << "`local static thread guard'";
352 else
353 OS << "`local static guard'";
Zachary Turner03312862018-08-27 03:48:03 +0000354 if (ScopeIndex > 0)
355 OS << "{" << ScopeIndex << "}";
356}
357
Zachary Turner38d2edd2018-08-29 03:59:17 +0000358void ConversionOperatorIdentifierNode::output(OutputStream &OS,
359 OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000360 OS << "operator";
Zachary Turner38d2edd2018-08-29 03:59:17 +0000361 outputTemplateParameters(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000362 OS << " ";
Zachary Turner38d2edd2018-08-29 03:59:17 +0000363 TargetType->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000364}
365
Zachary Turner38d2edd2018-08-29 03:59:17 +0000366void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000367 if (IsDestructor)
368 OS << "~";
Zachary Turner38d2edd2018-08-29 03:59:17 +0000369 Class->output(OS, Flags);
370 outputTemplateParameters(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000371}
372
Zachary Turner38d2edd2018-08-29 03:59:17 +0000373void LiteralOperatorIdentifierNode::output(OutputStream &OS,
374 OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000375 OS << "operator \"\"" << Name;
Zachary Turner38d2edd2018-08-29 03:59:17 +0000376 outputTemplateParameters(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000377}
378
379void FunctionSignatureNode::outputPre(OutputStream &OS,
Zachary Turner38d2edd2018-08-29 03:59:17 +0000380 OutputFlags Flags) const {
Martin Storsjoda92ed82019-10-15 08:29:56 +0000381 if (!(Flags & OF_NoAccessSpecifier)) {
382 if (FunctionClass & FC_Public)
383 OS << "public: ";
384 if (FunctionClass & FC_Protected)
385 OS << "protected: ";
386 if (FunctionClass & FC_Private)
387 OS << "private: ";
Zachary Turner03312862018-08-27 03:48:03 +0000388 }
Zachary Turner03312862018-08-27 03:48:03 +0000389
Martin Storsjoda92ed82019-10-15 08:29:56 +0000390 if (!(Flags & OF_NoMemberType)) {
391 if (!(FunctionClass & FC_Global)) {
392 if (FunctionClass & FC_Static)
393 OS << "static ";
394 }
395 if (FunctionClass & FC_Virtual)
396 OS << "virtual ";
Nico Webera92b4632018-11-13 20:18:26 +0000397
Martin Storsjoda92ed82019-10-15 08:29:56 +0000398 if (FunctionClass & FC_ExternC)
399 OS << "extern \"C\" ";
400 }
401
402 if (!(Flags & OF_NoReturnType) && ReturnType) {
Zachary Turner38d2edd2018-08-29 03:59:17 +0000403 ReturnType->outputPre(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000404 OS << " ";
405 }
406
Zachary Turner38d2edd2018-08-29 03:59:17 +0000407 if (!(Flags & OF_NoCallingConvention))
Zachary Turner03312862018-08-27 03:48:03 +0000408 outputCallingConvention(OS, CallConvention);
409}
410
411void FunctionSignatureNode::outputPost(OutputStream &OS,
Zachary Turner38d2edd2018-08-29 03:59:17 +0000412 OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000413 if (!(FunctionClass & FC_NoParameterList)) {
414 OS << "(";
415 if (Params)
Zachary Turner38d2edd2018-08-29 03:59:17 +0000416 Params->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000417 else
418 OS << "void";
Nico Weber1dce8262019-06-04 19:10:08 +0000419
420 if (IsVariadic) {
421 if (OS.back() != '(')
422 OS << ", ";
423 OS << "...";
424 }
Zachary Turner03312862018-08-27 03:48:03 +0000425 OS << ")";
426 }
427
428 if (Quals & Q_Const)
429 OS << " const";
430 if (Quals & Q_Volatile)
431 OS << " volatile";
432 if (Quals & Q_Restrict)
433 OS << " __restrict";
434 if (Quals & Q_Unaligned)
435 OS << " __unaligned";
436
Zachary Turner2fe49002019-01-08 21:05:51 +0000437 if (IsNoexcept)
438 OS << " noexcept";
439
Zachary Turner03312862018-08-27 03:48:03 +0000440 if (RefQualifier == FunctionRefQualifier::Reference)
441 OS << " &";
442 else if (RefQualifier == FunctionRefQualifier::RValueReference)
443 OS << " &&";
444
Martin Storsjoda92ed82019-10-15 08:29:56 +0000445 if (!(Flags & OF_NoReturnType) && ReturnType)
Zachary Turner38d2edd2018-08-29 03:59:17 +0000446 ReturnType->outputPost(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000447}
448
Zachary Turner38d2edd2018-08-29 03:59:17 +0000449void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000450 OS << "[thunk]: ";
451
452 FunctionSignatureNode::outputPre(OS, Flags);
453}
454
Zachary Turner38d2edd2018-08-29 03:59:17 +0000455void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000456 if (FunctionClass & FC_StaticThisAdjust) {
457 OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
458 } else if (FunctionClass & FC_VirtualThisAdjust) {
459 if (FunctionClass & FC_VirtualThisAdjustEx) {
460 OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
461 << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
462 << ", " << ThisAdjust.StaticOffset << "}'";
463 } else {
464 OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
465 << ThisAdjust.StaticOffset << "}'";
466 }
467 }
468
469 FunctionSignatureNode::outputPost(OS, Flags);
470}
471
Zachary Turner38d2edd2018-08-29 03:59:17 +0000472void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000473 if (Pointee->kind() == NodeKind::FunctionSignature) {
474 // If this is a pointer to a function, don't output the calling convention.
475 // It needs to go inside the parentheses.
476 const FunctionSignatureNode *Sig =
477 static_cast<const FunctionSignatureNode *>(Pointee);
Zachary Turner38d2edd2018-08-29 03:59:17 +0000478 Sig->outputPre(OS, OF_NoCallingConvention);
Zachary Turner03312862018-08-27 03:48:03 +0000479 } else
Zachary Turner38d2edd2018-08-29 03:59:17 +0000480 Pointee->outputPre(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000481
482 outputSpaceIfNecessary(OS);
483
484 if (Quals & Q_Unaligned)
485 OS << "__unaligned ";
486
487 if (Pointee->kind() == NodeKind::ArrayType) {
488 OS << "(";
489 } else if (Pointee->kind() == NodeKind::FunctionSignature) {
490 OS << "(";
491 const FunctionSignatureNode *Sig =
492 static_cast<const FunctionSignatureNode *>(Pointee);
493 outputCallingConvention(OS, Sig->CallConvention);
494 OS << " ";
495 }
496
497 if (ClassParent) {
Zachary Turner38d2edd2018-08-29 03:59:17 +0000498 ClassParent->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000499 OS << "::";
500 }
501
502 switch (Affinity) {
503 case PointerAffinity::Pointer:
504 OS << "*";
505 break;
506 case PointerAffinity::Reference:
507 OS << "&";
508 break;
509 case PointerAffinity::RValueReference:
510 OS << "&&";
511 break;
512 default:
513 assert(false);
514 }
515 outputQualifiers(OS, Quals, false, false);
516}
517
Zachary Turner38d2edd2018-08-29 03:59:17 +0000518void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000519 if (Pointee->kind() == NodeKind::ArrayType ||
520 Pointee->kind() == NodeKind::FunctionSignature)
521 OS << ")";
522
Zachary Turner38d2edd2018-08-29 03:59:17 +0000523 Pointee->outputPost(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000524}
525
Zachary Turner38d2edd2018-08-29 03:59:17 +0000526void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
Zachary Turnerba797b62019-01-02 18:33:12 +0000527 if (!(Flags & OF_NoTagSpecifier)) {
528 switch (Tag) {
529 OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class");
530 OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct");
531 OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union");
532 OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum");
533 }
534 OS << " ";
Zachary Turner03312862018-08-27 03:48:03 +0000535 }
Zachary Turner38d2edd2018-08-29 03:59:17 +0000536 QualifiedName->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000537 outputQualifiers(OS, Quals, true, false);
538}
539
Zachary Turner38d2edd2018-08-29 03:59:17 +0000540void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
Zachary Turner03312862018-08-27 03:48:03 +0000541
Zachary Turner38d2edd2018-08-29 03:59:17 +0000542void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
543 ElementType->outputPre(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000544 outputQualifiers(OS, Quals, true, false);
545}
546
Zachary Turner38d2edd2018-08-29 03:59:17 +0000547void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags,
548 Node *N) const {
Zachary Turner03312862018-08-27 03:48:03 +0000549 assert(N->kind() == NodeKind::IntegerLiteral);
550 IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
551 if (ILN->Value != 0)
Zachary Turner38d2edd2018-08-29 03:59:17 +0000552 ILN->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000553}
554
Zachary Turner38d2edd2018-08-29 03:59:17 +0000555void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS,
556 OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000557 if (Dimensions->Count == 0)
558 return;
559
Zachary Turner38d2edd2018-08-29 03:59:17 +0000560 outputOneDimension(OS, Flags, Dimensions->Nodes[0]);
Zachary Turner03312862018-08-27 03:48:03 +0000561 for (size_t I = 1; I < Dimensions->Count; ++I) {
562 OS << "][";
Zachary Turner38d2edd2018-08-29 03:59:17 +0000563 outputOneDimension(OS, Flags, Dimensions->Nodes[I]);
Zachary Turner03312862018-08-27 03:48:03 +0000564 }
565}
566
Zachary Turner38d2edd2018-08-29 03:59:17 +0000567void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000568 OS << "[";
Zachary Turner38d2edd2018-08-29 03:59:17 +0000569 outputDimensionsImpl(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000570 OS << "]";
571
Zachary Turner38d2edd2018-08-29 03:59:17 +0000572 ElementType->outputPost(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000573}
574
Zachary Turner38d2edd2018-08-29 03:59:17 +0000575void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
576 Name->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000577}
578
Zachary Turner38d2edd2018-08-29 03:59:17 +0000579void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000580 Signature->outputPre(OS, Flags);
581 outputSpaceIfNecessary(OS);
Zachary Turner38d2edd2018-08-29 03:59:17 +0000582 Name->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000583 Signature->outputPost(OS, Flags);
584}
585
Zachary Turner38d2edd2018-08-29 03:59:17 +0000586void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
Martin Storsjoda92ed82019-10-15 08:29:56 +0000587 const char *AccessSpec = nullptr;
588 bool IsStatic = true;
Zachary Turner03312862018-08-27 03:48:03 +0000589 switch (SC) {
590 case StorageClass::PrivateStatic:
Martin Storsjoda92ed82019-10-15 08:29:56 +0000591 AccessSpec = "private";
Nico Webera92b4632018-11-13 20:18:26 +0000592 break;
Zachary Turner03312862018-08-27 03:48:03 +0000593 case StorageClass::PublicStatic:
Martin Storsjoda92ed82019-10-15 08:29:56 +0000594 AccessSpec = "public";
Nico Webera92b4632018-11-13 20:18:26 +0000595 break;
Zachary Turner03312862018-08-27 03:48:03 +0000596 case StorageClass::ProtectedStatic:
Martin Storsjoda92ed82019-10-15 08:29:56 +0000597 AccessSpec = "protected";
Reid Kleckner4dc0b1a2018-11-01 19:54:45 +0000598 break;
Zachary Turner03312862018-08-27 03:48:03 +0000599 default:
Martin Storsjoda92ed82019-10-15 08:29:56 +0000600 IsStatic = false;
Zachary Turner03312862018-08-27 03:48:03 +0000601 break;
602 }
Martin Storsjoda92ed82019-10-15 08:29:56 +0000603 if (!(Flags & OF_NoAccessSpecifier) && AccessSpec)
604 OS << AccessSpec << ": ";
605 if (!(Flags & OF_NoMemberType) && IsStatic)
606 OS << "static ";
Zachary Turner03312862018-08-27 03:48:03 +0000607
608 if (Type) {
Zachary Turner38d2edd2018-08-29 03:59:17 +0000609 Type->outputPre(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000610 outputSpaceIfNecessary(OS);
611 }
Zachary Turner38d2edd2018-08-29 03:59:17 +0000612 Name->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000613 if (Type)
Zachary Turner38d2edd2018-08-29 03:59:17 +0000614 Type->outputPost(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000615}
616
Zachary Turnerb2fef1a2018-08-29 04:12:44 +0000617void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
618 Identifier->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000619}
Zachary Turnerb2fef1a2018-08-29 04:12:44 +0000620void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
Zachary Turner03312862018-08-27 03:48:03 +0000621
Zachary Turner38d2edd2018-08-29 03:59:17 +0000622void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {
623 Components->output(OS, Flags, "::");
624}
625
626void RttiBaseClassDescriptorNode::output(OutputStream &OS,
627 OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000628 OS << "`RTTI Base Class Descriptor at (";
629 OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
Zachary Turner38d2edd2018-08-29 03:59:17 +0000630 << this->Flags;
Zachary Turner03312862018-08-27 03:48:03 +0000631 OS << ")'";
632}
633
Zachary Turner38d2edd2018-08-29 03:59:17 +0000634void LocalStaticGuardVariableNode::output(OutputStream &OS,
635 OutputFlags Flags) const {
636 Name->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000637}
638
Zachary Turner38d2edd2018-08-29 03:59:17 +0000639void VcallThunkIdentifierNode::output(OutputStream &OS,
640 OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000641 OS << "`vcall'{" << OffsetInVTable << ", {flat}}";
642}
643
Zachary Turner38d2edd2018-08-29 03:59:17 +0000644void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
Zachary Turner03312862018-08-27 03:48:03 +0000645 outputQualifiers(OS, Quals, false, true);
Zachary Turner38d2edd2018-08-29 03:59:17 +0000646 Name->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000647 if (TargetName) {
648 OS << "{for `";
Zachary Turner38d2edd2018-08-29 03:59:17 +0000649 TargetName->output(OS, Flags);
Zachary Turner03312862018-08-27 03:48:03 +0000650 OS << "'}";
651 }
652 return;
653}