1//===----------------------- PartialDemangleTest.cpp ----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include <cstdlib>
10#include "llvm/Demangle/Demangle.h"
11#include "gtest/gtest.h"
12
13struct ChoppedName {
14 const char *Mangled;
15 const char *ContextName, *BaseName, *ReturnType, *Params;
16};
17
18static ChoppedName NamesToTest[] = {
19 {.Mangled: "_Z1fv", .ContextName: "", .BaseName: "f", .ReturnType: "", .Params: "()"},
20 {.Mangled: "_ZN1a1b1cIiiiEEvm", .ContextName: "a::b", .BaseName: "c", .ReturnType: "void", .Params: "(unsigned long)"},
21 {.Mangled: "_ZZ5OuterIiEivEN5Inner12inner_memberEv",
22 .ContextName: "int Outer<int>()::Inner", .BaseName: "inner_member", .ReturnType: "", .Params: "()"},
23 {.Mangled: "_Z1fIiEPFvvEv", .ContextName: "", .BaseName: "f", .ReturnType: "void (*)()", .Params: "()"},
24 {.Mangled: "_ZN1S1fIiEEvv", .ContextName: "S", .BaseName: "f", .ReturnType: "void", .Params: "()"},
25
26 // Call operator for a lambda in f().
27 {.Mangled: "_ZZ1fvENK3$_0clEi", .ContextName: "f()::$_0", .BaseName: "operator()", .ReturnType: "", .Params: "(int)"},
28
29 // A call operator for a lambda in a lambda in f().
30 {.Mangled: "_ZZZ1fvENK3$_0clEvENKUlvE_clEv",
31 .ContextName: "f()::$_0::operator()() const::'lambda'()", .BaseName: "operator()", .ReturnType: "", .Params: "()"},
32
33 {.Mangled: "_ZZN1S1fEiiEd0_NKUlvE_clEv",
34 .ContextName: "S::f(int, int)::'lambda'()", .BaseName: "operator()", .ReturnType: "", .Params: "()"},
35
36 {.Mangled: "_ZN1Scv7MuncherIJDpPT_EEIJFivEA_iEEEv",
37 .ContextName: "S", .BaseName: "operator Muncher<int (*)(), int (*) []>", .ReturnType: "", .Params: "()"},
38
39 // Attributes.
40 {.Mangled: "_ZN5test4IdE1fEUa9enable_ifIXeqfL0p_Li1EEXeqfL0p0_Li2EEEi",
41 .ContextName: "test4<double>", .BaseName: "f", .ReturnType: "", .Params: "(int)"},
42 {.Mangled: "_ZN1SC2B8ctor_tagEv", .ContextName: "S", .BaseName: "S", .ReturnType: "", .Params: "()"},
43 {.Mangled: "_ZN1S1fB4MERPIiEEvv", .ContextName: "S", .BaseName: "f", .ReturnType: "void", .Params: "()"},
44
45 {.Mangled: "_ZNSsC1EmcRKSaIcE",
46 .ContextName: "std::basic_string<char, std::char_traits<char>, std::allocator<char>>",
47 .BaseName: "basic_string", .ReturnType: "", .Params: "(unsigned long, char, std::allocator<char> const&)"},
48 {.Mangled: "_ZNSsixEm", .ContextName: "std::string", .BaseName: "operator[]", .ReturnType: "", .Params: "(unsigned long)"},
49 {.Mangled: "_ZSt17__throw_bad_allocv", .ContextName: "std", .BaseName: "__throw_bad_alloc", .ReturnType: "", .Params: "()"},
50
51 {.Mangled: "_ZN1AI1BEC2Ev", .ContextName: "A<B>", .BaseName: "A", .ReturnType: "", .Params: "()"},
52 {.Mangled: "_ZN1AI1BED2Ev", .ContextName: "A<B>", .BaseName: "~A", .ReturnType: "", .Params: "()"},
53 {.Mangled: "_ZN1AI1BECI24BaseEi", .ContextName: "A<B>", .BaseName: "A", .ReturnType: "", .Params: "(int)"},
54 {.Mangled: "_ZNKR1AI1BE1fIiEEiv", .ContextName: "A<B>", .BaseName: "f", .ReturnType: "int", .Params: "()"},
55
56 {.Mangled: "_ZN1SIJicfEE3mfnIJjcdEEEvicfDpT_", .ContextName: "S<int, char, float>",
57 .BaseName: "mfn", .ReturnType: "void", .Params: "(int, char, float, unsigned int, char, double)"},
58};
59
60TEST(PartialDemanglerTest, TestNameChopping) {
61 size_t Size = 1;
62 char *Buf = static_cast<char *>(std::malloc(size: Size));
63
64 llvm::ItaniumPartialDemangler D;
65
66 for (ChoppedName &N : NamesToTest) {
67 EXPECT_FALSE(D.partialDemangle(N.Mangled));
68 EXPECT_TRUE(D.isFunction());
69 EXPECT_FALSE(D.isData());
70 EXPECT_FALSE(D.isSpecialName());
71
72 Buf = D.getFunctionDeclContextName(Buf, N: &Size);
73 EXPECT_STREQ(Buf, N.ContextName);
74
75 Buf = D.getFunctionBaseName(Buf, N: &Size);
76 EXPECT_STREQ(Buf, N.BaseName);
77
78 Buf = D.getFunctionReturnType(Buf, N: &Size);
79 EXPECT_STREQ(Buf, N.ReturnType);
80
81 Buf = D.getFunctionParameters(Buf, N: &Size);
82 EXPECT_STREQ(Buf, N.Params);
83 }
84
85 std::free(ptr: Buf);
86}
87
88TEST(PartialDemanglerTest, TestNameMeta) {
89 llvm::ItaniumPartialDemangler Demangler;
90
91 EXPECT_FALSE(Demangler.partialDemangle("_ZNK1f1gEv"));
92 EXPECT_TRUE(Demangler.isFunction());
93 EXPECT_TRUE(Demangler.hasFunctionQualifiers());
94 EXPECT_FALSE(Demangler.isSpecialName());
95 EXPECT_FALSE(Demangler.isData());
96
97 EXPECT_FALSE(Demangler.partialDemangle("_Z1fv"));
98 EXPECT_FALSE(Demangler.hasFunctionQualifiers());
99
100 EXPECT_FALSE(Demangler.partialDemangle("_ZTV1S"));
101 EXPECT_TRUE(Demangler.isSpecialName());
102 EXPECT_FALSE(Demangler.isData());
103 EXPECT_FALSE(Demangler.isFunction());
104
105 EXPECT_FALSE(Demangler.partialDemangle("_ZN1aDC1a1b1cEE"));
106 EXPECT_FALSE(Demangler.isFunction());
107 EXPECT_FALSE(Demangler.isSpecialName());
108 EXPECT_TRUE(Demangler.isData());
109}
110
111TEST(PartialDemanglerTest, TestCtorOrDtor) {
112 static const char *Pos[] = {
113 "_ZN1AC1Ev", // A::A()
114 "_ZN1AC1IiEET_", // A::A<int>(int)
115 "_ZN1AD2Ev", // A::~A()
116 "_ZN1BIiEC1IcEET_", // B<int>::B<char>(char)
117 "_ZN1AC1B1TEv", // A::A[abi:T]()
118 "_ZNSt1AD2Ev", // std::A::~A()
119 "_ZN2ns1AD1Ev", // ns::A::~A()
120 };
121 static const char *Neg[] = {
122 "_Z1fv",
123 "_ZN1A1gIiEEvT_", // void A::g<int>(int)
124 };
125
126 llvm::ItaniumPartialDemangler D;
127 for (const char *N : Pos) {
128 EXPECT_FALSE(D.partialDemangle(N));
129 EXPECT_TRUE(D.isCtorOrDtor());
130 }
131 for (const char *N : Neg) {
132 EXPECT_FALSE(D.partialDemangle(N));
133 EXPECT_FALSE(D.isCtorOrDtor());
134 }
135}
136
137TEST(PartialDemanglerTest, TestMisc) {
138 llvm::ItaniumPartialDemangler D1, D2;
139
140 EXPECT_FALSE(D1.partialDemangle("_Z1fv"));
141 EXPECT_FALSE(D2.partialDemangle("_Z1g"));
142 std::swap(a&: D1, b&: D2);
143 EXPECT_FALSE(D1.isFunction());
144 EXPECT_TRUE(D2.isFunction());
145
146 EXPECT_TRUE(D1.partialDemangle("Not a mangled name!"));
147}
148
149TEST(PartialDemanglerTest, TestPrintCases) {
150 llvm::ItaniumPartialDemangler D;
151
152 const size_t OriginalSize = 4;
153 char *Buf = static_cast<char *>(std::malloc(size: OriginalSize));
154 const char *OriginalBuf = Buf;
155
156 // Default success case: Result fits into the given buffer.
157 // Res points to Buf. N returns string size including null termination.
158 {
159 EXPECT_FALSE(D.partialDemangle("_ZN1a1bEv"));
160
161 size_t N = OriginalSize;
162 char *Res = D.getFunctionDeclContextName(Buf, N: &N);
163 EXPECT_STREQ("a", Res);
164 EXPECT_EQ(OriginalBuf, Res);
165 EXPECT_EQ(strlen(Res) + 1, N);
166 }
167
168 // Realloc success case: Result does not fit into the given buffer.
169 // Res points to the new or extended buffer. N returns string size
170 // including null termination. Buf was extended or freed.
171 {
172 EXPECT_FALSE(D.partialDemangle("_ZN1a1b1cIiiiEEvm"));
173
174 size_t N = OriginalSize;
175 char *Res = D.finishDemangle(Buf, N: &N);
176 EXPECT_STREQ("void a::b::c<int, int, int>(unsigned long)", Res);
177 EXPECT_EQ(strlen(Res) + 1, N);
178 Buf = Res;
179 }
180
181 // Failure case: a::c is not a function.
182 // Res is nullptr. N remains unchanged.
183 {
184 EXPECT_FALSE(D.partialDemangle("_ZN1a1cE"));
185
186 size_t N = OriginalSize;
187 char *Res = D.getFunctionName(Buf, N: &N);
188 EXPECT_EQ(nullptr, Res);
189 EXPECT_EQ(OriginalSize, N);
190 }
191
192 std::free(ptr: Buf);
193}
194

source code of llvm/unittests/Demangle/PartialDemangleTest.cpp