Skip to content

Commit 76a1cae

Browse files
NerixyzJaddyen
authored andcommitted
[LLDB] Add formatters for MSVC STL std::string_view and friends (llvm#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.
1 parent c3d834b commit 76a1cae

File tree

8 files changed

+189
-4
lines changed

8 files changed

+189
-4
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: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,33 @@ 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+
stream << "Summary Unavailable";
128+
return true;
129+
}
130+
131+
StreamString scratch_stream;
132+
success = StringBufferSummaryProvider<element_type>(
133+
scratch_stream, summary_options, data_sp, size, prefix_token);
134+
135+
if (success)
136+
stream << scratch_stream.GetData();
137+
else
138+
stream << "Summary Unavailable";
139+
return true;
140+
}
141+
115142
bool lldb_private::formatters::IsMsvcStlStringType(ValueObject &valobj) {
116143
std::vector<uint32_t> indexes;
117144
return valobj.GetCompilerType().GetIndexOfChildMemberWithName("_Mypair", true,
@@ -153,3 +180,39 @@ bool lldb_private::formatters::MsvcStlStringSummaryProvider<
153180
return MsvcStlStringSummaryProviderImpl<StringElementType::UTF32>(
154181
valobj, stream, summary_options, "U");
155182
}
183+
184+
bool lldb_private::formatters::MsvcStlWStringViewSummaryProvider(
185+
ValueObject &valobj, Stream &stream,
186+
const TypeSummaryOptions &summary_options) {
187+
return formatStringViewImpl<StringElementType::UTF16>(valobj, stream,
188+
summary_options, "L");
189+
}
190+
191+
template <>
192+
bool lldb_private::formatters::MsvcStlStringViewSummaryProvider<
193+
StringElementType::ASCII>(ValueObject &valobj, Stream &stream,
194+
const TypeSummaryOptions &summary_options) {
195+
return formatStringViewImpl<StringElementType::ASCII>(valobj, stream,
196+
summary_options, "");
197+
}
198+
template <>
199+
bool lldb_private::formatters::MsvcStlStringViewSummaryProvider<
200+
StringElementType::UTF8>(ValueObject &valobj, Stream &stream,
201+
const TypeSummaryOptions &summary_options) {
202+
return formatStringViewImpl<StringElementType::UTF8>(valobj, stream,
203+
summary_options, "u8");
204+
}
205+
template <>
206+
bool lldb_private::formatters::MsvcStlStringViewSummaryProvider<
207+
StringElementType::UTF16>(ValueObject &valobj, Stream &stream,
208+
const TypeSummaryOptions &summary_options) {
209+
return formatStringViewImpl<StringElementType::UTF16>(valobj, stream,
210+
summary_options, "u");
211+
}
212+
template <>
213+
bool lldb_private::formatters::MsvcStlStringViewSummaryProvider<
214+
StringElementType::UTF32>(ValueObject &valobj, Stream &stream,
215+
const TypeSummaryOptions &summary_options) {
216+
return formatStringViewImpl<StringElementType::UTF32>(valobj, stream,
217+
summary_options, "U");
218+
}

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: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,6 @@ 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
@@ -163,3 +160,8 @@ def cleanup():
163160
def test_libcxx(self):
164161
self.build(dictionary={"USE_LIBCPP": 1})
165162
self.do_test()
163+
164+
@add_test_categories(["msvcstl"])
165+
def test_msvcstl(self):
166+
self.build()
167+
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)