LCOV - code coverage report
Current view: top level - lib/Demangle - ItaniumDemangle.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 203 509 39.9 %
Date: 2018-10-20 13:21:21 Functions: 39 130 30.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===------------------------- ItaniumDemangle.cpp ------------------------===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is dual licensed under the MIT and the University of Illinois Open
       6             : // Source Licenses. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : 
      10             : // FIXME: (possibly) incomplete list of features that clang mangles that this
      11             : // file does not yet support:
      12             : //   - C++ modules TS
      13             : 
      14             : #include "llvm/Demangle/Demangle.h"
      15             : #include "llvm/Demangle/ItaniumDemangle.h"
      16             : 
      17             : #include <cassert>
      18             : #include <cctype>
      19             : #include <cstdio>
      20             : #include <cstdlib>
      21             : #include <cstring>
      22             : #include <functional>
      23             : #include <numeric>
      24             : #include <utility>
      25             : #include <vector>
      26             : 
      27             : using namespace llvm;
      28             : using namespace llvm::itanium_demangle;
      29             : 
      30             : constexpr const char *itanium_demangle::FloatData<float>::spec;
      31             : constexpr const char *itanium_demangle::FloatData<double>::spec;
      32             : constexpr const char *itanium_demangle::FloatData<long double>::spec;
      33             : 
      34             : // <discriminator> := _ <non-negative number>      # when number < 10
      35             : //                 := __ <non-negative number> _   # when number >= 10
      36             : //  extension      := decimal-digit+               # at the end of string
      37          13 : const char *itanium_demangle::parse_discriminator(const char *first,
      38             :                                                   const char *last) {
      39             :   // parse but ignore discriminator
      40          13 :   if (first != last) {
      41           8 :     if (*first == '_') {
      42           0 :       const char *t1 = first + 1;
      43           0 :       if (t1 != last) {
      44           0 :         if (std::isdigit(*t1))
      45           0 :           first = t1 + 1;
      46           0 :         else if (*t1 == '_') {
      47           0 :           for (++t1; t1 != last && std::isdigit(*t1); ++t1)
      48             :             ;
      49           0 :           if (t1 != last && *t1 == '_')
      50           0 :             first = t1 + 1;
      51             :         }
      52             :       }
      53           8 :     } else if (std::isdigit(*first)) {
      54           0 :       const char *t1 = first + 1;
      55           0 :       for (; t1 != last && std::isdigit(*t1); ++t1)
      56             :         ;
      57           0 :       if (t1 == last)
      58             :         first = last;
      59             :     }
      60             :   }
      61          13 :   return first;
      62             : }
      63             : 
      64             : #ifndef NDEBUG
      65             : namespace {
      66             : struct DumpVisitor {
      67             :   unsigned Depth = 0;
      68             :   bool PendingNewline = false;
      69             : 
      70             :   template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
      71             :     return true;
      72             :   }
      73             :   static bool wantsNewline(NodeArray A) { return !A.empty(); }
      74             :   static constexpr bool wantsNewline(...) { return false; }
      75             : 
      76             :   template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
      77             :     for (bool B : {wantsNewline(Vs)...})
      78             :       if (B)
      79             :         return true;
      80             :     return false;
      81             :   }
      82             : 
      83             :   void printStr(const char *S) { fprintf(stderr, "%s", S); }
      84             :   void print(StringView SV) {
      85             :     fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin());
      86             :   }
      87             :   void print(const Node *N) {
      88             :     if (N)
      89             :       N->visit(std::ref(*this));
      90             :     else
      91             :       printStr("<null>");
      92             :   }
      93             :   void print(NodeOrString NS) {
      94             :     if (NS.isNode())
      95             :       print(NS.asNode());
      96             :     else if (NS.isString())
      97             :       print(NS.asString());
      98             :     else
      99             :       printStr("NodeOrString()");
     100             :   }
     101             :   void print(NodeArray A) {
     102             :     ++Depth;
     103             :     printStr("{");
     104             :     bool First = true;
     105             :     for (const Node *N : A) {
     106             :       if (First)
     107             :         print(N);
     108             :       else
     109             :         printWithComma(N);
     110             :       First = false;
     111             :     }
     112             :     printStr("}");
     113             :     --Depth;
     114             :   }
     115             : 
     116             :   // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
     117             :   void print(bool B) { printStr(B ? "true" : "false"); }
     118             : 
     119             :   template <class T>
     120             :   typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {
     121             :     fprintf(stderr, "%llu", (unsigned long long)N);
     122             :   }
     123             : 
     124             :   template <class T>
     125             :   typename std::enable_if<std::is_signed<T>::value>::type print(T N) {
     126             :     fprintf(stderr, "%lld", (long long)N);
     127             :   }
     128             : 
     129             :   void print(ReferenceKind RK) {
     130             :     switch (RK) {
     131             :     case ReferenceKind::LValue:
     132             :       return printStr("ReferenceKind::LValue");
     133             :     case ReferenceKind::RValue:
     134             :       return printStr("ReferenceKind::RValue");
     135             :     }
     136             :   }
     137             :   void print(FunctionRefQual RQ) {
     138             :     switch (RQ) {
     139             :     case FunctionRefQual::FrefQualNone:
     140             :       return printStr("FunctionRefQual::FrefQualNone");
     141             :     case FunctionRefQual::FrefQualLValue:
     142             :       return printStr("FunctionRefQual::FrefQualLValue");
     143             :     case FunctionRefQual::FrefQualRValue:
     144             :       return printStr("FunctionRefQual::FrefQualRValue");
     145             :     }
     146             :   }
     147             :   void print(Qualifiers Qs) {
     148             :     if (!Qs) return printStr("QualNone");
     149             :     struct QualName { Qualifiers Q; const char *Name; } Names[] = {
     150             :       {QualConst, "QualConst"},
     151             :       {QualVolatile, "QualVolatile"},
     152             :       {QualRestrict, "QualRestrict"},
     153             :     };
     154             :     for (QualName Name : Names) {
     155             :       if (Qs & Name.Q) {
     156             :         printStr(Name.Name);
     157             :         Qs = Qualifiers(Qs & ~Name.Q);
     158             :         if (Qs) printStr(" | ");
     159             :       }
     160             :     }
     161             :   }
     162             :   void print(SpecialSubKind SSK) {
     163             :     switch (SSK) {
     164             :     case SpecialSubKind::allocator:
     165             :       return printStr("SpecialSubKind::allocator");
     166             :     case SpecialSubKind::basic_string:
     167             :       return printStr("SpecialSubKind::basic_string");
     168             :     case SpecialSubKind::string:
     169             :       return printStr("SpecialSubKind::string");
     170             :     case SpecialSubKind::istream:
     171             :       return printStr("SpecialSubKind::istream");
     172             :     case SpecialSubKind::ostream:
     173             :       return printStr("SpecialSubKind::ostream");
     174             :     case SpecialSubKind::iostream:
     175             :       return printStr("SpecialSubKind::iostream");
     176             :     }
     177             :   }
     178             : 
     179             :   void newLine() {
     180             :     printStr("\n");
     181             :     for (unsigned I = 0; I != Depth; ++I)
     182             :       printStr(" ");
     183             :     PendingNewline = false;
     184             :   }
     185             : 
     186             :   template<typename T> void printWithPendingNewline(T V) {
     187             :     print(V);
     188             :     if (wantsNewline(V))
     189             :       PendingNewline = true;
     190             :   }
     191             : 
     192             :   template<typename T> void printWithComma(T V) {
     193             :     if (PendingNewline || wantsNewline(V)) {
     194             :       printStr(",");
     195             :       newLine();
     196             :     } else {
     197             :       printStr(", ");
     198             :     }
     199             : 
     200             :     printWithPendingNewline(V);
     201             :   }
     202             : 
     203             :   struct CtorArgPrinter {
     204             :     DumpVisitor &Visitor;
     205             : 
     206             :     template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {
     207             :       if (Visitor.anyWantNewline(V, Vs...))
     208             :         Visitor.newLine();
     209             :       Visitor.printWithPendingNewline(V);
     210             :       int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };
     211             :       (void)PrintInOrder;
     212             :     }
     213             :   };
     214             : 
     215             :   template<typename NodeT> void operator()(const NodeT *Node) {
     216             :     Depth += 2;
     217             :     fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());
     218             :     Node->match(CtorArgPrinter{*this});
     219             :     fprintf(stderr, ")");
     220             :     Depth -= 2;
     221             :   }
     222             : 
     223             :   void operator()(const ForwardTemplateReference *Node) {
     224             :     Depth += 2;
     225             :     fprintf(stderr, "ForwardTemplateReference(");
     226             :     if (Node->Ref && !Node->Printing) {
     227             :       Node->Printing = true;
     228             :       CtorArgPrinter{*this}(Node->Ref);
     229             :       Node->Printing = false;
     230             :     } else {
     231             :       CtorArgPrinter{*this}(Node->Index);
     232             :     }
     233             :     fprintf(stderr, ")");
     234             :     Depth -= 2;
     235             :   }
     236             : };
     237             : }
     238             : 
     239             : void itanium_demangle::Node::dump() const {
     240             :   DumpVisitor V;
     241             :   visit(std::ref(V));
     242             :   V.newLine();
     243             : }
     244             : #endif
     245             : 
     246             : namespace {
     247             : class BumpPointerAllocator {
     248             :   struct BlockMeta {
     249             :     BlockMeta* Next;
     250             :     size_t Current;
     251             :   };
     252             : 
     253             :   static constexpr size_t AllocSize = 4096;
     254             :   static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
     255             : 
     256             :   alignas(long double) char InitialBuffer[AllocSize];
     257             :   BlockMeta* BlockList = nullptr;
     258             : 
     259           0 :   void grow() {
     260           0 :     char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
     261           0 :     if (NewMeta == nullptr)
     262           0 :       std::terminate();
     263           0 :     BlockList = new (NewMeta) BlockMeta{BlockList, 0};
     264           0 :   }
     265             : 
     266           0 :   void* allocateMassive(size_t NBytes) {
     267           0 :     NBytes += sizeof(BlockMeta);
     268           0 :     BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
     269           0 :     if (NewMeta == nullptr)
     270           0 :       std::terminate();
     271           0 :     BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
     272           0 :     return static_cast<void*>(NewMeta + 1);
     273             :   }
     274             : 
     275             : public:
     276             :   BumpPointerAllocator()
     277         501 :       : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
     278             : 
     279        4673 :   void* allocate(size_t N) {
     280        4673 :     N = (N + 15u) & ~15u;
     281        4673 :     if (N + BlockList->Current >= UsableAllocSize) {
     282           0 :       if (N > UsableAllocSize)
     283           0 :         return allocateMassive(N);
     284           0 :       grow();
     285             :     }
     286        4673 :     BlockList->Current += N;
     287        4673 :     return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
     288        4673 :                               BlockList->Current - N);
     289             :   }
     290             : 
     291         549 :   void reset() {
     292        1098 :     while (BlockList) {
     293             :       BlockMeta* Tmp = BlockList;
     294         549 :       BlockList = BlockList->Next;
     295         549 :       if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
     296           0 :         std::free(Tmp);
     297             :     }
     298         549 :     BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
     299         549 :   }
     300             : 
     301             :   ~BumpPointerAllocator() { reset(); }
     302             : };
     303             : 
     304             : class DefaultAllocator {
     305             :   BumpPointerAllocator Alloc;
     306             : 
     307             : public:
     308          39 :   void reset() { Alloc.reset(); }
     309             : 
     310        1993 :   template<typename T, typename ...Args> T *makeNode(Args &&...args) {
     311        2372 :     return new (Alloc.allocate(sizeof(T)))
     312        1993 :         T(std::forward<Args>(args)...);
     313             :   }
     314           0 : 
     315           0 :   void *allocateNodeArray(size_t sz) {
     316           0 :     return Alloc.allocate(sizeof(Node *) * sz);
     317             :   }
     318           0 : };
     319           0 : }  // unnamed namespace
     320           0 : 
     321             : //===----------------------------------------------------------------------===//
     322           0 : // Code beyond this point should not be synchronized with libc++abi.
     323           0 : //===----------------------------------------------------------------------===//
     324           0 : 
     325             : using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
     326           0 : 
     327           0 : char *llvm::itaniumDemangle(const char *MangledName, char *Buf,
     328           0 :                             size_t *N, int *Status) {
     329             :   if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
     330           0 :     if (Status)
     331           0 :       *Status = demangle_invalid_args;
     332           0 :     return nullptr;
     333             :   }
     334           0 : 
     335           0 :   int InternalStatus = demangle_success;
     336           0 :   Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
     337             :   OutputStream S;
     338           0 : 
     339           0 :   Node *AST = Parser.parse();
     340           0 : 
     341             :   if (AST == nullptr)
     342           0 :     InternalStatus = demangle_invalid_mangled_name;
     343           0 :   else if (initializeOutputStream(Buf, N, S, 1024))
     344           0 :     InternalStatus = demangle_memory_alloc_failure;
     345             :   else {
     346           0 :     assert(Parser.ForwardTemplateRefs.empty());
     347           0 :     AST->print(S);
     348           0 :     S += '\0';
     349             :     if (N != nullptr)
     350           0 :       *N = S.getCurrentPosition();
     351           0 :     Buf = S.getBuffer();
     352           0 :   }
     353             : 
     354           0 :   if (Status)
     355           0 :     *Status = InternalStatus;
     356           0 :   return InternalStatus == demangle_success ? Buf : nullptr;
     357             : }
     358           4 : 
     359           4 : bool llvm::itaniumFindTypesInMangledName(const char *MangledName, void *Ctx,
     360           4 :                                          void (*Callback)(void *,
     361             :                                                           const char *)) {
     362           0 :   Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
     363           0 :   Parser.TypeCallback = Callback;
     364           0 :   Parser.TypeCallbackContext = Ctx;
     365             :   return Parser.parse() == nullptr;
     366           0 : }
     367           0 : 
     368           0 : ItaniumPartialDemangler::ItaniumPartialDemangler()
     369             :     : RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {}
     370           0 : 
     371           0 : ItaniumPartialDemangler::~ItaniumPartialDemangler() {
     372           0 :   delete static_cast<Demangler *>(Context);
     373             : }
     374           0 : 
     375           0 : ItaniumPartialDemangler::ItaniumPartialDemangler(
     376           0 :     ItaniumPartialDemangler &&Other)
     377             :     : RootNode(Other.RootNode), Context(Other.Context) {
     378           0 :   Other.Context = Other.RootNode = nullptr;
     379           0 : }
     380           0 : 
     381             : ItaniumPartialDemangler &ItaniumPartialDemangler::
     382           0 : operator=(ItaniumPartialDemangler &&Other) {
     383           0 :   std::swap(RootNode, Other.RootNode);
     384           0 :   std::swap(Context, Other.Context);
     385             :   return *this;
     386           0 : }
     387           0 : 
     388           0 : // Demangle MangledName into an AST, storing it into this->RootNode.
     389             : bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
     390           0 :   Demangler *Parser = static_cast<Demangler *>(Context);
     391           0 :   size_t Len = std::strlen(MangledName);
     392           0 :   Parser->reset(MangledName, MangledName + Len);
     393             :   RootNode = Parser->parse();
     394           0 :   return RootNode == nullptr;
     395           0 : }
     396           0 : 
     397             : static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
     398           0 :   OutputStream S;
     399           0 :   if (initializeOutputStream(Buf, N, S, 128))
     400           0 :     return nullptr;
     401             :   RootNode->print(S);
     402           0 :   S += '\0';
     403           0 :   if (N != nullptr)
     404           0 :     *N = S.getCurrentPosition();
     405             :   return S.getBuffer();
     406           0 : }
     407           0 : 
     408           0 : char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
     409             :   if (!isFunction())
     410           0 :     return nullptr;
     411           0 : 
     412           0 :   const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
     413             : 
     414           0 :   while (true) {
     415           0 :     switch (Name->getKind()) {
     416           0 :     case Node::KAbiTagAttr:
     417             :       Name = static_cast<const AbiTagAttr *>(Name)->Base;
     418           0 :       continue;
     419           0 :     case Node::KStdQualifiedName:
     420           0 :       Name = static_cast<const StdQualifiedName *>(Name)->Child;
     421             :       continue;
     422          10 :     case Node::KNestedName:
     423          10 :       Name = static_cast<const NestedName *>(Name)->Name;
     424          10 :       continue;
     425             :     case Node::KLocalName:
     426           0 :       Name = static_cast<const LocalName *>(Name)->Entity;
     427           0 :       continue;
     428           0 :     case Node::KNameWithTemplateArgs:
     429             :       Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
     430           0 :       continue;
     431           0 :     default:
     432           0 :       return printNode(Name, Buf, N);
     433             :     }
     434           1 :   }
     435           1 : }
     436           1 : 
     437             : char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
     438           0 :                                                           size_t *N) const {
     439           0 :   if (!isFunction())
     440           0 :     return nullptr;
     441             :   const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
     442         163 : 
     443         163 :   OutputStream S;
     444         163 :   if (initializeOutputStream(Buf, N, S, 128))
     445             :     return nullptr;
     446           0 : 
     447           0 :  KeepGoingLocalFunction:
     448           0 :   while (true) {
     449             :     if (Name->getKind() == Node::KAbiTagAttr) {
     450           0 :       Name = static_cast<const AbiTagAttr *>(Name)->Base;
     451           0 :       continue;
     452           0 :     }
     453             :     if (Name->getKind() == Node::KNameWithTemplateArgs) {
     454           5 :       Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
     455           5 :       continue;
     456           5 :     }
     457             :     break;
     458          11 :   }
     459          11 : 
     460          11 :   switch (Name->getKind()) {
     461             :   case Node::KStdQualifiedName:
     462           0 :     S += "std";
     463           0 :     break;
     464           0 :   case Node::KNestedName:
     465             :     static_cast<const NestedName *>(Name)->Qual->print(S);
     466         105 :     break;
     467         105 :   case Node::KLocalName: {
     468         105 :     auto *LN = static_cast<const LocalName *>(Name);
     469             :     LN->Encoding->print(S);
     470          27 :     S += "::";
     471          27 :     Name = LN->Entity;
     472          27 :     goto KeepGoingLocalFunction;
     473             :   }
     474           0 :   default:
     475           0 :     break;
     476           0 :   }
     477             :   S += '\0';
     478           0 :   if (N != nullptr)
     479           0 :     *N = S.getCurrentPosition();
     480           0 :   return S.getBuffer();
     481             : }
     482           0 : 
     483           0 : char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
     484           0 :   if (!isFunction())
     485             :     return nullptr;
     486           0 :   auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName();
     487           0 :   return printNode(Name, Buf, N);
     488           0 : }
     489             : 
     490           8 : char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
     491           8 :                                                      size_t *N) const {
     492           8 :   if (!isFunction())
     493             :     return nullptr;
     494           5 :   NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
     495           5 : 
     496           5 :   OutputStream S;
     497             :   if (initializeOutputStream(Buf, N, S, 128))
     498        1518 :     return nullptr;
     499        1518 : 
     500        1518 :   S += '(';
     501             :   Params.printWithComma(S);
     502           0 :   S += ')';
     503           0 :   S += '\0';
     504           0 :   if (N != nullptr)
     505             :     *N = S.getCurrentPosition();
     506           0 :   return S.getBuffer();
     507           0 : }
     508           0 : 
     509             : char *ItaniumPartialDemangler::getFunctionReturnType(
     510           0 :     char *Buf, size_t *N) const {
     511           0 :   if (!isFunction())
     512           0 :     return nullptr;
     513             : 
     514           0 :   OutputStream S;
     515           0 :   if (initializeOutputStream(Buf, N, S, 128))
     516           0 :     return nullptr;
     517             : 
     518           0 :   if (const Node *Ret =
     519           0 :           static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
     520           0 :     Ret->print(S);
     521             : 
     522           0 :   S += '\0';
     523           0 :   if (N != nullptr)
     524           0 :     *N = S.getCurrentPosition();
     525             :   return S.getBuffer();
     526           0 : }
     527           0 : 
     528           0 : char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
     529             :   assert(RootNode != nullptr && "must call partialDemangle()");
     530           0 :   return printNode(static_cast<Node *>(RootNode), Buf, N);
     531           0 : }
     532           0 : 
     533             : bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
     534           0 :   assert(RootNode != nullptr && "must call partialDemangle()");
     535           0 :   if (!isFunction())
     536           0 :     return false;
     537             :   auto *E = static_cast<const FunctionEncoding *>(RootNode);
     538           0 :   return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone;
     539           0 : }
     540           0 : 
     541             : bool ItaniumPartialDemangler::isCtorOrDtor() const {
     542           1 :   const Node *N = static_cast<const Node *>(RootNode);
     543           1 :   while (N) {
     544           1 :     switch (N->getKind()) {
     545             :     default:
     546           2 :       return false;
     547           2 :     case Node::KCtorDtorName:
     548           2 :       return true;
     549             : 
     550           0 :     case Node::KAbiTagAttr:
     551           0 :       N = static_cast<const AbiTagAttr *>(N)->Base;
     552           0 :       break;
     553             :     case Node::KFunctionEncoding:
     554           0 :       N = static_cast<const FunctionEncoding *>(N)->getName();
     555           0 :       break;
     556           0 :     case Node::KLocalName:
     557             :       N = static_cast<const LocalName *>(N)->Entity;
     558           0 :       break;
     559           0 :     case Node::KNameWithTemplateArgs:
     560           0 :       N = static_cast<const NameWithTemplateArgs *>(N)->Name;
     561             :       break;
     562           0 :     case Node::KNestedName:
     563           0 :       N = static_cast<const NestedName *>(N)->Name;
     564           0 :       break;
     565             :     case Node::KStdQualifiedName:
     566           0 :       N = static_cast<const StdQualifiedName *>(N)->Child;
     567           0 :       break;
     568           0 :     }
     569             :   }
     570           0 :   return false;
     571           0 : }
     572           0 : 
     573             : bool ItaniumPartialDemangler::isFunction() const {
     574           0 :   assert(RootNode != nullptr && "must call partialDemangle()");
     575           0 :   return static_cast<const Node *>(RootNode)->getKind() ==
     576           0 :          Node::KFunctionEncoding;
     577             : }
     578           0 : 
     579           0 : bool ItaniumPartialDemangler::isSpecialName() const {
     580           0 :   assert(RootNode != nullptr && "must call partialDemangle()");
     581             :   auto K = static_cast<const Node *>(RootNode)->getKind();
     582           0 :   return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName;
     583           0 : }
     584           0 : 
     585             : bool ItaniumPartialDemangler::isData() const {
     586           0 :   return !isFunction() && !isSpecialName();
     587           0 : }

Generated by: LCOV version 1.13