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 default: 111 break; 112 } 113 } 114 115 std::string Node::toString(OutputFlags Flags) const { 116 OutputStream OS; 117 initializeOutputStream(nullptr, nullptr, OS, 1024); 118 this->output(OS, Flags); 119 OS << '\0'; 120 return {OS.getBuffer()}; 121 } 122 123 void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 124 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"); 130 OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char8, "char8_t"); 131 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 150 void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const { 151 output(OS, Flags, ", "); 152 } 153 154 void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags, 155 StringView Separator) const { 156 if (Count == 0) 157 return; 158 if (Nodes[0]) 159 Nodes[0]->output(OS, Flags); 160 for (size_t I = 1; I < Count; ++I) { 161 OS << Separator; 162 Nodes[I]->output(OS, Flags); 163 } 164 } 165 166 void EncodedStringLiteralNode::output(OutputStream &OS, 167 OutputFlags Flags) const { 168 switch (Char) { 169 case CharKind::Wchar: 170 OS << "L\""; 171 break; 172 case CharKind::Char: 173 OS << "\""; 174 break; 175 case CharKind::Char16: 176 OS << "u\""; 177 break; 178 case CharKind::Char32: 179 OS << "U\""; 180 break; 181 } 182 OS << DecodedString << "\""; 183 if (IsTruncated) 184 OS << "..."; 185 } 186 187 void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const { 188 if (IsNegative) 189 OS << '-'; 190 OS << Value; 191 } 192 193 void TemplateParameterReferenceNode::output(OutputStream &OS, 194 OutputFlags Flags) const { 195 if (ThunkOffsetCount > 0) 196 OS << "{"; 197 else if (Affinity == PointerAffinity::Pointer) 198 OS << "&"; 199 200 if (Symbol) { 201 Symbol->output(OS, Flags); 202 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 215 void IdentifierNode::outputTemplateParameters(OutputStream &OS, 216 OutputFlags Flags) const { 217 if (!TemplateParams) 218 return; 219 OS << "<"; 220 TemplateParams->output(OS, Flags); 221 OS << ">"; 222 } 223 224 void DynamicStructorIdentifierNode::output(OutputStream &OS, 225 OutputFlags Flags) const { 226 if (IsDestructor) 227 OS << "`dynamic atexit destructor for "; 228 else 229 OS << "`dynamic initializer for "; 230 231 if (Variable) { 232 OS << "`"; 233 Variable->output(OS, Flags); 234 OS << "''"; 235 } else { 236 OS << "'"; 237 Name->output(OS, Flags); 238 OS << "''"; 239 } 240 } 241 242 void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const { 243 OS << Name; 244 outputTemplateParameters(OS, Flags); 245 } 246 247 void IntrinsicFunctionIdentifierNode::output(OutputStream &OS, 248 OutputFlags Flags) const { 249 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'"); 338 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait, 339 "operator co_await"); 340 OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>"); 341 case IntrinsicFunctionKind::MaxIntrinsic: 342 case IntrinsicFunctionKind::None: 343 break; 344 } 345 outputTemplateParameters(OS, Flags); 346 } 347 348 void LocalStaticGuardIdentifierNode::output(OutputStream &OS, 349 OutputFlags Flags) const { 350 if (IsThread) 351 OS << "`local static thread guard'"; 352 else 353 OS << "`local static guard'"; 354 if (ScopeIndex > 0) 355 OS << "{" << ScopeIndex << "}"; 356 } 357 358 void ConversionOperatorIdentifierNode::output(OutputStream &OS, 359 OutputFlags Flags) const { 360 OS << "operator"; 361 outputTemplateParameters(OS, Flags); 362 OS << " "; 363 TargetType->output(OS, Flags); 364 } 365 366 void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const { 367 if (IsDestructor) 368 OS << "~"; 369 Class->output(OS, Flags); 370 outputTemplateParameters(OS, Flags); 371 } 372 373 void LiteralOperatorIdentifierNode::output(OutputStream &OS, 374 OutputFlags Flags) const { 375 OS << "operator \"\"" << Name; 376 outputTemplateParameters(OS, Flags); 377 } 378 379 void FunctionSignatureNode::outputPre(OutputStream &OS, 380 OutputFlags Flags) const { 381 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: "; 388 } 389 390 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 "; 397 398 if (FunctionClass & FC_ExternC) 399 OS << "extern \"C\" "; 400 } 401 402 if (!(Flags & OF_NoReturnType) && ReturnType) { 403 ReturnType->outputPre(OS, Flags); 404 OS << " "; 405 } 406 407 if (!(Flags & OF_NoCallingConvention)) 408 outputCallingConvention(OS, CallConvention); 409 } 410 411 void FunctionSignatureNode::outputPost(OutputStream &OS, 412 OutputFlags Flags) const { 413 if (!(FunctionClass & FC_NoParameterList)) { 414 OS << "("; 415 if (Params) 416 Params->output(OS, Flags); 417 else 418 OS << "void"; 419 420 if (IsVariadic) { 421 if (OS.back() != '(') 422 OS << ", "; 423 OS << "..."; 424 } 425 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 437 if (IsNoexcept) 438 OS << " noexcept"; 439 440 if (RefQualifier == FunctionRefQualifier::Reference) 441 OS << " &"; 442 else if (RefQualifier == FunctionRefQualifier::RValueReference) 443 OS << " &&"; 444 445 if (!(Flags & OF_NoReturnType) && ReturnType) 446 ReturnType->outputPost(OS, Flags); 447 } 448 449 void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 450 OS << "[thunk]: "; 451 452 FunctionSignatureNode::outputPre(OS, Flags); 453 } 454 455 void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const { 456 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 472 void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 473 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); 478 Sig->outputPre(OS, OF_NoCallingConvention); 479 } else 480 Pointee->outputPre(OS, Flags); 481 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) { 498 ClassParent->output(OS, Flags); 499 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 518 void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const { 519 if (Pointee->kind() == NodeKind::ArrayType || 520 Pointee->kind() == NodeKind::FunctionSignature) 521 OS << ")"; 522 523 Pointee->outputPost(OS, Flags); 524 } 525 526 void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 527 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 << " "; 535 } 536 QualifiedName->output(OS, Flags); 537 outputQualifiers(OS, Quals, true, false); 538 } 539 540 void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {} 541 542 void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 543 ElementType->outputPre(OS, Flags); 544 outputQualifiers(OS, Quals, true, false); 545 } 546 547 void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags, 548 Node *N) const { 549 assert(N->kind() == NodeKind::IntegerLiteral); 550 IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N); 551 if (ILN->Value != 0) 552 ILN->output(OS, Flags); 553 } 554 555 void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS, 556 OutputFlags Flags) const { 557 if (Dimensions->Count == 0) 558 return; 559 560 outputOneDimension(OS, Flags, Dimensions->Nodes[0]); 561 for (size_t I = 1; I < Dimensions->Count; ++I) { 562 OS << "]["; 563 outputOneDimension(OS, Flags, Dimensions->Nodes[I]); 564 } 565 } 566 567 void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const { 568 OS << "["; 569 outputDimensionsImpl(OS, Flags); 570 OS << "]"; 571 572 ElementType->outputPost(OS, Flags); 573 } 574 575 void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const { 576 Name->output(OS, Flags); 577 } 578 579 void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { 580 Signature->outputPre(OS, Flags); 581 outputSpaceIfNecessary(OS); 582 Name->output(OS, Flags); 583 Signature->outputPost(OS, Flags); 584 } 585 586 void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { 587 const char *AccessSpec = nullptr; 588 bool IsStatic = true; 589 switch (SC) { 590 case StorageClass::PrivateStatic: 591 AccessSpec = "private"; 592 break; 593 case StorageClass::PublicStatic: 594 AccessSpec = "public"; 595 break; 596 case StorageClass::ProtectedStatic: 597 AccessSpec = "protected"; 598 break; 599 default: 600 IsStatic = false; 601 break; 602 } 603 if (!(Flags & OF_NoAccessSpecifier) && AccessSpec) 604 OS << AccessSpec << ": "; 605 if (!(Flags & OF_NoMemberType) && IsStatic) 606 OS << "static "; 607 608 if (Type) { 609 Type->outputPre(OS, Flags); 610 outputSpaceIfNecessary(OS); 611 } 612 Name->output(OS, Flags); 613 if (Type) 614 Type->outputPost(OS, Flags); 615 } 616 617 void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const { 618 Identifier->output(OS, Flags); 619 } 620 void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {} 621 622 void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const { 623 Components->output(OS, Flags, "::"); 624 } 625 626 void RttiBaseClassDescriptorNode::output(OutputStream &OS, 627 OutputFlags Flags) const { 628 OS << "`RTTI Base Class Descriptor at ("; 629 OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", " 630 << this->Flags; 631 OS << ")'"; 632 } 633 634 void LocalStaticGuardVariableNode::output(OutputStream &OS, 635 OutputFlags Flags) const { 636 Name->output(OS, Flags); 637 } 638 639 void VcallThunkIdentifierNode::output(OutputStream &OS, 640 OutputFlags Flags) const { 641 OS << "`vcall'{" << OffsetInVTable << ", {flat}}"; 642 } 643 644 void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const { 645 outputQualifiers(OS, Quals, false, true); 646 Name->output(OS, Flags); 647 if (TargetName) { 648 OS << "{for `"; 649 TargetName->output(OS, Flags); 650 OS << "'}"; 651 } 652 return; 653 } 654