diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h @@ -58,6 +58,9 @@ bool ContainsPath(llvm::StringRef path); + private: + llvm::StringRef GetBasenameNoTemplateParameters(); + protected: void Parse(); bool TrySimplifiedParse(); diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -269,9 +269,21 @@ return res; } +llvm::StringRef +CPlusPlusLanguage::MethodName::GetBasenameNoTemplateParameters() { + llvm::StringRef basename = GetBasename(); + size_t arg_start, arg_end; + llvm::StringRef parens("<>", 2); + if (ReverseFindMatchingChars(basename, parens, arg_start, arg_end)) + return basename.substr(0, arg_start); + + return {}; +} + bool CPlusPlusLanguage::MethodName::ContainsPath(llvm::StringRef path) { if (!m_parsed) Parse(); + // If we can't parse the incoming name, then just check that it contains path. if (m_parse_error) return m_full.GetStringRef().contains(path); @@ -286,8 +298,23 @@ if (!success) return m_full.GetStringRef().contains(path); - if (identifier != GetBasename()) + // Basename may include template arguments. + // E.g., + // GetBaseName(): func + // identifier : func + // + // ...but we still want to account for identifiers with template parameter + // lists, e.g., when users set breakpoints on template specializations. + // + // E.g., + // GetBaseName(): func + // identifier : func + // + // Try to match the basename with or without template parameters. + if (GetBasename() != identifier && + GetBasenameNoTemplateParameters() != identifier) return false; + // Incoming path only had an identifier, so we match. if (context.empty()) return true; diff --git a/lldb/test/API/functionalities/breakpoint/cpp/Makefile b/lldb/test/API/functionalities/breakpoint/cpp/Makefile --- a/lldb/test/API/functionalities/breakpoint/cpp/Makefile +++ b/lldb/test/API/functionalities/breakpoint/cpp/Makefile @@ -1,4 +1,5 @@ CXX_SOURCES := main.cpp +CXXFLAGS_EXTRAS := -std=c++14 ifneq (,$(findstring icc,$(CC))) CXXFLAGS_EXTRAS := -debug inline-debug-info diff --git a/lldb/test/API/functionalities/breakpoint/cpp/TestCPPBreakpointLocations.py b/lldb/test/API/functionalities/breakpoint/cpp/TestCPPBreakpointLocations.py --- a/lldb/test/API/functionalities/breakpoint/cpp/TestCPPBreakpointLocations.py +++ b/lldb/test/API/functionalities/breakpoint/cpp/TestCPPBreakpointLocations.py @@ -54,6 +54,28 @@ {'name': 'a::c::func1()', 'loc_names': ['a::c::func1()']}, {'name': 'b::c::func1()', 'loc_names': ['b::c::func1()']}, {'name': 'c::d::func2()', 'loc_names': ['c::d::func2()']}, + + # Template cases + {'name': 'func', 'loc_names': []}, + {'name': 'func', 'loc_names': ['auto ns::Foo::func()']}, + {'name': 'func', 'loc_names': ['auto ns::Foo::func()', + 'auto ns::Foo::func>()']}, + # {'name': 'func>', 'loc_names': ['auto ns::Foo::func>()']}, # FIXME + + {'name': 'operator', 'loc_names': []}, + {'name': 'ns::Foo::operator bool', 'loc_names': ['ns::Foo::operator bool()']}, + + {'name': 'operator a::c', 'loc_names': ['ns::Foo::operator a::c()']}, + {'name': 'operator ns::Foo', 'loc_names': ['ns::Foo::operator ns::Foo>()']}, + + # FIXME: Currently doesn't work because 'import' is seen as a reserved keyword by the CPlusPlusNameParser + # {'name': 'import', 'loc_names': [auto ns::Foo::import>()]}, + + {'name': 'operator<<', 'loc_names': []}, + {'name': 'operator<<', 'loc_names': ['void ns::Foo::operator<<(int)']}, + {'name': 'ns::Foo::operator<<', 'loc_names': ['void ns::Foo::operator<<(int)', + 'void ns::Foo::operator<<>(ns::Foo)']}, + # {'name': 'operator<<>', 'loc_names': ['void ns::Foo::operator<<>(ns::Foo)']}, # FIXME ] for bp_dict in bp_dicts: diff --git a/lldb/test/API/functionalities/breakpoint/cpp/main.cpp b/lldb/test/API/functionalities/breakpoint/cpp/main.cpp --- a/lldb/test/API/functionalities/breakpoint/cpp/main.cpp +++ b/lldb/test/API/functionalities/breakpoint/cpp/main.cpp @@ -82,6 +82,20 @@ }; } +namespace ns { +template struct Foo { + template void import() {} + + template auto func() {} + + operator bool() { return true; } + + template operator T() { return {}; } + + template void operator<<(T t) {} +}; +} // namespace ns + int main (int argc, char const *argv[]) { a::c ac; @@ -98,5 +112,16 @@ bc.func3(); cd.func2(); cd.func3(); + + ns::Foo f; + f.import (); + f.func(); + f.func>(); + f.operator bool(); + f.operator a::c(); + f.operator ns::Foo(); + f.operator<<(5); + f.operator<< >({}); + return 0; } diff --git a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp --- a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp +++ b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp @@ -143,7 +143,11 @@ CPlusPlusLanguage::MethodName reference_3(ConstString("int func01()")); CPlusPlusLanguage::MethodName reference_4(ConstString("bar::baz::operator bool()")); - + CPlusPlusLanguage::MethodName reference_5( + ConstString("bar::baz::operator bool>()")); + CPlusPlusLanguage::MethodName reference_6(ConstString( + "bar::baz::operator<<, Type>>()")); + EXPECT_TRUE(reference_1.ContainsPath("func01")); EXPECT_TRUE(reference_1.ContainsPath("bar::func01")); EXPECT_TRUE(reference_1.ContainsPath("foo::bar::func01")); @@ -160,10 +164,23 @@ EXPECT_FALSE(reference_3.ContainsPath("func")); EXPECT_FALSE(reference_3.ContainsPath("bar::func01")); + EXPECT_TRUE(reference_4.ContainsPath("operator")); EXPECT_TRUE(reference_4.ContainsPath("operator bool")); EXPECT_TRUE(reference_4.ContainsPath("baz::operator bool")); EXPECT_TRUE(reference_4.ContainsPath("bar::baz::operator bool")); EXPECT_FALSE(reference_4.ContainsPath("az::operator bool")); + + EXPECT_TRUE(reference_5.ContainsPath("operator")); + EXPECT_TRUE(reference_5.ContainsPath("operator bool")); + EXPECT_TRUE(reference_5.ContainsPath("operator bool>")); + EXPECT_FALSE(reference_5.ContainsPath("operator bool")); + EXPECT_FALSE(reference_5.ContainsPath("operator bool>")); + + EXPECT_TRUE(reference_6.ContainsPath("operator")); + EXPECT_TRUE(reference_6.ContainsPath("operator<<")); + EXPECT_TRUE(reference_6.ContainsPath( + "bar::baz::operator<<, Type>>()")); + EXPECT_FALSE(reference_6.ContainsPath("operator<<>")); } TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) {