https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/150318
>From 87f45bf97c50a7478fded9702972a83f667c1f68 Mon Sep 17 00:00:00 2001 From: Nerixyz <nerix...@outlook.de> Date: Wed, 23 Jul 2025 22:31:28 +0200 Subject: [PATCH 1/2] [LLDB] Add formatters for MSVC STL std::string_view and friends --- .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 52 ++++++++++++++++ .../Plugins/Language/CPlusPlus/MsvcStl.cpp | 61 +++++++++++++++++++ .../Plugins/Language/CPlusPlus/MsvcStl.h | 9 +++ .../TestDataFormatterStdStringView.py | 16 +++-- .../generic/string_view/main.cpp | 1 - .../generic/u8string_view/Makefile | 4 ++ .../TestDataFormatterStdU8StringView.py | 44 +++++++++++++ .../generic/u8string_view/main.cpp | 12 ++++ 8 files changed, 193 insertions(+), 6 deletions(-) create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/Makefile create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/main.cpp diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index e69f2f677e9ab..46753c5efc331 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -1363,6 +1363,28 @@ static void RegisterStdStringSummaryProvider( summary_sp); } +static void RegisterStdStringViewSummaryProvider( + const lldb::TypeCategoryImplSP &category_sp, llvm::StringRef string_ty, + llvm::StringRef char_ty, lldb::TypeSummaryImplSP summary_sp) { + // std::string_view + category_sp->AddTypeSummary( + std::make_shared<lldb_private::TypeNameSpecifierImpl>( + string_ty, eFormatterMatchExact), + summary_sp); + + // std::basic_string_view<char, std::char_traits<char>> + // NativePDB has spaces at different positions compared to PDB and DWARF, so + // use a regex and make them optional. + category_sp->AddTypeSummary( + std::make_shared<lldb_private::TypeNameSpecifierImpl>( + llvm::formatv( + "^std::basic_string_view<{0}, ?std::char_traits<{0}> ?>$", + char_ty) + .str(), + eFormatterMatchRegex), + summary_sp); +} + static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { if (!cpp_category_sp) return; @@ -1863,6 +1885,36 @@ static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { MsvcStlStringSummaryProvider<StringElementType::UTF32>, "MSVC STL std::u32string summary provider")); + RegisterStdStringViewSummaryProvider( + cpp_category_sp, "std::string_view", "char", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, + MsvcStlStringViewSummaryProvider<StringElementType::ASCII>, + "MSVC STL std::string_view summary provider")); + RegisterStdStringViewSummaryProvider( + cpp_category_sp, "std::u8string_view", "char8_t", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, + MsvcStlStringViewSummaryProvider<StringElementType::UTF8>, + "MSVC STL std::u8string_view summary provider")); + RegisterStdStringViewSummaryProvider( + cpp_category_sp, "std::u16string_view", "char16_t", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, + MsvcStlStringViewSummaryProvider<StringElementType::UTF16>, + "MSVC STL std::u16string_view summary provider")); + RegisterStdStringViewSummaryProvider( + cpp_category_sp, "std::u32string_view", "char32_t", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, + MsvcStlStringViewSummaryProvider<StringElementType::UTF32>, + "MSVC STL std::u32string_view summary provider")); + RegisterStdStringViewSummaryProvider( + cpp_category_sp, "std::wstring_view", "wchar_t", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, MsvcStlWStringViewSummaryProvider, + "MSVC STL std::wstring_view summary provider")); + stl_summary_flags.SetDontShowChildren(false); AddCXXSynthetic(cpp_category_sp, MsvcStlAtomicSyntheticFrontEndCreator, diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp index 5d0f20b1beaae..133bc5bb30ad3 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp @@ -112,6 +112,31 @@ static bool formatStringImpl(ValueObject &valobj, Stream &stream, return true; } +template <StringPrinter::StringElementType element_type> +static bool formatStringViewImpl(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, + std::string prefix_token) { + auto data_sp = valobj.GetChildMemberWithName("_Mydata"); + auto size_sp = valobj.GetChildMemberWithName("_Mysize"); + if (!data_sp || !size_sp) + return false; + + bool success = false; + uint64_t size = size_sp->GetValueAsUnsigned(0, &success); + if (!success) + return false; + + StreamString scratch_stream; + success = StringBufferSummaryProvider<element_type>( + scratch_stream, summary_options, data_sp, size, prefix_token); + + if (success) + stream << scratch_stream.GetData(); + else + stream << "Summary Unavailable"; + return true; +} + bool lldb_private::formatters::IsMsvcStlStringType(ValueObject &valobj) { std::vector<uint32_t> indexes; return valobj.GetCompilerType().GetIndexOfChildMemberWithName("_Mypair", true, @@ -153,3 +178,39 @@ bool lldb_private::formatters::MsvcStlStringSummaryProvider< return MsvcStlStringSummaryProviderImpl<StringElementType::UTF32>( valobj, stream, summary_options, "U"); } + +bool lldb_private::formatters::MsvcStlWStringViewSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return formatStringViewImpl<StringElementType::UTF16>(valobj, stream, + summary_options, "L"); +} + +template <> +bool lldb_private::formatters::MsvcStlStringViewSummaryProvider< + StringElementType::ASCII>(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return formatStringViewImpl<StringElementType::ASCII>(valobj, stream, + summary_options, ""); +} +template <> +bool lldb_private::formatters::MsvcStlStringViewSummaryProvider< + StringElementType::UTF8>(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return formatStringViewImpl<StringElementType::UTF8>(valobj, stream, + summary_options, "u8"); +} +template <> +bool lldb_private::formatters::MsvcStlStringViewSummaryProvider< + StringElementType::UTF16>(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return formatStringViewImpl<StringElementType::UTF16>(valobj, stream, + summary_options, "u"); +} +template <> +bool lldb_private::formatters::MsvcStlStringViewSummaryProvider< + StringElementType::UTF32>(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return formatStringViewImpl<StringElementType::UTF32>(valobj, stream, + summary_options, "U"); +} diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h index 490794ccbfb53..8a4918127584f 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h @@ -29,6 +29,15 @@ bool MsvcStlWStringSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // VC 2015+ std::wstring +template <StringPrinter::StringElementType element_type> +bool MsvcStlStringViewSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options); // std::{u8,u16,u32}?string_view + +bool MsvcStlWStringViewSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); // std::wstring_view + // MSVC STL std::shared_ptr<> and std::weak_ptr<> bool IsMsvcStlSmartPointer(ValueObject &valobj); bool MsvcStlSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream, 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 8c053f0843f9b..c4f39d1804091 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 @@ -78,14 +78,12 @@ def cleanup(): "u32_string", type="std::u32string_view", summary='U"🍄🍅🍆🍌"' ) self.expect_var_path("u32_empty", type="std::u32string_view", summary='U""') - self.expect_var_path( - "oops", type="std::string_view", summary='"Hellooo World\\n"' - ) # 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") + null_summary = null_obj.GetSummary() + self.assertTrue(null_summary == "Summary Unavailable" or null_summary is None) self.assertEqual(str(null_obj), "(std::string_view *) null_str = nullptr") self.runCmd("n") @@ -151,7 +149,10 @@ def cleanup(): ) broken_obj = self.frame().GetValueForVariablePath("in_str_view") - self.assertEqual(broken_obj.GetSummary(), "Summary Unavailable") + broken_summary = broken_obj.GetSummary() + self.assertTrue( + broken_summary == "Summary Unavailable" or broken_summary is None + ) @expectedFailureAll( bugnumber="llvm.org/pr36109", debug_info="gmodules", triple=".*-android" @@ -163,3 +164,8 @@ def cleanup(): def test_libcxx(self): self.build(dictionary={"USE_LIBCPP": 1}) self.do_test() + + @add_test_categories(["msvcstl"]) + def test_msvcstl(self): + self.build() + self.do_test() diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/main.cpp index 1e164786bc1a9..e8781fbdf56f9 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/main.cpp @@ -95,7 +95,6 @@ int main() { std::string_view *null_str = nullptr; std::string hello = "Hellooo "; - std::string_view oops = hello + "World\n"; q_source[0] = 'H'; // Set break point at this line. diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/Makefile new file mode 100644 index 0000000000000..4f79c0a900c3a --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/Makefile @@ -0,0 +1,4 @@ +CXX_SOURCES := main.cpp +CXXFLAGS_EXTRAS := -std=c++20 + +include Makefile.rules 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 new file mode 100644 index 0000000000000..1e35a0f6bb040 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py @@ -0,0 +1,44 @@ +# coding=utf8 +""" +Test std::u8string_view summary. +""" + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class StdU8StringViewDataFormatterTestCase(TestBase): + def do_test(self): + lldbutil.run_to_source_breakpoint( + self, "Set break point at this line.", lldb.SBFileSpec("main.cpp") + ) + + 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"', + ], + ) + + @expectedFailureAll(bugnumber="No libc++ formatters for std::u8string_view yet.") + @add_test_categories(["libc++"]) + def test_libcxx(self): + self.build(dictionary={"USE_LIBCPP": 1}) + self.do_test() + + @expectedFailureAll(bugnumber="No libstdc++ formatters for std::u8string_view yet.") + @add_test_categories(["libstdcxx"]) + def test_libstdcxx(self): + self.build(dictionary={"USE_LIBSTDCPP": 1}) + self.do_test() + + @add_test_categories(["msvcstl"]) + def test_msvc(self): + self.build() + self.do_test() diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/main.cpp new file mode 100644 index 0000000000000..458e783a0238a --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/main.cpp @@ -0,0 +1,12 @@ +#include <cstdio> +#include <string_view> + +int main() { + 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"ABC"); + u8_text = u8"ABCd"; + + std::puts("// Set break point at this line."); +} >From ee24302d68f3eccd901e1b711c82fbfac81f8640 Mon Sep 17 00:00:00 2001 From: Nerixyz <nerix...@outlook.de> Date: Fri, 25 Jul 2025 16:55:18 +0200 Subject: [PATCH 2/2] fix: print "Summary Unavailable" if size can't be read --- lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp | 6 ++++-- .../generic/string_view/TestDataFormatterStdStringView.py | 8 ++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp index 133bc5bb30ad3..8fb305b284bbb 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp @@ -123,8 +123,10 @@ static bool formatStringViewImpl(ValueObject &valobj, Stream &stream, bool success = false; uint64_t size = size_sp->GetValueAsUnsigned(0, &success); - if (!success) - return false; + if (!success) { + stream << "Summary Unavailable"; + return true; + } StreamString scratch_stream; success = StringBufferSummaryProvider<element_type>( 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 c4f39d1804091..181141886c5a2 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 @@ -82,8 +82,7 @@ def cleanup(): # 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") - null_summary = null_obj.GetSummary() - self.assertTrue(null_summary == "Summary Unavailable" or null_summary is None) + self.assertEqual(null_obj.GetSummary(), "Summary Unavailable") self.assertEqual(str(null_obj), "(std::string_view *) null_str = nullptr") self.runCmd("n") @@ -149,10 +148,7 @@ def cleanup(): ) broken_obj = self.frame().GetValueForVariablePath("in_str_view") - broken_summary = broken_obj.GetSummary() - self.assertTrue( - broken_summary == "Summary Unavailable" or broken_summary is None - ) + self.assertEqual(broken_obj.GetSummary(), "Summary Unavailable") @expectedFailureAll( bugnumber="llvm.org/pr36109", debug_info="gmodules", triple=".*-android" _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits