1 //===-- CPlusPlusLanguageTest.cpp -------------------------------*- C++ -*-===// 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 "gmock/gmock.h" 10 #include "gtest/gtest.h" 11 12 using namespace lldb_private; 13 14 TEST(CPlusPlusLanguage, MethodNameParsing) { 15 struct TestCase { 16 std::string input; 17 std::string context, basename, arguments, qualifiers, scope_qualified_name; 18 }; 19 20 TestCase test_cases[] = { 21 {"main(int, char *[]) ", "", "main", "(int, char *[])", "", "main"}, 22 {"foo::bar(baz) const", "foo", "bar", "(baz)", "const", "foo::bar"}, 23 {"foo::~bar(baz)", "foo", "~bar", "(baz)", "", "foo::~bar"}, 24 {"a::b::c::d(e,f)", "a::b::c", "d", "(e,f)", "", "a::b::c::d"}, 25 {"void f(int)", "", "f", "(int)", "", "f"}, 26 27 // Operators 28 {"std::basic_ostream<char, std::char_traits<char> >& " 29 "std::operator<<<std::char_traits<char> >" 30 "(std::basic_ostream<char, std::char_traits<char> >&, char const*)", 31 "std", "operator<<<std::char_traits<char> >", 32 "(std::basic_ostream<char, std::char_traits<char> >&, char const*)", "", 33 "std::operator<<<std::char_traits<char> >"}, 34 {"operator delete[](void*, clang::ASTContext const&, unsigned long)", "", 35 "operator delete[]", "(void*, clang::ASTContext const&, unsigned long)", 36 "", "operator delete[]"}, 37 {"llvm::Optional<clang::PostInitializer>::operator bool() const", 38 "llvm::Optional<clang::PostInitializer>", "operator bool", "()", "const", 39 "llvm::Optional<clang::PostInitializer>::operator bool"}, 40 {"(anonymous namespace)::FactManager::operator[](unsigned short)", 41 "(anonymous namespace)::FactManager", "operator[]", "(unsigned short)", 42 "", "(anonymous namespace)::FactManager::operator[]"}, 43 {"const int& std::map<int, pair<short, int>>::operator[](short) const", 44 "std::map<int, pair<short, int>>", "operator[]", "(short)", "const", 45 "std::map<int, pair<short, int>>::operator[]"}, 46 {"CompareInsn::operator()(llvm::StringRef, InsnMatchEntry const&)", 47 "CompareInsn", "operator()", "(llvm::StringRef, InsnMatchEntry const&)", 48 "", "CompareInsn::operator()"}, 49 {"llvm::Optional<llvm::MCFixupKind>::operator*() const &", 50 "llvm::Optional<llvm::MCFixupKind>", "operator*", "()", "const &", 51 "llvm::Optional<llvm::MCFixupKind>::operator*"}, 52 // Internal classes 53 {"operator<<(Cls, Cls)::Subclass::function()", 54 "operator<<(Cls, Cls)::Subclass", "function", "()", "", 55 "operator<<(Cls, Cls)::Subclass::function"}, 56 {"SAEC::checkFunction(context&) const::CallBack::CallBack(int)", 57 "SAEC::checkFunction(context&) const::CallBack", "CallBack", "(int)", "", 58 "SAEC::checkFunction(context&) const::CallBack::CallBack"}, 59 // Anonymous namespace 60 {"XX::(anonymous namespace)::anon_class::anon_func() const", 61 "XX::(anonymous namespace)::anon_class", "anon_func", "()", "const", 62 "XX::(anonymous namespace)::anon_class::anon_func"}, 63 64 // Lambda 65 {"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const", 66 "main::{lambda()#1}::operator()() const::{lambda()#1}", "operator()", "()", "const", 67 "main::{lambda()#1}::operator()() const::{lambda()#1}::operator()"}, 68 69 // Function pointers 70 {"string (*f(vector<int>&&))(float)", "", "f", "(vector<int>&&)", "", 71 "f"}, 72 {"void (*&std::_Any_data::_M_access<void (*)()>())()", "std::_Any_data", 73 "_M_access<void (*)()>", "()", "", 74 "std::_Any_data::_M_access<void (*)()>"}, 75 {"void (*(*(*(*(*(*(*(* const&func1(int))())())())())())())())()", "", 76 "func1", "(int)", "", "func1"}, 77 78 // Decltype 79 {"decltype(nullptr)&& std::forward<decltype(nullptr)>" 80 "(std::remove_reference<decltype(nullptr)>::type&)", 81 "std", "forward<decltype(nullptr)>", 82 "(std::remove_reference<decltype(nullptr)>::type&)", "", 83 "std::forward<decltype(nullptr)>"}, 84 85 // Templates 86 {"void llvm::PM<llvm::Module, llvm::AM<llvm::Module>>::" 87 "addPass<llvm::VP>(llvm::VP)", 88 "llvm::PM<llvm::Module, llvm::AM<llvm::Module>>", "addPass<llvm::VP>", 89 "(llvm::VP)", "", 90 "llvm::PM<llvm::Module, llvm::AM<llvm::Module>>::" 91 "addPass<llvm::VP>"}, 92 {"void std::vector<Class, std::allocator<Class> >" 93 "::_M_emplace_back_aux<Class const&>(Class const&)", 94 "std::vector<Class, std::allocator<Class> >", 95 "_M_emplace_back_aux<Class const&>", "(Class const&)", "", 96 "std::vector<Class, std::allocator<Class> >::" 97 "_M_emplace_back_aux<Class const&>"}, 98 {"unsigned long llvm::countTrailingOnes<unsigned int>" 99 "(unsigned int, llvm::ZeroBehavior)", 100 "llvm", "countTrailingOnes<unsigned int>", 101 "(unsigned int, llvm::ZeroBehavior)", "", 102 "llvm::countTrailingOnes<unsigned int>"}, 103 {"std::enable_if<(10u)<(64), bool>::type llvm::isUInt<10u>(unsigned " 104 "long)", 105 "llvm", "isUInt<10u>", "(unsigned long)", "", "llvm::isUInt<10u>"}, 106 {"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>()", "", 107 "f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>", "()", "", 108 "f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>"}}; 109 110 for (const auto &test : test_cases) { 111 CPlusPlusLanguage::MethodName method(ConstString(test.input)); 112 EXPECT_TRUE(method.IsValid()) << test.input; 113 if (method.IsValid()) { 114 EXPECT_EQ(test.context, method.GetContext().str()); 115 EXPECT_EQ(test.basename, method.GetBasename().str()); 116 EXPECT_EQ(test.arguments, method.GetArguments().str()); 117 EXPECT_EQ(test.qualifiers, method.GetQualifiers().str()); 118 EXPECT_EQ(test.scope_qualified_name, method.GetScopeQualifiedName()); 119 } 120 } 121 } 122 123 TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) { 124 struct TestCase { 125 std::string input; 126 std::string context, basename; 127 }; 128 129 TestCase test_cases[] = { 130 {"main", "", "main"}, 131 {"main ", "", "main"}, 132 {"foo01::bar", "foo01", "bar"}, 133 {"foo::~bar", "foo", "~bar"}, 134 {"std::vector<int>::push_back", "std::vector<int>", "push_back"}, 135 {"operator<<(Cls, Cls)::Subclass::function", 136 "operator<<(Cls, Cls)::Subclass", "function"}, 137 {"std::vector<Class, std::allocator<Class>>" 138 "::_M_emplace_back_aux<Class const&>", 139 "std::vector<Class, std::allocator<Class>>", 140 "_M_emplace_back_aux<Class const&>"}, 141 {"`anonymous namespace'::foo", "`anonymous namespace'", "foo"}, 142 {"`operator<<A>'::`2'::B<0>::operator>", 143 "`operator<<A>'::`2'::B<0>", 144 "operator>"}, 145 {"`anonymous namespace'::S::<<::__l2::Foo", 146 "`anonymous namespace'::S::<<::__l2", 147 "Foo"}}; 148 149 llvm::StringRef context, basename; 150 for (const auto &test : test_cases) { 151 EXPECT_TRUE(CPlusPlusLanguage::ExtractContextAndIdentifier( 152 test.input.c_str(), context, basename)); 153 EXPECT_EQ(test.context, context.str()); 154 EXPECT_EQ(test.basename, basename.str()); 155 } 156 157 EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier("void", context, 158 basename)); 159 EXPECT_FALSE( 160 CPlusPlusLanguage::ExtractContextAndIdentifier("321", context, basename)); 161 EXPECT_FALSE( 162 CPlusPlusLanguage::ExtractContextAndIdentifier("", context, basename)); 163 EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( 164 "selector:", context, basename)); 165 EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( 166 "selector:otherField:", context, basename)); 167 EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( 168 "abc::", context, basename)); 169 EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( 170 "f<A<B><C>>", context, basename)); 171 } 172 173 static std::set<std::string> FindAlternate(llvm::StringRef Name) { 174 std::set<ConstString> Results; 175 uint32_t Count = CPlusPlusLanguage::FindAlternateFunctionManglings( 176 ConstString(Name), Results); 177 EXPECT_EQ(Count, Results.size()); 178 std::set<std::string> Strings; 179 for (ConstString Str : Results) 180 Strings.insert(Str.GetStringRef()); 181 return Strings; 182 } 183 184 TEST(CPlusPlusLanguage, FindAlternateFunctionManglings) { 185 using namespace testing; 186 187 EXPECT_THAT(FindAlternate("_ZN1A1fEv"), 188 UnorderedElementsAre("_ZNK1A1fEv", "_ZLN1A1fEv")); 189 EXPECT_THAT(FindAlternate("_ZN1A1fEa"), Contains("_ZN1A1fEc")); 190 EXPECT_THAT(FindAlternate("_ZN1A1fEx"), Contains("_ZN1A1fEl")); 191 EXPECT_THAT(FindAlternate("_ZN1A1fEy"), Contains("_ZN1A1fEm")); 192 EXPECT_THAT(FindAlternate("_ZN1A1fEai"), Contains("_ZN1A1fEci")); 193 EXPECT_THAT(FindAlternate("_bogus"), IsEmpty()); 194 } 195