[Lldb-commits] [lldb] [lldb][DataFormatter] Unwrap reference type when formatting std::unordered_map (PR #145872)
Michael Buch via lldb-commits
lldb-commits at lists.llvm.org
Thu Jun 26 05:49:36 PDT 2025
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/145872
>From f86827c1592779537b10dafcbf8b8abba4acccf2 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 26 Jun 2025 12:06:13 +0100
Subject: [PATCH 1/2] [lldb][DataFormatter] Unwrap reference type when
formatting std::unordered_map
Desugar any potential references/typedefs before checking
`isStdTemplate`. Previously, the typename might've been:
```
const std::unordered_map<...> &
```
for references. This patch gets the pointee type before grabbing the
canonical type. `GetNonReferenceType` will unwrap typedefs too, so we
should always end up with a non-reference before we get to
`GetCanonicalType`.
https://github.com/llvm/llvm-project/issues/145847
---
.../Language/CPlusPlus/LibCxxUnorderedMap.cpp | 6 +-
.../TestDataFormatterLibccUnorderedMap.py | 128 ++++++++++++++++++
.../libcxx/unordered_map/main.cpp | 13 ++
3 files changed, 145 insertions(+), 2 deletions(-)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
index ffc33395830bb..501fd0945b82c 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -113,8 +113,10 @@ CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
// wraps a std::pair. Peel away the internal wrapper type - whose structure is
// of no value to users, to expose the std::pair. This matches the structure
// returned by the std::map synthetic provider.
- if (isUnorderedMap(
- m_backend.GetCompilerType().GetCanonicalType().GetTypeName())) {
+ if (isUnorderedMap(m_backend.GetCompilerType()
+ .GetNonReferenceType()
+ .GetCanonicalType()
+ .GetTypeName())) {
std::string name;
CompilerType field_type =
element_type.GetFieldAtIndex(0, name, nullptr, nullptr, nullptr);
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/TestDataFormatterLibccUnorderedMap.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/TestDataFormatterLibccUnorderedMap.py
index c021a46a17b51..3b412996c6cb4 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/TestDataFormatterLibccUnorderedMap.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/TestDataFormatterLibccUnorderedMap.py
@@ -64,3 +64,131 @@ def test_iterator_formatters(self):
ValueCheck(name="second", summary='"Qux"'),
],
)
+
+ lldbutil.continue_to_breakpoint(process, bkpt)
+
+ # Test references to std::unordered_map
+ self.expect_var_path(
+ "ref1",
+ summary="size=2",
+ type="const StringMapT &",
+ children=[
+ ValueCheck(
+ name="[0]",
+ children=[
+ ValueCheck(name="first", summary='"Baz"'),
+ ValueCheck(name="second", summary='"Qux"'),
+ ],
+ ),
+ ValueCheck(
+ name="[1]",
+ children=[
+ ValueCheck(name="first", summary='"Foo"'),
+ ValueCheck(name="second", summary='"Bar"'),
+ ],
+ ),
+ ],
+ )
+
+ self.expect_var_path(
+ "ref2",
+ summary="size=2",
+ type="StringMapT &",
+ children=[
+ ValueCheck(
+ name="[0]",
+ children=[
+ ValueCheck(name="first", summary='"Baz"'),
+ ValueCheck(name="second", summary='"Qux"'),
+ ],
+ ),
+ ValueCheck(
+ name="[1]",
+ children=[
+ ValueCheck(name="first", summary='"Foo"'),
+ ValueCheck(name="second", summary='"Bar"'),
+ ],
+ ),
+ ],
+ )
+
+ self.expect_var_path(
+ "ref3",
+ summary="size=2",
+ type="StringMapTRef",
+ children=[
+ ValueCheck(
+ name="[0]",
+ children=[
+ ValueCheck(name="first", summary='"Baz"'),
+ ValueCheck(name="second", summary='"Qux"'),
+ ],
+ ),
+ ValueCheck(
+ name="[1]",
+ children=[
+ ValueCheck(name="first", summary='"Foo"'),
+ ValueCheck(name="second", summary='"Bar"'),
+ ],
+ ),
+ ],
+ )
+
+ self.expect_var_path(
+ "ref4",
+ summary="size=2",
+ type="const StringMapT &",
+ children=[
+ ValueCheck(
+ name="[0]",
+ children=[
+ ValueCheck(name="first", summary='"Baz"'),
+ ValueCheck(name="second", summary='"Qux"'),
+ ],
+ ),
+ ValueCheck(
+ name="[1]",
+ children=[
+ ValueCheck(name="first", summary='"Foo"'),
+ ValueCheck(name="second", summary='"Bar"'),
+ ],
+ ),
+ ],
+ )
+
+ self.expect_var_path(
+ "ref5",
+ summary="size=1",
+ type="const StringMapT &&",
+ children=[
+ ValueCheck(
+ name="[0]",
+ children=[
+ ValueCheck(name="first", summary='"Foo"'),
+ ValueCheck(name="second", summary='"Bar"'),
+ ],
+ ),
+ ],
+ )
+
+ self.expect_var_path(
+ "ref6",
+ summary="size=1",
+ type="StringMapT &&",
+ children=[
+ ValueCheck(
+ name="[0]",
+ children=[
+ ValueCheck(name="first", summary='"Baz"'),
+ ValueCheck(name="second", summary='"Qux"'),
+ ],
+ ),
+ ],
+ )
+
+ # FIXME: we're getting this wrong.
+ self.expect_var_path(
+ "ref7",
+ summary="size=0",
+ type="const StringMapT *const &",
+ )
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/main.cpp
index adcea69629770..b3bfdfbbdd7f7 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/main.cpp
@@ -3,6 +3,14 @@
#include <unordered_map>
using StringMapT = std::unordered_map<std::string, std::string>;
+using StringMapTRef = const StringMapT &;
+
+void check_references(const StringMapT &ref1, StringMapT &ref2,
+ StringMapTRef ref3, StringMapTRef &ref4,
+ const StringMapT &&ref5, StringMapT &&ref6,
+ const StringMapT *const &ref7) {
+ std::printf("Break here");
+}
int main() {
StringMapT string_map;
@@ -21,7 +29,12 @@ int main() {
StringMapT::const_iterator const_baz = string_map.find("Baz");
auto bucket_it = string_map.begin(string_map.bucket("Baz"));
auto const_bucket_it = string_map.cbegin(string_map.bucket("Baz"));
+
std::printf("Break here");
+
+ check_references(string_map, string_map, string_map, string_map,
+ StringMapT{{"Foo", "Bar"}}, StringMapT{{"Baz", "Qux"}},
+ &string_map);
}
return 0;
>From 3c23be1889009a68ab61a3842e7cb8ffca00516a Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 26 Jun 2025 13:49:06 +0100
Subject: [PATCH 2/2] fixup! add helper function in test
---
.../TestDataFormatterLibccUnorderedMap.py | 139 +++---------------
.../libcxx/unordered_map/main.cpp | 14 +-
2 files changed, 29 insertions(+), 124 deletions(-)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/TestDataFormatterLibccUnorderedMap.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/TestDataFormatterLibccUnorderedMap.py
index 3b412996c6cb4..2b1bd676a5b34 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/TestDataFormatterLibccUnorderedMap.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/TestDataFormatterLibccUnorderedMap.py
@@ -9,6 +9,22 @@
class LibcxxUnorderedMapDataFormatterTestCase(TestBase):
+ def check_reference(self, var_name: str, expected_type: str):
+ self.expect_var_path(
+ var_name,
+ summary="size=1",
+ type=expected_type,
+ children=[
+ ValueCheck(
+ name="[0]",
+ children=[
+ ValueCheck(name="first", summary='"Hello"'),
+ ValueCheck(name="second", summary='"World"'),
+ ],
+ ),
+ ],
+ )
+
@add_test_categories(["libc++"])
def test_iterator_formatters(self):
"""Test that std::unordered_map related structures are formatted correctly when printed.
@@ -68,123 +84,12 @@ def test_iterator_formatters(self):
lldbutil.continue_to_breakpoint(process, bkpt)
# Test references to std::unordered_map
- self.expect_var_path(
- "ref1",
- summary="size=2",
- type="const StringMapT &",
- children=[
- ValueCheck(
- name="[0]",
- children=[
- ValueCheck(name="first", summary='"Baz"'),
- ValueCheck(name="second", summary='"Qux"'),
- ],
- ),
- ValueCheck(
- name="[1]",
- children=[
- ValueCheck(name="first", summary='"Foo"'),
- ValueCheck(name="second", summary='"Bar"'),
- ],
- ),
- ],
- )
-
- self.expect_var_path(
- "ref2",
- summary="size=2",
- type="StringMapT &",
- children=[
- ValueCheck(
- name="[0]",
- children=[
- ValueCheck(name="first", summary='"Baz"'),
- ValueCheck(name="second", summary='"Qux"'),
- ],
- ),
- ValueCheck(
- name="[1]",
- children=[
- ValueCheck(name="first", summary='"Foo"'),
- ValueCheck(name="second", summary='"Bar"'),
- ],
- ),
- ],
- )
-
- self.expect_var_path(
- "ref3",
- summary="size=2",
- type="StringMapTRef",
- children=[
- ValueCheck(
- name="[0]",
- children=[
- ValueCheck(name="first", summary='"Baz"'),
- ValueCheck(name="second", summary='"Qux"'),
- ],
- ),
- ValueCheck(
- name="[1]",
- children=[
- ValueCheck(name="first", summary='"Foo"'),
- ValueCheck(name="second", summary='"Bar"'),
- ],
- ),
- ],
- )
-
- self.expect_var_path(
- "ref4",
- summary="size=2",
- type="const StringMapT &",
- children=[
- ValueCheck(
- name="[0]",
- children=[
- ValueCheck(name="first", summary='"Baz"'),
- ValueCheck(name="second", summary='"Qux"'),
- ],
- ),
- ValueCheck(
- name="[1]",
- children=[
- ValueCheck(name="first", summary='"Foo"'),
- ValueCheck(name="second", summary='"Bar"'),
- ],
- ),
- ],
- )
-
- self.expect_var_path(
- "ref5",
- summary="size=1",
- type="const StringMapT &&",
- children=[
- ValueCheck(
- name="[0]",
- children=[
- ValueCheck(name="first", summary='"Foo"'),
- ValueCheck(name="second", summary='"Bar"'),
- ],
- ),
- ],
- )
-
- self.expect_var_path(
- "ref6",
- summary="size=1",
- type="StringMapT &&",
- children=[
- ValueCheck(
- name="[0]",
- children=[
- ValueCheck(name="first", summary='"Baz"'),
- ValueCheck(name="second", summary='"Qux"'),
- ],
- ),
- ],
- )
+ self.check_reference("ref1", "const StringMapT &")
+ self.check_reference("ref2", "StringMapT &")
+ self.check_reference("ref3", "StringMapTRef")
+ self.check_reference("ref4", "const StringMapT &")
+ self.check_reference("ref5", "const StringMapT &&")
+ self.check_reference("ref6", "StringMapT &&")
# FIXME: we're getting this wrong.
self.expect_var_path(
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/main.cpp
index b3bfdfbbdd7f7..c581fded1ec5f 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered_map/main.cpp
@@ -5,10 +5,10 @@
using StringMapT = std::unordered_map<std::string, std::string>;
using StringMapTRef = const StringMapT &;
-void check_references(const StringMapT &ref1, StringMapT &ref2,
- StringMapTRef ref3, StringMapTRef &ref4,
- const StringMapT &&ref5, StringMapT &&ref6,
- const StringMapT *const &ref7) {
+static void check_references(const StringMapT &ref1, StringMapT &ref2,
+ StringMapTRef ref3, StringMapTRef &ref4,
+ const StringMapT &&ref5, StringMapT &&ref6,
+ const StringMapT *const &ref7) {
std::printf("Break here");
}
@@ -32,9 +32,9 @@ int main() {
std::printf("Break here");
- check_references(string_map, string_map, string_map, string_map,
- StringMapT{{"Foo", "Bar"}}, StringMapT{{"Baz", "Qux"}},
- &string_map);
+ StringMapT tmp{{"Hello", "World"}};
+ check_references(tmp, tmp, tmp, tmp, StringMapT{tmp}, StringMapT{tmp},
+ &tmp);
}
return 0;
More information about the lldb-commits
mailing list