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