[Lldb-commits] [lldb] [lldb][Formatter] Consolidate libstdc++ and libc++ unique_ptr formatter tests into generic test (PR #147031)

Michael Buch via lldb-commits lldb-commits at lists.llvm.org
Fri Jul 4 03:08:11 PDT 2025


https://github.com/Michael137 created https://github.com/llvm/llvm-project/pull/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 https://github.com/llvm/llvm-project/pull/146740

>From afa00be16641075f71bb7ce15e568ecb3b126719 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 3 Jul 2025 15:41:44 +0100
Subject: [PATCH] [lldb][Formatter] Consolidate libstdc++ and libc++ unique_ptr
 formatter tests into generic test

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 https://github.com/llvm/llvm-project/pull/146740
---
 .../Plugins/Language/CPlusPlus/LibCxx.cpp     |   2 +-
 .../{libcxx => generic}/unique_ptr/Makefile   |   2 -
 .../TestDataFormatterStdUniquePtr.py}         |  71 +++++++++-
 .../{libcxx => generic}/unique_ptr/main.cpp   |  17 ++-
 .../libstdcpp/unique_ptr/Makefile             |   5 -
 .../TestDataFormatterStdUniquePtr.py          | 134 ------------------
 .../TestDataFormatterInvalidStdUniquePtr.py   |   4 -
 .../libstdcpp/unique_ptr/invalid/main.cpp     |  11 --
 .../libstdcpp/unique_ptr/main.cpp             |  35 -----
 9 files changed, 82 insertions(+), 199 deletions(-)
 rename lldb/test/API/functionalities/data-formatter/data-formatter-stl/{libcxx => generic}/unique_ptr/Makefile (92%)
 rename lldb/test/API/functionalities/data-formatter/data-formatter-stl/{libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py => generic/unique_ptr/TestDataFormatterStdUniquePtr.py} (64%)
 rename lldb/test/API/functionalities/data-formatter/data-formatter-stl/{libcxx => generic}/unique_ptr/main.cpp (74%)
 delete mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/Makefile
 delete mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/TestDataFormatterStdUniquePtr.py
 delete mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/TestDataFormatterInvalidStdUniquePtr.py
 delete mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/main.cpp
 delete mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/main.cpp

diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index 009586f525282..51e43b2f62a1e 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -399,7 +399,7 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
     return 0;
   if (name == "deleter")
     return 1;
-  if (name == "$$dereference$$")
+  if (name == "obj" || name == "object" || name == "$$dereference$$")
     return 2;
   return llvm::createStringError("Type has no child named '%s'",
                                  name.AsCString());
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/Makefile
similarity index 92%
rename from lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile
rename to lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/Makefile
index c1c8b4a2a0a53..ece665a0fd5b7 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/Makefile
@@ -1,7 +1,5 @@
 CXX_SOURCES := main.cpp
 
-USE_LIBCPP := 1
-
 # We need debug info tuning for lldb in order to emit the preferred name for
 # std::string. See https://reviews.llvm.org/D145803.
 CXXFLAGS_EXTRAS := -std=c++14 -glldb
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py
similarity index 64%
rename from lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
rename to lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py
index 25a1cd82a4baa..57e1ea9f234f8 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py
@@ -1,8 +1,7 @@
 """
-Test lldb data formatter for libc++ std::unique_ptr.
+Test lldb data formatter for std::unique_ptr.
 """
 
-
 import lldb
 from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
@@ -32,10 +31,8 @@ def make_expected_basic_string_ptr(self) -> str:
                 "std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >"
             )
 
-    @add_test_categories(["libc++"])
-    def test_unique_ptr_variables(self):
+    def do_test(self):
         """Test `frame variable` output for `std::unique_ptr` types."""
-        self.build()
 
         lldbutil.run_to_source_breakpoint(
             self, "// break here", lldb.SBFileSpec("main.cpp")
@@ -121,3 +118,67 @@ def test_unique_ptr_variables(self):
         self.expect_var_path("ptr_node->next->value", value="2")
         self.expect_var_path("(*ptr_node).value", value="1")
         self.expect_var_path("(*(*ptr_node).next).value", value="2")
+
+    @add_test_categories(["libstdcxx"])
+    def test_libstdcxx(self):
+        self.build(dictionary={"USE_LIBSTDCPP": 1})
+        self.do_test()
+
+    @add_test_categories(["libc++"])
+    def test_libcxx(self):
+        self.build(dictionary={"USE_LIBCPP": 1})
+        self.do_test()
+
+    def do_test_recursive_unique_ptr(self):
+        # Tests that LLDB can handle when we have a loop in the unique_ptr
+        # reference chain and that it correctly handles the different options
+        # for the frame variable command in this case.
+        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_source_regexp(self, "Set break point at this line.")
+        self.runCmd("run", RUN_SUCCEEDED)
+        self.expect(
+            "thread list",
+            STOPPED_DUE_TO_BREAKPOINT,
+            substrs=["stopped", "stop reason = breakpoint"],
+        )
+
+        self.expect("frame variable f1->next", substrs=["next = NodeU @"])
+        self.expect(
+            "frame variable --ptr-depth=1 f1->next",
+            substrs=["next = NodeU @", "value = 2"],
+        )
+        self.expect(
+            "frame variable --ptr-depth=2 f1->next",
+            substrs=["next = NodeU @", "value = 1", "value = 2"],
+        )
+
+        frame = self.frame()
+        self.assertTrue(frame.IsValid())
+        self.assertEqual(
+            2,
+            frame.GetValueForVariablePath("f1->next.object.value").GetValueAsUnsigned(),
+        )
+        self.assertEqual(
+            2, frame.GetValueForVariablePath("f1->next->value").GetValueAsUnsigned()
+        )
+        self.assertEqual(
+            1,
+            frame.GetValueForVariablePath(
+                "f1->next.object.next.obj.value"
+            ).GetValueAsUnsigned(),
+        )
+        self.assertEqual(
+            1,
+            frame.GetValueForVariablePath("f1->next->next->value").GetValueAsUnsigned(),
+        )
+
+    @add_test_categories(["libstdcxx"])
+    def test_recursive_unique_ptr_libstdcxx(self):
+        self.build(dictionary={"USE_LIBSTDCPP": 1})
+        self.do_test_recursive_unique_ptr()
+
+    @add_test_categories(["libc++"])
+    def test_recursive_unique_ptr_libcxx(self):
+        self.build(dictionary={"USE_LIBCPP": 1})
+        self.do_test_recursive_unique_ptr()
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/main.cpp
similarity index 74%
rename from lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp
rename to lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/main.cpp
index afdddf0bbaf16..15e9f70dbd6aa 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/main.cpp
@@ -15,11 +15,20 @@ struct NodeU {
 // representation when the type of the second element is an empty class. So
 // we need a deleter class with a dummy data member to trigger the other path.
 struct NonEmptyIntDeleter {
-  void operator()(int* ptr) { delete ptr; }
+  void operator()(int *ptr) { delete ptr; }
 
   int dummy_ = 9999;
 };
 
+static void recursive() {
+  // Set up a structure where we have a loop in the unique_ptr chain.
+  NodeU *f1 = new NodeU{nullptr, 1};
+  NodeU *f2 = new NodeU{nullptr, 2};
+  f1->next.reset(f2);
+  f2->next.reset(f1);
+  std::puts("Set break point at this line.");
+}
+
 int main() {
   std::unique_ptr<int> up_empty;
   std::unique_ptr<int> up_int = std::make_unique<int>(10);
@@ -33,5 +42,9 @@ int main() {
       std::unique_ptr<NodeU>(new NodeU{nullptr, 2});
   ptr_node = std::unique_ptr<NodeU>(new NodeU{std::move(ptr_node), 1});
 
-  return 0; // break here
+  std::puts("// break here");
+
+  recursive();
+
+  return 0;
 }
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/Makefile
deleted file mode 100644
index bf8e6b8703f36..0000000000000
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-CXX_SOURCES := main.cpp
-
-USE_LIBSTDCPP := 1
-
-include Makefile.rules
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/TestDataFormatterStdUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/TestDataFormatterStdUniquePtr.py
deleted file mode 100644
index 8f57dc88f3187..0000000000000
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/TestDataFormatterStdUniquePtr.py
+++ /dev/null
@@ -1,134 +0,0 @@
-"""
-Test lldb data formatter subsystem.
-"""
-
-import lldb
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-
-
-class StdUniquePtrDataFormatterTestCase(TestBase):
-    @add_test_categories(["libstdcxx"])
-    @expectedFailureAll(bugnumber="llvm.org/pr50861", compiler="gcc")
-    @skipIf(oslist=["linux"], archs=["arm$", "aarch64"])
-    def test_with_run_command(self):
-        self.build()
-        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
-
-        lldbutil.run_break_set_by_source_regexp(self, "Set break point at this line.")
-        self.runCmd("run", RUN_SUCCEEDED)
-
-        # The stop reason of the thread should be breakpoint.
-        self.expect(
-            "thread list",
-            STOPPED_DUE_TO_BREAKPOINT,
-            substrs=["stopped", "stop reason = breakpoint"],
-        )
-
-        frame = self.frame()
-        self.assertTrue(frame.IsValid())
-
-        self.expect("frame variable nup", substrs=["nup = nullptr"])
-        self.expect("frame variable iup", substrs=["iup = 123"])
-        self.expect("frame variable sup", substrs=['sup = "foobar"'])
-
-        self.expect("frame variable ndp", substrs=["ndp = nullptr"])
-        self.expect(
-            "frame variable idp", substrs=["idp = 456", "deleter = ", "a = 1", "b = 2"]
-        )
-        self.expect(
-            "frame variable sdp",
-            substrs=['sdp = "baz"', "deleter = ", "a = 3", "b = 4"],
-        )
-
-        self.assertEqual(
-            123, frame.GetValueForVariablePath("iup.object").GetValueAsUnsigned()
-        )
-        self.assertEqual(
-            123, frame.GetValueForVariablePath("*iup").GetValueAsUnsigned()
-        )
-        self.assertFalse(frame.GetValueForVariablePath("iup.deleter").IsValid())
-
-        self.assertEqual(
-            '"foobar"', frame.GetValueForVariablePath("sup.object").GetSummary()
-        )
-        self.assertEqual('"foobar"', frame.GetValueForVariablePath("*sup").GetSummary())
-        self.assertFalse(frame.GetValueForVariablePath("sup.deleter").IsValid())
-
-        self.assertEqual(
-            456, frame.GetValueForVariablePath("idp.object").GetValueAsUnsigned()
-        )
-        self.assertEqual(
-            456, frame.GetValueForVariablePath("*idp").GetValueAsUnsigned()
-        )
-        self.assertEqual(
-            '"baz"', frame.GetValueForVariablePath("sdp.object").GetSummary()
-        )
-        self.assertEqual('"baz"', frame.GetValueForVariablePath("*sdp").GetSummary())
-
-        idp_deleter = frame.GetValueForVariablePath("idp.deleter")
-        self.assertTrue(idp_deleter.IsValid())
-        self.assertEqual(
-            1, idp_deleter.GetChildMemberWithName("a").GetValueAsUnsigned()
-        )
-        self.assertEqual(
-            2, idp_deleter.GetChildMemberWithName("b").GetValueAsUnsigned()
-        )
-
-        sdp_deleter = frame.GetValueForVariablePath("sdp.deleter")
-        self.assertTrue(sdp_deleter.IsValid())
-        self.assertEqual(
-            3, sdp_deleter.GetChildMemberWithName("a").GetValueAsUnsigned()
-        )
-        self.assertEqual(
-            4, sdp_deleter.GetChildMemberWithName("b").GetValueAsUnsigned()
-        )
-
-    @skipIfFreeBSD
-    @skipIfWindows  # libstdcpp not ported to Windows
-    @skipIfDarwin  # doesn't compile on Darwin
-    @skipIfwatchOS  # libstdcpp not ported to watchos
-    @skipIf(oslist=["linux"], archs=["arm$", "aarch64"])
-    @add_test_categories(["libstdcxx"])
-    def test_recursive_unique_ptr(self):
-        # Tests that LLDB can handle when we have a loop in the unique_ptr
-        # reference chain and that it correctly handles the different options
-        # for the frame variable command in this case.
-        self.build()
-        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
-
-        lldbutil.run_break_set_by_source_regexp(self, "Set break point at this line.")
-        self.runCmd("run", RUN_SUCCEEDED)
-        self.expect(
-            "thread list",
-            STOPPED_DUE_TO_BREAKPOINT,
-            substrs=["stopped", "stop reason = breakpoint"],
-        )
-
-        self.expect("frame variable f1->fp", substrs=["fp = Foo @ 0x"])
-        self.expect(
-            "frame variable --ptr-depth=1 f1->fp", substrs=["data = 2", "fp = Foo @ 0x"]
-        )
-        self.expect(
-            "frame variable --ptr-depth=2 f1->fp",
-            substrs=["data = 2", "fp = Foo @ 0x", "data = 1"],
-        )
-
-        frame = self.frame()
-        self.assertTrue(frame.IsValid())
-        self.assertEqual(
-            2, frame.GetValueForVariablePath("f1->fp.object.data").GetValueAsUnsigned()
-        )
-        self.assertEqual(
-            2, frame.GetValueForVariablePath("f1->fp->data").GetValueAsUnsigned()
-        )
-        self.assertEqual(
-            1,
-            frame.GetValueForVariablePath(
-                "f1->fp.object.fp.object.data"
-            ).GetValueAsUnsigned(),
-        )
-        self.assertEqual(
-            1, frame.GetValueForVariablePath("f1->fp->fp->data").GetValueAsUnsigned()
-        )
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/TestDataFormatterInvalidStdUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/TestDataFormatterInvalidStdUniquePtr.py
deleted file mode 100644
index 9cacfce989769..0000000000000
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/TestDataFormatterInvalidStdUniquePtr.py
+++ /dev/null
@@ -1,4 +0,0 @@
-import lldbsuite.test.lldbinline as lldbinline
-from lldbsuite.test.decorators import *
-
-lldbinline.MakeInlineTest(__file__, globals(), [no_debug_info_test])
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/main.cpp
deleted file mode 100644
index b12cab231695b..0000000000000
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/main.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-// Test that we don't crash when trying to pretty-print structures that don't
-// have the layout our data formatters expect.
-namespace std {
-template<typename T, typename Deleter = void>
-class unique_ptr {};
-}
-
-int main() {
-  std::unique_ptr<int> U;
-  return 0; //% self.expect("frame variable U", substrs=["unique_ptr", "{}"])
-}
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/main.cpp
deleted file mode 100644
index dd0072764d4e6..0000000000000
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/main.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <memory>
-#include <string>
-
-struct Deleter {
-  void operator()(void *) {}
-
-  int a;
-  int b;
-};
-
-struct Foo {
-  int data;
-  std::unique_ptr<Foo> fp;
-};
-
-int main() {
-  std::unique_ptr<char> nup;
-  std::unique_ptr<int> iup(new int{123});
-  std::unique_ptr<std::string> sup(new std::string("foobar"));
-
-  std::unique_ptr<char, Deleter> ndp;
-  std::unique_ptr<int, Deleter> idp(new int{456}, Deleter{1, 2});
-  std::unique_ptr<std::string, Deleter> sdp(new std::string("baz"),
-                                            Deleter{3, 4});
-
-  std::unique_ptr<Foo> fp(new Foo{3});
-
-  // Set up a structure where we have a loop in the unique_ptr chain.
-  Foo* f1 = new Foo{1};
-  Foo* f2 = new Foo{2};
-  f1->fp.reset(f2);
-  f2->fp.reset(f1);
-
-  return 0; // Set break point at this line.
-}



More information about the lldb-commits mailing list