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