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