1341825Sdim//===------------------------- ItaniumDemangle.cpp ------------------------===// 2311116Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6311116Sdim// 7311116Sdim//===----------------------------------------------------------------------===// 8311116Sdim 9341825Sdim// FIXME: (possibly) incomplete list of features that clang mangles that this 10341825Sdim// file does not yet support: 11341825Sdim// - C++ modules TS 12341825Sdim 13311116Sdim#include "llvm/Demangle/Demangle.h" 14344779Sdim#include "llvm/Demangle/ItaniumDemangle.h" 15311116Sdim 16341825Sdim#include <cassert> 17311116Sdim#include <cctype> 18341825Sdim#include <cstdio> 19311116Sdim#include <cstdlib> 20311116Sdim#include <cstring> 21344779Sdim#include <functional> 22311116Sdim#include <numeric> 23341825Sdim#include <utility> 24311116Sdim#include <vector> 25311116Sdim 26344779Sdimusing namespace llvm; 27344779Sdimusing namespace llvm::itanium_demangle; 28311116Sdim 29344779Sdimconstexpr const char *itanium_demangle::FloatData<float>::spec; 30344779Sdimconstexpr const char *itanium_demangle::FloatData<double>::spec; 31344779Sdimconstexpr const char *itanium_demangle::FloatData<long double>::spec; 32311116Sdim 33344779Sdim// <discriminator> := _ <non-negative number> # when number < 10 34344779Sdim// := __ <non-negative number> _ # when number >= 10 35344779Sdim// extension := decimal-digit+ # at the end of string 36344779Sdimconst char *itanium_demangle::parse_discriminator(const char *first, 37344779Sdim const char *last) { 38344779Sdim // parse but ignore discriminator 39344779Sdim if (first != last) { 40344779Sdim if (*first == '_') { 41344779Sdim const char *t1 = first + 1; 42344779Sdim if (t1 != last) { 43344779Sdim if (std::isdigit(*t1)) 44344779Sdim first = t1 + 1; 45344779Sdim else if (*t1 == '_') { 46344779Sdim for (++t1; t1 != last && std::isdigit(*t1); ++t1) 47344779Sdim ; 48344779Sdim if (t1 != last && *t1 == '_') 49344779Sdim first = t1 + 1; 50344779Sdim } 51311116Sdim } 52344779Sdim } else if (std::isdigit(*first)) { 53344779Sdim const char *t1 = first + 1; 54344779Sdim for (; t1 != last && std::isdigit(*t1); ++t1) 55344779Sdim ; 56344779Sdim if (t1 == last) 57344779Sdim first = last; 58311116Sdim } 59311116Sdim } 60344779Sdim return first; 61311116Sdim} 62311116Sdim 63344779Sdim#ifndef NDEBUG 64344779Sdimnamespace { 65344779Sdimstruct DumpVisitor { 66344779Sdim unsigned Depth = 0; 67344779Sdim bool PendingNewline = false; 68341825Sdim 69344779Sdim template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) { 70344779Sdim return true; 71341825Sdim } 72344779Sdim static bool wantsNewline(NodeArray A) { return !A.empty(); } 73344779Sdim static constexpr bool wantsNewline(...) { return false; } 74341825Sdim 75344779Sdim template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) { 76344779Sdim for (bool B : {wantsNewline(Vs)...}) 77344779Sdim if (B) 78344779Sdim return true; 79344779Sdim return false; 80341825Sdim } 81341825Sdim 82344779Sdim void printStr(const char *S) { fprintf(stderr, "%s", S); } 83344779Sdim void print(StringView SV) { 84344779Sdim fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin()); 85341825Sdim } 86344779Sdim void print(const Node *N) { 87344779Sdim if (N) 88344779Sdim N->visit(std::ref(*this)); 89344779Sdim else 90344779Sdim printStr("<null>"); 91341825Sdim } 92344779Sdim void print(NodeArray A) { 93344779Sdim ++Depth; 94344779Sdim printStr("{"); 95344779Sdim bool First = true; 96344779Sdim for (const Node *N : A) { 97344779Sdim if (First) 98344779Sdim print(N); 99344779Sdim else 100344779Sdim printWithComma(N); 101344779Sdim First = false; 102311116Sdim } 103344779Sdim printStr("}"); 104344779Sdim --Depth; 105311116Sdim } 106311116Sdim 107344779Sdim // Overload used when T is exactly 'bool', not merely convertible to 'bool'. 108344779Sdim void print(bool B) { printStr(B ? "true" : "false"); } 109311116Sdim 110344779Sdim template <class T> 111344779Sdim typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) { 112344779Sdim fprintf(stderr, "%llu", (unsigned long long)N); 113341825Sdim } 114341825Sdim 115344779Sdim template <class T> 116344779Sdim typename std::enable_if<std::is_signed<T>::value>::type print(T N) { 117344779Sdim fprintf(stderr, "%lld", (long long)N); 118341825Sdim } 119341825Sdim 120344779Sdim void print(ReferenceKind RK) { 121344779Sdim switch (RK) { 122344779Sdim case ReferenceKind::LValue: 123344779Sdim return printStr("ReferenceKind::LValue"); 124344779Sdim case ReferenceKind::RValue: 125344779Sdim return printStr("ReferenceKind::RValue"); 126341825Sdim } 127341825Sdim } 128344779Sdim void print(FunctionRefQual RQ) { 129344779Sdim switch (RQ) { 130344779Sdim case FunctionRefQual::FrefQualNone: 131344779Sdim return printStr("FunctionRefQual::FrefQualNone"); 132344779Sdim case FunctionRefQual::FrefQualLValue: 133344779Sdim return printStr("FunctionRefQual::FrefQualLValue"); 134344779Sdim case FunctionRefQual::FrefQualRValue: 135344779Sdim return printStr("FunctionRefQual::FrefQualRValue"); 136341825Sdim } 137341825Sdim } 138344779Sdim void print(Qualifiers Qs) { 139344779Sdim if (!Qs) return printStr("QualNone"); 140344779Sdim struct QualName { Qualifiers Q; const char *Name; } Names[] = { 141344779Sdim {QualConst, "QualConst"}, 142344779Sdim {QualVolatile, "QualVolatile"}, 143344779Sdim {QualRestrict, "QualRestrict"}, 144344779Sdim }; 145344779Sdim for (QualName Name : Names) { 146344779Sdim if (Qs & Name.Q) { 147344779Sdim printStr(Name.Name); 148344779Sdim Qs = Qualifiers(Qs & ~Name.Q); 149344779Sdim if (Qs) printStr(" | "); 150344779Sdim } 151341825Sdim } 152341825Sdim } 153344779Sdim void print(SpecialSubKind SSK) { 154341825Sdim switch (SSK) { 155341825Sdim case SpecialSubKind::allocator: 156344779Sdim return printStr("SpecialSubKind::allocator"); 157341825Sdim case SpecialSubKind::basic_string: 158344779Sdim return printStr("SpecialSubKind::basic_string"); 159341825Sdim case SpecialSubKind::string: 160344779Sdim return printStr("SpecialSubKind::string"); 161341825Sdim case SpecialSubKind::istream: 162344779Sdim return printStr("SpecialSubKind::istream"); 163341825Sdim case SpecialSubKind::ostream: 164344779Sdim return printStr("SpecialSubKind::ostream"); 165341825Sdim case SpecialSubKind::iostream: 166344779Sdim return printStr("SpecialSubKind::iostream"); 167341825Sdim } 168341825Sdim } 169360784Sdim void print(TemplateParamKind TPK) { 170360784Sdim switch (TPK) { 171360784Sdim case TemplateParamKind::Type: 172360784Sdim return printStr("TemplateParamKind::Type"); 173360784Sdim case TemplateParamKind::NonType: 174360784Sdim return printStr("TemplateParamKind::NonType"); 175360784Sdim case TemplateParamKind::Template: 176360784Sdim return printStr("TemplateParamKind::Template"); 177360784Sdim } 178360784Sdim } 179341825Sdim 180344779Sdim void newLine() { 181344779Sdim printStr("\n"); 182344779Sdim for (unsigned I = 0; I != Depth; ++I) 183344779Sdim printStr(" "); 184344779Sdim PendingNewline = false; 185341825Sdim } 186341825Sdim 187344779Sdim template<typename T> void printWithPendingNewline(T V) { 188344779Sdim print(V); 189344779Sdim if (wantsNewline(V)) 190344779Sdim PendingNewline = true; 191341825Sdim } 192341825Sdim 193344779Sdim template<typename T> void printWithComma(T V) { 194344779Sdim if (PendingNewline || wantsNewline(V)) { 195344779Sdim printStr(","); 196344779Sdim newLine(); 197344779Sdim } else { 198344779Sdim printStr(", "); 199311116Sdim } 200311116Sdim 201344779Sdim printWithPendingNewline(V); 202311116Sdim } 203311116Sdim 204344779Sdim struct CtorArgPrinter { 205344779Sdim DumpVisitor &Visitor; 206311116Sdim 207344779Sdim template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) { 208344779Sdim if (Visitor.anyWantNewline(V, Vs...)) 209344779Sdim Visitor.newLine(); 210344779Sdim Visitor.printWithPendingNewline(V); 211344779Sdim int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 }; 212344779Sdim (void)PrintInOrder; 213311116Sdim } 214344779Sdim }; 215341825Sdim 216344779Sdim template<typename NodeT> void operator()(const NodeT *Node) { 217344779Sdim Depth += 2; 218344779Sdim fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name()); 219344779Sdim Node->match(CtorArgPrinter{*this}); 220344779Sdim fprintf(stderr, ")"); 221344779Sdim Depth -= 2; 222311116Sdim } 223311116Sdim 224344779Sdim void operator()(const ForwardTemplateReference *Node) { 225344779Sdim Depth += 2; 226344779Sdim fprintf(stderr, "ForwardTemplateReference("); 227344779Sdim if (Node->Ref && !Node->Printing) { 228344779Sdim Node->Printing = true; 229344779Sdim CtorArgPrinter{*this}(Node->Ref); 230344779Sdim Node->Printing = false; 231311116Sdim } else { 232344779Sdim CtorArgPrinter{*this}(Node->Index); 233311116Sdim } 234344779Sdim fprintf(stderr, ")"); 235344779Sdim Depth -= 2; 236311116Sdim } 237341825Sdim}; 238344779Sdim} 239311116Sdim 240344779Sdimvoid itanium_demangle::Node::dump() const { 241344779Sdim DumpVisitor V; 242344779Sdim visit(std::ref(V)); 243344779Sdim V.newLine(); 244344779Sdim} 245341825Sdim#endif 246311116Sdim 247344779Sdimnamespace { 248341825Sdimclass BumpPointerAllocator { 249341825Sdim struct BlockMeta { 250341825Sdim BlockMeta* Next; 251341825Sdim size_t Current; 252341825Sdim }; 253311116Sdim 254341825Sdim static constexpr size_t AllocSize = 4096; 255341825Sdim static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta); 256341825Sdim 257341825Sdim alignas(long double) char InitialBuffer[AllocSize]; 258341825Sdim BlockMeta* BlockList = nullptr; 259341825Sdim 260341825Sdim void grow() { 261341825Sdim char* NewMeta = static_cast<char *>(std::malloc(AllocSize)); 262341825Sdim if (NewMeta == nullptr) 263341825Sdim std::terminate(); 264341825Sdim BlockList = new (NewMeta) BlockMeta{BlockList, 0}; 265311116Sdim } 266311116Sdim 267341825Sdim void* allocateMassive(size_t NBytes) { 268341825Sdim NBytes += sizeof(BlockMeta); 269341825Sdim BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes)); 270341825Sdim if (NewMeta == nullptr) 271341825Sdim std::terminate(); 272341825Sdim BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0}; 273341825Sdim return static_cast<void*>(NewMeta + 1); 274341825Sdim } 275311116Sdim 276341825Sdimpublic: 277341825Sdim BumpPointerAllocator() 278341825Sdim : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {} 279311116Sdim 280341825Sdim void* allocate(size_t N) { 281341825Sdim N = (N + 15u) & ~15u; 282341825Sdim if (N + BlockList->Current >= UsableAllocSize) { 283341825Sdim if (N > UsableAllocSize) 284341825Sdim return allocateMassive(N); 285341825Sdim grow(); 286311116Sdim } 287341825Sdim BlockList->Current += N; 288341825Sdim return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) + 289341825Sdim BlockList->Current - N); 290311116Sdim } 291311116Sdim 292341825Sdim void reset() { 293341825Sdim while (BlockList) { 294341825Sdim BlockMeta* Tmp = BlockList; 295341825Sdim BlockList = BlockList->Next; 296341825Sdim if (reinterpret_cast<char*>(Tmp) != InitialBuffer) 297341825Sdim std::free(Tmp); 298311116Sdim } 299341825Sdim BlockList = new (InitialBuffer) BlockMeta{nullptr, 0}; 300311116Sdim } 301311116Sdim 302341825Sdim ~BumpPointerAllocator() { reset(); } 303341825Sdim}; 304311116Sdim 305344779Sdimclass DefaultAllocator { 306344779Sdim BumpPointerAllocator Alloc; 307341825Sdim 308341825Sdimpublic: 309344779Sdim void reset() { Alloc.reset(); } 310311116Sdim 311344779Sdim template<typename T, typename ...Args> T *makeNode(Args &&...args) { 312344779Sdim return new (Alloc.allocate(sizeof(T))) 313341825Sdim T(std::forward<Args>(args)...); 314341825Sdim } 315341825Sdim 316344779Sdim void *allocateNodeArray(size_t sz) { 317344779Sdim return Alloc.allocate(sizeof(Node *) * sz); 318341825Sdim } 319341825Sdim}; 320344779Sdim} // unnamed namespace 321341825Sdim 322344779Sdim//===----------------------------------------------------------------------===// 323344779Sdim// Code beyond this point should not be synchronized with libc++abi. 324344779Sdim//===----------------------------------------------------------------------===// 325341825Sdim 326344779Sdimusing Demangler = itanium_demangle::ManglingParser<DefaultAllocator>; 327341825Sdim 328341825Sdimchar *llvm::itaniumDemangle(const char *MangledName, char *Buf, 329341825Sdim size_t *N, int *Status) { 330341825Sdim if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) { 331341825Sdim if (Status) 332341825Sdim *Status = demangle_invalid_args; 333341825Sdim return nullptr; 334311116Sdim } 335341825Sdim 336341825Sdim int InternalStatus = demangle_success; 337344779Sdim Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); 338341825Sdim OutputStream S; 339341825Sdim 340341825Sdim Node *AST = Parser.parse(); 341341825Sdim 342341825Sdim if (AST == nullptr) 343341825Sdim InternalStatus = demangle_invalid_mangled_name; 344344779Sdim else if (!initializeOutputStream(Buf, N, S, 1024)) 345341825Sdim InternalStatus = demangle_memory_alloc_failure; 346341825Sdim else { 347341825Sdim assert(Parser.ForwardTemplateRefs.empty()); 348341825Sdim AST->print(S); 349341825Sdim S += '\0'; 350341825Sdim if (N != nullptr) 351341825Sdim *N = S.getCurrentPosition(); 352341825Sdim Buf = S.getBuffer(); 353341825Sdim } 354341825Sdim 355341825Sdim if (Status) 356341825Sdim *Status = InternalStatus; 357341825Sdim return InternalStatus == demangle_success ? Buf : nullptr; 358311116Sdim} 359311116Sdim 360341825SdimItaniumPartialDemangler::ItaniumPartialDemangler() 361344779Sdim : RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {} 362311116Sdim 363341825SdimItaniumPartialDemangler::~ItaniumPartialDemangler() { 364344779Sdim delete static_cast<Demangler *>(Context); 365341825Sdim} 366311116Sdim 367341825SdimItaniumPartialDemangler::ItaniumPartialDemangler( 368341825Sdim ItaniumPartialDemangler &&Other) 369341825Sdim : RootNode(Other.RootNode), Context(Other.Context) { 370341825Sdim Other.Context = Other.RootNode = nullptr; 371341825Sdim} 372311116Sdim 373341825SdimItaniumPartialDemangler &ItaniumPartialDemangler:: 374341825Sdimoperator=(ItaniumPartialDemangler &&Other) { 375341825Sdim std::swap(RootNode, Other.RootNode); 376341825Sdim std::swap(Context, Other.Context); 377341825Sdim return *this; 378311116Sdim} 379311116Sdim 380341825Sdim// Demangle MangledName into an AST, storing it into this->RootNode. 381341825Sdimbool ItaniumPartialDemangler::partialDemangle(const char *MangledName) { 382344779Sdim Demangler *Parser = static_cast<Demangler *>(Context); 383341825Sdim size_t Len = std::strlen(MangledName); 384341825Sdim Parser->reset(MangledName, MangledName + Len); 385341825Sdim RootNode = Parser->parse(); 386341825Sdim return RootNode == nullptr; 387341825Sdim} 388341825Sdim 389344779Sdimstatic char *printNode(const Node *RootNode, char *Buf, size_t *N) { 390341825Sdim OutputStream S; 391344779Sdim if (!initializeOutputStream(Buf, N, S, 128)) 392311116Sdim return nullptr; 393341825Sdim RootNode->print(S); 394341825Sdim S += '\0'; 395341825Sdim if (N != nullptr) 396341825Sdim *N = S.getCurrentPosition(); 397341825Sdim return S.getBuffer(); 398341825Sdim} 399341825Sdim 400341825Sdimchar *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const { 401341825Sdim if (!isFunction()) 402341825Sdim return nullptr; 403341825Sdim 404344779Sdim const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName(); 405341825Sdim 406341825Sdim while (true) { 407341825Sdim switch (Name->getKind()) { 408341825Sdim case Node::KAbiTagAttr: 409344779Sdim Name = static_cast<const AbiTagAttr *>(Name)->Base; 410341825Sdim continue; 411341825Sdim case Node::KStdQualifiedName: 412344779Sdim Name = static_cast<const StdQualifiedName *>(Name)->Child; 413341825Sdim continue; 414341825Sdim case Node::KNestedName: 415344779Sdim Name = static_cast<const NestedName *>(Name)->Name; 416341825Sdim continue; 417341825Sdim case Node::KLocalName: 418344779Sdim Name = static_cast<const LocalName *>(Name)->Entity; 419341825Sdim continue; 420341825Sdim case Node::KNameWithTemplateArgs: 421344779Sdim Name = static_cast<const NameWithTemplateArgs *>(Name)->Name; 422341825Sdim continue; 423341825Sdim default: 424341825Sdim return printNode(Name, Buf, N); 425341825Sdim } 426311116Sdim } 427341825Sdim} 428341825Sdim 429341825Sdimchar *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf, 430341825Sdim size_t *N) const { 431341825Sdim if (!isFunction()) 432341825Sdim return nullptr; 433344779Sdim const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName(); 434341825Sdim 435341825Sdim OutputStream S; 436344779Sdim if (!initializeOutputStream(Buf, N, S, 128)) 437341825Sdim return nullptr; 438341825Sdim 439341825Sdim KeepGoingLocalFunction: 440341825Sdim while (true) { 441341825Sdim if (Name->getKind() == Node::KAbiTagAttr) { 442344779Sdim Name = static_cast<const AbiTagAttr *>(Name)->Base; 443341825Sdim continue; 444311116Sdim } 445341825Sdim if (Name->getKind() == Node::KNameWithTemplateArgs) { 446344779Sdim Name = static_cast<const NameWithTemplateArgs *>(Name)->Name; 447341825Sdim continue; 448311116Sdim } 449341825Sdim break; 450341825Sdim } 451341825Sdim 452341825Sdim switch (Name->getKind()) { 453341825Sdim case Node::KStdQualifiedName: 454341825Sdim S += "std"; 455341825Sdim break; 456341825Sdim case Node::KNestedName: 457344779Sdim static_cast<const NestedName *>(Name)->Qual->print(S); 458341825Sdim break; 459341825Sdim case Node::KLocalName: { 460344779Sdim auto *LN = static_cast<const LocalName *>(Name); 461341825Sdim LN->Encoding->print(S); 462341825Sdim S += "::"; 463341825Sdim Name = LN->Entity; 464341825Sdim goto KeepGoingLocalFunction; 465341825Sdim } 466341825Sdim default: 467341825Sdim break; 468341825Sdim } 469341825Sdim S += '\0'; 470341825Sdim if (N != nullptr) 471341825Sdim *N = S.getCurrentPosition(); 472341825Sdim return S.getBuffer(); 473311116Sdim} 474341825Sdim 475341825Sdimchar *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const { 476341825Sdim if (!isFunction()) 477341825Sdim return nullptr; 478341825Sdim auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName(); 479341825Sdim return printNode(Name, Buf, N); 480341825Sdim} 481341825Sdim 482341825Sdimchar *ItaniumPartialDemangler::getFunctionParameters(char *Buf, 483341825Sdim size_t *N) const { 484341825Sdim if (!isFunction()) 485341825Sdim return nullptr; 486341825Sdim NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams(); 487341825Sdim 488341825Sdim OutputStream S; 489344779Sdim if (!initializeOutputStream(Buf, N, S, 128)) 490341825Sdim return nullptr; 491341825Sdim 492341825Sdim S += '('; 493341825Sdim Params.printWithComma(S); 494341825Sdim S += ')'; 495341825Sdim S += '\0'; 496341825Sdim if (N != nullptr) 497341825Sdim *N = S.getCurrentPosition(); 498341825Sdim return S.getBuffer(); 499341825Sdim} 500341825Sdim 501341825Sdimchar *ItaniumPartialDemangler::getFunctionReturnType( 502341825Sdim char *Buf, size_t *N) const { 503341825Sdim if (!isFunction()) 504341825Sdim return nullptr; 505341825Sdim 506341825Sdim OutputStream S; 507344779Sdim if (!initializeOutputStream(Buf, N, S, 128)) 508341825Sdim return nullptr; 509341825Sdim 510344779Sdim if (const Node *Ret = 511344779Sdim static_cast<const FunctionEncoding *>(RootNode)->getReturnType()) 512341825Sdim Ret->print(S); 513341825Sdim 514341825Sdim S += '\0'; 515341825Sdim if (N != nullptr) 516341825Sdim *N = S.getCurrentPosition(); 517341825Sdim return S.getBuffer(); 518341825Sdim} 519341825Sdim 520341825Sdimchar *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const { 521341825Sdim assert(RootNode != nullptr && "must call partialDemangle()"); 522341825Sdim return printNode(static_cast<Node *>(RootNode), Buf, N); 523341825Sdim} 524341825Sdim 525341825Sdimbool ItaniumPartialDemangler::hasFunctionQualifiers() const { 526341825Sdim assert(RootNode != nullptr && "must call partialDemangle()"); 527341825Sdim if (!isFunction()) 528341825Sdim return false; 529344779Sdim auto *E = static_cast<const FunctionEncoding *>(RootNode); 530341825Sdim return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone; 531341825Sdim} 532341825Sdim 533341825Sdimbool ItaniumPartialDemangler::isCtorOrDtor() const { 534344779Sdim const Node *N = static_cast<const Node *>(RootNode); 535341825Sdim while (N) { 536341825Sdim switch (N->getKind()) { 537341825Sdim default: 538341825Sdim return false; 539341825Sdim case Node::KCtorDtorName: 540341825Sdim return true; 541341825Sdim 542341825Sdim case Node::KAbiTagAttr: 543344779Sdim N = static_cast<const AbiTagAttr *>(N)->Base; 544341825Sdim break; 545341825Sdim case Node::KFunctionEncoding: 546344779Sdim N = static_cast<const FunctionEncoding *>(N)->getName(); 547341825Sdim break; 548341825Sdim case Node::KLocalName: 549344779Sdim N = static_cast<const LocalName *>(N)->Entity; 550341825Sdim break; 551341825Sdim case Node::KNameWithTemplateArgs: 552344779Sdim N = static_cast<const NameWithTemplateArgs *>(N)->Name; 553341825Sdim break; 554341825Sdim case Node::KNestedName: 555344779Sdim N = static_cast<const NestedName *>(N)->Name; 556341825Sdim break; 557341825Sdim case Node::KStdQualifiedName: 558344779Sdim N = static_cast<const StdQualifiedName *>(N)->Child; 559341825Sdim break; 560341825Sdim } 561341825Sdim } 562341825Sdim return false; 563341825Sdim} 564341825Sdim 565341825Sdimbool ItaniumPartialDemangler::isFunction() const { 566341825Sdim assert(RootNode != nullptr && "must call partialDemangle()"); 567344779Sdim return static_cast<const Node *>(RootNode)->getKind() == 568344779Sdim Node::KFunctionEncoding; 569341825Sdim} 570341825Sdim 571341825Sdimbool ItaniumPartialDemangler::isSpecialName() const { 572341825Sdim assert(RootNode != nullptr && "must call partialDemangle()"); 573344779Sdim auto K = static_cast<const Node *>(RootNode)->getKind(); 574341825Sdim return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName; 575341825Sdim} 576341825Sdim 577341825Sdimbool ItaniumPartialDemangler::isData() const { 578341825Sdim return !isFunction() && !isSpecialName(); 579341825Sdim} 580