180814287SRaphael Isemann //===-- CPlusPlusLanguageTest.cpp -----------------------------------------===//
29361c439SPavel Labath //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69361c439SPavel Labath //
79361c439SPavel Labath //===----------------------------------------------------------------------===//
89361c439SPavel Labath #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
94a585a3eSAdrian Prantl #include "Plugins/Language/CPlusPlus/CPlusPlusNameParser.h"
10a65f6aafSAlex Langford #include "TestingSupport/SubsystemRAII.h"
11a65f6aafSAlex Langford #include "lldb/lldb-enumerations.h"
124865ff1eSPavel Labath #include "gmock/gmock.h"
134865ff1eSPavel Labath #include "gtest/gtest.h"
149361c439SPavel Labath
159361c439SPavel Labath using namespace lldb_private;
169361c439SPavel Labath
TEST(CPlusPlusLanguage,MethodNameParsing)17a633ee6eSEugene Zemtsov TEST(CPlusPlusLanguage, MethodNameParsing) {
189361c439SPavel Labath struct TestCase {
199361c439SPavel Labath std::string input;
209361c439SPavel Labath std::string context, basename, arguments, qualifiers, scope_qualified_name;
219361c439SPavel Labath };
229361c439SPavel Labath
23b9c1b51eSKate Stone TestCase test_cases[] = {
24a633ee6eSEugene Zemtsov {"main(int, char *[]) ", "", "main", "(int, char *[])", "", "main"},
25a633ee6eSEugene Zemtsov {"foo::bar(baz) const", "foo", "bar", "(baz)", "const", "foo::bar"},
26a633ee6eSEugene Zemtsov {"foo::~bar(baz)", "foo", "~bar", "(baz)", "", "foo::~bar"},
27a633ee6eSEugene Zemtsov {"a::b::c::d(e,f)", "a::b::c", "d", "(e,f)", "", "a::b::c::d"},
28a633ee6eSEugene Zemtsov {"void f(int)", "", "f", "(int)", "", "f"},
29a633ee6eSEugene Zemtsov
30a633ee6eSEugene Zemtsov // Operators
319361c439SPavel Labath {"std::basic_ostream<char, std::char_traits<char> >& "
329361c439SPavel Labath "std::operator<<<std::char_traits<char> >"
339361c439SPavel Labath "(std::basic_ostream<char, std::char_traits<char> >&, char const*)",
349361c439SPavel Labath "std", "operator<<<std::char_traits<char> >",
359361c439SPavel Labath "(std::basic_ostream<char, std::char_traits<char> >&, char const*)", "",
36a633ee6eSEugene Zemtsov "std::operator<<<std::char_traits<char> >"},
37a633ee6eSEugene Zemtsov {"operator delete[](void*, clang::ASTContext const&, unsigned long)", "",
38a633ee6eSEugene Zemtsov "operator delete[]", "(void*, clang::ASTContext const&, unsigned long)",
39a633ee6eSEugene Zemtsov "", "operator delete[]"},
40a633ee6eSEugene Zemtsov {"llvm::Optional<clang::PostInitializer>::operator bool() const",
41a633ee6eSEugene Zemtsov "llvm::Optional<clang::PostInitializer>", "operator bool", "()", "const",
42a633ee6eSEugene Zemtsov "llvm::Optional<clang::PostInitializer>::operator bool"},
43a633ee6eSEugene Zemtsov {"(anonymous namespace)::FactManager::operator[](unsigned short)",
44a633ee6eSEugene Zemtsov "(anonymous namespace)::FactManager", "operator[]", "(unsigned short)",
45a633ee6eSEugene Zemtsov "", "(anonymous namespace)::FactManager::operator[]"},
46a633ee6eSEugene Zemtsov {"const int& std::map<int, pair<short, int>>::operator[](short) const",
47a633ee6eSEugene Zemtsov "std::map<int, pair<short, int>>", "operator[]", "(short)", "const",
48a633ee6eSEugene Zemtsov "std::map<int, pair<short, int>>::operator[]"},
49a633ee6eSEugene Zemtsov {"CompareInsn::operator()(llvm::StringRef, InsnMatchEntry const&)",
50a633ee6eSEugene Zemtsov "CompareInsn", "operator()", "(llvm::StringRef, InsnMatchEntry const&)",
51a633ee6eSEugene Zemtsov "", "CompareInsn::operator()"},
52a633ee6eSEugene Zemtsov {"llvm::Optional<llvm::MCFixupKind>::operator*() const &",
53a633ee6eSEugene Zemtsov "llvm::Optional<llvm::MCFixupKind>", "operator*", "()", "const &",
54a633ee6eSEugene Zemtsov "llvm::Optional<llvm::MCFixupKind>::operator*"},
55a633ee6eSEugene Zemtsov // Internal classes
56a633ee6eSEugene Zemtsov {"operator<<(Cls, Cls)::Subclass::function()",
57a633ee6eSEugene Zemtsov "operator<<(Cls, Cls)::Subclass", "function", "()", "",
58a633ee6eSEugene Zemtsov "operator<<(Cls, Cls)::Subclass::function"},
59a633ee6eSEugene Zemtsov {"SAEC::checkFunction(context&) const::CallBack::CallBack(int)",
60a633ee6eSEugene Zemtsov "SAEC::checkFunction(context&) const::CallBack", "CallBack", "(int)", "",
61a633ee6eSEugene Zemtsov "SAEC::checkFunction(context&) const::CallBack::CallBack"},
62a633ee6eSEugene Zemtsov // Anonymous namespace
63a633ee6eSEugene Zemtsov {"XX::(anonymous namespace)::anon_class::anon_func() const",
64a633ee6eSEugene Zemtsov "XX::(anonymous namespace)::anon_class", "anon_func", "()", "const",
65a633ee6eSEugene Zemtsov "XX::(anonymous namespace)::anon_class::anon_func"},
66a633ee6eSEugene Zemtsov
67055e65f0SJim Ingham // Lambda
68055e65f0SJim Ingham {"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const",
69055e65f0SJim Ingham "main::{lambda()#1}::operator()() const::{lambda()#1}", "operator()", "()", "const",
70055e65f0SJim Ingham "main::{lambda()#1}::operator()() const::{lambda()#1}::operator()"},
71055e65f0SJim Ingham
72a633ee6eSEugene Zemtsov // Function pointers
73a633ee6eSEugene Zemtsov {"string (*f(vector<int>&&))(float)", "", "f", "(vector<int>&&)", "",
74a633ee6eSEugene Zemtsov "f"},
75a633ee6eSEugene Zemtsov {"void (*&std::_Any_data::_M_access<void (*)()>())()", "std::_Any_data",
76a633ee6eSEugene Zemtsov "_M_access<void (*)()>", "()", "",
77a633ee6eSEugene Zemtsov "std::_Any_data::_M_access<void (*)()>"},
78a633ee6eSEugene Zemtsov {"void (*(*(*(*(*(*(*(* const&func1(int))())())())())())())())()", "",
79a633ee6eSEugene Zemtsov "func1", "(int)", "", "func1"},
80a633ee6eSEugene Zemtsov
81a633ee6eSEugene Zemtsov // Decltype
82a633ee6eSEugene Zemtsov {"decltype(nullptr)&& std::forward<decltype(nullptr)>"
83a633ee6eSEugene Zemtsov "(std::remove_reference<decltype(nullptr)>::type&)",
84a633ee6eSEugene Zemtsov "std", "forward<decltype(nullptr)>",
85a633ee6eSEugene Zemtsov "(std::remove_reference<decltype(nullptr)>::type&)", "",
86a633ee6eSEugene Zemtsov "std::forward<decltype(nullptr)>"},
87a633ee6eSEugene Zemtsov
88a633ee6eSEugene Zemtsov // Templates
89a633ee6eSEugene Zemtsov {"void llvm::PM<llvm::Module, llvm::AM<llvm::Module>>::"
90a633ee6eSEugene Zemtsov "addPass<llvm::VP>(llvm::VP)",
91a633ee6eSEugene Zemtsov "llvm::PM<llvm::Module, llvm::AM<llvm::Module>>", "addPass<llvm::VP>",
92a633ee6eSEugene Zemtsov "(llvm::VP)", "",
93a633ee6eSEugene Zemtsov "llvm::PM<llvm::Module, llvm::AM<llvm::Module>>::"
94a633ee6eSEugene Zemtsov "addPass<llvm::VP>"},
95a633ee6eSEugene Zemtsov {"void std::vector<Class, std::allocator<Class> >"
96a633ee6eSEugene Zemtsov "::_M_emplace_back_aux<Class const&>(Class const&)",
97a633ee6eSEugene Zemtsov "std::vector<Class, std::allocator<Class> >",
98a633ee6eSEugene Zemtsov "_M_emplace_back_aux<Class const&>", "(Class const&)", "",
99a633ee6eSEugene Zemtsov "std::vector<Class, std::allocator<Class> >::"
100a633ee6eSEugene Zemtsov "_M_emplace_back_aux<Class const&>"},
101a633ee6eSEugene Zemtsov {"unsigned long llvm::countTrailingOnes<unsigned int>"
102a633ee6eSEugene Zemtsov "(unsigned int, llvm::ZeroBehavior)",
103a633ee6eSEugene Zemtsov "llvm", "countTrailingOnes<unsigned int>",
104a633ee6eSEugene Zemtsov "(unsigned int, llvm::ZeroBehavior)", "",
105a633ee6eSEugene Zemtsov "llvm::countTrailingOnes<unsigned int>"},
106a633ee6eSEugene Zemtsov {"std::enable_if<(10u)<(64), bool>::type llvm::isUInt<10u>(unsigned "
107a633ee6eSEugene Zemtsov "long)",
108a633ee6eSEugene Zemtsov "llvm", "isUInt<10u>", "(unsigned long)", "", "llvm::isUInt<10u>"},
109a633ee6eSEugene Zemtsov {"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>()", "",
110a633ee6eSEugene Zemtsov "f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>", "()", "",
111a633ee6eSEugene Zemtsov "f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>"}};
1129361c439SPavel Labath
113b9c1b51eSKate Stone for (const auto &test : test_cases) {
1149361c439SPavel Labath CPlusPlusLanguage::MethodName method(ConstString(test.input));
115a633ee6eSEugene Zemtsov EXPECT_TRUE(method.IsValid()) << test.input;
116a633ee6eSEugene Zemtsov if (method.IsValid()) {
117a633ee6eSEugene Zemtsov EXPECT_EQ(test.context, method.GetContext().str());
118a633ee6eSEugene Zemtsov EXPECT_EQ(test.basename, method.GetBasename().str());
119a633ee6eSEugene Zemtsov EXPECT_EQ(test.arguments, method.GetArguments().str());
120a633ee6eSEugene Zemtsov EXPECT_EQ(test.qualifiers, method.GetQualifiers().str());
1219361c439SPavel Labath EXPECT_EQ(test.scope_qualified_name, method.GetScopeQualifiedName());
1229361c439SPavel Labath }
1239361c439SPavel Labath }
124a633ee6eSEugene Zemtsov }
125a633ee6eSEugene Zemtsov
TEST(CPlusPlusLanguage,ContainsPath)126*3339000eSJim Ingham TEST(CPlusPlusLanguage, ContainsPath) {
127*3339000eSJim Ingham CPlusPlusLanguage::MethodName
128*3339000eSJim Ingham reference_1(ConstString("int foo::bar::func01(int a, double b)"));
129*3339000eSJim Ingham CPlusPlusLanguage::MethodName
130*3339000eSJim Ingham reference_2(ConstString("int foofoo::bar::func01(std::string a, int b)"));
131*3339000eSJim Ingham CPlusPlusLanguage::MethodName reference_3(ConstString("int func01()"));
132*3339000eSJim Ingham CPlusPlusLanguage::MethodName
133*3339000eSJim Ingham reference_4(ConstString("bar::baz::operator bool()"));
134*3339000eSJim Ingham
135*3339000eSJim Ingham EXPECT_TRUE(reference_1.ContainsPath("func01"));
136*3339000eSJim Ingham EXPECT_TRUE(reference_1.ContainsPath("bar::func01"));
137*3339000eSJim Ingham EXPECT_TRUE(reference_1.ContainsPath("foo::bar::func01"));
138*3339000eSJim Ingham EXPECT_FALSE(reference_1.ContainsPath("func"));
139*3339000eSJim Ingham EXPECT_FALSE(reference_1.ContainsPath("baz::func01"));
140*3339000eSJim Ingham EXPECT_FALSE(reference_1.ContainsPath("::bar::func01"));
141*3339000eSJim Ingham EXPECT_FALSE(reference_1.ContainsPath("::foo::baz::func01"));
142*3339000eSJim Ingham EXPECT_FALSE(reference_1.ContainsPath("foo::bar::baz::func01"));
143*3339000eSJim Ingham
144*3339000eSJim Ingham EXPECT_TRUE(reference_2.ContainsPath("foofoo::bar::func01"));
145*3339000eSJim Ingham EXPECT_FALSE(reference_2.ContainsPath("foo::bar::func01"));
146*3339000eSJim Ingham
147*3339000eSJim Ingham EXPECT_TRUE(reference_3.ContainsPath("func01"));
148*3339000eSJim Ingham EXPECT_FALSE(reference_3.ContainsPath("func"));
149*3339000eSJim Ingham EXPECT_FALSE(reference_3.ContainsPath("bar::func01"));
150*3339000eSJim Ingham
151*3339000eSJim Ingham EXPECT_TRUE(reference_4.ContainsPath("operator bool"));
152*3339000eSJim Ingham EXPECT_TRUE(reference_4.ContainsPath("baz::operator bool"));
153*3339000eSJim Ingham EXPECT_TRUE(reference_4.ContainsPath("bar::baz::operator bool"));
154*3339000eSJim Ingham EXPECT_FALSE(reference_4.ContainsPath("az::operator bool"));
155*3339000eSJim Ingham }
156*3339000eSJim Ingham
TEST(CPlusPlusLanguage,ExtractContextAndIdentifier)157a633ee6eSEugene Zemtsov TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) {
158a633ee6eSEugene Zemtsov struct TestCase {
159a633ee6eSEugene Zemtsov std::string input;
160a633ee6eSEugene Zemtsov std::string context, basename;
161a633ee6eSEugene Zemtsov };
162a633ee6eSEugene Zemtsov
163a633ee6eSEugene Zemtsov TestCase test_cases[] = {
164a633ee6eSEugene Zemtsov {"main", "", "main"},
16557537102SEugene Zemtsov {"main ", "", "main"},
166a633ee6eSEugene Zemtsov {"foo01::bar", "foo01", "bar"},
167a633ee6eSEugene Zemtsov {"foo::~bar", "foo", "~bar"},
168a633ee6eSEugene Zemtsov {"std::vector<int>::push_back", "std::vector<int>", "push_back"},
169a633ee6eSEugene Zemtsov {"operator<<(Cls, Cls)::Subclass::function",
170a633ee6eSEugene Zemtsov "operator<<(Cls, Cls)::Subclass", "function"},
171a633ee6eSEugene Zemtsov {"std::vector<Class, std::allocator<Class>>"
172a633ee6eSEugene Zemtsov "::_M_emplace_back_aux<Class const&>",
173a633ee6eSEugene Zemtsov "std::vector<Class, std::allocator<Class>>",
174c1e530eeSAleksandr Urakov "_M_emplace_back_aux<Class const&>"},
175c1e530eeSAleksandr Urakov {"`anonymous namespace'::foo", "`anonymous namespace'", "foo"},
1768016d61eSshafik {"`operator<<A>'::`2'::B<0>::operator>", "`operator<<A>'::`2'::B<0>",
177c1e530eeSAleksandr Urakov "operator>"},
178c1e530eeSAleksandr Urakov {"`anonymous namespace'::S::<<::__l2::Foo",
1798016d61eSshafik "`anonymous namespace'::S::<<::__l2", "Foo"},
1808016d61eSshafik // These cases are idiosyncratic in how clang generates debug info for
1818016d61eSshafik // names when we have template parameters. They are not valid C++ names
1828016d61eSshafik // but if we fix this we need to support them for older compilers.
1838016d61eSshafik {"A::operator><A::B>", "A", "operator><A::B>"},
1848016d61eSshafik {"operator><A::B>", "", "operator><A::B>"},
1858016d61eSshafik {"A::operator<<A::B>", "A", "operator<<A::B>"},
1868016d61eSshafik {"operator<<A::B>", "", "operator<<A::B>"},
1878016d61eSshafik {"A::operator<<<A::B>", "A", "operator<<<A::B>"},
1888016d61eSshafik {"operator<<<A::B>", "", "operator<<<A::B>"},
1898016d61eSshafik };
190a633ee6eSEugene Zemtsov
191a633ee6eSEugene Zemtsov llvm::StringRef context, basename;
192a633ee6eSEugene Zemtsov for (const auto &test : test_cases) {
193a633ee6eSEugene Zemtsov EXPECT_TRUE(CPlusPlusLanguage::ExtractContextAndIdentifier(
194a633ee6eSEugene Zemtsov test.input.c_str(), context, basename));
195a633ee6eSEugene Zemtsov EXPECT_EQ(test.context, context.str());
196a633ee6eSEugene Zemtsov EXPECT_EQ(test.basename, basename.str());
197a633ee6eSEugene Zemtsov }
198a633ee6eSEugene Zemtsov
199a633ee6eSEugene Zemtsov EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier("void", context,
200a633ee6eSEugene Zemtsov basename));
201a633ee6eSEugene Zemtsov EXPECT_FALSE(
202a633ee6eSEugene Zemtsov CPlusPlusLanguage::ExtractContextAndIdentifier("321", context, basename));
203a633ee6eSEugene Zemtsov EXPECT_FALSE(
204a633ee6eSEugene Zemtsov CPlusPlusLanguage::ExtractContextAndIdentifier("", context, basename));
205a633ee6eSEugene Zemtsov EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
206a633ee6eSEugene Zemtsov "selector:", context, basename));
20757537102SEugene Zemtsov EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
20857537102SEugene Zemtsov "selector:otherField:", context, basename));
20957537102SEugene Zemtsov EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
21057537102SEugene Zemtsov "abc::", context, basename));
2119e916e5eSEugene Zemtsov EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
2129e916e5eSEugene Zemtsov "f<A<B><C>>", context, basename));
2138016d61eSshafik
2148016d61eSshafik // We expect these cases to fail until we turn on C++2a
2158016d61eSshafik EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
2168016d61eSshafik "A::operator<=><A::B>", context, basename));
2178016d61eSshafik EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
2188016d61eSshafik "operator<=><A::B>", context, basename));
219a633ee6eSEugene Zemtsov }
2204865ff1eSPavel Labath
GenerateAlternate(llvm::StringRef Name)221a65f6aafSAlex Langford static std::vector<std::string> GenerateAlternate(llvm::StringRef Name) {
222a65f6aafSAlex Langford std::vector<std::string> Strings;
223a65f6aafSAlex Langford if (Language *CPlusPlusLang =
224a65f6aafSAlex Langford Language::FindPlugin(lldb::eLanguageTypeC_plus_plus)) {
225a65f6aafSAlex Langford std::vector<ConstString> Results =
226a65f6aafSAlex Langford CPlusPlusLang->GenerateAlternateFunctionManglings(ConstString(Name));
2274865ff1eSPavel Labath for (ConstString Str : Results)
228a65f6aafSAlex Langford Strings.push_back(std::string(Str.GetStringRef()));
229a65f6aafSAlex Langford }
2304865ff1eSPavel Labath return Strings;
2314865ff1eSPavel Labath }
2324865ff1eSPavel Labath
TEST(CPlusPlusLanguage,GenerateAlternateFunctionManglings)233a65f6aafSAlex Langford TEST(CPlusPlusLanguage, GenerateAlternateFunctionManglings) {
2344865ff1eSPavel Labath using namespace testing;
2354865ff1eSPavel Labath
236a65f6aafSAlex Langford SubsystemRAII<CPlusPlusLanguage> lang;
237a65f6aafSAlex Langford
238a65f6aafSAlex Langford EXPECT_THAT(GenerateAlternate("_ZN1A1fEv"),
2394865ff1eSPavel Labath UnorderedElementsAre("_ZNK1A1fEv", "_ZLN1A1fEv"));
240a65f6aafSAlex Langford EXPECT_THAT(GenerateAlternate("_ZN1A1fEa"), Contains("_ZN1A1fEc"));
241a65f6aafSAlex Langford EXPECT_THAT(GenerateAlternate("_ZN1A1fEx"), Contains("_ZN1A1fEl"));
242a65f6aafSAlex Langford EXPECT_THAT(GenerateAlternate("_ZN1A1fEy"), Contains("_ZN1A1fEm"));
243a65f6aafSAlex Langford EXPECT_THAT(GenerateAlternate("_ZN1A1fEai"), Contains("_ZN1A1fEci"));
244a65f6aafSAlex Langford EXPECT_THAT(GenerateAlternate("_ZN1AC1Ev"), Contains("_ZN1AC2Ev"));
245a65f6aafSAlex Langford EXPECT_THAT(GenerateAlternate("_ZN1AD1Ev"), Contains("_ZN1AD2Ev"));
246a65f6aafSAlex Langford EXPECT_THAT(GenerateAlternate("_bogus"), IsEmpty());
2474865ff1eSPavel Labath }
2484a585a3eSAdrian Prantl
TEST(CPlusPlusLanguage,CPlusPlusNameParser)2494a585a3eSAdrian Prantl TEST(CPlusPlusLanguage, CPlusPlusNameParser) {
2504a585a3eSAdrian Prantl // Don't crash.
2514a585a3eSAdrian Prantl CPlusPlusNameParser((const char *)nullptr);
2524a585a3eSAdrian Prantl }
253