Skip to content

Commit 074ccde

Browse files
authored
[lldb][Formatter] Consolidate libstdc++ and libc++ unique_ptr formatter tests into generic test (#147031)
The libc++ test was a subset of the tests in libstdc++. This test moves the libc++ test into `generic` and somne additional test-cases from `libstdc++` (specifically the recursive unique_ptr case). It turns out the libstdc++ formatter supports dereferencing using the "object" or "obj" names. We could either drop those from the tests or support the same for libc++. I took the latter approach but don't have strong opinions on this. Split out from #146740
1 parent 0860f7a commit 074ccde

File tree

10 files changed

+90
-240
lines changed

10 files changed

+90
-240
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
411411
return 0;
412412
if (name == "deleter")
413413
return 1;
414-
if (name == "$$dereference$$")
414+
if (name == "obj" || name == "object" || name == "$$dereference$$")
415415
return 2;
416416
return llvm::createStringError("Type has no child named '%s'",
417417
name.AsCString());

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

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ class LibStdcppUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
4242
// objects are only destroyed when every shared pointer to any of them
4343
// is destroyed, so we must not store a shared pointer to any ValueObject
4444
// derived from our backend ValueObject (since we're in the same cluster).
45-
ValueObject* m_ptr_obj = nullptr;
46-
ValueObject* m_obj_obj = nullptr;
45+
ValueObject *m_ptr_obj = nullptr;
4746
ValueObject* m_del_obj = nullptr;
4847

4948
ValueObjectSP GetTuple();
@@ -107,7 +106,6 @@ lldb::ChildCacheState LibStdcppUniquePtrSyntheticFrontEnd::Update() {
107106
if (del_obj)
108107
m_del_obj = del_obj->Clone(ConstString("deleter")).get();
109108
}
110-
m_obj_obj = nullptr;
111109

112110
return lldb::ChildCacheState::eRefetch;
113111
}
@@ -119,15 +117,13 @@ LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
119117
if (idx == 1 && m_del_obj)
120118
return m_del_obj->GetSP();
121119
if (idx == 2) {
122-
if (m_ptr_obj && !m_obj_obj) {
123-
Status error;
124-
ValueObjectSP obj_obj = m_ptr_obj->Dereference(error);
125-
if (error.Success()) {
126-
m_obj_obj = obj_obj->Clone(ConstString("object")).get();
120+
if (m_ptr_obj) {
121+
Status status;
122+
auto value_sp = m_ptr_obj->Dereference(status);
123+
if (status.Success()) {
124+
return value_sp;
127125
}
128126
}
129-
if (m_obj_obj)
130-
return m_obj_obj->GetSP();
131127
}
132128
return lldb::ValueObjectSP();
133129
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
CXX_SOURCES := main.cpp
2-
3-
USE_LIBSTDCPP := 1
2+
CXXFLAGS_EXTRAS := -std=c++14
43

54
include Makefile.rules
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,23 @@
11
"""
2-
Test lldb data formatter for libc++ std::unique_ptr.
2+
Test lldb data formatter for std::unique_ptr.
33
"""
44

5-
65
import lldb
76
from lldbsuite.test.decorators import *
87
from lldbsuite.test.lldbtest import *
98
from lldbsuite.test import lldbutil
109

1110

1211
class TestCase(TestBase):
13-
def make_expected_type(self, pointee_type: str, qualifiers: str = "") -> str:
14-
if qualifiers:
15-
qualifiers = " " + qualifiers
16-
17-
if self.expectedCompiler(["clang"]) and self.expectedCompilerVersion(
18-
[">", "16.0"]
19-
):
20-
return f"std::unique_ptr<{pointee_type}>{qualifiers}"
21-
else:
22-
return f"std::unique_ptr<{pointee_type}, std::default_delete<{pointee_type}> >{qualifiers}"
23-
24-
def make_expected_basic_string_ptr(self) -> str:
25-
if self.expectedCompiler(["clang"]) and self.expectedCompilerVersion(
26-
[">", "16.0"]
27-
):
28-
return f"std::unique_ptr<std::string>"
29-
else:
30-
return (
31-
"std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, "
32-
"std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >"
33-
)
34-
35-
@add_test_categories(["libc++"])
36-
def test_unique_ptr_variables(self):
12+
def do_test(self):
3713
"""Test `frame variable` output for `std::unique_ptr` types."""
38-
self.build()
3914

4015
lldbutil.run_to_source_breakpoint(
4116
self, "// break here", lldb.SBFileSpec("main.cpp")
4217
)
4318

4419
valobj = self.expect_var_path(
4520
"up_empty",
46-
type=self.make_expected_type("int"),
4721
summary="nullptr",
4822
children=[ValueCheck(name="pointer")],
4923
)
@@ -57,36 +31,32 @@ def test_unique_ptr_variables(self):
5731

5832
valobj = self.expect_var_path(
5933
"up_int",
60-
type=self.make_expected_type("int"),
6134
summary="10",
6235
children=[ValueCheck(name="pointer")],
6336
)
6437
self.assertNotEqual(valobj.child[0].unsigned, 0)
6538

6639
valobj = self.expect_var_path(
6740
"up_int_ref",
68-
type=self.make_expected_type("int", qualifiers="&"),
6941
summary="10",
7042
children=[ValueCheck(name="pointer")],
7143
)
7244
self.assertNotEqual(valobj.child[0].unsigned, 0)
7345

7446
valobj = self.expect_var_path(
7547
"up_int_ref_ref",
76-
type=self.make_expected_type("int", qualifiers="&&"),
7748
summary="10",
7849
children=[ValueCheck(name="pointer")],
7950
)
8051
self.assertNotEqual(valobj.child[0].unsigned, 0)
8152

8253
valobj = self.expect_var_path(
8354
"up_str",
84-
type=self.make_expected_basic_string_ptr(),
8555
summary='"hello"',
8656
children=[ValueCheck(name="pointer", summary='"hello"')],
8757
)
8858

89-
valobj = self.expect_var_path("up_user", type=self.make_expected_type("User"))
59+
valobj = self.expect_var_path("up_user")
9060
self.assertRegex(valobj.summary, "^User @ 0x0*[1-9a-f][0-9a-f]+$")
9161
self.assertNotEqual(valobj.child[0].unsigned, 0)
9262

@@ -121,3 +91,67 @@ def test_unique_ptr_variables(self):
12191
self.expect_var_path("ptr_node->next->value", value="2")
12292
self.expect_var_path("(*ptr_node).value", value="1")
12393
self.expect_var_path("(*(*ptr_node).next).value", value="2")
94+
95+
@add_test_categories(["libstdcxx"])
96+
def test_libstdcxx(self):
97+
self.build(dictionary={"USE_LIBSTDCPP": 1})
98+
self.do_test()
99+
100+
@add_test_categories(["libc++"])
101+
def test_libcxx(self):
102+
self.build(dictionary={"USE_LIBCPP": 1})
103+
self.do_test()
104+
105+
def do_test_recursive_unique_ptr(self):
106+
# Tests that LLDB can handle when we have a loop in the unique_ptr
107+
# reference chain and that it correctly handles the different options
108+
# for the frame variable command in this case.
109+
self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
110+
111+
lldbutil.run_break_set_by_source_regexp(self, "Set break point at this line.")
112+
self.runCmd("run", RUN_SUCCEEDED)
113+
self.expect(
114+
"thread list",
115+
STOPPED_DUE_TO_BREAKPOINT,
116+
substrs=["stopped", "stop reason = breakpoint"],
117+
)
118+
119+
self.expect("frame variable f1->next", substrs=["next = NodeU @"])
120+
self.expect(
121+
"frame variable --ptr-depth=1 f1->next",
122+
substrs=["next = NodeU @", "value = 2"],
123+
)
124+
self.expect(
125+
"frame variable --ptr-depth=2 f1->next",
126+
substrs=["next = NodeU @", "value = 1", "value = 2"],
127+
)
128+
129+
frame = self.frame()
130+
self.assertTrue(frame.IsValid())
131+
self.assertEqual(
132+
2,
133+
frame.GetValueForVariablePath("f1->next.object.value").GetValueAsUnsigned(),
134+
)
135+
self.assertEqual(
136+
2, frame.GetValueForVariablePath("f1->next->value").GetValueAsUnsigned()
137+
)
138+
self.assertEqual(
139+
1,
140+
frame.GetValueForVariablePath(
141+
"f1->next.object.next.obj.value"
142+
).GetValueAsUnsigned(),
143+
)
144+
self.assertEqual(
145+
1,
146+
frame.GetValueForVariablePath("f1->next->next->value").GetValueAsUnsigned(),
147+
)
148+
149+
@add_test_categories(["libstdcxx"])
150+
def test_recursive_unique_ptr_libstdcxx(self):
151+
self.build(dictionary={"USE_LIBSTDCPP": 1})
152+
self.do_test_recursive_unique_ptr()
153+
154+
@add_test_categories(["libc++"])
155+
def test_recursive_unique_ptr_libcxx(self):
156+
self.build(dictionary={"USE_LIBCPP": 1})
157+
self.do_test_recursive_unique_ptr()

lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp renamed to lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/main.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,20 @@ struct NodeU {
1515
// representation when the type of the second element is an empty class. So
1616
// we need a deleter class with a dummy data member to trigger the other path.
1717
struct NonEmptyIntDeleter {
18-
void operator()(int* ptr) { delete ptr; }
18+
void operator()(int *ptr) { delete ptr; }
1919

2020
int dummy_ = 9999;
2121
};
2222

23+
static void recursive() {
24+
// Set up a structure where we have a loop in the unique_ptr chain.
25+
NodeU *f1 = new NodeU{nullptr, 1};
26+
NodeU *f2 = new NodeU{nullptr, 2};
27+
f1->next.reset(f2);
28+
f2->next.reset(f1);
29+
std::puts("Set break point at this line.");
30+
}
31+
2332
int main() {
2433
std::unique_ptr<int> up_empty;
2534
std::unique_ptr<int> up_int = std::make_unique<int>(10);
@@ -33,5 +42,9 @@ int main() {
3342
std::unique_ptr<NodeU>(new NodeU{nullptr, 2});
3443
ptr_node = std::unique_ptr<NodeU>(new NodeU{std::move(ptr_node), 1});
3544

36-
return 0; // break here
45+
std::puts("// break here");
46+
47+
recursive();
48+
49+
return 0;
3750
}

lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile

Lines changed: 0 additions & 8 deletions
This file was deleted.

lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/TestDataFormatterStdUniquePtr.py

Lines changed: 0 additions & 134 deletions
This file was deleted.

lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/TestDataFormatterInvalidStdUniquePtr.py

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)