[Lldb-commits] [lldb] [LLDB] Make MSVC STL formatters work with (Native/DIA) PDB (PR #150513)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Nov 5 13:59:17 PST 2025
https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/150513
>From 709ca11c5393864867812d26df7fcd7ee4462557 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 24 Jul 2025 21:38:26 +0200
Subject: [PATCH 1/8] fix(string): make spaces in matcher optional
---
.../Language/CPlusPlus/CPlusPlusLanguage.cpp | 32 ++++++++-----------
1 file changed, 13 insertions(+), 19 deletions(-)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index e69f2f677e9ab..cd7cda4c91f04 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1335,31 +1335,25 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
static void RegisterStdStringSummaryProvider(
const lldb::TypeCategoryImplSP &category_sp, llvm::StringRef string_ty,
llvm::StringRef char_ty, lldb::TypeSummaryImplSP summary_sp) {
- auto makeSpecifier = [](llvm::StringRef name) {
- return std::make_shared<lldb_private::TypeNameSpecifierImpl>(
- name, eFormatterMatchExact);
- };
-
- category_sp->AddTypeSummary(makeSpecifier(string_ty), summary_sp);
-
- // std::basic_string<char>
category_sp->AddTypeSummary(
- makeSpecifier(llvm::formatv("std::basic_string<{}>", char_ty).str()),
+ std::make_shared<lldb_private::TypeNameSpecifierImpl>(
+ string_ty, eFormatterMatchExact),
summary_sp);
- // std::basic_string<char,std::char_traits<char>,std::allocator<char> >
+
+ // std::basic_string<char>
category_sp->AddTypeSummary(
- makeSpecifier(llvm::formatv("std::basic_string<{0},std::char_traits<{0}>,"
- "std::allocator<{0}> >",
- char_ty)
- .str()),
+ std::make_shared<lldb_private::TypeNameSpecifierImpl>(
+ llvm::formatv("std::basic_string<{}>", char_ty).str(),
+ eFormatterMatchExact),
summary_sp);
- // std::basic_string<char, std::char_traits<char>, std::allocator<char> >
+ // std::basic_string<char, std::char_traits<char>, std::allocator<char>>
category_sp->AddTypeSummary(
- makeSpecifier(
- llvm::formatv("std::basic_string<{0}, std::char_traits<{0}>, "
- "std::allocator<{0}> >",
+ std::make_shared<lldb_private::TypeNameSpecifierImpl>(
+ llvm::formatv("std::basic_string<{0}, ?std::char_traits<{0}>, "
+ "?std::allocator<{0}> ?>",
char_ty)
- .str()),
+ .str(),
+ eFormatterMatchRegex),
summary_sp);
}
>From 119861a03b673ebeb0830cb3ddb7fe3fa069fefa Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 24 Jul 2025 21:39:29 +0200
Subject: [PATCH 2/8] fix(list): fallback to type of value if templates are
unavailable
---
.../Language/CPlusPlus/GenericList.cpp | 20 ++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
index ea1edbfd3ac9b..3d4dcfa3b4ff5 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
@@ -526,9 +526,17 @@ ValueObjectSP MsvcStlForwardListFrontEnd::GetChildAtIndex(uint32_t idx) {
lldb::ChildCacheState MsvcStlForwardListFrontEnd::Update() {
AbstractListFrontEnd::Update();
- if (auto head_sp =
- m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Myhead"}))
- m_head = head_sp.get();
+ auto head_sp =
+ m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Myhead"});
+ if (!head_sp)
+ return ChildCacheState::eRefetch;
+
+ m_head = head_sp.get();
+ if (!m_element_type) {
+ auto val_sp = head_sp->GetChildMemberWithName("_Myval");
+ if (val_sp)
+ m_element_type = val_sp->GetCompilerType();
+ }
return ChildCacheState::eRefetch;
}
@@ -606,6 +614,12 @@ lldb::ChildCacheState MsvcStlListFrontEnd::Update() {
m_head = first.get();
m_tail = last.get();
+ if (!m_element_type) {
+ auto val_sp = m_head->GetChildMemberWithName("_Myval");
+ if (val_sp)
+ m_element_type = val_sp->GetCompilerType();
+ }
+
return lldb::ChildCacheState::eRefetch;
}
>From 12b4e322ddf54ae3f7eb72a89dbe5d62a9ddfc8b Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 24 Jul 2025 21:41:13 +0200
Subject: [PATCH 3/8] fix(optional): try searching for _Value first
---
.../Language/CPlusPlus/GenericOptional.cpp | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
index 7fc6eb55d4e3e..f9c8c0be7420d 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
@@ -117,12 +117,16 @@ ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(uint32_t _idx) {
ValueObjectSP candidate = val_sp->GetChildMemberWithName("_M_value");
if (candidate)
val_sp = candidate;
- } else if (m_stdlib == StdLib::MsvcStl)
- // Same issue as with LibCxx
- val_sp = m_backend.GetChildMemberWithName("_Has_value")
- ->GetParent()
- ->GetChildAtIndex(0)
- ->GetChildMemberWithName("_Value");
+ } else if (m_stdlib == StdLib::MsvcStl) {
+ // PDB flattens anonymous unions to the parent
+ val_sp = m_backend.GetChildMemberWithName("_Value");
+ // With DWARF and NativePDB, same issue as with LibCxx
+ if (!val_sp)
+ val_sp = m_backend.GetChildMemberWithName("_Has_value")
+ ->GetParent()
+ ->GetChildAtIndex(0)
+ ->GetChildMemberWithName("_Value");
+ }
if (!val_sp)
return ValueObjectSP();
>From e6fda6a3920cd262eb2c89125823f31e6503549b Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 24 Jul 2025 21:41:40 +0200
Subject: [PATCH 4/8] fix(deque): fall back to element type if templates are
unvailable
---
.../Plugins/Language/CPlusPlus/MsvcStlDeque.cpp | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp
index 873354381a6da..aa313abb04be2 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp
@@ -111,13 +111,6 @@ lldb_private::formatters::MsvcStlDequeSyntheticFrontEnd::Update() {
if (!block_size.IsValid())
return lldb::eRefetch;
- auto element_type = deque_type.GetTypeTemplateArgument(0);
- if (!element_type)
- return lldb::eRefetch;
- auto element_size = element_type.GetByteSize(nullptr);
- if (!element_size)
- return lldb::eRefetch;
-
auto offset_sp = storage_sp->GetChildMemberWithName("_Myoff");
auto map_size_sp = storage_sp->GetChildMemberWithName("_Mapsize");
auto map_sp = storage_sp->GetChildMemberWithName("_Map");
@@ -138,6 +131,16 @@ lldb_private::formatters::MsvcStlDequeSyntheticFrontEnd::Update() {
if (!ok)
return lldb::eRefetch;
+ auto element_type = deque_type.GetTypeTemplateArgument(0);
+ if (!element_type) {
+ element_type = map_sp->GetCompilerType().GetPointeeType().GetPointeeType();
+ if (!element_type)
+ return lldb::eRefetch;
+ }
+ auto element_size = element_type.GetByteSize(nullptr);
+ if (!element_size)
+ return lldb::eRefetch;
+
m_map = map_sp.get();
m_exe_ctx_ref = m_backend.GetExecutionContextRef();
m_block_size = block_size.ULongLong();
>From eeef5f3cca3f51a0e02e0117017c4bbf13ae4070 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 24 Jul 2025 21:42:52 +0200
Subject: [PATCH 5/8] fix(variant): support DIA PDB
---
.../Plugins/Language/CPlusPlus/MsvcStlVariant.cpp | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
index 52a3d98d2af4b..093726bb10595 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
@@ -42,7 +42,11 @@ namespace {
// }
ValueObjectSP GetStorageMember(ValueObject &valobj, llvm::StringRef name) {
- // Find the union
+ // DIA PDB flattens the union into the storage
+ if (valobj.GetNumChildrenIgnoringErrors(3) >= 2)
+ return valobj.GetChildMemberWithName(name);
+
+ // DWARF and NativePDB: Find the union
ValueObjectSP union_sp = valobj.GetChildAtIndex(0);
if (!union_sp)
return nullptr;
@@ -119,8 +123,12 @@ bool formatters::MsvcStlVariantSummaryProvider(
storage_type = storage_type.GetTypedefedType();
CompilerType active_type = storage_type.GetTypeTemplateArgument(1, true);
- if (!active_type)
- return false;
+ if (!active_type) {
+ ValueObjectSP head = GetHead(*storage);
+ active_type = head->GetCompilerType();
+ if (!active_type)
+ return false;
+ }
stream << " Active Type = " << active_type.GetDisplayTypeName() << " ";
return true;
>From 66ab512bc28995d9e49caa233b8589d670938ab9 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 24 Jul 2025 21:43:19 +0200
Subject: [PATCH 6/8] fix(variant): support non-trivially destructable types
---
.../Language/CPlusPlus/MsvcStlVariant.cpp | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
index 093726bb10595..b3a93a0786740 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
@@ -69,14 +69,18 @@ std::optional<int64_t> GetIndexValue(ValueObject &valobj) {
}
ValueObjectSP GetNthStorage(ValueObject &outer, int64_t index) {
- // We need to find the std::_Variant_storage base class.
-
- // -> std::_SMF_control (typedef to std::_Variant_base)
- ValueObjectSP container_sp = outer.GetSP()->GetChildAtIndex(0);
- if (!container_sp)
+ // navigate "down" to std::_SMF_control/std::_Variant_base
+ // by finding the holder of "_Which". This might be down a few levels if a
+ // variant member isn't trivally destructible/copyable/etc.
+ ValueObjectSP which_sp = outer.GetChildMemberWithName("_Which");
+ if (!which_sp)
return nullptr;
- // -> std::_Variant_storage
- container_sp = container_sp->GetChildAtIndex(0);
+ ValueObject *parent = which_sp->GetParent();
+ if (!parent)
+ return nullptr;
+
+ // Now go to std::_Variant_storage
+ ValueObjectSP container_sp = parent->GetChildAtIndex(0);
if (!container_sp)
return nullptr;
>From 25baf3501bcb052f39aaeca3192c9c200c25fec1 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 24 Jul 2025 21:44:29 +0200
Subject: [PATCH 7/8] test(STL): add shell tests for STL types with PDB and
NativePDB
---
.../Shell/SymbolFile/NativePDB/stl_types.test | 188 +++++++++++++++++
lldb/test/Shell/SymbolFile/PDB/stl_types.test | 197 ++++++++++++++++++
2 files changed, 385 insertions(+)
create mode 100644 lldb/test/Shell/SymbolFile/NativePDB/stl_types.test
create mode 100644 lldb/test/Shell/SymbolFile/PDB/stl_types.test
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/stl_types.test b/lldb/test/Shell/SymbolFile/NativePDB/stl_types.test
new file mode 100644
index 0000000000000..45960a80211e0
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/stl_types.test
@@ -0,0 +1,188 @@
+# REQUIRES: target-windows
+
+# Test that LLDB can format types from MSVC's STL
+# RUN: split-file %s %t
+# RUN: %build --compiler=clang-cl --std c++20 -o %t.exe -- %t/main.cpp
+# RUN: %lldb -f %t.exe -s \
+# RUN: %t/commands.input 2>&1 | FileCheck %s
+
+#--- main.cpp
+
+#include <bitset>
+#include <coroutine>
+#include <deque>
+#include <forward_list>
+#include <list>
+#include <map>
+#include <memory>
+#include <optional>
+#include <set>
+#include <string>
+#include <tuple>
+#include <unordered_map>
+#include <unordered_set>
+#include <variant>
+#include <vector>
+
+int main() {
+ std::shared_ptr<int> sp = std::make_shared<int>(41);
+ std::weak_ptr<int> wp = sp;
+ std::unique_ptr<int> unique(new int(42));
+ std::optional<std::u16string> opt = u"abc";
+ std::string str = "str";
+ std::u8string u8str = u8"str";
+ std::wstring wStr = L"wstr";
+ std::tuple<int, bool, float> tuple{1, false, 4.2};
+ std::coroutine_handle<> coroHandle;
+ std::bitset<16> bitset(123);
+
+ std::map<int, int> map{{1, 2}, {2, 4}, {3, 6}};
+ auto mapIt = map.find(3);
+ std::set<int> set{1, 2, 3};
+ std::multimap<int, int> mMap{{1, 2}, {1, 1}, {2, 4}};
+ std::multiset<int> mSet{1, 2, 3};
+
+ std::variant<int, float, std::string, std::monostate> variant = "wow";
+ std::list<int> list{1, 2, 3};
+ std::forward_list<int> fwList{1, 2, 3};
+
+ std::unordered_map<int, int> uMap{{1, 2}, {2, 4}, {3, 6}};
+ std::unordered_set<int> uSet{1, 2, 4};
+ std::unordered_multimap<int, int> uMMap{{1, 2}, {1, 1}, {2, 4}};
+ std::unordered_multiset<int> uMSet{1, 1, 2};
+ std::deque<int> deque{1, 2, 3};
+ std::vector<int> vec{1, 2, 3};
+ return 0; // break here
+}
+
+#--- commands.input
+
+br s -p "break here"
+r
+
+fr v sp
+fr v wp
+fr v unique
+# FIXME: _Has_value is put into the anonymous union along with _Value
+# fr v opt
+fr v str
+fr v u8str
+fr v wStr
+fr v tuple
+fr v map
+fr v mapIt
+fr v set
+fr v mMap
+fr v mSet
+fr v variant
+fr v list
+fr v fwList
+fr v uMap
+fr v uSet
+fr v uMMap
+fr v uMSet
+# FIXME: Static _Block_size is found but doesn't have a value
+# fr v deque
+fr v vec
+
+quit
+
+# CHECK: (lldb) fr v sp
+# CHECK-NEXT: (std::shared_ptr<int>) sp = 41 strong=1 weak=1 {
+# CHECK-NEXT: pointer = 0x{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v wp
+# CHECK-NEXT: (std::weak_ptr<int>) wp = 41 strong=1 weak=1 {
+# CHECK-NEXT: pointer = 0x{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v unique
+# CHECK-NEXT: (std::unique_ptr<int, std::default_delete<int>>) unique = 42 {
+# CHECK-NEXT: pointer = 0x{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v str
+# CHECK-NEXT: (std::basic_string<char, std::char_traits<char>, std::allocator<char>>) str = "str"
+# CHECK-NEXT: (lldb) fr v u8str
+# CHECK-NEXT: (std::basic_string<char8_t, std::char_traits<char8_t>, std::allocator<char8_t>>) u8str = u8"str"
+# CHECK-NEXT: (lldb) fr v wStr
+# CHECK-NEXT: (std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>) wStr = L"wstr"
+# CHECK-NEXT: (lldb) fr v tuple
+# CHECK-NEXT: (std::tuple<int, bool, float>) tuple = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = false
+# CHECK-NEXT: [2] = 4.{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v map
+# CHECK-NEXT: (std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int>>>) map = size=3 {
+# CHECK-NEXT: [0] = (first = 1, second = 2)
+# CHECK-NEXT: [1] = (first = 2, second = 4)
+# CHECK-NEXT: [2] = (first = 3, second = 6)
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v mapIt
+# CHECK-NEXT: (std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<int const, int>>>>) mapIt = {
+# CHECK-NEXT: first = 3
+# CHECK-NEXT: second = 6
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v set
+# CHECK-NEXT: (std::set<int, std::less<int>, std::allocator<int>>) set = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v mMap
+# CHECK-NEXT: (std::multimap<int, int, std::less<int>, std::allocator<std::pair<int const, int>>>) mMap = size=3 {
+# CHECK-NEXT: [0] = (first = 1, second = 2)
+# CHECK-NEXT: [1] = (first = 1, second = 1)
+# CHECK-NEXT: [2] = (first = 2, second = 4)
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v mSet
+# CHECK-NEXT: (std::multiset<int, std::less<int>, std::allocator<int>>) mSet = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v variant
+# CHECK-NEXT: (std::variant<int, float, std::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::monostate>) variant = Active Type = std::basic_string<char, std::char_traits<char>, std::allocator<char>> {
+# CHECK-NEXT: Value = "wow"
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v list
+# CHECK-NEXT: (std::list<int, std::allocator<int>>) list = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v fwList
+# CHECK-NEXT: (std::forward_list<int, std::allocator<int>>) fwList = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v uMap
+# CHECK-NEXT: (std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<int const, int>>>) uMap = size=3 {
+# CHECK-NEXT: [0] = (first = 1, second = 2)
+# CHECK-NEXT: [1] = (first = 2, second = 4)
+# CHECK-NEXT: [2] = (first = 3, second = 6)
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v uSet
+# CHECK-NEXT: (std::unordered_set<int, std::hash<int>, std::equal_to<int>, std::allocator<int>>) uSet = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 4
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v uMMap
+# CHECK-NEXT: (std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<int const, int>>>) uMMap = size=3 {
+# CHECK-NEXT: [0] = (first = 1, second = 2)
+# CHECK-NEXT: [1] = (first = 1, second = 1)
+# CHECK-NEXT: [2] = (first = 2, second = 4)
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v uMSet
+# CHECK-NEXT: (std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, std::allocator<int>>) uMSet = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 1
+# CHECK-NEXT: [2] = 2
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v vec
+# CHECK-NEXT: (std::vector<int, std::allocator<int>>) vec = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
diff --git a/lldb/test/Shell/SymbolFile/PDB/stl_types.test b/lldb/test/Shell/SymbolFile/PDB/stl_types.test
new file mode 100644
index 0000000000000..0472bf5f27f06
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/PDB/stl_types.test
@@ -0,0 +1,197 @@
+# REQUIRES: target-windows
+
+# Test that LLDB can format types from MSVC's STL
+# RUN: split-file %s %t
+# RUN: %build --compiler=clang-cl --std c++20 -o %t.exe -- %t/main.cpp
+# RUN: %lldb -f %t.exe -s \
+# RUN: %t/commands.input 2>&1 | FileCheck %s
+
+#--- main.cpp
+
+#include <bitset>
+#include <coroutine>
+#include <deque>
+#include <forward_list>
+#include <list>
+#include <map>
+#include <memory>
+#include <optional>
+#include <set>
+#include <string>
+#include <tuple>
+#include <unordered_map>
+#include <unordered_set>
+#include <variant>
+#include <vector>
+
+int main() {
+ std::shared_ptr<int> sp = std::make_shared<int>(41);
+ std::weak_ptr<int> wp = sp;
+ std::unique_ptr<int> unique(new int(42));
+ std::optional<std::u16string> opt = u"abc";
+ std::string str = "str";
+ std::u8string u8str = u8"str";
+ std::wstring wStr = L"wstr";
+ std::tuple<int, bool, float> tuple{1, false, 4.2};
+ std::coroutine_handle<> coroHandle;
+ std::bitset<16> bitset(123);
+
+ std::map<int, int> map{{1, 2}, {2, 4}, {3, 6}};
+ auto mapIt = map.find(3);
+ std::set<int> set{1, 2, 3};
+ std::multimap<int, int> mMap{{1, 2}, {1, 1}, {2, 4}};
+ std::multiset<int> mSet{1, 2, 3};
+
+ std::variant<int, float, std::string, std::monostate> variant = "wow";
+ std::list<int> list{1, 2, 3};
+ std::forward_list<int> fwList{1, 2, 3};
+
+ std::unordered_map<int, int> uMap{{1, 2}, {2, 4}, {3, 6}};
+ std::unordered_set<int> uSet{1, 2, 4};
+ std::unordered_multimap<int, int> uMMap{{1, 2}, {1, 1}, {2, 4}};
+ std::unordered_multiset<int> uMSet{1, 1, 2};
+ std::deque<int> deque{1, 2, 3};
+ std::vector<int> vec{1, 2, 3};
+ return 0; // break here
+}
+
+#--- commands.input
+
+br s -p "break here"
+r
+
+fr v sp
+fr v wp
+fr v unique
+fr v opt
+fr v str
+# FIXME: char8_t is not recognized as a type -
+# the string has a void pointer/void array for SSO storage.
+# fr v u8str
+fr v wStr
+fr v tuple
+fr v map
+fr v mapIt
+fr v set
+fr v mMap
+fr v mSet
+fr v variant
+fr v list
+fr v fwList
+fr v uMap
+fr v uSet
+fr v uMMap
+fr v uMSet
+# FIXME: Static _Block_size is found but doesn't have a value
+fr v deque
+fr v vec
+
+quit
+
+# CHECK: (lldb) fr v sp
+# CHECK-NEXT: (std::shared_ptr<int>) sp = 41 strong=1 weak=1 {
+# CHECK-NEXT: pointer = 0x{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v wp
+# CHECK-NEXT: (std::weak_ptr<int>) wp = 41 strong=1 weak=1 {
+# CHECK-NEXT: pointer = 0x{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v unique
+# CHECK-NEXT: (std::unique_ptr<int,std::default_delete<int> >) unique = 42 {
+# CHECK-NEXT: pointer = 0x{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v opt
+# CHECK-NEXT: (std::optional<std::basic_string<char16_t,std::char_traits<char16_t>,std::allocator<char16_t> > >) opt = Has Value=true {
+# CHECK-NEXT: Value = u"abc"
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v str
+# CHECK-NEXT: (std::basic_string<char,std::char_traits<char>,std::allocator<char> >) str = "str"
+# CHECK-NEXT: (lldb) fr v wStr
+# CHECK-NEXT: (std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >) wStr = L"wstr"
+# CHECK-NEXT: (lldb) fr v tuple
+# CHECK-NEXT: (std::tuple<int,bool,float>) tuple = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = false
+# CHECK-NEXT: [2] = 4.{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v map
+# CHECK-NEXT: (std::map<int,int,std::less<int>,std::allocator<std::pair<const int,int> > >) map = size=3 {
+# CHECK-NEXT: [0] = (first = 1, second = 2)
+# CHECK-NEXT: [1] = (first = 2, second = 4)
+# CHECK-NEXT: [2] = (first = 3, second = 6)
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v mapIt
+# CHECK-NEXT: (std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const int,int> > > >) mapIt = {
+# CHECK-NEXT: first = 3
+# CHECK-NEXT: second = 6
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v set
+# CHECK-NEXT: (std::set<int,std::less<int>,std::allocator<int> >) set = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v mMap
+# CHECK-NEXT: (std::multimap<int,int,std::less<int>,std::allocator<std::pair<const int,int> > >) mMap = size=3 {
+# CHECK-NEXT: [0] = (first = 1, second = 2)
+# CHECK-NEXT: [1] = (first = 1, second = 1)
+# CHECK-NEXT: [2] = (first = 2, second = 4)
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v mSet
+# CHECK-NEXT: (std::multiset<int,std::less<int>,std::allocator<int> >) mSet = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v variant
+# CHECK-NEXT: (std::variant<int,float,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::monostate>) variant = Active Type = std::basic_string<char,std::char_traits<char>,std::allocator<char> > {
+# CHECK-NEXT: Value = "wow"
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v list
+# CHECK-NEXT: (std::list<int,std::allocator<int> >) list = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v fwList
+# CHECK-NEXT: (std::forward_list<int,std::allocator<int> >) fwList = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v uMap
+# CHECK-NEXT: (std::unordered_map<int,int,std::hash<int>,std::equal_to<int>,std::allocator<std::pair<const int,int> > >) uMap = size=3 {
+# CHECK-NEXT: [0] = (first = 1, second = 2)
+# CHECK-NEXT: [1] = (first = 2, second = 4)
+# CHECK-NEXT: [2] = (first = 3, second = 6)
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v uSet
+# CHECK-NEXT: (std::unordered_set<int,std::hash<int>,std::equal_to<int>,std::allocator<int> >) uSet = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 4
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v uMMap
+# CHECK-NEXT: (std::unordered_multimap<int,int,std::hash<int>,std::equal_to<int>,std::allocator<std::pair<const int,int> > >) uMMap = size=3 {
+# CHECK-NEXT: [0] = (first = 1, second = 2)
+# CHECK-NEXT: [1] = (first = 1, second = 1)
+# CHECK-NEXT: [2] = (first = 2, second = 4)
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v uMSet
+# CHECK-NEXT: (std::unordered_multiset<int,std::hash<int>,std::equal_to<int>,std::allocator<int> >) uMSet = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 1
+# CHECK-NEXT: [2] = 2
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v deque
+# CHECK-NEXT: (std::deque<int,std::allocator<int> >) deque = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v vec
+# CHECK-NEXT: (std::vector<int,std::allocator<int> >) vec = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
>From 81dac36ea620544a1862d671581611258228b1f8 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Wed, 5 Nov 2025 22:58:51 +0100
Subject: [PATCH 8/8] refactor: use API tests
---
.../Language/CPlusPlus/MsvcStlAtomic.cpp | 26 ++-
.../NativePDB/UdtRecordCompleter.cpp | 8 +-
.../atomic/TestDataFormatterStdAtomic.py | 2 +
.../deque/TestDataFormatterGenericDeque.py | 2 +
.../TestDataFormatterGenericForwardList.py | 2 +
.../list/TestDataFormatterGenericList.py | 2 +
.../generic/map/TestDataFormatterStdMap.py | 2 +
.../TestDataFormatterGenericMultiMap.py | 2 +
.../TestDataFormatterGenericMultiSet.py | 2 +
.../TestDataFormatterGenericOptional.py | 14 +-
.../set/TestDataFormatterGenericSet.py | 2 +
.../TestDataFormatterStdSharedPtr.py | 14 +-
.../string/TestDataFormatterStdString.py | 81 ++++---
.../TestDataFormatterStdStringView.py | 74 ++++---
.../tuple/TestDataFormatterStdTuple.py | 2 +
.../u8string/TestDataFormatterStdU8String.py | 16 +-
.../TestDataFormatterStdU8StringView.py | 16 +-
.../TestDataFormatterStdUniquePtr.py | 12 +-
.../TestDataFormatterGenericUnordered.py | 38 +++-
.../variant/TestDataFormatterStdVariant.py | 2 +
.../vbool/TestDataFormatterStdVBool.py | 2 +
.../vector/TestDataFormatterStdVector.py | 22 +-
.../Shell/SymbolFile/NativePDB/stl_types.test | 188 -----------------
lldb/test/Shell/SymbolFile/PDB/stl_types.test | 197 ------------------
24 files changed, 260 insertions(+), 468 deletions(-)
delete mode 100644 lldb/test/Shell/SymbolFile/NativePDB/stl_types.test
delete mode 100644 lldb/test/Shell/SymbolFile/PDB/stl_types.test
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlAtomic.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlAtomic.cpp
index 020ba10166231..fd700eee9e1a4 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlAtomic.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlAtomic.cpp
@@ -8,6 +8,7 @@
#include "MsvcStl.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
using namespace lldb;
@@ -64,10 +65,31 @@ lldb_private::formatters::MsvcStlAtomicSyntheticFrontEnd::Update() {
if (!storage_sp)
return lldb::ChildCacheState::eRefetch;
- m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0);
- if (!m_element_type)
+ CompilerType backend_type = m_backend.GetCompilerType();
+ if (!backend_type)
return lldb::ChildCacheState::eRefetch;
+ m_element_type = backend_type.GetTypeTemplateArgument(0);
+ // PDB doesn't have info about templates, so this uses the return type of
+ // `load`. Which is equivalent to the template type.
+ if (!m_element_type) {
+ auto ast_ctx = backend_type.GetTypeSystem<TypeSystemClang>();
+ if (!ast_ctx)
+ return lldb::ChildCacheState::eRefetch;
+
+ clang::CXXRecordDecl *record_decl =
+ TypeSystemClang::GetAsCXXRecordDecl(backend_type.GetOpaqueQualType());
+ for (const auto *method : record_decl->methods()) {
+ if (method->getDeclName().isIdentifier() && method->getName() == "load") {
+ m_element_type = ast_ctx->GetType(method->getReturnType());
+ break;
+ }
+ }
+
+ if (!m_element_type)
+ return lldb::ChildCacheState::eRefetch;
+ }
+
m_storage = storage_sp.get();
return lldb::ChildCacheState::eRefetch;
}
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
index 46cf9b8524ede..bfaba7f91b711 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -168,7 +168,13 @@ Error UdtRecordCompleter::visitKnownMember(
// Static constant members may be a const[expr] declaration.
// Query the symbol's value as the variable initializer if valid.
if (member_ct.IsConst() && member_ct.IsCompleteType()) {
- std::string qual_name = decl->getQualifiedNameAsString();
+ std::string qual_name;
+ if (m_record.record.kind == Member::Struct)
+ qual_name = (m_cvr.cr.Name + "::" + static_data_member.Name).str();
+ else if (m_record.record.kind == Member::Union)
+ qual_name = (m_cvr.ur.Name + "::" + static_data_member.Name).str();
+ else
+ qual_name = decl->getQualifiedNameAsString();
auto results =
m_index.globals().findRecordsByName(qual_name, m_index.symrecords());
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/TestDataFormatterStdAtomic.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/TestDataFormatterStdAtomic.py
index bdf12ca3b86db..67c2c359c9afb 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/TestDataFormatterStdAtomic.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/atomic/TestDataFormatterStdAtomic.py
@@ -10,6 +10,8 @@
class StdAtomicTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def get_variable(self, name):
var = self.frame().FindVariable(name)
var.SetPreferDynamicValue(lldb.eDynamicCanRunTarget)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/TestDataFormatterGenericDeque.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/TestDataFormatterGenericDeque.py
index 2332eff7b10dd..2b22281a87318 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/TestDataFormatterGenericDeque.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/TestDataFormatterGenericDeque.py
@@ -5,6 +5,8 @@
class GenericDequeDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def findVariable(self, name):
var = self.frame().FindVariable(name)
self.assertTrue(var.IsValid())
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py
index 45695c43b42a9..1db0c489bc7f9 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py
@@ -9,6 +9,8 @@
class TestDataFormatterGenericForwardList(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def setUp(self):
TestBase.setUp(self)
self.line = line_number("main.cpp", "// break here")
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.py
index c0207e6ab5911..fbd021190214b 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.py
@@ -10,6 +10,8 @@
class GenericListDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/map/TestDataFormatterStdMap.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/map/TestDataFormatterStdMap.py
index 07d6c963eb05d..ca2d2d6b49541 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/map/TestDataFormatterStdMap.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/map/TestDataFormatterStdMap.py
@@ -9,6 +9,8 @@
class StdMapDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def setUp(self):
TestBase.setUp(self)
ns = "ndk" if lldbplatformutil.target_is_android() else ""
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multimap/TestDataFormatterGenericMultiMap.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multimap/TestDataFormatterGenericMultiMap.py
index 7ac79714db88d..4b0854b180e0a 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multimap/TestDataFormatterGenericMultiMap.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multimap/TestDataFormatterGenericMultiMap.py
@@ -11,6 +11,8 @@
class GenericMultiMapDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def setUp(self):
TestBase.setUp(self)
self.namespace = "std"
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multiset/TestDataFormatterGenericMultiSet.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multiset/TestDataFormatterGenericMultiSet.py
index 7e922fccdf7d7..e846e072777f8 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multiset/TestDataFormatterGenericMultiSet.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multiset/TestDataFormatterGenericMultiSet.py
@@ -10,6 +10,8 @@
class GenericMultiSetDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def setUp(self):
TestBase.setUp(self)
self.namespace = "std"
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py
index 7bb4f75de4e59..c88e83bb5b1f4 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py
@@ -5,6 +5,8 @@
class GenericOptionalDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def do_test_with_run_command(self):
"""Test that that file and class static variables display correctly."""
@@ -55,7 +57,11 @@ def cleanup():
self.expect(
"frame var numbers",
substrs=[
- "(optional_int_vect) numbers = Has Value=true {",
+ (
+ "(std::optional<std::vector<int, std::allocator<int>>>) numbers = Has Value=true {"
+ if self.getDebugInfo() == "pdb"
+ else "(optional_int_vect) numbers = Has Value=true {"
+ ),
"Value = size=4 {",
"[0] = 1",
"[1] = 2",
@@ -69,7 +75,11 @@ def cleanup():
self.expect(
"frame var ostring",
substrs=[
- "(optional_string) ostring = Has Value=true {",
+ (
+ "(std::optional<std::basic_string<char, std::char_traits<char>, std::allocator<char>>>) ostring = Has Value=true {"
+ if self.getDebugInfo() == "pdb"
+ else "(optional_string) ostring = Has Value=true {"
+ ),
'Value = "hello"',
"}",
],
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/set/TestDataFormatterGenericSet.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/set/TestDataFormatterGenericSet.py
index 1ac5e323e23e3..355f0c6edba19 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/set/TestDataFormatterGenericSet.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/set/TestDataFormatterGenericSet.py
@@ -10,6 +10,8 @@
class GenericSetDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def setUp(self):
TestBase.setUp(self)
self.namespace = "std"
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/shared_ptr/TestDataFormatterStdSharedPtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/shared_ptr/TestDataFormatterStdSharedPtr.py
index d71fbf8d5f81a..2574891a7df7e 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/shared_ptr/TestDataFormatterStdSharedPtr.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/shared_ptr/TestDataFormatterStdSharedPtr.py
@@ -9,6 +9,8 @@
class TestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def do_test(self):
"""Test `frame variable` output for `std::shared_ptr` types."""
(_, process, _, bkpt) = lldbutil.run_to_source_breakpoint(
@@ -62,7 +64,7 @@ def do_test(self):
valobj = self.expect_var_path("sp_user", type="std::shared_ptr<User>")
self.assertRegex(
valobj.summary,
- "element_type @ 0x0*[1-9a-f][0-9a-f]+( strong=1)? weak=0",
+ f"{"User" if self.getDebugInfo() == "pdb" else "element_type"} @ 0x0*[1-9a-f][0-9a-f]+( strong=1)? weak=0",
)
self.assertNotEqual(valobj.child[0].unsigned, 0)
@@ -77,7 +79,15 @@ def do_test(self):
self.assertEqual(str(valobj), '(User) *pointer = (id = 30, name = "steph")')
self.expect_var_path("sp_user->id", type="int", value="30")
- self.expect_var_path("sp_user->name", type="std::string", summary='"steph"')
+ self.expect_var_path(
+ "sp_user->name",
+ type=(
+ "std::basic_string<char, std::char_traits<char>, std::allocator<char>>"
+ if self.getDebugInfo() == "pdb"
+ else "std::string"
+ ),
+ summary='"steph"',
+ )
valobj = self.expect_var_path(
"si", type="std::shared_ptr<int>", summary="47 strong=2 weak=0"
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py
index 6a27b5d2f0780..00047e419de37 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py
@@ -11,6 +11,8 @@
class StdStringDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
@@ -18,6 +20,17 @@ def setUp(self):
self.main_spec = lldb.SBFileSpec("main.cpp")
self.namespace = "std"
+ def _makeStringName(self, typedef: str, char_type: str, allocator=None):
+ if allocator is None:
+ allocator = self.namespace + "::allocator"
+
+ if self.getDebugInfo() == "pdb":
+ return f"{self.namespace}::basic_string<{char_type}, std::char_traits<{char_type}>, {allocator}<{char_type}>>"
+
+ if typedef.startswith("::"):
+ return self.namespace + typedef
+ return typedef
+
def do_test(self):
"""Test that that file and class static variables display correctly."""
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
@@ -36,10 +49,17 @@ def cleanup():
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
- ns = self.namespace
+ string_name = self._makeStringName("::string", "char")
+ wstring_name = self._makeStringName("::wstring", "wchar_t")
+ custom_string_name = self._makeStringName(
+ "CustomString", "char", allocator="CustomAlloc"
+ )
+ custom_wstring_name = self._makeStringName(
+ "CustomWString", "wchar_t", allocator="CustomAlloc"
+ )
# Check 'S' pre-assignment.
- self.expect("frame variable S", substrs=['(%s::wstring) S = L"!!!!"' % ns])
+ self.expect("frame variable S", substrs=[f'({wstring_name}) S = L"!!!!"'])
thread.StepOver()
@@ -54,34 +74,31 @@ def cleanup():
)
self.expect_expr(
- "s", result_type=ns + "::wstring", result_summary='L"hello world! מזל טוב!"'
+ "s", result_type=wstring_name, result_summary='L"hello world! מזל טוב!"'
)
- self.expect_expr(
- "q", result_type=ns + "::string", result_summary='"hello world"'
- )
+ self.expect_expr("q", result_type=string_name, result_summary='"hello world"')
self.expect_expr(
"Q",
- result_type=ns + "::string",
+ result_type=string_name,
result_summary='"quite a long std::strin with lots of info inside it"',
)
self.expect(
"frame variable",
substrs=[
- '(%s::wstring) wempty = L""' % ns,
- '(%s::wstring) s = L"hello world! מזל טוב!"' % ns,
- '(%s::wstring) S = L"!!!!!"' % ns,
+ f'({wstring_name}) wempty = L""',
+ f'({wstring_name}) s = L"hello world! מזל טוב!"',
+ f'({wstring_name}) S = L"!!!!!"',
"(const wchar_t *) mazeltov = 0x",
'L"מזל טוב"',
- '(%s::string) empty = ""' % ns,
- '(%s::string) q = "hello world"' % ns,
- '(%s::string) Q = "quite a long std::strin with lots of info inside it"'
- % ns,
- "(%s::string *) null_str = nullptr" % ns,
- '(CustomString) custom_str = "hello!"',
- '(CustomWString) custom_wstr = L"hello!"',
+ f'({string_name}) empty = ""',
+ f'({string_name}) q = "hello world"',
+ f'({string_name}) Q = "quite a long std::strin with lots of info inside it"',
+ f"({string_name} *) null_str = nullptr",
+ f'({custom_string_name}) custom_str = "hello!"',
+ f'({custom_wstring_name}) custom_wstr = L"hello!"',
],
)
@@ -136,19 +153,26 @@ def do_test_multibyte(self):
self, "Set break point at this line.", self.main_spec
)
- ns = self.namespace
+ u16string_name = self._makeStringName("::u16string", "char16_t")
+ u32string_name = self._makeStringName("::u32string", "char32_t")
+ custom_u16string_name = self._makeStringName(
+ "CustomStringU16", "char16_t", allocator="CustomAlloc"
+ )
+ custom_u32string_name = self._makeStringName(
+ "CustomStringU32", "char32_t", allocator="CustomAlloc"
+ )
self.expect(
"frame variable",
substrs=[
- '(%s::u16string) u16_string = u"ß水氶"' % ns,
- '(%s::u16string) u16_empty = u""' % ns,
- '(%s::u32string) u32_string = U"🍄🍅🍆🍌"' % ns,
- '(%s::u32string) u32_empty = U""' % ns,
- '(CustomStringU16) custom_u16 = u"ß水氶"',
- '(CustomStringU16) custom_u16_empty = u""',
- '(CustomStringU32) custom_u32 = U"🍄🍅🍆🍌"',
- '(CustomStringU32) custom_u32_empty = U""',
+ f'({u16string_name}) u16_string = u"ß水氶"',
+ f'({u16string_name}) u16_empty = u""',
+ f'({u32string_name}) u32_string = U"🍄🍅🍆🍌"',
+ f'({u32string_name}) u32_empty = U""',
+ f'({custom_u16string_name}) custom_u16 = u"ß水氶"',
+ f'({custom_u16string_name}) custom_u16_empty = u""',
+ f'({custom_u32string_name}) custom_u32 = U"🍄🍅🍆🍌"',
+ f'({custom_u32string_name}) custom_u32_empty = U""',
],
)
@@ -271,9 +295,8 @@ def do_test_embedded_null(self):
self.expect(
"frame variable",
substrs=[
- '(%s::string) IHaveEmbeddedZeros = "a\\0b\\0c\\0d"' % ns,
- '(%s::wstring) IHaveEmbeddedZerosToo = L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"'
- % ns,
+ f'({self._makeStringName("::string", "char")}) IHaveEmbeddedZeros = "a\\0b\\0c\\0d"',
+ f'({self._makeStringName("::wstring", "wchar_t")}) IHaveEmbeddedZerosToo = L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"',
],
)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py
index 181141886c5a2..884e689c21655 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py
@@ -11,6 +11,8 @@
class StdStringViewDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
@@ -20,6 +22,12 @@ def setUp(self):
"main.cpp", "// Break here to look at bad string view."
)
+ def _makeStringName(self, typedef: str, char_type: str):
+ if self.getDebugInfo() == "pdb":
+ return f"std::basic_string_view<{char_type}, std::char_traits<{char_type}>>"
+
+ return typedef
+
def do_test(self):
"""Test that that file and class static variables display correctly."""
self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
@@ -51,39 +59,49 @@ def cleanup():
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
- self.expect_var_path("wempty", type="std::wstring_view", summary='L""')
+ string_view_name = self._makeStringName("std::string_view", "char")
+ wstring_view_name = self._makeStringName("std::wstring_view", "wchar_t")
+ u16string_view_name = self._makeStringName("std::u16string_view", "char16_t")
+ u32string_view_name = self._makeStringName("std::u32string_view", "char32_t")
+ string_name = (
+ "std::basic_string<char, std::char_traits<char>, std::allocator<char>>"
+ if self.getDebugInfo() == "pdb"
+ else "std::string"
+ )
+
+ self.expect_var_path("wempty", type=wstring_view_name, summary='L""')
self.expect_var_path(
- "s", type="std::wstring_view", summary='L"hello world! מזל טוב!"'
+ "s", type=wstring_view_name, summary='L"hello world! מזל טוב!"'
)
- self.expect_var_path("S", type="std::wstring_view", summary='L"!!!!"')
- self.expect_var_path("empty", type="std::string_view", summary='""')
- self.expect_var_path("q_source", type="std::string", summary='"hello world"')
- self.expect_var_path("q", type="std::string_view", summary='"hello world"')
+ self.expect_var_path("S", type=wstring_view_name, summary='L"!!!!"')
+ self.expect_var_path("empty", type=string_view_name, summary='""')
+ self.expect_var_path("q_source", type=string_name, summary='"hello world"')
+ self.expect_var_path("q", type=string_view_name, summary='"hello world"')
self.expect_var_path(
"Q",
- type="std::string_view",
+ type=string_view_name,
summary='"quite a long std::strin with lots of info inside it"',
)
self.expect_var_path(
- "IHaveEmbeddedZeros", type="std::string_view", summary='"a\\0b\\0c\\0d"'
+ "IHaveEmbeddedZeros", type=string_view_name, summary='"a\\0b\\0c\\0d"'
)
self.expect_var_path(
"IHaveEmbeddedZerosToo",
- type="std::wstring_view",
+ type=wstring_view_name,
summary='L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"',
)
- self.expect_var_path("u16_string", type="std::u16string_view", summary='u"ß水氶"')
- self.expect_var_path("u16_empty", type="std::u16string_view", summary='u""')
+ self.expect_var_path("u16_string", type=u16string_view_name, summary='u"ß水氶"')
+ self.expect_var_path("u16_empty", type=u16string_view_name, summary='u""')
self.expect_var_path(
- "u32_string", type="std::u32string_view", summary='U"🍄🍅🍆🍌"'
+ "u32_string", type=u32string_view_name, summary='U"🍄🍅🍆🍌"'
)
- self.expect_var_path("u32_empty", type="std::u32string_view", summary='U""')
+ self.expect_var_path("u32_empty", type=u32string_view_name, summary='U""')
# GetSummary returns None so can't be checked by expect_var_path, so we
# use the str representation instead
null_obj = self.frame().GetValueForVariablePath("null_str")
self.assertEqual(null_obj.GetSummary(), "Summary Unavailable")
- self.assertEqual(str(null_obj), "(std::string_view *) null_str = nullptr")
+ self.assertEqual(str(null_obj), f"({string_view_name} *) null_str = nullptr")
self.runCmd("n")
@@ -108,37 +126,37 @@ def cleanup():
self.expect_expr(
"s",
- result_type="std::wstring_view",
+ result_type=wstring_view_name,
result_summary='L"hello world! מזל טוב!"',
)
- self.expect_var_path("wempty", type="std::wstring_view", summary='L""')
+ self.expect_var_path("wempty", type=wstring_view_name, summary='L""')
self.expect_var_path(
- "s", type="std::wstring_view", summary='L"hello world! מזל טוב!"'
+ "s", type=wstring_view_name, summary='L"hello world! מזל טוב!"'
)
- self.expect_var_path("S", type="std::wstring_view", summary='L"!!!!"')
- self.expect_var_path("empty", type="std::string_view", summary='""')
- self.expect_var_path("q_source", type="std::string", summary='"Hello world"')
- self.expect_var_path("q", type="std::string_view", summary='"Hello world"')
+ self.expect_var_path("S", type=wstring_view_name, summary='L"!!!!"')
+ self.expect_var_path("empty", type=string_view_name, summary='""')
+ self.expect_var_path("q_source", type=string_name, summary='"Hello world"')
+ self.expect_var_path("q", type=string_view_name, summary='"Hello world"')
self.expect_var_path(
"Q",
- type="std::string_view",
+ type=string_view_name,
summary='"quite a long std::strin with lots of info inside it"',
)
self.expect_var_path(
- "IHaveEmbeddedZeros", type="std::string_view", summary='"a\\0b\\0c\\0d"'
+ "IHaveEmbeddedZeros", type=string_view_name, summary='"a\\0b\\0c\\0d"'
)
self.expect_var_path(
"IHaveEmbeddedZerosToo",
- type="std::wstring_view",
+ type=wstring_view_name,
summary='L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"',
)
- self.expect_var_path("u16_string", type="std::u16string_view", summary='u"ß水氶"')
- self.expect_var_path("u16_empty", type="std::u16string_view", summary='u""')
+ self.expect_var_path("u16_string", type=u16string_view_name, summary='u"ß水氶"')
+ self.expect_var_path("u16_empty", type=u16string_view_name, summary='u""')
self.expect_var_path(
- "u32_string", type="std::u32string_view", summary='U"🍄🍅🍆🍌"'
+ "u32_string", type=u32string_view_name, summary='U"🍄🍅🍆🍌"'
)
- self.expect_var_path("u32_empty", type="std::u32string_view", summary='U""')
+ self.expect_var_path("u32_empty", type=u32string_view_name, summary='U""')
self.runCmd("cont")
self.expect(
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/tuple/TestDataFormatterStdTuple.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/tuple/TestDataFormatterStdTuple.py
index b23d549fe4c18..898438729ff8f 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/tuple/TestDataFormatterStdTuple.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/tuple/TestDataFormatterStdTuple.py
@@ -9,6 +9,8 @@
class TestDataFormatterStdTuple(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def setUp(self):
TestBase.setUp(self)
self.line = line_number("main.cpp", "// break here")
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string/TestDataFormatterStdU8String.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string/TestDataFormatterStdU8String.py
index b983ee175d389..dda97945f9b23 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string/TestDataFormatterStdU8String.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string/TestDataFormatterStdU8String.py
@@ -11,18 +11,26 @@
class StdU8StringDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def do_test(self):
lldbutil.run_to_source_breakpoint(
self, "Set break point at this line.", lldb.SBFileSpec("main.cpp")
)
+ string_name = (
+ "std::basic_string<char8_t, std::char_traits<char8_t>, std::allocator<char8_t>>"
+ if self.getDebugInfo() == "pdb"
+ else "std::u8string"
+ )
+
self.expect(
"frame variable",
substrs=[
- '(std::u8string) u8_string_small = u8"🍄"',
- '(std::u8string) u8_string = u8"❤️👍📄📁😃🧑🌾"',
- '(std::u8string) u8_empty = u8""',
- '(std::u8string) u8_text = u8"ABCd"',
+ f'({string_name}) u8_string_small = u8"🍄"',
+ f'({string_name}) u8_string = u8"❤️👍📄📁😃🧑🌾"',
+ f'({string_name}) u8_empty = u8""',
+ f'({string_name}) u8_text = u8"ABCd"',
],
)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py
index 1e35a0f6bb040..6cf72d18a864f 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py
@@ -11,18 +11,26 @@
class StdU8StringViewDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def do_test(self):
lldbutil.run_to_source_breakpoint(
self, "Set break point at this line.", lldb.SBFileSpec("main.cpp")
)
+ string_view_name = (
+ "std::basic_string_view<char8_t, std::char_traits<char8_t>>"
+ if self.getDebugInfo() == "pdb"
+ else "std::u8string_view"
+ )
+
self.expect(
"frame variable",
substrs=[
- '(std::u8string_view) u8_string_small = u8"🍄"',
- '(std::u8string_view) u8_string = u8"❤️👍📄📁😃🧑🌾"',
- '(std::u8string_view) u8_empty = u8""',
- '(std::u8string_view) u8_text = u8"ABCd"',
+ f'({string_view_name}) u8_string_small = u8"🍄"',
+ f'({string_view_name}) u8_string = u8"❤️👍📄📁😃🧑🌾"',
+ f'({string_view_name}) u8_empty = u8""',
+ f'({string_view_name}) u8_text = u8"ABCd"',
],
)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py
index 0b68b1b532bb0..1516db698798d 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py
@@ -9,6 +9,8 @@
class TestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def do_test(self):
"""Test `frame variable` output for `std::unique_ptr` types."""
@@ -84,7 +86,15 @@ def do_test(self):
self.assertNotEqual(valobj.child[0].unsigned, 0)
self.expect_var_path("up_user->id", type="int", value="30")
- self.expect_var_path("up_user->name", type="std::string", summary='"steph"')
+ self.expect_var_path(
+ "up_user->name",
+ type=(
+ "std::basic_string<char, std::char_traits<char>, std::allocator<char>>"
+ if self.getDebugInfo() == "pdb"
+ else "std::string"
+ ),
+ summary='"steph"',
+ )
self.runCmd("settings set target.experimental.use-DIL true")
self.expect_var_path("ptr_node->value", value="1")
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py
index dd740bd43b063..239ffa2f6149b 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py
@@ -4,6 +4,8 @@
class GenericUnorderedDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def setUp(self):
TestBase.setUp(self)
self.namespace = "std"
@@ -49,7 +51,11 @@ def cleanup():
self.look_for_content_and_continue(
"map",
[
- "UnorderedMap",
+ (
+ "std::unordered_map<int, std::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::hash" # ...
+ if self.getDebugInfo() == "pdb"
+ else "UnorderedMap"
+ ),
children_are_key_value,
"size=5 {",
"hello",
@@ -63,7 +69,11 @@ def cleanup():
self.look_for_content_and_continue(
"mmap",
[
- "UnorderedMultiMap",
+ (
+ "std::unordered_multimap<int, std::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::hash" # ...
+ if self.getDebugInfo() == "pdb"
+ else "UnorderedMultiMap"
+ ),
children_are_key_value,
"size=6 {",
"first = 3",
@@ -76,7 +86,11 @@ def cleanup():
self.look_for_content_and_continue(
"iset",
[
- "IntsUnorderedSet",
+ (
+ "std::unordered_set<int, std::hash<int>, std::equal_to<int>, std::allocator<int>>"
+ if self.getDebugInfo() == "pdb"
+ else "IntsUnorderedSet"
+ ),
"size=5 {",
r"\[\d\] = 5",
r"\[\d\] = 3",
@@ -87,7 +101,11 @@ def cleanup():
self.look_for_content_and_continue(
"sset",
[
- "StringsUnorderedSet",
+ (
+ "std::unordered_set<std::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::hash" # ...
+ if self.getDebugInfo() == "pdb"
+ else "StringsUnorderedSet"
+ ),
"size=5 {",
r'\[\d\] = "is"',
r'\[\d\] = "world"',
@@ -98,7 +116,11 @@ def cleanup():
self.look_for_content_and_continue(
"imset",
[
- "IntsUnorderedMultiSet",
+ (
+ "std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, std::allocator<int>>"
+ if self.getDebugInfo() == "pdb"
+ else "IntsUnorderedMultiSet"
+ ),
"size=6 {",
"(\\[\\d\\] = 3(\\n|.)+){3}",
r"\[\d\] = 2",
@@ -109,7 +131,11 @@ def cleanup():
self.look_for_content_and_continue(
"smset",
[
- "StringsUnorderedMultiSet",
+ (
+ "std::unordered_multiset<std::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::hash" # ...
+ if self.getDebugInfo() == "pdb"
+ else "StringsUnorderedMultiSet"
+ ),
"size=5 {",
'(\\[\\d\\] = "is"(\\n|.)+){2}',
'(\\[\\d\\] = "world"(\\n|.)+){2}',
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/variant/TestDataFormatterStdVariant.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/variant/TestDataFormatterStdVariant.py
index 9f32ad97c1f0a..1ae07a91dfe3d 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/variant/TestDataFormatterStdVariant.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/variant/TestDataFormatterStdVariant.py
@@ -9,6 +9,8 @@
class StdVariantDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def do_test(self):
"""Test that that file and class static variables display correctly."""
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/vbool/TestDataFormatterStdVBool.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/vbool/TestDataFormatterStdVBool.py
index dd142d2be193b..f74092ca3a0b8 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/vbool/TestDataFormatterStdVBool.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/vbool/TestDataFormatterStdVBool.py
@@ -9,6 +9,8 @@
class StdVBoolDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/vector/TestDataFormatterStdVector.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/vector/TestDataFormatterStdVector.py
index d4da60f86a315..ab2e8a7ceb37d 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/vector/TestDataFormatterStdVector.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/vector/TestDataFormatterStdVector.py
@@ -9,6 +9,8 @@
class StdVectorDataFormatterTestCase(TestBase):
+ TEST_WITH_PDB_DEBUG_INFO = True
+
def check_numbers(self, var_name, show_ptr=False):
patterns = []
substrs = [
@@ -106,19 +108,25 @@ def cleanup():
],
)
+ int_vect = (
+ "std::vector<int, std::allocator<int>>"
+ if self.getDebugInfo() == "pdb"
+ else "int_vect"
+ )
+
# check access to synthetic children
self.runCmd(
- 'type summary add --summary-string "item 0 is ${var[0]}" std::int_vect int_vect'
+ f'type summary add --summary-string "item 0 is ${{var[0]}}" std::int_vect "{int_vect}"'
)
self.expect("frame variable numbers", substrs=["item 0 is 1"])
self.runCmd(
- 'type summary add --summary-string "item 0 is ${svar[0]}" std::int_vect int_vect'
+ f'type summary add --summary-string "item 0 is ${{svar[0]}}" std::int_vect "{int_vect}"'
)
self.expect("frame variable numbers", substrs=["item 0 is 1"])
# move on with synths
self.runCmd("type summary delete std::int_vect")
- self.runCmd("type summary delete int_vect")
+ self.runCmd(f'type summary delete "{int_vect}"')
# add some more data
lldbutil.continue_to_breakpoint(process, bkpt)
@@ -142,9 +150,15 @@ def cleanup():
self.expect("expression strings", substrs=["goofy", "is", "smart"])
+ string_vect = (
+ "std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char>>>>"
+ if self.getDebugInfo() == "pdb"
+ else "string_vect"
+ )
+
# test summaries based on synthetic children
self.runCmd(
- 'type summary add std::string_vect string_vect --summary-string "vector has ${svar%#} items" -e'
+ f'type summary add std::string_vect "{string_vect}" --summary-string "vector has ${{svar%#}} items" -e'
)
self.expect(
"frame variable strings",
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/stl_types.test b/lldb/test/Shell/SymbolFile/NativePDB/stl_types.test
deleted file mode 100644
index 45960a80211e0..0000000000000
--- a/lldb/test/Shell/SymbolFile/NativePDB/stl_types.test
+++ /dev/null
@@ -1,188 +0,0 @@
-# REQUIRES: target-windows
-
-# Test that LLDB can format types from MSVC's STL
-# RUN: split-file %s %t
-# RUN: %build --compiler=clang-cl --std c++20 -o %t.exe -- %t/main.cpp
-# RUN: %lldb -f %t.exe -s \
-# RUN: %t/commands.input 2>&1 | FileCheck %s
-
-#--- main.cpp
-
-#include <bitset>
-#include <coroutine>
-#include <deque>
-#include <forward_list>
-#include <list>
-#include <map>
-#include <memory>
-#include <optional>
-#include <set>
-#include <string>
-#include <tuple>
-#include <unordered_map>
-#include <unordered_set>
-#include <variant>
-#include <vector>
-
-int main() {
- std::shared_ptr<int> sp = std::make_shared<int>(41);
- std::weak_ptr<int> wp = sp;
- std::unique_ptr<int> unique(new int(42));
- std::optional<std::u16string> opt = u"abc";
- std::string str = "str";
- std::u8string u8str = u8"str";
- std::wstring wStr = L"wstr";
- std::tuple<int, bool, float> tuple{1, false, 4.2};
- std::coroutine_handle<> coroHandle;
- std::bitset<16> bitset(123);
-
- std::map<int, int> map{{1, 2}, {2, 4}, {3, 6}};
- auto mapIt = map.find(3);
- std::set<int> set{1, 2, 3};
- std::multimap<int, int> mMap{{1, 2}, {1, 1}, {2, 4}};
- std::multiset<int> mSet{1, 2, 3};
-
- std::variant<int, float, std::string, std::monostate> variant = "wow";
- std::list<int> list{1, 2, 3};
- std::forward_list<int> fwList{1, 2, 3};
-
- std::unordered_map<int, int> uMap{{1, 2}, {2, 4}, {3, 6}};
- std::unordered_set<int> uSet{1, 2, 4};
- std::unordered_multimap<int, int> uMMap{{1, 2}, {1, 1}, {2, 4}};
- std::unordered_multiset<int> uMSet{1, 1, 2};
- std::deque<int> deque{1, 2, 3};
- std::vector<int> vec{1, 2, 3};
- return 0; // break here
-}
-
-#--- commands.input
-
-br s -p "break here"
-r
-
-fr v sp
-fr v wp
-fr v unique
-# FIXME: _Has_value is put into the anonymous union along with _Value
-# fr v opt
-fr v str
-fr v u8str
-fr v wStr
-fr v tuple
-fr v map
-fr v mapIt
-fr v set
-fr v mMap
-fr v mSet
-fr v variant
-fr v list
-fr v fwList
-fr v uMap
-fr v uSet
-fr v uMMap
-fr v uMSet
-# FIXME: Static _Block_size is found but doesn't have a value
-# fr v deque
-fr v vec
-
-quit
-
-# CHECK: (lldb) fr v sp
-# CHECK-NEXT: (std::shared_ptr<int>) sp = 41 strong=1 weak=1 {
-# CHECK-NEXT: pointer = 0x{{.*}}
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v wp
-# CHECK-NEXT: (std::weak_ptr<int>) wp = 41 strong=1 weak=1 {
-# CHECK-NEXT: pointer = 0x{{.*}}
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v unique
-# CHECK-NEXT: (std::unique_ptr<int, std::default_delete<int>>) unique = 42 {
-# CHECK-NEXT: pointer = 0x{{.*}}
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v str
-# CHECK-NEXT: (std::basic_string<char, std::char_traits<char>, std::allocator<char>>) str = "str"
-# CHECK-NEXT: (lldb) fr v u8str
-# CHECK-NEXT: (std::basic_string<char8_t, std::char_traits<char8_t>, std::allocator<char8_t>>) u8str = u8"str"
-# CHECK-NEXT: (lldb) fr v wStr
-# CHECK-NEXT: (std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>) wStr = L"wstr"
-# CHECK-NEXT: (lldb) fr v tuple
-# CHECK-NEXT: (std::tuple<int, bool, float>) tuple = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = false
-# CHECK-NEXT: [2] = 4.{{.*}}
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v map
-# CHECK-NEXT: (std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int>>>) map = size=3 {
-# CHECK-NEXT: [0] = (first = 1, second = 2)
-# CHECK-NEXT: [1] = (first = 2, second = 4)
-# CHECK-NEXT: [2] = (first = 3, second = 6)
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v mapIt
-# CHECK-NEXT: (std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<int const, int>>>>) mapIt = {
-# CHECK-NEXT: first = 3
-# CHECK-NEXT: second = 6
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v set
-# CHECK-NEXT: (std::set<int, std::less<int>, std::allocator<int>>) set = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 2
-# CHECK-NEXT: [2] = 3
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v mMap
-# CHECK-NEXT: (std::multimap<int, int, std::less<int>, std::allocator<std::pair<int const, int>>>) mMap = size=3 {
-# CHECK-NEXT: [0] = (first = 1, second = 2)
-# CHECK-NEXT: [1] = (first = 1, second = 1)
-# CHECK-NEXT: [2] = (first = 2, second = 4)
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v mSet
-# CHECK-NEXT: (std::multiset<int, std::less<int>, std::allocator<int>>) mSet = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 2
-# CHECK-NEXT: [2] = 3
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v variant
-# CHECK-NEXT: (std::variant<int, float, std::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::monostate>) variant = Active Type = std::basic_string<char, std::char_traits<char>, std::allocator<char>> {
-# CHECK-NEXT: Value = "wow"
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v list
-# CHECK-NEXT: (std::list<int, std::allocator<int>>) list = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 2
-# CHECK-NEXT: [2] = 3
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v fwList
-# CHECK-NEXT: (std::forward_list<int, std::allocator<int>>) fwList = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 2
-# CHECK-NEXT: [2] = 3
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v uMap
-# CHECK-NEXT: (std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<int const, int>>>) uMap = size=3 {
-# CHECK-NEXT: [0] = (first = 1, second = 2)
-# CHECK-NEXT: [1] = (first = 2, second = 4)
-# CHECK-NEXT: [2] = (first = 3, second = 6)
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v uSet
-# CHECK-NEXT: (std::unordered_set<int, std::hash<int>, std::equal_to<int>, std::allocator<int>>) uSet = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 2
-# CHECK-NEXT: [2] = 4
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v uMMap
-# CHECK-NEXT: (std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<int const, int>>>) uMMap = size=3 {
-# CHECK-NEXT: [0] = (first = 1, second = 2)
-# CHECK-NEXT: [1] = (first = 1, second = 1)
-# CHECK-NEXT: [2] = (first = 2, second = 4)
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v uMSet
-# CHECK-NEXT: (std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, std::allocator<int>>) uMSet = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 1
-# CHECK-NEXT: [2] = 2
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v vec
-# CHECK-NEXT: (std::vector<int, std::allocator<int>>) vec = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 2
-# CHECK-NEXT: [2] = 3
-# CHECK-NEXT: }
diff --git a/lldb/test/Shell/SymbolFile/PDB/stl_types.test b/lldb/test/Shell/SymbolFile/PDB/stl_types.test
deleted file mode 100644
index 0472bf5f27f06..0000000000000
--- a/lldb/test/Shell/SymbolFile/PDB/stl_types.test
+++ /dev/null
@@ -1,197 +0,0 @@
-# REQUIRES: target-windows
-
-# Test that LLDB can format types from MSVC's STL
-# RUN: split-file %s %t
-# RUN: %build --compiler=clang-cl --std c++20 -o %t.exe -- %t/main.cpp
-# RUN: %lldb -f %t.exe -s \
-# RUN: %t/commands.input 2>&1 | FileCheck %s
-
-#--- main.cpp
-
-#include <bitset>
-#include <coroutine>
-#include <deque>
-#include <forward_list>
-#include <list>
-#include <map>
-#include <memory>
-#include <optional>
-#include <set>
-#include <string>
-#include <tuple>
-#include <unordered_map>
-#include <unordered_set>
-#include <variant>
-#include <vector>
-
-int main() {
- std::shared_ptr<int> sp = std::make_shared<int>(41);
- std::weak_ptr<int> wp = sp;
- std::unique_ptr<int> unique(new int(42));
- std::optional<std::u16string> opt = u"abc";
- std::string str = "str";
- std::u8string u8str = u8"str";
- std::wstring wStr = L"wstr";
- std::tuple<int, bool, float> tuple{1, false, 4.2};
- std::coroutine_handle<> coroHandle;
- std::bitset<16> bitset(123);
-
- std::map<int, int> map{{1, 2}, {2, 4}, {3, 6}};
- auto mapIt = map.find(3);
- std::set<int> set{1, 2, 3};
- std::multimap<int, int> mMap{{1, 2}, {1, 1}, {2, 4}};
- std::multiset<int> mSet{1, 2, 3};
-
- std::variant<int, float, std::string, std::monostate> variant = "wow";
- std::list<int> list{1, 2, 3};
- std::forward_list<int> fwList{1, 2, 3};
-
- std::unordered_map<int, int> uMap{{1, 2}, {2, 4}, {3, 6}};
- std::unordered_set<int> uSet{1, 2, 4};
- std::unordered_multimap<int, int> uMMap{{1, 2}, {1, 1}, {2, 4}};
- std::unordered_multiset<int> uMSet{1, 1, 2};
- std::deque<int> deque{1, 2, 3};
- std::vector<int> vec{1, 2, 3};
- return 0; // break here
-}
-
-#--- commands.input
-
-br s -p "break here"
-r
-
-fr v sp
-fr v wp
-fr v unique
-fr v opt
-fr v str
-# FIXME: char8_t is not recognized as a type -
-# the string has a void pointer/void array for SSO storage.
-# fr v u8str
-fr v wStr
-fr v tuple
-fr v map
-fr v mapIt
-fr v set
-fr v mMap
-fr v mSet
-fr v variant
-fr v list
-fr v fwList
-fr v uMap
-fr v uSet
-fr v uMMap
-fr v uMSet
-# FIXME: Static _Block_size is found but doesn't have a value
-fr v deque
-fr v vec
-
-quit
-
-# CHECK: (lldb) fr v sp
-# CHECK-NEXT: (std::shared_ptr<int>) sp = 41 strong=1 weak=1 {
-# CHECK-NEXT: pointer = 0x{{.*}}
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v wp
-# CHECK-NEXT: (std::weak_ptr<int>) wp = 41 strong=1 weak=1 {
-# CHECK-NEXT: pointer = 0x{{.*}}
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v unique
-# CHECK-NEXT: (std::unique_ptr<int,std::default_delete<int> >) unique = 42 {
-# CHECK-NEXT: pointer = 0x{{.*}}
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v opt
-# CHECK-NEXT: (std::optional<std::basic_string<char16_t,std::char_traits<char16_t>,std::allocator<char16_t> > >) opt = Has Value=true {
-# CHECK-NEXT: Value = u"abc"
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v str
-# CHECK-NEXT: (std::basic_string<char,std::char_traits<char>,std::allocator<char> >) str = "str"
-# CHECK-NEXT: (lldb) fr v wStr
-# CHECK-NEXT: (std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >) wStr = L"wstr"
-# CHECK-NEXT: (lldb) fr v tuple
-# CHECK-NEXT: (std::tuple<int,bool,float>) tuple = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = false
-# CHECK-NEXT: [2] = 4.{{.*}}
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v map
-# CHECK-NEXT: (std::map<int,int,std::less<int>,std::allocator<std::pair<const int,int> > >) map = size=3 {
-# CHECK-NEXT: [0] = (first = 1, second = 2)
-# CHECK-NEXT: [1] = (first = 2, second = 4)
-# CHECK-NEXT: [2] = (first = 3, second = 6)
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v mapIt
-# CHECK-NEXT: (std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const int,int> > > >) mapIt = {
-# CHECK-NEXT: first = 3
-# CHECK-NEXT: second = 6
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v set
-# CHECK-NEXT: (std::set<int,std::less<int>,std::allocator<int> >) set = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 2
-# CHECK-NEXT: [2] = 3
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v mMap
-# CHECK-NEXT: (std::multimap<int,int,std::less<int>,std::allocator<std::pair<const int,int> > >) mMap = size=3 {
-# CHECK-NEXT: [0] = (first = 1, second = 2)
-# CHECK-NEXT: [1] = (first = 1, second = 1)
-# CHECK-NEXT: [2] = (first = 2, second = 4)
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v mSet
-# CHECK-NEXT: (std::multiset<int,std::less<int>,std::allocator<int> >) mSet = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 2
-# CHECK-NEXT: [2] = 3
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v variant
-# CHECK-NEXT: (std::variant<int,float,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::monostate>) variant = Active Type = std::basic_string<char,std::char_traits<char>,std::allocator<char> > {
-# CHECK-NEXT: Value = "wow"
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v list
-# CHECK-NEXT: (std::list<int,std::allocator<int> >) list = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 2
-# CHECK-NEXT: [2] = 3
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v fwList
-# CHECK-NEXT: (std::forward_list<int,std::allocator<int> >) fwList = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 2
-# CHECK-NEXT: [2] = 3
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v uMap
-# CHECK-NEXT: (std::unordered_map<int,int,std::hash<int>,std::equal_to<int>,std::allocator<std::pair<const int,int> > >) uMap = size=3 {
-# CHECK-NEXT: [0] = (first = 1, second = 2)
-# CHECK-NEXT: [1] = (first = 2, second = 4)
-# CHECK-NEXT: [2] = (first = 3, second = 6)
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v uSet
-# CHECK-NEXT: (std::unordered_set<int,std::hash<int>,std::equal_to<int>,std::allocator<int> >) uSet = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 2
-# CHECK-NEXT: [2] = 4
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v uMMap
-# CHECK-NEXT: (std::unordered_multimap<int,int,std::hash<int>,std::equal_to<int>,std::allocator<std::pair<const int,int> > >) uMMap = size=3 {
-# CHECK-NEXT: [0] = (first = 1, second = 2)
-# CHECK-NEXT: [1] = (first = 1, second = 1)
-# CHECK-NEXT: [2] = (first = 2, second = 4)
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v uMSet
-# CHECK-NEXT: (std::unordered_multiset<int,std::hash<int>,std::equal_to<int>,std::allocator<int> >) uMSet = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 1
-# CHECK-NEXT: [2] = 2
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v deque
-# CHECK-NEXT: (std::deque<int,std::allocator<int> >) deque = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 2
-# CHECK-NEXT: [2] = 3
-# CHECK-NEXT: }
-# CHECK-NEXT: (lldb) fr v vec
-# CHECK-NEXT: (std::vector<int,std::allocator<int> >) vec = size=3 {
-# CHECK-NEXT: [0] = 1
-# CHECK-NEXT: [1] = 2
-# CHECK-NEXT: [2] = 3
-# CHECK-NEXT: }
More information about the lldb-commits
mailing list