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