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, 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, Q_Const, SpaceBefore); 71 SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Volatile, SpaceBefore); 72 SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Restrict, 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(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 } 153 outputQualifiers(OB, Quals, true, false); 154 } 155 156 void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags) const { 157 output(OB, Flags, ", "); 158 } 159 160 void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags, 161 std::string_view Separator) const { 162 if (Count == 0) 163 return; 164 if (Nodes[0]) 165 Nodes[0]->output(OB, Flags); 166 for (size_t I = 1; I < Count; ++I) { 167 OB << Separator; 168 Nodes[I]->output(OB, Flags); 169 } 170 } 171 172 void EncodedStringLiteralNode::output(OutputBuffer &OB, 173 OutputFlags Flags) const { 174 switch (Char) { 175 case CharKind::Wchar: 176 OB << "L\""; 177 break; 178 case CharKind::Char: 179 OB << "\""; 180 break; 181 case CharKind::Char16: 182 OB << "u\""; 183 break; 184 case CharKind::Char32: 185 OB << "U\""; 186 break; 187 } 188 OB << DecodedString << "\""; 189 if (IsTruncated) 190 OB << "..."; 191 } 192 193 void IntegerLiteralNode::output(OutputBuffer &OB, OutputFlags Flags) const { 194 if (IsNegative) 195 OB << '-'; 196 OB << Value; 197 } 198 199 void TemplateParameterReferenceNode::output(OutputBuffer &OB, 200 OutputFlags Flags) const { 201 if (ThunkOffsetCount > 0) 202 OB << "{"; 203 else if (Affinity == PointerAffinity::Pointer) 204 OB << "&"; 205 206 if (Symbol) { 207 Symbol->output(OB, Flags); 208 if (ThunkOffsetCount > 0) 209 OB << ", "; 210 } 211 212 if (ThunkOffsetCount > 0) 213 OB << ThunkOffsets[0]; 214 for (int I = 1; I < ThunkOffsetCount; ++I) { 215 OB << ", " << ThunkOffsets[I]; 216 } 217 if (ThunkOffsetCount > 0) 218 OB << "}"; 219 } 220 221 void IdentifierNode::outputTemplateParameters(OutputBuffer &OB, 222 OutputFlags Flags) const { 223 if (!TemplateParams) 224 return; 225 OB << "<"; 226 TemplateParams->output(OB, Flags); 227 OB << ">"; 228 } 229 230 void DynamicStructorIdentifierNode::output(OutputBuffer &OB, 231 OutputFlags Flags) const { 232 if (IsDestructor) 233 OB << "`dynamic atexit destructor for "; 234 else 235 OB << "`dynamic initializer for "; 236 237 if (Variable) { 238 OB << "`"; 239 Variable->output(OB, Flags); 240 OB << "''"; 241 } else { 242 OB << "'"; 243 Name->output(OB, Flags); 244 OB << "''"; 245 } 246 } 247 248 void NamedIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { 249 OB << Name; 250 outputTemplateParameters(OB, Flags); 251 } 252 253 void IntrinsicFunctionIdentifierNode::output(OutputBuffer &OB, 254 OutputFlags Flags) const { 255 switch (Operator) { 256 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new"); 257 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete"); 258 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator="); 259 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>"); 260 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<"); 261 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!"); 262 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator=="); 263 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!="); 264 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript, 265 "operator[]"); 266 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->"); 267 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++"); 268 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--"); 269 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-"); 270 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+"); 271 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*"); 272 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&"); 273 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer, 274 "operator->*"); 275 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/"); 276 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%"); 277 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<"); 278 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<="); 279 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>"); 280 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual, 281 "operator>="); 282 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,"); 283 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()"); 284 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~"); 285 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^"); 286 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|"); 287 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&"); 288 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||"); 289 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*="); 290 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+="); 291 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-="); 292 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/="); 293 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%="); 294 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>="); 295 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<="); 296 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual, 297 "operator&="); 298 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual, 299 "operator|="); 300 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual, 301 "operator^="); 302 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'"); 303 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor, 304 "`vector deleting dtor'"); 305 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure, 306 "`default ctor closure'"); 307 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor, 308 "`scalar deleting dtor'"); 309 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter, 310 "`vector ctor iterator'"); 311 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter, 312 "`vector dtor iterator'"); 313 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter, 314 "`vector vbase ctor iterator'"); 315 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap, 316 "`virtual displacement map'"); 317 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter, 318 "`eh vector ctor iterator'"); 319 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter, 320 "`eh vector dtor iterator'"); 321 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter, 322 "`eh vector vbase ctor iterator'"); 323 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure, 324 "`copy ctor closure'"); 325 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure, 326 "`local vftable ctor closure'"); 327 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]"); 328 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete, 329 "operator delete[]"); 330 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter, 331 "`managed vector ctor iterator'"); 332 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter, 333 "`managed vector dtor iterator'"); 334 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter, 335 "`EH vector copy ctor iterator'"); 336 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter, 337 "`EH vector vbase copy ctor iterator'"); 338 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter, 339 "`vector copy ctor iterator'"); 340 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter, 341 "`vector vbase copy constructor iterator'"); 342 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter, 343 "`managed vector vbase copy constructor iterator'"); 344 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait, 345 "operator co_await"); 346 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>"); 347 case IntrinsicFunctionKind::MaxIntrinsic: 348 case IntrinsicFunctionKind::None: 349 break; 350 } 351 outputTemplateParameters(OB, Flags); 352 } 353 354 void LocalStaticGuardIdentifierNode::output(OutputBuffer &OB, 355 OutputFlags Flags) const { 356 if (IsThread) 357 OB << "`local static thread guard'"; 358 else 359 OB << "`local static guard'"; 360 if (ScopeIndex > 0) 361 OB << "{" << ScopeIndex << "}"; 362 } 363 364 void ConversionOperatorIdentifierNode::output(OutputBuffer &OB, 365 OutputFlags Flags) const { 366 OB << "operator"; 367 outputTemplateParameters(OB, Flags); 368 OB << " "; 369 TargetType->output(OB, Flags); 370 } 371 372 void StructorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const { 373 if (IsDestructor) 374 OB << "~"; 375 Class->output(OB, Flags); 376 outputTemplateParameters(OB, Flags); 377 } 378 379 void LiteralOperatorIdentifierNode::output(OutputBuffer &OB, 380 OutputFlags Flags) const { 381 OB << "operator \"\"" << Name; 382 outputTemplateParameters(OB, Flags); 383 } 384 385 void FunctionSignatureNode::outputPre(OutputBuffer &OB, 386 OutputFlags Flags) const { 387 if (!(Flags & OF_NoAccessSpecifier)) { 388 if (FunctionClass & FC_Public) 389 OB << "public: "; 390 if (FunctionClass & FC_Protected) 391 OB << "protected: "; 392 if (FunctionClass & FC_Private) 393 OB << "private: "; 394 } 395 396 if (!(Flags & OF_NoMemberType)) { 397 if (!(FunctionClass & FC_Global)) { 398 if (FunctionClass & FC_Static) 399 OB << "static "; 400 } 401 if (FunctionClass & FC_Virtual) 402 OB << "virtual "; 403 404 if (FunctionClass & FC_ExternC) 405 OB << "extern \"C\" "; 406 } 407 408 if (!(Flags & OF_NoReturnType) && ReturnType) { 409 ReturnType->outputPre(OB, Flags); 410 OB << " "; 411 } 412 413 if (!(Flags & OF_NoCallingConvention)) 414 outputCallingConvention(OB, CallConvention); 415 } 416 417 void FunctionSignatureNode::outputPost(OutputBuffer &OB, 418 OutputFlags Flags) const { 419 if (!(FunctionClass & FC_NoParameterList)) { 420 OB << "("; 421 if (Params) 422 Params->output(OB, Flags); 423 else 424 OB << "void"; 425 426 if (IsVariadic) { 427 if (OB.back() != '(') 428 OB << ", "; 429 OB << "..."; 430 } 431 OB << ")"; 432 } 433 434 if (Quals & Q_Const) 435 OB << " const"; 436 if (Quals & Q_Volatile) 437 OB << " volatile"; 438 if (Quals & Q_Restrict) 439 OB << " __restrict"; 440 if (Quals & Q_Unaligned) 441 OB << " __unaligned"; 442 443 if (IsNoexcept) 444 OB << " noexcept"; 445 446 if (RefQualifier == FunctionRefQualifier::Reference) 447 OB << " &"; 448 else if (RefQualifier == FunctionRefQualifier::RValueReference) 449 OB << " &&"; 450 451 if (!(Flags & OF_NoReturnType) && ReturnType) 452 ReturnType->outputPost(OB, Flags); 453 } 454 455 void ThunkSignatureNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { 456 OB << "[thunk]: "; 457 458 FunctionSignatureNode::outputPre(OB, Flags); 459 } 460 461 void ThunkSignatureNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { 462 if (FunctionClass & FC_StaticThisAdjust) { 463 OB << "`adjustor{" << ThisAdjust.StaticOffset << "}'"; 464 } else if (FunctionClass & FC_VirtualThisAdjust) { 465 if (FunctionClass & FC_VirtualThisAdjustEx) { 466 OB << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", " 467 << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset 468 << ", " << ThisAdjust.StaticOffset << "}'"; 469 } else { 470 OB << "`vtordisp{" << ThisAdjust.VtordispOffset << ", " 471 << ThisAdjust.StaticOffset << "}'"; 472 } 473 } 474 475 FunctionSignatureNode::outputPost(OB, Flags); 476 } 477 478 void PointerTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { 479 if (Pointee->kind() == NodeKind::FunctionSignature) { 480 // If this is a pointer to a function, don't output the calling convention. 481 // It needs to go inside the parentheses. 482 const FunctionSignatureNode *Sig = 483 static_cast<const FunctionSignatureNode *>(Pointee); 484 Sig->outputPre(OB, OF_NoCallingConvention); 485 } else 486 Pointee->outputPre(OB, Flags); 487 488 outputSpaceIfNecessary(OB); 489 490 if (Quals & Q_Unaligned) 491 OB << "__unaligned "; 492 493 if (Pointee->kind() == NodeKind::ArrayType) { 494 OB << "("; 495 } else if (Pointee->kind() == NodeKind::FunctionSignature) { 496 OB << "("; 497 const FunctionSignatureNode *Sig = 498 static_cast<const FunctionSignatureNode *>(Pointee); 499 outputCallingConvention(OB, Sig->CallConvention); 500 OB << " "; 501 } 502 503 if (ClassParent) { 504 ClassParent->output(OB, Flags); 505 OB << "::"; 506 } 507 508 switch (Affinity) { 509 case PointerAffinity::Pointer: 510 OB << "*"; 511 break; 512 case PointerAffinity::Reference: 513 OB << "&"; 514 break; 515 case PointerAffinity::RValueReference: 516 OB << "&&"; 517 break; 518 default: 519 assert(false); 520 } 521 outputQualifiers(OB, Quals, false, false); 522 } 523 524 void PointerTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { 525 if (Pointee->kind() == NodeKind::ArrayType || 526 Pointee->kind() == NodeKind::FunctionSignature) 527 OB << ")"; 528 529 Pointee->outputPost(OB, Flags); 530 } 531 532 void TagTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { 533 if (!(Flags & OF_NoTagSpecifier)) { 534 switch (Tag) { 535 OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class"); 536 OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct"); 537 OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union"); 538 OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum"); 539 } 540 OB << " "; 541 } 542 QualifiedName->output(OB, Flags); 543 outputQualifiers(OB, Quals, true, false); 544 } 545 546 void TagTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {} 547 548 void ArrayTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { 549 ElementType->outputPre(OB, Flags); 550 outputQualifiers(OB, Quals, true, false); 551 } 552 553 void ArrayTypeNode::outputOneDimension(OutputBuffer &OB, OutputFlags Flags, 554 Node *N) const { 555 assert(N->kind() == NodeKind::IntegerLiteral); 556 IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N); 557 if (ILN->Value != 0) 558 ILN->output(OB, Flags); 559 } 560 561 void ArrayTypeNode::outputDimensionsImpl(OutputBuffer &OB, 562 OutputFlags Flags) const { 563 if (Dimensions->Count == 0) 564 return; 565 566 outputOneDimension(OB, Flags, Dimensions->Nodes[0]); 567 for (size_t I = 1; I < Dimensions->Count; ++I) { 568 OB << "]["; 569 outputOneDimension(OB, Flags, Dimensions->Nodes[I]); 570 } 571 } 572 573 void ArrayTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { 574 OB << "["; 575 outputDimensionsImpl(OB, Flags); 576 OB << "]"; 577 578 ElementType->outputPost(OB, Flags); 579 } 580 581 void SymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { 582 Name->output(OB, Flags); 583 } 584 585 void FunctionSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { 586 Signature->outputPre(OB, Flags); 587 outputSpaceIfNecessary(OB); 588 Name->output(OB, Flags); 589 Signature->outputPost(OB, Flags); 590 } 591 592 void VariableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { 593 const char *AccessSpec = nullptr; 594 bool IsStatic = true; 595 switch (SC) { 596 case StorageClass::PrivateStatic: 597 AccessSpec = "private"; 598 break; 599 case StorageClass::PublicStatic: 600 AccessSpec = "public"; 601 break; 602 case StorageClass::ProtectedStatic: 603 AccessSpec = "protected"; 604 break; 605 default: 606 IsStatic = false; 607 break; 608 } 609 if (!(Flags & OF_NoAccessSpecifier) && AccessSpec) 610 OB << AccessSpec << ": "; 611 if (!(Flags & OF_NoMemberType) && IsStatic) 612 OB << "static "; 613 614 if (!(Flags & OF_NoVariableType) && Type) { 615 Type->outputPre(OB, Flags); 616 outputSpaceIfNecessary(OB); 617 } 618 Name->output(OB, Flags); 619 if (!(Flags & OF_NoVariableType) && Type) 620 Type->outputPost(OB, Flags); 621 } 622 623 void CustomTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { 624 Identifier->output(OB, Flags); 625 } 626 void CustomTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {} 627 628 void QualifiedNameNode::output(OutputBuffer &OB, OutputFlags Flags) const { 629 Components->output(OB, Flags, "::"); 630 } 631 632 void RttiBaseClassDescriptorNode::output(OutputBuffer &OB, 633 OutputFlags Flags) const { 634 OB << "`RTTI Base Class Descriptor at ("; 635 OB << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", " 636 << this->Flags; 637 OB << ")'"; 638 } 639 640 void LocalStaticGuardVariableNode::output(OutputBuffer &OB, 641 OutputFlags Flags) const { 642 Name->output(OB, Flags); 643 } 644 645 void VcallThunkIdentifierNode::output(OutputBuffer &OB, 646 OutputFlags Flags) const { 647 OB << "`vcall'{" << OffsetInVTable << ", {flat}}"; 648 } 649 650 void SpecialTableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { 651 outputQualifiers(OB, Quals, false, true); 652 Name->output(OB, Flags); 653 if (TargetName) { 654 OB << "{for `"; 655 TargetName->output(OB, Flags); 656 OB << "'}"; 657 } 658 } 659