xref: /llvm-project/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp (revision 38389f3109e8c862debdec769026f12cadc85e7b)
1 //===-- CPlusPlusLanguageTest.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 #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
9 #include "Plugins/Language/CPlusPlus/CPlusPlusNameParser.h"
10 #include "TestingSupport/SubsystemRAII.h"
11 #include "lldb/lldb-enumerations.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
14 
15 using namespace lldb_private;
16 
17 TEST(CPlusPlusLanguage, MethodNameParsing) {
18   struct TestCase {
19     std::string input;
20     std::string context, basename, arguments, qualifiers, scope_qualified_name;
21   };
22 
23   TestCase test_cases[] = {
24       {"main(int, char *[]) ", "", "main", "(int, char *[])", "", "main"},
25       {"foo::bar(baz) const", "foo", "bar", "(baz)", "const", "foo::bar"},
26       {"foo::~bar(baz)", "foo", "~bar", "(baz)", "", "foo::~bar"},
27       {"a::b::c::d(e,f)", "a::b::c", "d", "(e,f)", "", "a::b::c::d"},
28       {"void f(int)", "", "f", "(int)", "", "f"},
29 
30       // Operators
31       {"std::basic_ostream<char, std::char_traits<char> >& "
32        "std::operator<<<std::char_traits<char> >"
33        "(std::basic_ostream<char, std::char_traits<char> >&, char const*)",
34        "std", "operator<<<std::char_traits<char> >",
35        "(std::basic_ostream<char, std::char_traits<char> >&, char const*)", "",
36        "std::operator<<<std::char_traits<char> >"},
37       {"operator delete[](void*, clang::ASTContext const&, unsigned long)", "",
38        "operator delete[]", "(void*, clang::ASTContext const&, unsigned long)",
39        "", "operator delete[]"},
40       {"llvm::Optional<clang::PostInitializer>::operator bool() const",
41        "llvm::Optional<clang::PostInitializer>", "operator bool", "()", "const",
42        "llvm::Optional<clang::PostInitializer>::operator bool"},
43       {"(anonymous namespace)::FactManager::operator[](unsigned short)",
44        "(anonymous namespace)::FactManager", "operator[]", "(unsigned short)",
45        "", "(anonymous namespace)::FactManager::operator[]"},
46       {"const int& std::map<int, pair<short, int>>::operator[](short) const",
47        "std::map<int, pair<short, int>>", "operator[]", "(short)", "const",
48        "std::map<int, pair<short, int>>::operator[]"},
49       {"CompareInsn::operator()(llvm::StringRef, InsnMatchEntry const&)",
50        "CompareInsn", "operator()", "(llvm::StringRef, InsnMatchEntry const&)",
51        "", "CompareInsn::operator()"},
52       {"llvm::Optional<llvm::MCFixupKind>::operator*() const &",
53        "llvm::Optional<llvm::MCFixupKind>", "operator*", "()", "const &",
54        "llvm::Optional<llvm::MCFixupKind>::operator*"},
55       {"auto std::__1::ranges::__begin::__fn::operator()[abi:v160000]<char "
56        "const, 18ul>(char const (&) [18ul]) const",
57        "std::__1::ranges::__begin::__fn",
58        "operator()[abi:v160000]<char const, 18ul>", "(char const (&) [18ul])",
59        "const",
60        "std::__1::ranges::__begin::__fn::operator()[abi:v160000]<char const, "
61        "18ul>"},
62       // Internal classes
63       {"operator<<(Cls, Cls)::Subclass::function()",
64        "operator<<(Cls, Cls)::Subclass", "function", "()", "",
65        "operator<<(Cls, Cls)::Subclass::function"},
66       {"SAEC::checkFunction(context&) const::CallBack::CallBack(int)",
67        "SAEC::checkFunction(context&) const::CallBack", "CallBack", "(int)", "",
68        "SAEC::checkFunction(context&) const::CallBack::CallBack"},
69       // Anonymous namespace
70       {"XX::(anonymous namespace)::anon_class::anon_func() const",
71        "XX::(anonymous namespace)::anon_class", "anon_func", "()", "const",
72        "XX::(anonymous namespace)::anon_class::anon_func"},
73 
74       // Lambda
75       {"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()() "
76        "const",
77        "main::{lambda()#1}::operator()() const::{lambda()#1}", "operator()",
78        "()", "const",
79        "main::{lambda()#1}::operator()() const::{lambda()#1}::operator()"},
80 
81       // Function pointers
82       {"string (*f(vector<int>&&))(float)", "", "f", "(vector<int>&&)", "",
83        "f"},
84       {"void (*&std::_Any_data::_M_access<void (*)()>())()", "std::_Any_data",
85        "_M_access<void (*)()>", "()", "",
86        "std::_Any_data::_M_access<void (*)()>"},
87       {"void (*(*(*(*(*(*(*(* const&func1(int))())())())())())())())()", "",
88        "func1", "(int)", "", "func1"},
89 
90       // Decltype
91       {"decltype(nullptr)&& std::forward<decltype(nullptr)>"
92        "(std::remove_reference<decltype(nullptr)>::type&)",
93        "std", "forward<decltype(nullptr)>",
94        "(std::remove_reference<decltype(nullptr)>::type&)", "",
95        "std::forward<decltype(nullptr)>"},
96 
97       // Templates
98       {"void llvm::PM<llvm::Module, llvm::AM<llvm::Module>>::"
99        "addPass<llvm::VP>(llvm::VP)",
100        "llvm::PM<llvm::Module, llvm::AM<llvm::Module>>", "addPass<llvm::VP>",
101        "(llvm::VP)", "",
102        "llvm::PM<llvm::Module, llvm::AM<llvm::Module>>::"
103        "addPass<llvm::VP>"},
104       {"void std::vector<Class, std::allocator<Class> >"
105        "::_M_emplace_back_aux<Class const&>(Class const&)",
106        "std::vector<Class, std::allocator<Class> >",
107        "_M_emplace_back_aux<Class const&>", "(Class const&)", "",
108        "std::vector<Class, std::allocator<Class> >::"
109        "_M_emplace_back_aux<Class const&>"},
110       {"unsigned long llvm::countTrailingOnes<unsigned int>"
111        "(unsigned int, llvm::ZeroBehavior)",
112        "llvm", "countTrailingOnes<unsigned int>",
113        "(unsigned int, llvm::ZeroBehavior)", "",
114        "llvm::countTrailingOnes<unsigned int>"},
115       {"std::enable_if<(10u)<(64), bool>::type llvm::isUInt<10u>(unsigned "
116        "long)",
117        "llvm", "isUInt<10u>", "(unsigned long)", "", "llvm::isUInt<10u>"},
118       {"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>()", "",
119        "f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>", "()", "",
120        "f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>"},
121       {"llvm::Optional<llvm::MCFixupKind>::operator*() const volatile &&",
122        "llvm::Optional<llvm::MCFixupKind>", "operator*", "()",
123        "const volatile &&", "llvm::Optional<llvm::MCFixupKind>::operator*"},
124       {"void foo<Dummy<char [10]>>()", "", "foo<Dummy<char [10]>>", "()", "",
125        "foo<Dummy<char [10]>>"},
126       {"void foo<Bar<Bar<int>[10]>>()", "", "foo<Bar<Bar<int>[10]>>", "()", "",
127        "foo<Bar<Bar<int>[10]>>"},
128       {"void foo<Bar[10]>()", "", "foo<Bar[10]>", "()", "",
129        "foo<Bar[10]>"},
130       {"void foo<Bar[]>()", "", "foo<Bar[]>", "()", "",
131        "foo<Bar[]>"},
132 
133       // auto return type
134       {"auto std::test_return_auto<int>() const", "std",
135        "test_return_auto<int>", "()", "const", "std::test_return_auto<int>"},
136       {"decltype(auto) std::test_return_auto<int>(int) const", "std",
137        "test_return_auto<int>", "(int)", "const", "std::test_return_auto<int>"},
138 
139       // abi_tag on class method
140       {"v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>> "
141        "v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>"
142        "::method2<v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<"
143        "int>>>(int, v1::v2::Dummy<int>) const &&",
144        // Context
145        "v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>",
146        // Basename
147        "method2<v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<"
148        "int>>>",
149        // Args, qualifiers
150        "(int, v1::v2::Dummy<int>)", "const &&",
151        // Full scope-qualified name without args
152        "v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>"
153        "::method2<v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<"
154        "int>>>"},
155 
156       // abi_tag on free function and template argument
157       {"v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>> "
158        "v1::v2::with_tag_in_ns[abi:f1][abi:f2]<v1::v2::Dummy[abi:c1][abi:c2]"
159        "<v1::v2::Dummy[abi:c1][abi:c2]<int>>>(int, v1::v2::Dummy<int>) const "
160        "&&",
161        // Context
162        "v1::v2",
163        // Basename
164        "with_tag_in_ns[abi:f1][abi:f2]<v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::"
165        "Dummy[abi:c1][abi:c2]<int>>>",
166        // Args, qualifiers
167        "(int, v1::v2::Dummy<int>)", "const &&",
168        // Full scope-qualified name without args
169        "v1::v2::with_tag_in_ns[abi:f1][abi:f2]<v1::v2::Dummy[abi:c1][abi:c2]<"
170        "v1::v2::Dummy[abi:c1][abi:c2]<int>>>"},
171 
172       // abi_tag with special characters
173       {"auto ns::with_tag_in_ns[abi:special tag,0.0][abi:special "
174        "tag,1.0]<Dummy<int>>"
175        "(float) const &&",
176        // Context
177        "ns",
178        // Basename
179        "with_tag_in_ns[abi:special tag,0.0][abi:special tag,1.0]<Dummy<int>>",
180        // Args, qualifiers
181        "(float)", "const &&",
182        // Full scope-qualified name without args
183        "ns::with_tag_in_ns[abi:special tag,0.0][abi:special "
184        "tag,1.0]<Dummy<int>>"},
185 
186       // abi_tag on operator overloads
187       {"std::__1::error_code::operator bool[abi:v160000]() const",
188        "std::__1::error_code", "operator bool[abi:v160000]", "()", "const",
189        "std::__1::error_code::operator bool[abi:v160000]"},
190 
191       {"auto ns::foo::operator[][abi:v160000](size_t) const", "ns::foo",
192        "operator[][abi:v160000]", "(size_t)", "const",
193        "ns::foo::operator[][abi:v160000]"},
194 
195       {"auto Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>(int) &",
196        "Foo[abi:abc]<int>", "operator<<<Foo[abi:abc]<int>>", "(int)", "&",
197        "Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>"}};
198 
199   for (const auto &test : test_cases) {
200     CPlusPlusLanguage::MethodName method(ConstString(test.input));
201     EXPECT_TRUE(method.IsValid()) << test.input;
202     if (method.IsValid()) {
203       EXPECT_EQ(test.context, method.GetContext().str());
204       EXPECT_EQ(test.basename, method.GetBasename().str());
205       EXPECT_EQ(test.arguments, method.GetArguments().str());
206       EXPECT_EQ(test.qualifiers, method.GetQualifiers().str());
207       EXPECT_EQ(test.scope_qualified_name, method.GetScopeQualifiedName());
208     }
209   }
210 }
211 
212 TEST(CPlusPlusLanguage, InvalidMethodNameParsing) {
213   // Tests that we correctly reject malformed function names
214 
215   std::string test_cases[] = {
216       "int Foo::operator[]<[10>()",
217       "Foo::operator bool[10]()",
218       "auto A::operator<=>[abi:tag]<A::B>()",
219       "auto A::operator<<<(int)",
220       "auto A::operator>>>(int)",
221       "auto A::operator<<<Type[abi:tag]<>(int)",
222       "auto A::operator<<<Type[abi:tag]<Type<int>>(int)",
223       "auto A::foo[(int)",
224       "auto A::foo[](int)",
225       "auto A::foo[bar](int)",
226       "auto A::foo[abi](int)",
227       "auto A::foo[abi:(int)",
228   };
229 
230   for (const auto &name : test_cases) {
231     CPlusPlusLanguage::MethodName method{ConstString(name)};
232     EXPECT_FALSE(method.IsValid()) << name;
233   }
234 }
235 
236 TEST(CPlusPlusLanguage, ContainsPath) {
237   CPlusPlusLanguage::MethodName
238       reference_1(ConstString("int foo::bar::func01(int a, double b)"));
239   CPlusPlusLanguage::MethodName
240       reference_2(ConstString("int foofoo::bar::func01(std::string a, int b)"));
241   CPlusPlusLanguage::MethodName reference_3(ConstString("int func01()"));
242   CPlusPlusLanguage::MethodName
243       reference_4(ConstString("bar::baz::operator bool()"));
244   CPlusPlusLanguage::MethodName reference_5(
245       ConstString("bar::baz::operator bool<int, Type<double>>()"));
246   CPlusPlusLanguage::MethodName reference_6(ConstString(
247       "bar::baz::operator<<<Type<double>, Type<std::vector<double>>>()"));
248 
249   EXPECT_TRUE(reference_1.ContainsPath(""));
250   EXPECT_TRUE(reference_1.ContainsPath("func01"));
251   EXPECT_TRUE(reference_1.ContainsPath("bar::func01"));
252   EXPECT_TRUE(reference_1.ContainsPath("foo::bar::func01"));
253   EXPECT_FALSE(reference_1.ContainsPath("func"));
254   EXPECT_FALSE(reference_1.ContainsPath("baz::func01"));
255   EXPECT_FALSE(reference_1.ContainsPath("::bar::func01"));
256   EXPECT_FALSE(reference_1.ContainsPath("::foo::baz::func01"));
257   EXPECT_FALSE(reference_1.ContainsPath("foo::bar::baz::func01"));
258 
259   EXPECT_TRUE(reference_2.ContainsPath(""));
260   EXPECT_TRUE(reference_2.ContainsPath("foofoo::bar::func01"));
261   EXPECT_FALSE(reference_2.ContainsPath("foo::bar::func01"));
262 
263   EXPECT_TRUE(reference_3.ContainsPath(""));
264   EXPECT_TRUE(reference_3.ContainsPath("func01"));
265   EXPECT_FALSE(reference_3.ContainsPath("func"));
266   EXPECT_FALSE(reference_3.ContainsPath("bar::func01"));
267 
268   EXPECT_TRUE(reference_4.ContainsPath(""));
269   EXPECT_TRUE(reference_4.ContainsPath("operator"));
270   EXPECT_TRUE(reference_4.ContainsPath("operator bool"));
271   EXPECT_TRUE(reference_4.ContainsPath("baz::operator bool"));
272   EXPECT_TRUE(reference_4.ContainsPath("bar::baz::operator bool"));
273   EXPECT_FALSE(reference_4.ContainsPath("az::operator bool"));
274 
275   EXPECT_TRUE(reference_5.ContainsPath(""));
276   EXPECT_TRUE(reference_5.ContainsPath("operator"));
277   EXPECT_TRUE(reference_5.ContainsPath("operator bool"));
278   EXPECT_TRUE(reference_5.ContainsPath("operator bool<int, Type<double>>"));
279   EXPECT_FALSE(reference_5.ContainsPath("operator bool<int, double>"));
280   EXPECT_FALSE(reference_5.ContainsPath("operator bool<int, Type<int>>"));
281 
282   EXPECT_TRUE(reference_6.ContainsPath(""));
283   EXPECT_TRUE(reference_6.ContainsPath("operator"));
284   EXPECT_TRUE(reference_6.ContainsPath("operator<<"));
285   EXPECT_TRUE(reference_6.ContainsPath(
286       "bar::baz::operator<<<Type<double>, Type<std::vector<double>>>()"));
287   EXPECT_FALSE(reference_6.ContainsPath("operator<<<Type<double>>"));
288 }
289 
290 TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) {
291   struct TestCase {
292     std::string input;
293     std::string context, basename;
294   };
295 
296   TestCase test_cases[] = {
297       {"main", "", "main"},
298       {"main     ", "", "main"},
299       {"foo01::bar", "foo01", "bar"},
300       {"foo::~bar", "foo", "~bar"},
301       {"std::vector<int>::push_back", "std::vector<int>", "push_back"},
302       {"operator<<(Cls, Cls)::Subclass::function",
303        "operator<<(Cls, Cls)::Subclass", "function"},
304       {"std::vector<Class, std::allocator<Class>>"
305        "::_M_emplace_back_aux<Class const&>",
306        "std::vector<Class, std::allocator<Class>>",
307        "_M_emplace_back_aux<Class const&>"},
308       {"`anonymous namespace'::foo", "`anonymous namespace'", "foo"},
309       {"`operator<<A>'::`2'::B<0>::operator>", "`operator<<A>'::`2'::B<0>",
310        "operator>"},
311       {"`anonymous namespace'::S::<<::__l2::Foo",
312        "`anonymous namespace'::S::<<::__l2", "Foo"},
313       // These cases are idiosyncratic in how clang generates debug info for
314       // names when we have template parameters. They are not valid C++ names
315       // but if we fix this we need to support them for older compilers.
316       {"A::operator><A::B>", "A", "operator><A::B>"},
317       {"operator><A::B>", "", "operator><A::B>"},
318       {"A::operator<<A::B>", "A", "operator<<A::B>"},
319       {"operator<<A::B>", "", "operator<<A::B>"},
320       {"A::operator<<<A::B>", "A", "operator<<<A::B>"},
321       {"operator<<<A::B>", "", "operator<<<A::B>"},
322   };
323 
324   llvm::StringRef context, basename;
325   for (const auto &test : test_cases) {
326     EXPECT_TRUE(CPlusPlusLanguage::ExtractContextAndIdentifier(
327         test.input.c_str(), context, basename));
328     EXPECT_EQ(test.context, context.str());
329     EXPECT_EQ(test.basename, basename.str());
330   }
331 
332   EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier("void", context,
333                                                               basename));
334   EXPECT_FALSE(
335       CPlusPlusLanguage::ExtractContextAndIdentifier("321", context, basename));
336   EXPECT_FALSE(
337       CPlusPlusLanguage::ExtractContextAndIdentifier("", context, basename));
338   EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
339       "selector:", context, basename));
340   EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
341       "selector:otherField:", context, basename));
342   EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
343       "abc::", context, basename));
344   EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
345       "f<A<B><C>>", context, basename));
346 
347   // We expect these cases to fail until we turn on C++2a
348   EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
349       "A::operator<=><A::B>", context, basename));
350   EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
351       "operator<=><A::B>", context, basename));
352 }
353 
354 static std::vector<std::string> GenerateAlternate(llvm::StringRef Name) {
355   std::vector<std::string> Strings;
356   if (Language *CPlusPlusLang =
357           Language::FindPlugin(lldb::eLanguageTypeC_plus_plus)) {
358     std::vector<ConstString> Results =
359         CPlusPlusLang->GenerateAlternateFunctionManglings(ConstString(Name));
360     for (ConstString Str : Results)
361       Strings.push_back(std::string(Str.GetStringRef()));
362   }
363   return Strings;
364 }
365 
366 TEST(CPlusPlusLanguage, GenerateAlternateFunctionManglings) {
367   using namespace testing;
368 
369   SubsystemRAII<CPlusPlusLanguage> lang;
370 
371   EXPECT_THAT(GenerateAlternate("_ZN1A1fEv"),
372               UnorderedElementsAre("_ZNK1A1fEv", "_ZLN1A1fEv"));
373   EXPECT_THAT(GenerateAlternate("_ZN1A1fEa"), Contains("_ZN1A1fEc"));
374   EXPECT_THAT(GenerateAlternate("_ZN1A1fEx"), Contains("_ZN1A1fEl"));
375   EXPECT_THAT(GenerateAlternate("_ZN1A1fEy"), Contains("_ZN1A1fEm"));
376   EXPECT_THAT(GenerateAlternate("_ZN1A1fEai"), Contains("_ZN1A1fEci"));
377   EXPECT_THAT(GenerateAlternate("_ZN1AC1Ev"), Contains("_ZN1AC2Ev"));
378   EXPECT_THAT(GenerateAlternate("_ZN1AD1Ev"), Contains("_ZN1AD2Ev"));
379   EXPECT_THAT(GenerateAlternate("_bogus"), IsEmpty());
380 }
381 
382 TEST(CPlusPlusLanguage, CPlusPlusNameParser) {
383   // Don't crash.
384   CPlusPlusNameParser((const char *)nullptr);
385 }
386