Skip to content

Conversation

Nerixyz
Copy link
Contributor

@Nerixyz Nerixyz commented Jul 23, 2025

Adds summaries for std::{,w,u8,u16,u32}string_views from MSVC's STL. A few functions from the string formatting can be reused.

Towards #24834.

@Nerixyz Nerixyz requested a review from JDevlieghere as a code owner July 23, 2025 20:42
@llvmbot llvmbot added the lldb label Jul 23, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 23, 2025

@llvm/pr-subscribers-lldb

Author: nerix (Nerixyz)

Changes

Adds summaries for std::{,w,u8,u16,u32}string_views from MSVC's STL. A few functions from the string formatting can be reused.

Towards #24834.


Full diff: https://github.com/llvm/llvm-project/pull/150318.diff

8 Files Affected:

  • (modified) lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (+52)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp (+61)
  • (modified) lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h (+9)
  • (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py (+11-5)
  • (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/main.cpp (-1)
  • (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/Makefile (+4)
  • (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py (+44)
  • (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/main.cpp (+12)
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.");
+}

@@ -95,7 +95,6 @@ int main() {
std::string_view *null_str = nullptr;

std::string hello = "Hellooo ";
std::string_view oops = hello + "World\n";
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tested implementation detail. For me, oops was "\0ellooo World\n", so I removed this.

Comment on lines 85 to 86
null_summary = null_obj.GetSummary()
self.assertTrue(null_summary == "Summary Unavailable" or null_summary is None)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a preference here. I think not providing a summary at all should be as acceptable as saying "Summary Unavailable".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer being consistent with the other formatters and printing "Summary Unavailable". Not printing anything might get confused for "string is empty".

Copy link
Member

@Michael137 Michael137 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (just left comment re. null summary)

@Michael137 Michael137 merged commit 7b42e7c into llvm:main Jul 25, 2025
9 checks passed
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Jul 28, 2025
…#150318)

Adds summaries for `std::{,w,u8,u16,u32}string_view`s from MSVC's STL. A
few functions from the string formatting can be reused.

Towards llvm#24834.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants