diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index a2199cb65cd35..878b77da56939 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -1291,15 +1291,15 @@ 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( - name, eFormatterMatchExact); - }; - - category_sp->AddTypeSummary(makeSpecifier(string_ty), summary_sp); + category_sp->AddTypeSummary( + std::make_shared( + string_ty, eFormatterMatchExact), + summary_sp); category_sp->AddTypeSummary( - makeSpecifier(llvm::formatv("std::basic_string<{}>", char_ty).str()), + std::make_shared( + llvm::formatv("std::basic_string<{}>", char_ty).str(), + eFormatterMatchExact), summary_sp); category_sp->AddTypeSummary( diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp index 5289027fbd8af..0b754586aa55f 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; } 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(); 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(); + 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/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(); diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp index 52a3d98d2af4b..b3a93a0786740 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; @@ -65,14 +69,18 @@ std::optional 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; + ValueObject *parent = which_sp->GetParent(); + if (!parent) return nullptr; - // -> std::_Variant_storage - container_sp = container_sp->GetChildAtIndex(0); + + // Now go to std::_Variant_storage + ValueObjectSP container_sp = parent->GetChildAtIndex(0); if (!container_sp) return nullptr; @@ -119,8 +127,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; 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>>) 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::allocator>>) 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") 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, std::allocator>" + if self.getDebugInfo() == "pdb" + else "std::string" + ), + summary='"steph"', + ) valobj = self.expect_var_path( "si", type="std::shared_ptr", 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, std::allocator>" + 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, std::allocator>" + 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>" + 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, std::allocator>" + 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, std::allocator>, 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, std::allocator>, 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, std::equal_to, std::allocator>" + 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::allocator>, 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, std::equal_to, std::allocator>" + 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::allocator>, 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>" + 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::allocator>, std::allocator, std::allocator>>>" + 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",