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