brintos

brintos / llvm-project-archived public Read only

0
0
Text · 26.1 KiB · c054181 Raw
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