Skip to content

Commit d4a55ad

Browse files
committed
[lldb][Breakpoint] Fix setting breakpoints on templates by basename
This patch fixes a regression with setting breakpoints on template functions by name. E.g.,: ``` $ cat main.cpp template<typename T> struct Foo { template<typename U> void func() {} }; int main() { Foo<int> f; f.func<double>(); } (lldb) br se -n func ``` This has regressed since `3339000e0bda696c2e29173d15958c0a4978a143` where we started using the `CPlusPlusNameParser` for getting the basename of the function symbol and match it exactly against the name in the breakpoint command. The parser will include template parameters in the basename, so the exact match will always fail **Testing** * Added API tests * Added unit-tests Differential Revision: https://reviews.llvm.org/D135921
1 parent c116bd9 commit d4a55ad

File tree

6 files changed

+110
-2
lines changed

6 files changed

+110
-2
lines changed

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,21 @@ std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() {
269269
return res;
270270
}
271271

272+
llvm::StringRef
273+
CPlusPlusLanguage::MethodName::GetBasenameNoTemplateParameters() {
274+
llvm::StringRef basename = GetBasename();
275+
size_t arg_start, arg_end;
276+
llvm::StringRef parens("<>", 2);
277+
if (ReverseFindMatchingChars(basename, parens, arg_start, arg_end))
278+
return basename.substr(0, arg_start);
279+
280+
return basename;
281+
}
282+
272283
bool CPlusPlusLanguage::MethodName::ContainsPath(llvm::StringRef path) {
273284
if (!m_parsed)
274285
Parse();
286+
275287
// If we can't parse the incoming name, then just check that it contains path.
276288
if (m_parse_error)
277289
return m_full.GetStringRef().contains(path);
@@ -286,8 +298,23 @@ bool CPlusPlusLanguage::MethodName::ContainsPath(llvm::StringRef path) {
286298
if (!success)
287299
return m_full.GetStringRef().contains(path);
288300

289-
if (identifier != GetBasename())
301+
// Basename may include template arguments.
302+
// E.g.,
303+
// GetBaseName(): func<int>
304+
// identifier : func
305+
//
306+
// ...but we still want to account for identifiers with template parameter
307+
// lists, e.g., when users set breakpoints on template specializations.
308+
//
309+
// E.g.,
310+
// GetBaseName(): func<uint32_t>
311+
// identifier : func<int32_t*>
312+
//
313+
// Try to match the basename with or without template parameters.
314+
if (GetBasename() != identifier &&
315+
GetBasenameNoTemplateParameters() != identifier)
290316
return false;
317+
291318
// Incoming path only had an identifier, so we match.
292319
if (context.empty())
293320
return true;

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,21 @@ class CPlusPlusLanguage : public Language {
5858

5959
bool ContainsPath(llvm::StringRef path);
6060

61+
private:
62+
/// Returns the Basename of this method without a template parameter
63+
/// list, if any.
64+
///
65+
// Examples:
66+
//
67+
// +--------------------------------+---------+
68+
// | MethodName | Returns |
69+
// +--------------------------------+---------+
70+
// | void func() | func |
71+
// | void func<int>() | func |
72+
// | void func<std::vector<int>>() | func |
73+
// +--------------------------------+---------+
74+
llvm::StringRef GetBasenameNoTemplateParameters();
75+
6176
protected:
6277
void Parse();
6378
bool TrySimplifiedParse();

lldb/test/API/functionalities/breakpoint/cpp/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
CXX_SOURCES := main.cpp
2+
CXXFLAGS_EXTRAS := -std=c++14
23

34
ifneq (,$(findstring icc,$(CC)))
45
CXXFLAGS_EXTRAS := -debug inline-debug-info

lldb/test/API/functionalities/breakpoint/cpp/TestCPPBreakpointLocations.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,23 @@ def breakpoint_id_tests(self):
5454
{'name': 'a::c::func1()', 'loc_names': ['a::c::func1()']},
5555
{'name': 'b::c::func1()', 'loc_names': ['b::c::func1()']},
5656
{'name': 'c::d::func2()', 'loc_names': ['c::d::func2()']},
57+
58+
# Template cases
59+
{'name': 'func<float>', 'loc_names': []},
60+
{'name': 'func<int>', 'loc_names': ['auto ns::Foo<double>::func<int>()']},
61+
{'name': 'func', 'loc_names': ['auto ns::Foo<double>::func<int>()',
62+
'auto ns::Foo<double>::func<ns::Foo<int>>()']},
63+
64+
{'name': 'operator', 'loc_names': []},
65+
{'name': 'ns::Foo<double>::operator bool', 'loc_names': ['ns::Foo<double>::operator bool()']},
66+
67+
{'name': 'operator a::c', 'loc_names': ['ns::Foo<double>::operator a::c<a::c>()']},
68+
{'name': 'operator ns::Foo<int>', 'loc_names': ['ns::Foo<double>::operator ns::Foo<int><ns::Foo<int>>()']},
69+
70+
{'name': 'operator<<<a::c>', 'loc_names': []},
71+
{'name': 'operator<<<int>', 'loc_names': ['void ns::Foo<double>::operator<<<int>(int)']},
72+
{'name': 'ns::Foo<double>::operator<<', 'loc_names': ['void ns::Foo<double>::operator<<<int>(int)',
73+
'void ns::Foo<double>::operator<<<ns::Foo<int>>(ns::Foo<int>)']},
5774
]
5875

5976
for bp_dict in bp_dicts:

lldb/test/API/functionalities/breakpoint/cpp/main.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,20 @@ namespace c {
8282
};
8383
}
8484

85+
namespace ns {
86+
template <typename Type> struct Foo {
87+
template <typename T> void import() {}
88+
89+
template <typename T> auto func() {}
90+
91+
operator bool() { return true; }
92+
93+
template <typename T> operator T() { return {}; }
94+
95+
template <typename T> void operator<<(T t) {}
96+
};
97+
} // namespace ns
98+
8599
int main (int argc, char const *argv[])
86100
{
87101
a::c ac;
@@ -98,5 +112,16 @@ int main (int argc, char const *argv[])
98112
bc.func3();
99113
cd.func2();
100114
cd.func3();
115+
116+
ns::Foo<double> f;
117+
f.import <int>();
118+
f.func<int>();
119+
f.func<ns::Foo<int>>();
120+
f.operator bool();
121+
f.operator a::c();
122+
f.operator ns::Foo<int>();
123+
f.operator<<(5);
124+
f.operator<< <ns::Foo<int>>({});
125+
101126
return 0;
102127
}

lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,12 @@ TEST(CPlusPlusLanguage, ContainsPath) {
143143
CPlusPlusLanguage::MethodName reference_3(ConstString("int func01()"));
144144
CPlusPlusLanguage::MethodName
145145
reference_4(ConstString("bar::baz::operator bool()"));
146-
146+
CPlusPlusLanguage::MethodName reference_5(
147+
ConstString("bar::baz::operator bool<int, Type<double>>()"));
148+
CPlusPlusLanguage::MethodName reference_6(ConstString(
149+
"bar::baz::operator<<<Type<double>, Type<std::vector<double>>>()"));
150+
151+
EXPECT_TRUE(reference_1.ContainsPath(""));
147152
EXPECT_TRUE(reference_1.ContainsPath("func01"));
148153
EXPECT_TRUE(reference_1.ContainsPath("bar::func01"));
149154
EXPECT_TRUE(reference_1.ContainsPath("foo::bar::func01"));
@@ -153,17 +158,35 @@ TEST(CPlusPlusLanguage, ContainsPath) {
153158
EXPECT_FALSE(reference_1.ContainsPath("::foo::baz::func01"));
154159
EXPECT_FALSE(reference_1.ContainsPath("foo::bar::baz::func01"));
155160

161+
EXPECT_TRUE(reference_2.ContainsPath(""));
156162
EXPECT_TRUE(reference_2.ContainsPath("foofoo::bar::func01"));
157163
EXPECT_FALSE(reference_2.ContainsPath("foo::bar::func01"));
158164

165+
EXPECT_TRUE(reference_3.ContainsPath(""));
159166
EXPECT_TRUE(reference_3.ContainsPath("func01"));
160167
EXPECT_FALSE(reference_3.ContainsPath("func"));
161168
EXPECT_FALSE(reference_3.ContainsPath("bar::func01"));
162169

170+
EXPECT_TRUE(reference_4.ContainsPath(""));
171+
EXPECT_TRUE(reference_4.ContainsPath("operator"));
163172
EXPECT_TRUE(reference_4.ContainsPath("operator bool"));
164173
EXPECT_TRUE(reference_4.ContainsPath("baz::operator bool"));
165174
EXPECT_TRUE(reference_4.ContainsPath("bar::baz::operator bool"));
166175
EXPECT_FALSE(reference_4.ContainsPath("az::operator bool"));
176+
177+
EXPECT_TRUE(reference_5.ContainsPath(""));
178+
EXPECT_TRUE(reference_5.ContainsPath("operator"));
179+
EXPECT_TRUE(reference_5.ContainsPath("operator bool"));
180+
EXPECT_TRUE(reference_5.ContainsPath("operator bool<int, Type<double>>"));
181+
EXPECT_FALSE(reference_5.ContainsPath("operator bool<int, double>"));
182+
EXPECT_FALSE(reference_5.ContainsPath("operator bool<int, Type<int>>"));
183+
184+
EXPECT_TRUE(reference_6.ContainsPath(""));
185+
EXPECT_TRUE(reference_6.ContainsPath("operator"));
186+
EXPECT_TRUE(reference_6.ContainsPath("operator<<"));
187+
EXPECT_TRUE(reference_6.ContainsPath(
188+
"bar::baz::operator<<<Type<double>, Type<std::vector<double>>>()"));
189+
EXPECT_FALSE(reference_6.ContainsPath("operator<<<Type<double>>"));
167190
}
168191

169192
TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) {

0 commit comments

Comments
 (0)