1bb7feae2SErik Pilkington //===------------------------- ItaniumDemangle.cpp ------------------------===//
2b940b66cSRafael Espindola //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b940b66cSRafael Espindola //
7b940b66cSRafael Espindola //===----------------------------------------------------------------------===//
8b940b66cSRafael Espindola 
9bb7feae2SErik Pilkington // FIXME: (possibly) incomplete list of features that clang mangles that this
10bb7feae2SErik Pilkington // file does not yet support:
11bb7feae2SErik Pilkington //   - C++ modules TS
12bb7feae2SErik Pilkington 
13b2881f1fSReid Kleckner #include "llvm/Demangle/Demangle.h"
148a57f2e0SRichard Smith #include "llvm/Demangle/ItaniumDemangle.h"
151a095524SSerge Pavlov 
16bb7feae2SErik Pilkington #include <cassert>
1799e17253SDavid Blaikie #include <cctype>
18bb7feae2SErik Pilkington #include <cstdio>
19b940b66cSRafael Espindola #include <cstdlib>
20b940b66cSRafael Espindola #include <cstring>
21a25e2069SDavid Blaikie #include <functional>
223a6fed4aSErik Pilkington #include <utility>
23b940b66cSRafael Espindola 
248a57f2e0SRichard Smith using namespace llvm;
258a57f2e0SRichard Smith using namespace llvm::itanium_demangle;
26bb7feae2SErik Pilkington 
278a57f2e0SRichard Smith constexpr const char *itanium_demangle::FloatData<float>::spec;
288a57f2e0SRichard Smith constexpr const char *itanium_demangle::FloatData<double>::spec;
298a57f2e0SRichard Smith constexpr const char *itanium_demangle::FloatData<long double>::spec;
30bb7feae2SErik Pilkington 
318a57f2e0SRichard Smith // <discriminator> := _ <non-negative number>      # when number < 10
328a57f2e0SRichard Smith //                 := __ <non-negative number> _   # when number >= 10
338a57f2e0SRichard Smith //  extension      := decimal-digit+               # at the end of string
parse_discriminator(const char * first,const char * last)348a57f2e0SRichard Smith const char *itanium_demangle::parse_discriminator(const char *first,
358a57f2e0SRichard Smith                                                   const char *last) {
368a57f2e0SRichard Smith   // parse but ignore discriminator
378a57f2e0SRichard Smith   if (first != last) {
388a57f2e0SRichard Smith     if (*first == '_') {
398a57f2e0SRichard Smith       const char *t1 = first + 1;
408a57f2e0SRichard Smith       if (t1 != last) {
418a57f2e0SRichard Smith         if (std::isdigit(*t1))
428a57f2e0SRichard Smith           first = t1 + 1;
438a57f2e0SRichard Smith         else if (*t1 == '_') {
448a57f2e0SRichard Smith           for (++t1; t1 != last && std::isdigit(*t1); ++t1)
458a57f2e0SRichard Smith             ;
468a57f2e0SRichard Smith           if (t1 != last && *t1 == '_')
478a57f2e0SRichard Smith             first = t1 + 1;
48bb7feae2SErik Pilkington         }
49bb7feae2SErik Pilkington       }
508a57f2e0SRichard Smith     } else if (std::isdigit(*first)) {
518a57f2e0SRichard Smith       const char *t1 = first + 1;
528a57f2e0SRichard Smith       for (; t1 != last && std::isdigit(*t1); ++t1)
538a57f2e0SRichard Smith         ;
548a57f2e0SRichard Smith       if (t1 == last)
558a57f2e0SRichard Smith         first = last;
56bb7feae2SErik Pilkington     }
573a6fed4aSErik Pilkington   }
588a57f2e0SRichard Smith   return first;
59bb7feae2SErik Pilkington }
60bb7feae2SErik Pilkington 
61bb7feae2SErik Pilkington #ifndef NDEBUG
628a57f2e0SRichard Smith namespace {
638a57f2e0SRichard Smith struct DumpVisitor {
648a57f2e0SRichard Smith   unsigned Depth = 0;
658a57f2e0SRichard Smith   bool PendingNewline = false;
668a57f2e0SRichard Smith 
wantsNewline__anon451de9200111::DumpVisitor678a57f2e0SRichard Smith   template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
688a57f2e0SRichard Smith     return true;
69bb7feae2SErik Pilkington   }
wantsNewline__anon451de9200111::DumpVisitor708a57f2e0SRichard Smith   static bool wantsNewline(NodeArray A) { return !A.empty(); }
wantsNewline__anon451de9200111::DumpVisitor718a57f2e0SRichard Smith   static constexpr bool wantsNewline(...) { return false; }
72bb7feae2SErik Pilkington 
anyWantNewline__anon451de9200111::DumpVisitor738a57f2e0SRichard Smith   template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
748a57f2e0SRichard Smith     for (bool B : {wantsNewline(Vs)...})
758a57f2e0SRichard Smith       if (B)
768a57f2e0SRichard Smith         return true;
778a57f2e0SRichard Smith     return false;
788c7013d4SErik Pilkington   }
798c7013d4SErik Pilkington 
printStr__anon451de9200111::DumpVisitor808a57f2e0SRichard Smith   void printStr(const char *S) { fprintf(stderr, "%s", S); }
print__anon451de9200111::DumpVisitor818a57f2e0SRichard Smith   void print(StringView SV) {
828a57f2e0SRichard Smith     fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin());
83bb7feae2SErik Pilkington   }
print__anon451de9200111::DumpVisitor848a57f2e0SRichard Smith   void print(const Node *N) {
858a57f2e0SRichard Smith     if (N)
868a57f2e0SRichard Smith       N->visit(std::ref(*this));
87bb7feae2SErik Pilkington     else
888a57f2e0SRichard Smith       printStr("<null>");
89bb7feae2SErik Pilkington   }
print__anon451de9200111::DumpVisitor908a57f2e0SRichard Smith   void print(NodeArray A) {
918a57f2e0SRichard Smith     ++Depth;
928a57f2e0SRichard Smith     printStr("{");
938a57f2e0SRichard Smith     bool First = true;
948a57f2e0SRichard Smith     for (const Node *N : A) {
958a57f2e0SRichard Smith       if (First)
968a57f2e0SRichard Smith         print(N);
978a57f2e0SRichard Smith       else
988a57f2e0SRichard Smith         printWithComma(N);
998a57f2e0SRichard Smith       First = false;
1008a57f2e0SRichard Smith     }
1018a57f2e0SRichard Smith     printStr("}");
1028a57f2e0SRichard Smith     --Depth;
1038a57f2e0SRichard Smith   }
104fbca8d54SErik Pilkington 
1058a57f2e0SRichard Smith   // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
print__anon451de9200111::DumpVisitor106fbca8d54SErik Pilkington   void print(bool B) { printStr(B ? "true" : "false"); }
107fbca8d54SErik Pilkington 
print__anon451de9200111::DumpVisitor1081bd6123bSJustin Lebar   template <class T> std::enable_if_t<std::is_unsigned<T>::value> print(T N) {
109fbca8d54SErik Pilkington     fprintf(stderr, "%llu", (unsigned long long)N);
1108a57f2e0SRichard Smith   }
111fbca8d54SErik Pilkington 
print__anon451de9200111::DumpVisitor1121bd6123bSJustin Lebar   template <class T> std::enable_if_t<std::is_signed<T>::value> print(T N) {
113fbca8d54SErik Pilkington     fprintf(stderr, "%lld", (long long)N);
1148a57f2e0SRichard Smith   }
115fbca8d54SErik Pilkington 
print__anon451de9200111::DumpVisitor1168a57f2e0SRichard Smith   void print(ReferenceKind RK) {
1178a57f2e0SRichard Smith     switch (RK) {
1188a57f2e0SRichard Smith     case ReferenceKind::LValue:
1198a57f2e0SRichard Smith       return printStr("ReferenceKind::LValue");
1208a57f2e0SRichard Smith     case ReferenceKind::RValue:
1218a57f2e0SRichard Smith       return printStr("ReferenceKind::RValue");
1228a57f2e0SRichard Smith     }
1238a57f2e0SRichard Smith   }
print__anon451de9200111::DumpVisitor1248a57f2e0SRichard Smith   void print(FunctionRefQual RQ) {
1258a57f2e0SRichard Smith     switch (RQ) {
1268a57f2e0SRichard Smith     case FunctionRefQual::FrefQualNone:
1278a57f2e0SRichard Smith       return printStr("FunctionRefQual::FrefQualNone");
1288a57f2e0SRichard Smith     case FunctionRefQual::FrefQualLValue:
1298a57f2e0SRichard Smith       return printStr("FunctionRefQual::FrefQualLValue");
1308a57f2e0SRichard Smith     case FunctionRefQual::FrefQualRValue:
1318a57f2e0SRichard Smith       return printStr("FunctionRefQual::FrefQualRValue");
1328a57f2e0SRichard Smith     }
1338a57f2e0SRichard Smith   }
print__anon451de9200111::DumpVisitor1348a57f2e0SRichard Smith   void print(Qualifiers Qs) {
1358a57f2e0SRichard Smith     if (!Qs) return printStr("QualNone");
1368a57f2e0SRichard Smith     struct QualName { Qualifiers Q; const char *Name; } Names[] = {
1378a57f2e0SRichard Smith       {QualConst, "QualConst"},
1388a57f2e0SRichard Smith       {QualVolatile, "QualVolatile"},
1398a57f2e0SRichard Smith       {QualRestrict, "QualRestrict"},
140bb7feae2SErik Pilkington     };
1418a57f2e0SRichard Smith     for (QualName Name : Names) {
1428a57f2e0SRichard Smith       if (Qs & Name.Q) {
1438a57f2e0SRichard Smith         printStr(Name.Name);
1448a57f2e0SRichard Smith         Qs = Qualifiers(Qs & ~Name.Q);
1458a57f2e0SRichard Smith         if (Qs) printStr(" | ");
146bb7feae2SErik Pilkington       }
147bb7feae2SErik Pilkington     }
148bb7feae2SErik Pilkington   }
print__anon451de9200111::DumpVisitor1498a57f2e0SRichard Smith   void print(SpecialSubKind SSK) {
1508a57f2e0SRichard Smith     switch (SSK) {
1518a57f2e0SRichard Smith     case SpecialSubKind::allocator:
1528a57f2e0SRichard Smith       return printStr("SpecialSubKind::allocator");
1538a57f2e0SRichard Smith     case SpecialSubKind::basic_string:
1548a57f2e0SRichard Smith       return printStr("SpecialSubKind::basic_string");
1558a57f2e0SRichard Smith     case SpecialSubKind::string:
1568a57f2e0SRichard Smith       return printStr("SpecialSubKind::string");
1578a57f2e0SRichard Smith     case SpecialSubKind::istream:
1588a57f2e0SRichard Smith       return printStr("SpecialSubKind::istream");
1598a57f2e0SRichard Smith     case SpecialSubKind::ostream:
1608a57f2e0SRichard Smith       return printStr("SpecialSubKind::ostream");
1618a57f2e0SRichard Smith     case SpecialSubKind::iostream:
1628a57f2e0SRichard Smith       return printStr("SpecialSubKind::iostream");
163bb7feae2SErik Pilkington     }
164bb7feae2SErik Pilkington   }
print__anon451de9200111::DumpVisitor1650e881b9fSRichard Smith   void print(TemplateParamKind TPK) {
1660e881b9fSRichard Smith     switch (TPK) {
1670e881b9fSRichard Smith     case TemplateParamKind::Type:
1680e881b9fSRichard Smith       return printStr("TemplateParamKind::Type");
1690e881b9fSRichard Smith     case TemplateParamKind::NonType:
1700e881b9fSRichard Smith       return printStr("TemplateParamKind::NonType");
1710e881b9fSRichard Smith     case TemplateParamKind::Template:
1720e881b9fSRichard Smith       return printStr("TemplateParamKind::Template");
1730e881b9fSRichard Smith     }
1740e881b9fSRichard Smith   }
print__anon451de9200111::DumpVisitor1754a4d0985SNathan Sidwell   void print(Node::Prec P) {
1764a4d0985SNathan Sidwell     switch (P) {
1774a4d0985SNathan Sidwell     case Node::Prec::Primary:
1784a4d0985SNathan Sidwell       return printStr("Node::Prec::Primary");
1794a4d0985SNathan Sidwell     case Node::Prec::Postfix:
1804a4d0985SNathan Sidwell       return printStr("Node::Prec::Postfix");
1814a4d0985SNathan Sidwell     case Node::Prec::Unary:
1824a4d0985SNathan Sidwell       return printStr("Node::Prec::Unary");
1834a4d0985SNathan Sidwell     case Node::Prec::Cast:
1844a4d0985SNathan Sidwell       return printStr("Node::Prec::Cast");
1854a4d0985SNathan Sidwell     case Node::Prec::PtrMem:
1864a4d0985SNathan Sidwell       return printStr("Node::Prec::PtrMem");
1874a4d0985SNathan Sidwell     case Node::Prec::Multiplicative:
1884a4d0985SNathan Sidwell       return printStr("Node::Prec::Multiplicative");
1894a4d0985SNathan Sidwell     case Node::Prec::Additive:
1904a4d0985SNathan Sidwell       return printStr("Node::Prec::Additive");
1914a4d0985SNathan Sidwell     case Node::Prec::Shift:
1924a4d0985SNathan Sidwell       return printStr("Node::Prec::Shift");
1934a4d0985SNathan Sidwell     case Node::Prec::Spaceship:
1944a4d0985SNathan Sidwell       return printStr("Node::Prec::Spaceship");
1954a4d0985SNathan Sidwell     case Node::Prec::Relational:
1964a4d0985SNathan Sidwell       return printStr("Node::Prec::Relational");
1974a4d0985SNathan Sidwell     case Node::Prec::Equality:
1984a4d0985SNathan Sidwell       return printStr("Node::Prec::Equality");
1994a4d0985SNathan Sidwell     case Node::Prec::And:
2004a4d0985SNathan Sidwell       return printStr("Node::Prec::And");
2014a4d0985SNathan Sidwell     case Node::Prec::Xor:
2024a4d0985SNathan Sidwell       return printStr("Node::Prec::Xor");
2034a4d0985SNathan Sidwell     case Node::Prec::Ior:
2044a4d0985SNathan Sidwell       return printStr("Node::Prec::Ior");
2054a4d0985SNathan Sidwell     case Node::Prec::AndIf:
2064a4d0985SNathan Sidwell       return printStr("Node::Prec::AndIf");
2074a4d0985SNathan Sidwell     case Node::Prec::OrIf:
2084a4d0985SNathan Sidwell       return printStr("Node::Prec::OrIf");
2094a4d0985SNathan Sidwell     case Node::Prec::Conditional:
2104a4d0985SNathan Sidwell       return printStr("Node::Prec::Conditional");
2114a4d0985SNathan Sidwell     case Node::Prec::Assign:
2124a4d0985SNathan Sidwell       return printStr("Node::Prec::Assign");
2134a4d0985SNathan Sidwell     case Node::Prec::Comma:
2144a4d0985SNathan Sidwell       return printStr("Node::Prec::Comma");
2154a4d0985SNathan Sidwell     case Node::Prec::Default:
2164a4d0985SNathan Sidwell       return printStr("Node::Prec::Default");
2174a4d0985SNathan Sidwell     }
2181d1cf9b6SDavid Blaikie   }
219bb7feae2SErik Pilkington 
newLine__anon451de9200111::DumpVisitor2208a57f2e0SRichard Smith   void newLine() {
2218a57f2e0SRichard Smith     printStr("\n");
2228a57f2e0SRichard Smith     for (unsigned I = 0; I != Depth; ++I)
2238a57f2e0SRichard Smith       printStr(" ");
2248a57f2e0SRichard Smith     PendingNewline = false;
225bb7feae2SErik Pilkington   }
226bb7feae2SErik Pilkington 
printWithPendingNewline__anon451de9200111::DumpVisitor2278a57f2e0SRichard Smith   template<typename T> void printWithPendingNewline(T V) {
2288a57f2e0SRichard Smith     print(V);
2298a57f2e0SRichard Smith     if (wantsNewline(V))
2308a57f2e0SRichard Smith       PendingNewline = true;
231bb7feae2SErik Pilkington   }
232bb7feae2SErik Pilkington 
printWithComma__anon451de9200111::DumpVisitor2338a57f2e0SRichard Smith   template<typename T> void printWithComma(T V) {
2348a57f2e0SRichard Smith     if (PendingNewline || wantsNewline(V)) {
2358a57f2e0SRichard Smith       printStr(",");
2368a57f2e0SRichard Smith       newLine();
237bb7feae2SErik Pilkington     } else {
2388a57f2e0SRichard Smith       printStr(", ");
239bb7feae2SErik Pilkington     }
2408a57f2e0SRichard Smith 
2418a57f2e0SRichard Smith     printWithPendingNewline(V);
2428a57f2e0SRichard Smith   }
2438a57f2e0SRichard Smith 
2448a57f2e0SRichard Smith   struct CtorArgPrinter {
2458a57f2e0SRichard Smith     DumpVisitor &Visitor;
2468a57f2e0SRichard Smith 
operator ()__anon451de9200111::DumpVisitor::CtorArgPrinter2478a57f2e0SRichard Smith     template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {
2488a57f2e0SRichard Smith       if (Visitor.anyWantNewline(V, Vs...))
2498a57f2e0SRichard Smith         Visitor.newLine();
2508a57f2e0SRichard Smith       Visitor.printWithPendingNewline(V);
2518a57f2e0SRichard Smith       int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };
2528a57f2e0SRichard Smith       (void)PrintInOrder;
253bb7feae2SErik Pilkington     }
254bb7feae2SErik Pilkington   };
255bb7feae2SErik Pilkington 
operator ()__anon451de9200111::DumpVisitor2568a57f2e0SRichard Smith   template<typename NodeT> void operator()(const NodeT *Node) {
2578a57f2e0SRichard Smith     Depth += 2;
2588a57f2e0SRichard Smith     fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());
2598a57f2e0SRichard Smith     Node->match(CtorArgPrinter{*this});
2608a57f2e0SRichard Smith     fprintf(stderr, ")");
2618a57f2e0SRichard Smith     Depth -= 2;
2628c7013d4SErik Pilkington   }
2638c7013d4SErik Pilkington 
operator ()__anon451de9200111::DumpVisitor2648a57f2e0SRichard Smith   void operator()(const ForwardTemplateReference *Node) {
2658a57f2e0SRichard Smith     Depth += 2;
2668a57f2e0SRichard Smith     fprintf(stderr, "ForwardTemplateReference(");
2678a57f2e0SRichard Smith     if (Node->Ref && !Node->Printing) {
2688a57f2e0SRichard Smith       Node->Printing = true;
2698a57f2e0SRichard Smith       CtorArgPrinter{*this}(Node->Ref);
2708a57f2e0SRichard Smith       Node->Printing = false;
271bb7feae2SErik Pilkington     } else {
2728a57f2e0SRichard Smith       CtorArgPrinter{*this}(Node->Index);
273bb7feae2SErik Pilkington     }
2748a57f2e0SRichard Smith     fprintf(stderr, ")");
2758a57f2e0SRichard Smith     Depth -= 2;
276bb7feae2SErik Pilkington   }
277bb7feae2SErik Pilkington };
278bb7feae2SErik Pilkington }
279bb7feae2SErik Pilkington 
dump() const2808a57f2e0SRichard Smith void itanium_demangle::Node::dump() const {
2818a57f2e0SRichard Smith   DumpVisitor V;
2828a57f2e0SRichard Smith   visit(std::ref(V));
2838a57f2e0SRichard Smith   V.newLine();
284bb7feae2SErik Pilkington }
285b940b66cSRafael Espindola #endif
286bb7feae2SErik Pilkington 
2878a57f2e0SRichard Smith namespace {
288bb7feae2SErik Pilkington class BumpPointerAllocator {
289bb7feae2SErik Pilkington   struct BlockMeta {
290bb7feae2SErik Pilkington     BlockMeta* Next;
291bb7feae2SErik Pilkington     size_t Current;
292bb7feae2SErik Pilkington   };
293bb7feae2SErik Pilkington 
294bb7feae2SErik Pilkington   static constexpr size_t AllocSize = 4096;
295bb7feae2SErik Pilkington   static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
296bb7feae2SErik Pilkington 
297892bd81aSSerge Pavlov   alignas(long double) char InitialBuffer[AllocSize];
298bb7feae2SErik Pilkington   BlockMeta* BlockList = nullptr;
299bb7feae2SErik Pilkington 
grow()300bb7feae2SErik Pilkington   void grow() {
30128e08a0aSErik Pilkington     char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
30228e08a0aSErik Pilkington     if (NewMeta == nullptr)
30328e08a0aSErik Pilkington       std::terminate();
304bb7feae2SErik Pilkington     BlockList = new (NewMeta) BlockMeta{BlockList, 0};
305bb7feae2SErik Pilkington   }
306bb7feae2SErik Pilkington 
allocateMassive(size_t NBytes)307bb7feae2SErik Pilkington   void* allocateMassive(size_t NBytes) {
308bb7feae2SErik Pilkington     NBytes += sizeof(BlockMeta);
30928e08a0aSErik Pilkington     BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
31028e08a0aSErik Pilkington     if (NewMeta == nullptr)
31128e08a0aSErik Pilkington       std::terminate();
312bb7feae2SErik Pilkington     BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
313bb7feae2SErik Pilkington     return static_cast<void*>(NewMeta + 1);
314bb7feae2SErik Pilkington   }
315bb7feae2SErik Pilkington 
316bb7feae2SErik Pilkington public:
BumpPointerAllocator()317bb7feae2SErik Pilkington   BumpPointerAllocator()
318bb7feae2SErik Pilkington       : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
319bb7feae2SErik Pilkington 
allocate(size_t N)320bb7feae2SErik Pilkington   void* allocate(size_t N) {
321bb7feae2SErik Pilkington     N = (N + 15u) & ~15u;
322bb7feae2SErik Pilkington     if (N + BlockList->Current >= UsableAllocSize) {
323bb7feae2SErik Pilkington       if (N > UsableAllocSize)
324bb7feae2SErik Pilkington         return allocateMassive(N);
325bb7feae2SErik Pilkington       grow();
326bb7feae2SErik Pilkington     }
327bb7feae2SErik Pilkington     BlockList->Current += N;
328bb7feae2SErik Pilkington     return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
329bb7feae2SErik Pilkington                               BlockList->Current - N);
330bb7feae2SErik Pilkington   }
331bb7feae2SErik Pilkington 
reset()332f2a9b0fdSErik Pilkington   void reset() {
333bb7feae2SErik Pilkington     while (BlockList) {
334bb7feae2SErik Pilkington       BlockMeta* Tmp = BlockList;
335bb7feae2SErik Pilkington       BlockList = BlockList->Next;
336bb7feae2SErik Pilkington       if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
33728e08a0aSErik Pilkington         std::free(Tmp);
338bb7feae2SErik Pilkington     }
339f2a9b0fdSErik Pilkington     BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
340bb7feae2SErik Pilkington   }
341f2a9b0fdSErik Pilkington 
~BumpPointerAllocator()342f2a9b0fdSErik Pilkington   ~BumpPointerAllocator() { reset(); }
343bb7feae2SErik Pilkington };
344bb7feae2SErik Pilkington 
345a6c34887SRichard Smith class DefaultAllocator {
346a6c34887SRichard Smith   BumpPointerAllocator Alloc;
347a6c34887SRichard Smith 
348a6c34887SRichard Smith public:
reset()349a6c34887SRichard Smith   void reset() { Alloc.reset(); }
350a6c34887SRichard Smith 
makeNode(Args &&...args)351a6c34887SRichard Smith   template<typename T, typename ...Args> T *makeNode(Args &&...args) {
352a6c34887SRichard Smith     return new (Alloc.allocate(sizeof(T)))
353a6c34887SRichard Smith         T(std::forward<Args>(args)...);
354a6c34887SRichard Smith   }
355a6c34887SRichard Smith 
allocateNodeArray(size_t sz)356a6c34887SRichard Smith   void *allocateNodeArray(size_t sz) {
357a6c34887SRichard Smith     return Alloc.allocate(sizeof(Node *) * sz);
358a6c34887SRichard Smith   }
359a6c34887SRichard Smith };
360bb7feae2SErik Pilkington }  // unnamed namespace
361bb7feae2SErik Pilkington 
3628a57f2e0SRichard Smith //===----------------------------------------------------------------------===//
3638a57f2e0SRichard Smith // Code beyond this point should not be synchronized with libc++abi.
3648a57f2e0SRichard Smith //===----------------------------------------------------------------------===//
3658a57f2e0SRichard Smith 
366f4c15824SPavel Labath using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
3678a57f2e0SRichard Smith 
itaniumDemangle(const char * MangledName,char * Buf,size_t * N,int * Status)368bb7feae2SErik Pilkington char *llvm::itaniumDemangle(const char *MangledName, char *Buf,
369bb7feae2SErik Pilkington                             size_t *N, int *Status) {
370bb7feae2SErik Pilkington   if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
371bb7feae2SErik Pilkington     if (Status)
3728a0efd09SZachary Turner       *Status = demangle_invalid_args;
373bb7feae2SErik Pilkington     return nullptr;
374bb7feae2SErik Pilkington   }
375bb7feae2SErik Pilkington 
3768a0efd09SZachary Turner   int InternalStatus = demangle_success;
3778a57f2e0SRichard Smith   Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
378*aabeb5ebSKirill Stoimenov   OutputBuffer OB;
379*aabeb5ebSKirill Stoimenov 
380bb7feae2SErik Pilkington   Node *AST = Parser.parse();
381bb7feae2SErik Pilkington 
382bb7feae2SErik Pilkington   if (AST == nullptr)
3838a0efd09SZachary Turner     InternalStatus = demangle_invalid_mangled_name;
384*aabeb5ebSKirill Stoimenov   else if (!initializeOutputBuffer(Buf, N, OB, 1024))
385*aabeb5ebSKirill Stoimenov     InternalStatus = demangle_memory_alloc_failure;
386f2a9b0fdSErik Pilkington   else {
387f2a9b0fdSErik Pilkington     assert(Parser.ForwardTemplateRefs.empty());
3882e97236aSLuís Ferreira     AST->print(OB);
3892e97236aSLuís Ferreira     OB += '\0';
390f2a9b0fdSErik Pilkington     if (N != nullptr)
3912e97236aSLuís Ferreira       *N = OB.getCurrentPosition();
3922e97236aSLuís Ferreira     Buf = OB.getBuffer();
393bb7feae2SErik Pilkington   }
394bb7feae2SErik Pilkington 
395bb7feae2SErik Pilkington   if (Status)
396bb7feae2SErik Pilkington     *Status = InternalStatus;
3978a0efd09SZachary Turner   return InternalStatus == demangle_success ? Buf : nullptr;
398b940b66cSRafael Espindola }
39967d82d6eSErik Pilkington 
ItaniumPartialDemangler()40067d82d6eSErik Pilkington ItaniumPartialDemangler::ItaniumPartialDemangler()
4018a57f2e0SRichard Smith     : RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {}
40267d82d6eSErik Pilkington 
~ItaniumPartialDemangler()40367d82d6eSErik Pilkington ItaniumPartialDemangler::~ItaniumPartialDemangler() {
4048a57f2e0SRichard Smith   delete static_cast<Demangler *>(Context);
40567d82d6eSErik Pilkington }
40667d82d6eSErik Pilkington 
ItaniumPartialDemangler(ItaniumPartialDemangler && Other)40767d82d6eSErik Pilkington ItaniumPartialDemangler::ItaniumPartialDemangler(
40867d82d6eSErik Pilkington     ItaniumPartialDemangler &&Other)
40967d82d6eSErik Pilkington     : RootNode(Other.RootNode), Context(Other.Context) {
41067d82d6eSErik Pilkington   Other.Context = Other.RootNode = nullptr;
41167d82d6eSErik Pilkington }
41267d82d6eSErik Pilkington 
41367d82d6eSErik Pilkington ItaniumPartialDemangler &ItaniumPartialDemangler::
operator =(ItaniumPartialDemangler && Other)41467d82d6eSErik Pilkington operator=(ItaniumPartialDemangler &&Other) {
41567d82d6eSErik Pilkington   std::swap(RootNode, Other.RootNode);
41667d82d6eSErik Pilkington   std::swap(Context, Other.Context);
41767d82d6eSErik Pilkington   return *this;
41867d82d6eSErik Pilkington }
41967d82d6eSErik Pilkington 
42067d82d6eSErik Pilkington // Demangle MangledName into an AST, storing it into this->RootNode.
partialDemangle(const char * MangledName)42167d82d6eSErik Pilkington bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
4228a57f2e0SRichard Smith   Demangler *Parser = static_cast<Demangler *>(Context);
42367d82d6eSErik Pilkington   size_t Len = std::strlen(MangledName);
42467d82d6eSErik Pilkington   Parser->reset(MangledName, MangledName + Len);
42567d82d6eSErik Pilkington   RootNode = Parser->parse();
42667d82d6eSErik Pilkington   return RootNode == nullptr;
42767d82d6eSErik Pilkington }
42867d82d6eSErik Pilkington 
printNode(const Node * RootNode,char * Buf,size_t * N)4298a57f2e0SRichard Smith static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
430*aabeb5ebSKirill Stoimenov   OutputBuffer OB;
431*aabeb5ebSKirill Stoimenov   if (!initializeOutputBuffer(Buf, N, OB, 128))
432*aabeb5ebSKirill Stoimenov     return nullptr;
4332e97236aSLuís Ferreira   RootNode->print(OB);
4342e97236aSLuís Ferreira   OB += '\0';
43567d82d6eSErik Pilkington   if (N != nullptr)
4362e97236aSLuís Ferreira     *N = OB.getCurrentPosition();
4372e97236aSLuís Ferreira   return OB.getBuffer();
43867d82d6eSErik Pilkington }
43967d82d6eSErik Pilkington 
getFunctionBaseName(char * Buf,size_t * N) const44067d82d6eSErik Pilkington char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
44167d82d6eSErik Pilkington   if (!isFunction())
44267d82d6eSErik Pilkington     return nullptr;
44367d82d6eSErik Pilkington 
4448a57f2e0SRichard Smith   const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
44567d82d6eSErik Pilkington 
44667d82d6eSErik Pilkington   while (true) {
44767d82d6eSErik Pilkington     switch (Name->getKind()) {
44867d82d6eSErik Pilkington     case Node::KAbiTagAttr:
4498a57f2e0SRichard Smith       Name = static_cast<const AbiTagAttr *>(Name)->Base;
45067d82d6eSErik Pilkington       continue;
451c354167aSNathan Sidwell     case Node::KModuleEntity:
452c354167aSNathan Sidwell       Name = static_cast<const ModuleEntity *>(Name)->Name;
453c354167aSNathan Sidwell       continue;
45467d82d6eSErik Pilkington     case Node::KNestedName:
4558a57f2e0SRichard Smith       Name = static_cast<const NestedName *>(Name)->Name;
45667d82d6eSErik Pilkington       continue;
45767d82d6eSErik Pilkington     case Node::KLocalName:
4588a57f2e0SRichard Smith       Name = static_cast<const LocalName *>(Name)->Entity;
45967d82d6eSErik Pilkington       continue;
46067d82d6eSErik Pilkington     case Node::KNameWithTemplateArgs:
4618a57f2e0SRichard Smith       Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
46267d82d6eSErik Pilkington       continue;
46367d82d6eSErik Pilkington     default:
46467d82d6eSErik Pilkington       return printNode(Name, Buf, N);
46567d82d6eSErik Pilkington     }
46667d82d6eSErik Pilkington   }
46767d82d6eSErik Pilkington }
46867d82d6eSErik Pilkington 
getFunctionDeclContextName(char * Buf,size_t * N) const46967d82d6eSErik Pilkington char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
47067d82d6eSErik Pilkington                                                           size_t *N) const {
47167d82d6eSErik Pilkington   if (!isFunction())
47267d82d6eSErik Pilkington     return nullptr;
4738a57f2e0SRichard Smith   const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
47467d82d6eSErik Pilkington 
475*aabeb5ebSKirill Stoimenov   OutputBuffer OB;
476*aabeb5ebSKirill Stoimenov   if (!initializeOutputBuffer(Buf, N, OB, 128))
477*aabeb5ebSKirill Stoimenov     return nullptr;
47867d82d6eSErik Pilkington 
47967d82d6eSErik Pilkington  KeepGoingLocalFunction:
48067d82d6eSErik Pilkington   while (true) {
48167d82d6eSErik Pilkington     if (Name->getKind() == Node::KAbiTagAttr) {
4828a57f2e0SRichard Smith       Name = static_cast<const AbiTagAttr *>(Name)->Base;
48367d82d6eSErik Pilkington       continue;
48467d82d6eSErik Pilkington     }
48567d82d6eSErik Pilkington     if (Name->getKind() == Node::KNameWithTemplateArgs) {
4868a57f2e0SRichard Smith       Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;
48767d82d6eSErik Pilkington       continue;
48867d82d6eSErik Pilkington     }
48967d82d6eSErik Pilkington     break;
49067d82d6eSErik Pilkington   }
49167d82d6eSErik Pilkington 
492c354167aSNathan Sidwell   if (Name->getKind() == Node::KModuleEntity)
493c354167aSNathan Sidwell     Name = static_cast<const ModuleEntity *>(Name)->Name;
494c354167aSNathan Sidwell 
49567d82d6eSErik Pilkington   switch (Name->getKind()) {
49667d82d6eSErik Pilkington   case Node::KNestedName:
4972e97236aSLuís Ferreira     static_cast<const NestedName *>(Name)->Qual->print(OB);
49867d82d6eSErik Pilkington     break;
49967d82d6eSErik Pilkington   case Node::KLocalName: {
5008a57f2e0SRichard Smith     auto *LN = static_cast<const LocalName *>(Name);
5012e97236aSLuís Ferreira     LN->Encoding->print(OB);
5022e97236aSLuís Ferreira     OB += "::";
50367d82d6eSErik Pilkington     Name = LN->Entity;
50467d82d6eSErik Pilkington     goto KeepGoingLocalFunction;
50567d82d6eSErik Pilkington   }
50667d82d6eSErik Pilkington   default:
50767d82d6eSErik Pilkington     break;
50867d82d6eSErik Pilkington   }
5092e97236aSLuís Ferreira   OB += '\0';
51067d82d6eSErik Pilkington   if (N != nullptr)
5112e97236aSLuís Ferreira     *N = OB.getCurrentPosition();
5122e97236aSLuís Ferreira   return OB.getBuffer();
51367d82d6eSErik Pilkington }
51467d82d6eSErik Pilkington 
getFunctionName(char * Buf,size_t * N) const51567d82d6eSErik Pilkington char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
51667d82d6eSErik Pilkington   if (!isFunction())
51767d82d6eSErik Pilkington     return nullptr;
51867d82d6eSErik Pilkington   auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName();
51967d82d6eSErik Pilkington   return printNode(Name, Buf, N);
52067d82d6eSErik Pilkington }
52167d82d6eSErik Pilkington 
getFunctionParameters(char * Buf,size_t * N) const52267d82d6eSErik Pilkington char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
52367d82d6eSErik Pilkington                                                      size_t *N) const {
52467d82d6eSErik Pilkington   if (!isFunction())
52567d82d6eSErik Pilkington     return nullptr;
52667d82d6eSErik Pilkington   NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
52767d82d6eSErik Pilkington 
528*aabeb5ebSKirill Stoimenov   OutputBuffer OB;
529*aabeb5ebSKirill Stoimenov   if (!initializeOutputBuffer(Buf, N, OB, 128))
530*aabeb5ebSKirill Stoimenov     return nullptr;
53167d82d6eSErik Pilkington 
5322e97236aSLuís Ferreira   OB += '(';
5332e97236aSLuís Ferreira   Params.printWithComma(OB);
5342e97236aSLuís Ferreira   OB += ')';
5352e97236aSLuís Ferreira   OB += '\0';
53667d82d6eSErik Pilkington   if (N != nullptr)
5372e97236aSLuís Ferreira     *N = OB.getCurrentPosition();
5382e97236aSLuís Ferreira   return OB.getBuffer();
53967d82d6eSErik Pilkington }
54067d82d6eSErik Pilkington 
getFunctionReturnType(char * Buf,size_t * N) const54167d82d6eSErik Pilkington char *ItaniumPartialDemangler::getFunctionReturnType(
54267d82d6eSErik Pilkington     char *Buf, size_t *N) const {
54367d82d6eSErik Pilkington   if (!isFunction())
54467d82d6eSErik Pilkington     return nullptr;
54567d82d6eSErik Pilkington 
546*aabeb5ebSKirill Stoimenov   OutputBuffer OB;
547*aabeb5ebSKirill Stoimenov   if (!initializeOutputBuffer(Buf, N, OB, 128))
548*aabeb5ebSKirill Stoimenov     return nullptr;
54967d82d6eSErik Pilkington 
5508a57f2e0SRichard Smith   if (const Node *Ret =
5518a57f2e0SRichard Smith           static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
5522e97236aSLuís Ferreira     Ret->print(OB);
55367d82d6eSErik Pilkington 
5542e97236aSLuís Ferreira   OB += '\0';
55567d82d6eSErik Pilkington   if (N != nullptr)
5562e97236aSLuís Ferreira     *N = OB.getCurrentPosition();
5572e97236aSLuís Ferreira   return OB.getBuffer();
55867d82d6eSErik Pilkington }
55967d82d6eSErik Pilkington 
finishDemangle(char * Buf,size_t * N) const56067d82d6eSErik Pilkington char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
56167d82d6eSErik Pilkington   assert(RootNode != nullptr && "must call partialDemangle()");
56267d82d6eSErik Pilkington   return printNode(static_cast<Node *>(RootNode), Buf, N);
56367d82d6eSErik Pilkington }
56467d82d6eSErik Pilkington 
hasFunctionQualifiers() const56567d82d6eSErik Pilkington bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
56667d82d6eSErik Pilkington   assert(RootNode != nullptr && "must call partialDemangle()");
56767d82d6eSErik Pilkington   if (!isFunction())
56867d82d6eSErik Pilkington     return false;
5698a57f2e0SRichard Smith   auto *E = static_cast<const FunctionEncoding *>(RootNode);
57067d82d6eSErik Pilkington   return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone;
57167d82d6eSErik Pilkington }
57267d82d6eSErik Pilkington 
isCtorOrDtor() const57379420acbSFangrui Song bool ItaniumPartialDemangler::isCtorOrDtor() const {
5748a57f2e0SRichard Smith   const Node *N = static_cast<const Node *>(RootNode);
57579420acbSFangrui Song   while (N) {
57679420acbSFangrui Song     switch (N->getKind()) {
57779420acbSFangrui Song     default:
57879420acbSFangrui Song       return false;
57979420acbSFangrui Song     case Node::KCtorDtorName:
58079420acbSFangrui Song       return true;
58179420acbSFangrui Song 
58279420acbSFangrui Song     case Node::KAbiTagAttr:
5838a57f2e0SRichard Smith       N = static_cast<const AbiTagAttr *>(N)->Base;
58479420acbSFangrui Song       break;
58579420acbSFangrui Song     case Node::KFunctionEncoding:
5868a57f2e0SRichard Smith       N = static_cast<const FunctionEncoding *>(N)->getName();
58779420acbSFangrui Song       break;
58879420acbSFangrui Song     case Node::KLocalName:
5898a57f2e0SRichard Smith       N = static_cast<const LocalName *>(N)->Entity;
59079420acbSFangrui Song       break;
59179420acbSFangrui Song     case Node::KNameWithTemplateArgs:
5928a57f2e0SRichard Smith       N = static_cast<const NameWithTemplateArgs *>(N)->Name;
59379420acbSFangrui Song       break;
59479420acbSFangrui Song     case Node::KNestedName:
5958a57f2e0SRichard Smith       N = static_cast<const NestedName *>(N)->Name;
59679420acbSFangrui Song       break;
597c354167aSNathan Sidwell     case Node::KModuleEntity:
598c354167aSNathan Sidwell       N = static_cast<const ModuleEntity *>(N)->Name;
599c354167aSNathan Sidwell       break;
60079420acbSFangrui Song     }
60179420acbSFangrui Song   }
60279420acbSFangrui Song   return false;
60379420acbSFangrui Song }
60479420acbSFangrui Song 
isFunction() const60567d82d6eSErik Pilkington bool ItaniumPartialDemangler::isFunction() const {
60667d82d6eSErik Pilkington   assert(RootNode != nullptr && "must call partialDemangle()");
6078a57f2e0SRichard Smith   return static_cast<const Node *>(RootNode)->getKind() ==
6088a57f2e0SRichard Smith          Node::KFunctionEncoding;
60967d82d6eSErik Pilkington }
61067d82d6eSErik Pilkington 
isSpecialName() const61167d82d6eSErik Pilkington bool ItaniumPartialDemangler::isSpecialName() const {
61267d82d6eSErik Pilkington   assert(RootNode != nullptr && "must call partialDemangle()");
6138a57f2e0SRichard Smith   auto K = static_cast<const Node *>(RootNode)->getKind();
61467d82d6eSErik Pilkington   return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName;
61567d82d6eSErik Pilkington }
61667d82d6eSErik Pilkington 
isData() const61767d82d6eSErik Pilkington bool ItaniumPartialDemangler::isData() const {
61867d82d6eSErik Pilkington   return !isFunction() && !isSpecialName();
61967d82d6eSErik Pilkington }
620