611 lines · cpp
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-exception6//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 "llvm/Support/Error.h"13#include "llvm/Testing/Support/Error.h"14#include "gmock/gmock.h"15#include "gtest/gtest.h"16#include <optional>17 18using namespace lldb_private;19 20TEST(CPlusPlusLanguage, MethodNameParsing) {21 struct TestCase {22 std::string input;23 std::string return_type, context, basename, arguments, qualifiers,24 scope_qualified_name;25 };26 27 TestCase test_cases[] = {28 {"main(int, char *[]) ", "", "", "main", "(int, char *[])", "", "main"},29 {"foo::bar(baz) const", "", "foo", "bar", "(baz)", "const", "foo::bar"},30 {"foo::~bar(baz)", "", "foo", "~bar", "(baz)", "", "foo::~bar"},31 {"a::b::c::d(e,f)", "", "a::b::c", "d", "(e,f)", "", "a::b::c::d"},32 {"void f(int)", "void", "", "f", "(int)", "", "f"},33 {"std::vector<int>foo::bar()", "std::vector<int>", "foo", "bar", "()", "",34 "foo::bar"},35 {"int foo::bar::func01(int a, double b)", "int", "foo::bar", "func01",36 "(int a, double b)", "", "foo::bar::func01"},37 38 // Operators39 {"std::basic_ostream<char, std::char_traits<char> >& "40 "std::operator<<<std::char_traits<char> >(std::basic_ostream<char, "41 "std::char_traits<char> >&, char const*)",42 "std::basic_ostream<char, std::char_traits<char> >&", "std",43 "operator<<<std::char_traits<char> >",44 "(std::basic_ostream<char, std::char_traits<char> >&, char const*)", "",45 "std::operator<<<std::char_traits<char> >"},46 {"operator delete[](void*, clang::ASTContext const&, unsigned long)", "",47 "", "operator delete[]",48 "(void*, clang::ASTContext const&, unsigned long)", "",49 "operator delete[]"},50 {"std::optional<clang::PostInitializer>::operator bool() const", "",51 "std::optional<clang::PostInitializer>", "operator bool", "()", "const",52 "std::optional<clang::PostInitializer>::operator bool"},53 {"(anonymous namespace)::FactManager::operator[](unsigned short)", "",54 "(anonymous namespace)::FactManager", "operator[]", "(unsigned short)",55 "", "(anonymous namespace)::FactManager::operator[]"},56 {"const int& std::map<int, pair<short, int>>::operator[](short) const",57 "const int&", "std::map<int, pair<short, int>>", "operator[]", "(short)",58 "const", "std::map<int, pair<short, int>>::operator[]"},59 {"CompareInsn::operator()(llvm::StringRef, InsnMatchEntry const&)", "",60 "CompareInsn", "operator()", "(llvm::StringRef, InsnMatchEntry const&)",61 "", "CompareInsn::operator()"},62 {"std::optional<llvm::MCFixupKind>::operator*() const &", "",63 "std::optional<llvm::MCFixupKind>", "operator*", "()", "const &",64 "std::optional<llvm::MCFixupKind>::operator*"},65 {"auto std::__1::ranges::__begin::__fn::operator()[abi:v160000]<char "66 "const, 18ul>(char const (&) [18ul]) const",67 "auto", "std::__1::ranges::__begin::__fn",68 "operator()[abi:v160000]<char const, 18ul>", "(char const (&) [18ul])",69 "const",70 "std::__1::ranges::__begin::__fn::operator()[abi:v160000]<char const, "71 "18ul>"},72 // Internal classes73 {"operator<<(Cls, Cls)::Subclass::function()", "",74 "operator<<(Cls, Cls)::Subclass", "function", "()", "",75 "operator<<(Cls, Cls)::Subclass::function"},76 {"SAEC::checkFunction(context&) const::CallBack::CallBack(int)", "",77 "SAEC::checkFunction(context&) const::CallBack", "CallBack", "(int)", "",78 "SAEC::checkFunction(context&) const::CallBack::CallBack"},79 // Anonymous namespace80 {"XX::(anonymous namespace)::anon_class::anon_func() const", "",81 "XX::(anonymous namespace)::anon_class", "anon_func", "()", "const",82 "XX::(anonymous namespace)::anon_class::anon_func"},83 84 // Lambda85 {"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()() "86 "const",87 "", "main::{lambda()#1}::operator()() const::{lambda()#1}", "operator()",88 "()", "const",89 "main::{lambda()#1}::operator()() const::{lambda()#1}::operator()"},90 91 // Function pointers92 {"string (*f(vector<int>&&))(float)", "", "", "f", "(vector<int>&&)", "",93 "f"},94 {"void (*&std::_Any_data::_M_access<void (*)()>())()", "",95 "std::_Any_data", "_M_access<void (*)()>", "()", "",96 "std::_Any_data::_M_access<void (*)()>"},97 {"void (*(*(*(*(*(*(*(* const&func1(int))())())())())())())())()", "", "",98 "func1", "(int)", "", "func1"},99 100 // Decltype101 {"decltype(nullptr)&& std::forward<decltype(nullptr)>"102 "(std::remove_reference<decltype(nullptr)>::type&)",103 "decltype(nullptr)&&", "std", "forward<decltype(nullptr)>",104 "(std::remove_reference<decltype(nullptr)>::type&)", "",105 "std::forward<decltype(nullptr)>"},106 107 // Templates108 {"vector<int > foo::bar::func(int)", "vector<int >", "foo::bar", "func",109 "(int)", "", "foo::bar::func"},110 {"void llvm::PM<llvm::Module, llvm::AM<llvm::Module>>::"111 "addPass<llvm::VP>(llvm::VP)",112 "void", "llvm::PM<llvm::Module, llvm::AM<llvm::Module>>",113 "addPass<llvm::VP>", "(llvm::VP)", "",114 "llvm::PM<llvm::Module, llvm::AM<llvm::Module>>::"115 "addPass<llvm::VP>"},116 {"void std::vector<Class, std::allocator<Class> >"117 "::_M_emplace_back_aux<Class const&>(Class const&)",118 "void", "std::vector<Class, std::allocator<Class> >",119 "_M_emplace_back_aux<Class const&>", "(Class const&)", "",120 "std::vector<Class, std::allocator<Class> >::"121 "_M_emplace_back_aux<Class const&>"},122 {"unsigned long llvm::countTrailingOnes<unsigned int>"123 "(unsigned int, llvm::ZeroBehavior)",124 "unsigned long", "llvm", "countTrailingOnes<unsigned int>",125 "(unsigned int, llvm::ZeroBehavior)", "",126 "llvm::countTrailingOnes<unsigned int>"},127 {"std::enable_if<(10u)<(64), bool>::type llvm::isUInt<10u>(unsigned "128 "long)",129 "std::enable_if<(10u)<(64), bool>::type", "llvm", "isUInt<10u>",130 "(unsigned long)", "", "llvm::isUInt<10u>"},131 {"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>()", "", "",132 "f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>", "()", "",133 "f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>"},134 {"std::optional<llvm::MCFixupKind>::operator*() const volatile &&", "",135 "std::optional<llvm::MCFixupKind>", "operator*", "()",136 "const volatile &&", "std::optional<llvm::MCFixupKind>::operator*"},137 {"void foo<Dummy<char [10]>>()", "void", "", "foo<Dummy<char [10]>>",138 "()", "", "foo<Dummy<char [10]>>"},139 {"void foo<Bar<Bar<int>[10]>>()", "void", "", "foo<Bar<Bar<int>[10]>>",140 "()", "", "foo<Bar<Bar<int>[10]>>"},141 {"void foo<Bar[10]>()", "void", "", "foo<Bar[10]>", "()", "",142 "foo<Bar[10]>"},143 {"void foo<Bar[]>()", "void", "", "foo<Bar[]>", "()", "", "foo<Bar[]>"},144 145 // auto return type146 {"auto std::test_return_auto<int>() const", "auto", "std",147 "test_return_auto<int>", "()", "const", "std::test_return_auto<int>"},148 {"decltype(auto) std::test_return_auto<int>(int) const", "decltype(auto)",149 "std", "test_return_auto<int>", "(int)", "const",150 "std::test_return_auto<int>"},151 152 // abi_tag on class method153 {"v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>> "154 "v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>"155 "::method2<v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<"156 "int>>>(int, v1::v2::Dummy<int>) const &&",157 // Return type158 "v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>",159 // Context160 "v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>",161 // Basename162 "method2<v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<"163 "int>>>",164 // Args, qualifiers165 "(int, v1::v2::Dummy<int>)", "const &&",166 // Full scope-qualified name without args167 "v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>"168 "::method2<v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<"169 "int>>>"},170 171 // abi_tag on free function and template argument172 {"v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>> "173 "v1::v2::with_tag_in_ns[abi:f1][abi:f2]<v1::v2::Dummy[abi:c1][abi:c2]"174 "<v1::v2::Dummy[abi:c1][abi:c2]<int>>>(int, v1::v2::Dummy<int>) const "175 "&&",176 // Return type177 "v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::Dummy[abi:c1][abi:c2]<int>>",178 // Context179 "v1::v2",180 // Basename181 "with_tag_in_ns[abi:f1][abi:f2]<v1::v2::Dummy[abi:c1][abi:c2]<v1::v2::"182 "Dummy[abi:c1][abi:c2]<int>>>",183 // Args, qualifiers184 "(int, v1::v2::Dummy<int>)", "const &&",185 // Full scope-qualified name without args186 "v1::v2::with_tag_in_ns[abi:f1][abi:f2]<v1::v2::Dummy[abi:c1][abi:c2]<"187 "v1::v2::Dummy[abi:c1][abi:c2]<int>>>"},188 189 // abi_tag with special characters190 {"auto ns::with_tag_in_ns[abi:special tag,0.0][abi:special "191 "tag,1.0]<Dummy<int>>"192 "(float) const &&",193 // Return type194 "auto",195 // Context196 "ns",197 // Basename198 "with_tag_in_ns[abi:special tag,0.0][abi:special tag,1.0]<Dummy<int>>",199 // Args, qualifiers200 "(float)", "const &&",201 // Full scope-qualified name without args202 "ns::with_tag_in_ns[abi:special tag,0.0][abi:special "203 "tag,1.0]<Dummy<int>>"},204 205 // abi_tag on operator overloads206 {"std::__1::error_code::operator bool[abi:v160000]() const", "",207 "std::__1::error_code", "operator bool[abi:v160000]", "()", "const",208 "std::__1::error_code::operator bool[abi:v160000]"},209 210 {"auto ns::foo::operator[][abi:v160000](size_t) const", "auto", "ns::foo",211 "operator[][abi:v160000]", "(size_t)", "const",212 "ns::foo::operator[][abi:v160000]"},213 214 {"auto Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>(int) &", "auto",215 "Foo[abi:abc]<int>", "operator<<<Foo[abi:abc]<int>>", "(int)", "&",216 "Foo[abi:abc]<int>::operator<<<Foo[abi:abc]<int>>"},217 218 {"auto A::operator<=>[abi:tag]<A::B>()", "auto", "A",219 "operator<=>[abi:tag]<A::B>", "()", "",220 "A::operator<=>[abi:tag]<A::B>"}};221 222 for (const auto &test : test_cases) {223 CPlusPlusLanguage::CxxMethodName method(ConstString(test.input));224 EXPECT_TRUE(method.IsValid()) << test.input;225 if (method.IsValid()) {226 EXPECT_EQ(test.return_type, method.GetReturnType().str());227 EXPECT_EQ(test.context, method.GetContext().str());228 EXPECT_EQ(test.basename, method.GetBasename().str());229 EXPECT_EQ(test.arguments, method.GetArguments().str());230 EXPECT_EQ(test.qualifiers, method.GetQualifiers().str());231 EXPECT_EQ(test.scope_qualified_name, method.GetScopeQualifiedName());232 }233 }234}235 236TEST(CPlusPlusLanguage, InvalidMethodNameParsing) {237 // Tests that we correctly reject malformed function names238 239 std::string test_cases[] = {240 "int Foo::operator[]<[10>()",241 "Foo::operator bool[10]()",242 "auto A::operator<<<(int)",243 "auto A::operator>>>(int)",244 "auto A::operator<<<Type[abi:tag]<>(int)",245 "auto A::operator<<<Type[abi:tag]<Type<int>>(int)",246 "auto A::foo[(int)",247 "auto A::foo[](int)",248 "auto A::foo[bar](int)",249 "auto A::foo[abi](int)",250 "auto A::foo[abi:(int)",251 };252 253 for (const auto &name : test_cases) {254 CPlusPlusLanguage::CxxMethodName method{ConstString(name)};255 EXPECT_FALSE(method.IsValid()) << name;256 }257}258 259TEST(CPlusPlusLanguage, ContainsPath) {260 CPlusPlusLanguage::CxxMethodName reference_1(261 ConstString("int foo::bar::func01(int a, double b)"));262 CPlusPlusLanguage::CxxMethodName reference_2(263 ConstString("int foofoo::bar::func01(std::string a, int b)"));264 CPlusPlusLanguage::CxxMethodName reference_3(ConstString("int func01()"));265 CPlusPlusLanguage::CxxMethodName reference_4(266 ConstString("bar::baz::operator bool()"));267 CPlusPlusLanguage::CxxMethodName reference_5(268 ConstString("bar::baz::operator bool<int, Type<double>>()"));269 CPlusPlusLanguage::CxxMethodName reference_6(ConstString(270 "bar::baz::operator<<<Type<double>, Type<std::vector<double>>>()"));271 272 EXPECT_TRUE(reference_1.ContainsPath(""));273 EXPECT_TRUE(reference_1.ContainsPath("func01"));274 EXPECT_TRUE(reference_1.ContainsPath("bar::func01"));275 EXPECT_TRUE(reference_1.ContainsPath("foo::bar::func01"));276 EXPECT_FALSE(reference_1.ContainsPath("func"));277 EXPECT_FALSE(reference_1.ContainsPath("baz::func01"));278 EXPECT_FALSE(reference_1.ContainsPath("::bar::func01"));279 EXPECT_FALSE(reference_1.ContainsPath("::foo::baz::func01"));280 EXPECT_FALSE(reference_1.ContainsPath("foo::bar::baz::func01"));281 282 EXPECT_TRUE(reference_2.ContainsPath(""));283 EXPECT_TRUE(reference_2.ContainsPath("foofoo::bar::func01"));284 EXPECT_FALSE(reference_2.ContainsPath("foo::bar::func01"));285 286 EXPECT_TRUE(reference_3.ContainsPath(""));287 EXPECT_TRUE(reference_3.ContainsPath("func01"));288 EXPECT_FALSE(reference_3.ContainsPath("func"));289 EXPECT_FALSE(reference_3.ContainsPath("bar::func01"));290 291 EXPECT_TRUE(reference_4.ContainsPath(""));292 EXPECT_TRUE(reference_4.ContainsPath("operator"));293 EXPECT_TRUE(reference_4.ContainsPath("operator bool"));294 EXPECT_TRUE(reference_4.ContainsPath("baz::operator bool"));295 EXPECT_TRUE(reference_4.ContainsPath("bar::baz::operator bool"));296 EXPECT_FALSE(reference_4.ContainsPath("az::operator bool"));297 298 EXPECT_TRUE(reference_5.ContainsPath(""));299 EXPECT_TRUE(reference_5.ContainsPath("operator"));300 EXPECT_TRUE(reference_5.ContainsPath("operator bool"));301 EXPECT_TRUE(reference_5.ContainsPath("operator bool<int, Type<double>>"));302 EXPECT_FALSE(reference_5.ContainsPath("operator bool<int, double>"));303 EXPECT_FALSE(reference_5.ContainsPath("operator bool<int, Type<int>>"));304 305 EXPECT_TRUE(reference_6.ContainsPath(""));306 EXPECT_TRUE(reference_6.ContainsPath("operator"));307 EXPECT_TRUE(reference_6.ContainsPath("operator<<"));308 EXPECT_TRUE(reference_6.ContainsPath(309 "bar::baz::operator<<<Type<double>, Type<std::vector<double>>>()"));310 EXPECT_FALSE(reference_6.ContainsPath("operator<<<Type<double>>"));311}312 313TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) {314 struct TestCase {315 std::string input;316 std::string context, basename;317 };318 319 TestCase test_cases[] = {320 {"main", "", "main"},321 {"main ", "", "main"},322 {"foo01::bar", "foo01", "bar"},323 {"foo::~bar", "foo", "~bar"},324 {"std::vector<int>::push_back", "std::vector<int>", "push_back"},325 {"operator<<(Cls, Cls)::Subclass::function",326 "operator<<(Cls, Cls)::Subclass", "function"},327 {"std::vector<Class, std::allocator<Class>>"328 "::_M_emplace_back_aux<Class const&>",329 "std::vector<Class, std::allocator<Class>>",330 "_M_emplace_back_aux<Class const&>"},331 {"`anonymous namespace'::foo", "`anonymous namespace'", "foo"},332 {"`operator<<A>'::`2'::B<0>::operator>", "`operator<<A>'::`2'::B<0>",333 "operator>"},334 {"`anonymous namespace'::S::<<::__l2::Foo",335 "`anonymous namespace'::S::<<::__l2", "Foo"},336 // These cases are idiosyncratic in how clang generates debug info for337 // names when we have template parameters. They are not valid C++ names338 // but if we fix this we need to support them for older compilers.339 {"A::operator><A::B>", "A", "operator><A::B>"},340 {"operator><A::B>", "", "operator><A::B>"},341 {"A::operator<<A::B>", "A", "operator<<A::B>"},342 {"operator<<A::B>", "", "operator<<A::B>"},343 {"A::operator<<<A::B>", "A", "operator<<<A::B>"},344 {"operator<<<A::B>", "", "operator<<<A::B>"},345 };346 347 llvm::StringRef context, basename;348 for (const auto &test : test_cases) {349 EXPECT_TRUE(CPlusPlusLanguage::ExtractContextAndIdentifier(350 test.input, context, basename));351 EXPECT_EQ(test.context, context.str());352 EXPECT_EQ(test.basename, basename.str());353 }354 355 EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier("void", context,356 basename));357 EXPECT_FALSE(358 CPlusPlusLanguage::ExtractContextAndIdentifier("321", context, basename));359 EXPECT_FALSE(360 CPlusPlusLanguage::ExtractContextAndIdentifier("", context, basename));361 EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(362 "selector:", context, basename));363 EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(364 "selector:otherField:", context, basename));365 EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(366 "abc::", context, basename));367 EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(368 "f<A<B><C>>", context, basename));369 370 EXPECT_TRUE(CPlusPlusLanguage::ExtractContextAndIdentifier(371 "A::operator<=><A::B>", context, basename));372 EXPECT_TRUE(CPlusPlusLanguage::ExtractContextAndIdentifier(373 "operator<=><A::B>", context, basename));374}375 376static std::vector<std::string> GenerateAlternate(llvm::StringRef Name) {377 std::vector<std::string> Strings;378 if (Language *CPlusPlusLang =379 Language::FindPlugin(lldb::eLanguageTypeC_plus_plus)) {380 std::vector<ConstString> Results =381 CPlusPlusLang->GenerateAlternateFunctionManglings(ConstString(Name));382 for (ConstString Str : Results)383 Strings.push_back(std::string(Str.GetStringRef()));384 }385 return Strings;386}387 388TEST(CPlusPlusLanguage, GenerateAlternateFunctionManglings) {389 using namespace testing;390 391 SubsystemRAII<CPlusPlusLanguage> lang;392 393 EXPECT_THAT(GenerateAlternate("_ZN1A1fEv"),394 UnorderedElementsAre("_ZNK1A1fEv", "_ZLN1A1fEv"));395 EXPECT_THAT(GenerateAlternate("_ZN1A1fEa"), Contains("_ZN1A1fEc"));396 EXPECT_THAT(GenerateAlternate("_ZN1A1fEx"), Contains("_ZN1A1fEl"));397 EXPECT_THAT(GenerateAlternate("_ZN1A1fEy"), Contains("_ZN1A1fEm"));398 EXPECT_THAT(GenerateAlternate("_ZN1A1fEai"), Contains("_ZN1A1fEci"));399 EXPECT_THAT(GenerateAlternate("_ZN1AC1Ev"), Contains("_ZN1AC2Ev"));400 EXPECT_THAT(GenerateAlternate("_ZN1AD1Ev"), Contains("_ZN1AD2Ev"));401 EXPECT_THAT(GenerateAlternate("_bogus"), IsEmpty());402}403 404TEST(CPlusPlusLanguage, CPlusPlusNameParser) {405 // Don't crash.406 CPlusPlusNameParser((const char *)nullptr);407}408 409TEST(CPlusPlusLanguage, DoesNotMatchCxx) {410 // Test that a symbol name that is NOT C++ does not match C++.411 412 SubsystemRAII<CPlusPlusLanguage> lang;413 Language *CPlusPlusLang =414 Language::FindPlugin(lldb::eLanguageTypeC_plus_plus);415 416 EXPECT_TRUE(CPlusPlusLang != nullptr);417 418 Mangled swiftSymbol("$sS");419 EXPECT_FALSE(CPlusPlusLang->SymbolNameFitsToLanguage(swiftSymbol));420}421 422TEST(CPlusPlusLanguage, MatchesCxx) {423 // Test that a symbol name that is C++ does match C++ (both Itanium and MSVC).424 425 SubsystemRAII<CPlusPlusLanguage> lang;426 Language *CPlusPlusLang =427 Language::FindPlugin(lldb::eLanguageTypeC_plus_plus);428 429 EXPECT_TRUE(CPlusPlusLang != nullptr);430 431 Mangled itaniumSymbol("_Z3Foo");432 EXPECT_TRUE(CPlusPlusLang->SymbolNameFitsToLanguage(itaniumSymbol));433 Mangled itaniumExtensionSymbol("___Z3Bar_block_invoke");434 EXPECT_TRUE(CPlusPlusLang->SymbolNameFitsToLanguage(itaniumExtensionSymbol));435 Mangled msvcSymbol("??x@@3AH");436 EXPECT_TRUE(CPlusPlusLang->SymbolNameFitsToLanguage(msvcSymbol));437}438 439struct ManglingSubstitutorTestCase {440 llvm::StringRef mangled;441 llvm::StringRef from;442 llvm::StringRef to;443 llvm::StringRef expected;444 bool expect_error;445};446 447struct ManglingSubstitutorTestFixture448 : public ::testing::TestWithParam<ManglingSubstitutorTestCase> {};449 450ManglingSubstitutorTestCase g_mangled_substitutor_type_test_cases[] = {451 {/*.mangled*/ "_Z3fooa", /*from*/ "a", /*to*/ "c", /*expected*/ "_Z3fooc",452 /*expect_error*/ false},453 {/*.mangled*/ "_Z3fooy", /*from*/ "y", /*to*/ "m", /*expected*/ "_Z3foom",454 /*expect_error*/ false},455 {/*.mangled*/ "_Z3foox", /*from*/ "x", /*to*/ "l", /*expected*/ "_Z3fool",456 /*expect_error*/ false},457 {/*.mangled*/ "_Z3baraa", /*from*/ "a", /*to*/ "c", /*expected*/ "_Z3barcc",458 /*expect_error*/ false},459 {/*.mangled*/ "_Z3foov", /*from*/ "x", /*to*/ "l", /*expected*/ "",460 /*expect_error*/ false},461 {/*.mangled*/ "_Z3fooB3Tagv", /*from*/ "Tag", /*to*/ "random",462 /*expected*/ "", /*expect_error*/ false},463 {/*.mangled*/ "_Z3foocc", /*from*/ "a", /*to*/ "c", /*expected*/ "",464 /*expect_error*/ false},465 {/*.mangled*/ "_ZN3fooIaE3barIaEEvaT_", /*from*/ "a", /*to*/ "c",466 /*expected*/ "_ZN3fooIcE3barIcEEvcT_", /*expect_error*/ false},467 {/*.mangled*/ "foo", /*from*/ "x", /*to*/ "l", /*expected*/ "",468 /*expect_error*/ true},469 {/*.mangled*/ "", /*from*/ "x", /*to*/ "l", /*expected*/ "",470 /*expect_error*/ true},471 // FIXME: these two cases are odd behaviours, though not realistic in472 // practice.473 {/*.mangled*/ "_Z3foox", /*from*/ "", /*to*/ "l", /*expected*/ "_Z3foolx",474 /*expect_error*/ false},475 {/*.mangled*/ "_Z3foox", /*from*/ "x", /*to*/ "", /*expected*/ "_Z3foo",476 /*expect_error*/ false}};477 478TEST_P(ManglingSubstitutorTestFixture, Type) {479 // Tests the CPlusPlusLanguage::SubstituteType_ItaniumMangle API.480 481 const auto &[mangled, from, to, expected, expect_error] = GetParam();482 483 auto subst_or_err =484 CPlusPlusLanguage::SubstituteType_ItaniumMangle(mangled, from, to);485 if (expect_error) {486 EXPECT_THAT_EXPECTED(subst_or_err, llvm::Failed());487 } else {488 EXPECT_THAT_EXPECTED(subst_or_err, llvm::Succeeded());489 EXPECT_EQ(*subst_or_err, expected);490 }491}492 493INSTANTIATE_TEST_SUITE_P(494 ManglingSubstitutorTypeTests, ManglingSubstitutorTestFixture,495 ::testing::ValuesIn(g_mangled_substitutor_type_test_cases));496 497struct ManglingSubstitutorStructorTestFixture498 : public ::testing::TestWithParam<ManglingSubstitutorTestCase> {};499 500ManglingSubstitutorTestCase g_mangled_substitutor_structor_test_cases[] = {501 {/*.mangled*/ "_ZN3FooC1Ev", /*from*/ "C1", /*to*/ "C2",502 /*expected*/ "_ZN3FooC2Ev", /*expect_error*/ false},503 {/*.mangled*/ "_ZN3FooC4Ev", /*from*/ "C4", /*to*/ "C2",504 /*expected*/ "_ZN3FooC2Ev", /*expect_error*/ false},505 {/*.mangled*/ "_ZN3FooC2Ev", /*from*/ "C1", /*to*/ "C2", /*expected*/ "",506 /*expect_error*/ false},507 {/*.mangled*/ "_ZN3FooD1Ev", /*from*/ "D1", /*to*/ "D2",508 /*expected*/ "_ZN3FooD2Ev", /*expect_error*/ false},509 {/*.mangled*/ "_ZN3FooD2Ev", /*from*/ "D1", /*to*/ "D2", /*expected*/ "",510 /*expect_error*/ false},511 {/*.mangled*/ "_ZN3FooD4Ev", /*from*/ "D4", /*to*/ "D2",512 /*expected*/ "_ZN3FooD2Ev", /*expect_error*/ false},513 {/*.mangled*/ "_ZN2D12C1C1I2C12D1EE2C12D1", /*from*/ "C1", /*to*/ "C2",514 /*expected*/ "_ZN2D12C1C2I2C12D1EE2C12D1", /*expect_error*/ false},515 {/*.mangled*/ "_ZN2D12C1D1I2C12D1EE2C12D1", /*from*/ "D1", /*to*/ "D2",516 /*expected*/ "_ZN2D12C1D2I2C12D1EE2C12D1", /*expect_error*/ false},517 {/*.mangled*/ "_ZN3FooC6Ev", /*from*/ "D1", /*to*/ "D2", /*expected*/ "",518 /*expect_error*/ true},519 {/*.mangled*/ "_ZN2D12C1B2D1C1I2C1B2C12D1B2D1EE2C1B2C12D1B2D1",520 /*from*/ "C1", /*to*/ "C2",521 /*expected*/ "_ZN2D12C1B2D1C2I2C1B2C12D1B2D1EE2C1B2C12D1B2D1",522 /*expect_error*/ false},523 {/*.mangled*/ "_ZN2D12C1B2D1D1I2C1B2C12D1B2D1EE2C1B2C12D1B2D1",524 /*from*/ "D1", /*to*/ "D2",525 /*expected*/ "_ZN2D12C1B2D1D2I2C1B2C12D1B2D1EE2C1B2C12D1B2D1",526 /*expect_error*/ false},527};528 529TEST_P(ManglingSubstitutorStructorTestFixture, Structors) {530 // Tests the CPlusPlusLanguage::SubstituteStructor_ItaniumMangle API.531 532 const auto &[mangled, from, to, expected, expect_error] = GetParam();533 534 auto subst_or_err =535 CPlusPlusLanguage::SubstituteStructor_ItaniumMangle(mangled, from, to);536 if (expect_error) {537 EXPECT_THAT_EXPECTED(subst_or_err, llvm::Failed());538 } else {539 EXPECT_THAT_EXPECTED(subst_or_err, llvm::Succeeded());540 EXPECT_EQ(*subst_or_err, expected);541 }542}543 544INSTANTIATE_TEST_SUITE_P(545 ManglingSubstitutorStructorTests, ManglingSubstitutorStructorTestFixture,546 ::testing::ValuesIn(g_mangled_substitutor_structor_test_cases));547 548TEST(CPlusPlusLanguage, ManglingSubstitutor_StructorAlias) {549 // Tests the CPlusPlusLanguage::SubstituteStructorAliases_ItaniumMangle API.550 {551 // Invalid mangling.552 auto subst_or_err =553 CPlusPlusLanguage::SubstituteStructorAliases_ItaniumMangle("Foo");554 EXPECT_THAT_EXPECTED(subst_or_err, llvm::Failed());555 }556 557 {558 // Ctor C1 alias.559 auto subst_or_err =560 CPlusPlusLanguage::SubstituteStructorAliases_ItaniumMangle(561 "_ZN3FooC1Ev");562 EXPECT_THAT_EXPECTED(subst_or_err, llvm::Succeeded());563 EXPECT_EQ(*subst_or_err, "_ZN3FooC2Ev");564 }565 566 {567 // Dtor D1 alias.568 auto subst_or_err =569 CPlusPlusLanguage::SubstituteStructorAliases_ItaniumMangle(570 "_ZN3FooD1Ev");571 EXPECT_THAT_EXPECTED(subst_or_err, llvm::Succeeded());572 EXPECT_EQ(*subst_or_err, "_ZN3FooD2Ev");573 }574 575 {576 // Ctor C2 not aliased.577 auto subst_or_err =578 CPlusPlusLanguage::SubstituteStructorAliases_ItaniumMangle(579 "_ZN3FooC2Ev");580 EXPECT_THAT_EXPECTED(subst_or_err, llvm::Succeeded());581 EXPECT_FALSE(*subst_or_err);582 }583 584 {585 // Dtor D2 not aliased.586 auto subst_or_err =587 CPlusPlusLanguage::SubstituteStructorAliases_ItaniumMangle(588 "_ZN3FooD2Ev");589 EXPECT_THAT_EXPECTED(subst_or_err, llvm::Succeeded());590 EXPECT_FALSE(*subst_or_err);591 }592 593 {594 // Check that ctor variants in other parts of the name don't get replaced.595 auto subst_or_err =596 CPlusPlusLanguage::SubstituteStructorAliases_ItaniumMangle(597 "_ZN2D12C1B2D1C1I2C1B2C12D1B2D1EE2C1B2C12D1B2D1");598 EXPECT_THAT_EXPECTED(subst_or_err, llvm::Succeeded());599 EXPECT_EQ(*subst_or_err, "_ZN2D12C1B2D1C2I2C1B2C12D1B2D1EE2C1B2C12D1B2D1");600 }601 602 {603 // Check that dtor variants in other parts of the name don't get replaced.604 auto subst_or_err =605 CPlusPlusLanguage::SubstituteStructorAliases_ItaniumMangle(606 "_ZN2D12C1B2D1D1I2C1B2C12D1B2D1EE2C1B2C12D1B2D1");607 EXPECT_THAT_EXPECTED(subst_or_err, llvm::Succeeded());608 EXPECT_EQ(*subst_or_err, "_ZN2D12C1B2D1D2I2C1B2C12D1B2D1EE2C1B2C12D1B2D1");609 }610}611