Skip to content

Commit 87f45bf

Browse files
committed
[LLDB] Add formatters for MSVC STL std::string_view and friends
1 parent dbc63f1 commit 87f45bf

File tree

8 files changed

+193
-6
lines changed

8 files changed

+193
-6
lines changed

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,28 @@ static void RegisterStdStringSummaryProvider(
13631363
summary_sp);
13641364
}
13651365

1366+
static void RegisterStdStringViewSummaryProvider(
1367+
const lldb::TypeCategoryImplSP &category_sp, llvm::StringRef string_ty,
1368+
llvm::StringRef char_ty, lldb::TypeSummaryImplSP summary_sp) {
1369+
// std::string_view
1370+
category_sp->AddTypeSummary(
1371+
std::make_shared<lldb_private::TypeNameSpecifierImpl>(
1372+
string_ty, eFormatterMatchExact),
1373+
summary_sp);
1374+
1375+
// std::basic_string_view<char, std::char_traits<char>>
1376+
// NativePDB has spaces at different positions compared to PDB and DWARF, so
1377+
// use a regex and make them optional.
1378+
category_sp->AddTypeSummary(
1379+
std::make_shared<lldb_private::TypeNameSpecifierImpl>(
1380+
llvm::formatv(
1381+
"^std::basic_string_view<{0}, ?std::char_traits<{0}> ?>$",
1382+
char_ty)
1383+
.str(),
1384+
eFormatterMatchRegex),
1385+
summary_sp);
1386+
}
1387+
13661388
static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
13671389
if (!cpp_category_sp)
13681390
return;
@@ -1863,6 +1885,36 @@ static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
18631885
MsvcStlStringSummaryProvider<StringElementType::UTF32>,
18641886
"MSVC STL std::u32string summary provider"));
18651887

1888+
RegisterStdStringViewSummaryProvider(
1889+
cpp_category_sp, "std::string_view", "char",
1890+
std::make_shared<CXXFunctionSummaryFormat>(
1891+
stl_summary_flags,
1892+
MsvcStlStringViewSummaryProvider<StringElementType::ASCII>,
1893+
"MSVC STL std::string_view summary provider"));
1894+
RegisterStdStringViewSummaryProvider(
1895+
cpp_category_sp, "std::u8string_view", "char8_t",
1896+
std::make_shared<CXXFunctionSummaryFormat>(
1897+
stl_summary_flags,
1898+
MsvcStlStringViewSummaryProvider<StringElementType::UTF8>,
1899+
"MSVC STL std::u8string_view summary provider"));
1900+
RegisterStdStringViewSummaryProvider(
1901+
cpp_category_sp, "std::u16string_view", "char16_t",
1902+
std::make_shared<CXXFunctionSummaryFormat>(
1903+
stl_summary_flags,
1904+
MsvcStlStringViewSummaryProvider<StringElementType::UTF16>,
1905+
"MSVC STL std::u16string_view summary provider"));
1906+
RegisterStdStringViewSummaryProvider(
1907+
cpp_category_sp, "std::u32string_view", "char32_t",
1908+
std::make_shared<CXXFunctionSummaryFormat>(
1909+
stl_summary_flags,
1910+
MsvcStlStringViewSummaryProvider<StringElementType::UTF32>,
1911+
"MSVC STL std::u32string_view summary provider"));
1912+
RegisterStdStringViewSummaryProvider(
1913+
cpp_category_sp, "std::wstring_view", "wchar_t",
1914+
std::make_shared<CXXFunctionSummaryFormat>(
1915+
stl_summary_flags, MsvcStlWStringViewSummaryProvider,
1916+
"MSVC STL std::wstring_view summary provider"));
1917+
18661918
stl_summary_flags.SetDontShowChildren(false);
18671919

18681920
AddCXXSynthetic(cpp_category_sp, MsvcStlAtomicSyntheticFrontEndCreator,

lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,31 @@ static bool formatStringImpl(ValueObject &valobj, Stream &stream,
112112
return true;
113113
}
114114

115+
template <StringPrinter::StringElementType element_type>
116+
static bool formatStringViewImpl(ValueObject &valobj, Stream &stream,
117+
const TypeSummaryOptions &summary_options,
118+
std::string prefix_token) {
119+
auto data_sp = valobj.GetChildMemberWithName("_Mydata");
120+
auto size_sp = valobj.GetChildMemberWithName("_Mysize");
121+
if (!data_sp || !size_sp)
122+
return false;
123+
124+
bool success = false;
125+
uint64_t size = size_sp->GetValueAsUnsigned(0, &success);
126+
if (!success)
127+
return false;
128+
129+
StreamString scratch_stream;
130+
success = StringBufferSummaryProvider<element_type>(
131+
scratch_stream, summary_options, data_sp, size, prefix_token);
132+
133+
if (success)
134+
stream << scratch_stream.GetData();
135+
else
136+
stream << "Summary Unavailable";
137+
return true;
138+
}
139+
115140
bool lldb_private::formatters::IsMsvcStlStringType(ValueObject &valobj) {
116141
std::vector<uint32_t> indexes;
117142
return valobj.GetCompilerType().GetIndexOfChildMemberWithName("_Mypair", true,
@@ -153,3 +178,39 @@ bool lldb_private::formatters::MsvcStlStringSummaryProvider<
153178
return MsvcStlStringSummaryProviderImpl<StringElementType::UTF32>(
154179
valobj, stream, summary_options, "U");
155180
}
181+
182+
bool lldb_private::formatters::MsvcStlWStringViewSummaryProvider(
183+
ValueObject &valobj, Stream &stream,
184+
const TypeSummaryOptions &summary_options) {
185+
return formatStringViewImpl<StringElementType::UTF16>(valobj, stream,
186+
summary_options, "L");
187+
}
188+
189+
template <>
190+
bool lldb_private::formatters::MsvcStlStringViewSummaryProvider<
191+
StringElementType::ASCII>(ValueObject &valobj, Stream &stream,
192+
const TypeSummaryOptions &summary_options) {
193+
return formatStringViewImpl<StringElementType::ASCII>(valobj, stream,
194+
summary_options, "");
195+
}
196+
template <>
197+
bool lldb_private::formatters::MsvcStlStringViewSummaryProvider<
198+
StringElementType::UTF8>(ValueObject &valobj, Stream &stream,
199+
const TypeSummaryOptions &summary_options) {
200+
return formatStringViewImpl<StringElementType::UTF8>(valobj, stream,
201+
summary_options, "u8");
202+
}
203+
template <>
204+
bool lldb_private::formatters::MsvcStlStringViewSummaryProvider<
205+
StringElementType::UTF16>(ValueObject &valobj, Stream &stream,
206+
const TypeSummaryOptions &summary_options) {
207+
return formatStringViewImpl<StringElementType::UTF16>(valobj, stream,
208+
summary_options, "u");
209+
}
210+
template <>
211+
bool lldb_private::formatters::MsvcStlStringViewSummaryProvider<
212+
StringElementType::UTF32>(ValueObject &valobj, Stream &stream,
213+
const TypeSummaryOptions &summary_options) {
214+
return formatStringViewImpl<StringElementType::UTF32>(valobj, stream,
215+
summary_options, "U");
216+
}

lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@ bool MsvcStlWStringSummaryProvider(
2929
ValueObject &valobj, Stream &stream,
3030
const TypeSummaryOptions &options); // VC 2015+ std::wstring
3131

32+
template <StringPrinter::StringElementType element_type>
33+
bool MsvcStlStringViewSummaryProvider(
34+
ValueObject &valobj, Stream &stream,
35+
const TypeSummaryOptions &summary_options); // std::{u8,u16,u32}?string_view
36+
37+
bool MsvcStlWStringViewSummaryProvider(
38+
ValueObject &valobj, Stream &stream,
39+
const TypeSummaryOptions &options); // std::wstring_view
40+
3241
// MSVC STL std::shared_ptr<> and std::weak_ptr<>
3342
bool IsMsvcStlSmartPointer(ValueObject &valobj);
3443
bool MsvcStlSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream,

lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,12 @@ def cleanup():
7878
"u32_string", type="std::u32string_view", summary='U"🍄🍅🍆🍌"'
7979
)
8080
self.expect_var_path("u32_empty", type="std::u32string_view", summary='U""')
81-
self.expect_var_path(
82-
"oops", type="std::string_view", summary='"Hellooo World\\n"'
83-
)
8481

8582
# GetSummary returns None so can't be checked by expect_var_path, so we
8683
# use the str representation instead
8784
null_obj = self.frame().GetValueForVariablePath("null_str")
88-
self.assertEqual(null_obj.GetSummary(), "Summary Unavailable")
85+
null_summary = null_obj.GetSummary()
86+
self.assertTrue(null_summary == "Summary Unavailable" or null_summary is None)
8987
self.assertEqual(str(null_obj), "(std::string_view *) null_str = nullptr")
9088

9189
self.runCmd("n")
@@ -151,7 +149,10 @@ def cleanup():
151149
)
152150

153151
broken_obj = self.frame().GetValueForVariablePath("in_str_view")
154-
self.assertEqual(broken_obj.GetSummary(), "Summary Unavailable")
152+
broken_summary = broken_obj.GetSummary()
153+
self.assertTrue(
154+
broken_summary == "Summary Unavailable" or broken_summary is None
155+
)
155156

156157
@expectedFailureAll(
157158
bugnumber="llvm.org/pr36109", debug_info="gmodules", triple=".*-android"
@@ -163,3 +164,8 @@ def cleanup():
163164
def test_libcxx(self):
164165
self.build(dictionary={"USE_LIBCPP": 1})
165166
self.do_test()
167+
168+
@add_test_categories(["msvcstl"])
169+
def test_msvcstl(self):
170+
self.build()
171+
self.do_test()

lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/main.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ int main() {
9595
std::string_view *null_str = nullptr;
9696

9797
std::string hello = "Hellooo ";
98-
std::string_view oops = hello + "World\n";
9998

10099
q_source[0] = 'H'; // Set break point at this line.
101100

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
CXX_SOURCES := main.cpp
2+
CXXFLAGS_EXTRAS := -std=c++20
3+
4+
include Makefile.rules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# coding=utf8
2+
"""
3+
Test std::u8string_view summary.
4+
"""
5+
6+
7+
import lldb
8+
from lldbsuite.test.decorators import *
9+
from lldbsuite.test.lldbtest import *
10+
from lldbsuite.test import lldbutil
11+
12+
13+
class StdU8StringViewDataFormatterTestCase(TestBase):
14+
def do_test(self):
15+
lldbutil.run_to_source_breakpoint(
16+
self, "Set break point at this line.", lldb.SBFileSpec("main.cpp")
17+
)
18+
19+
self.expect(
20+
"frame variable",
21+
substrs=[
22+
'(std::u8string_view) u8_string_small = u8"🍄"',
23+
'(std::u8string_view) u8_string = u8"❤️👍📄📁😃🧑‍🌾"',
24+
'(std::u8string_view) u8_empty = u8""',
25+
'(std::u8string_view) u8_text = u8"ABCd"',
26+
],
27+
)
28+
29+
@expectedFailureAll(bugnumber="No libc++ formatters for std::u8string_view yet.")
30+
@add_test_categories(["libc++"])
31+
def test_libcxx(self):
32+
self.build(dictionary={"USE_LIBCPP": 1})
33+
self.do_test()
34+
35+
@expectedFailureAll(bugnumber="No libstdc++ formatters for std::u8string_view yet.")
36+
@add_test_categories(["libstdcxx"])
37+
def test_libstdcxx(self):
38+
self.build(dictionary={"USE_LIBSTDCPP": 1})
39+
self.do_test()
40+
41+
@add_test_categories(["msvcstl"])
42+
def test_msvc(self):
43+
self.build()
44+
self.do_test()
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <cstdio>
2+
#include <string_view>
3+
4+
int main() {
5+
std::u8string_view u8_string_small(u8"🍄");
6+
std::u8string_view u8_string(u8"❤️👍📄📁😃🧑‍🌾");
7+
std::u8string_view u8_empty(u8"");
8+
std::u8string_view u8_text(u8"ABC");
9+
u8_text = u8"ABCd";
10+
11+
std::puts("// Set break point at this line.");
12+
}

0 commit comments

Comments
 (0)