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