Skip to content

Commit b14e03d

Browse files
authored
[LLDB] Consolidate C++ string buffer summaries (#144258)
As part of #143177, I moved the non-libc++ specific formatting of `std::string`s out to `CxxStringTypes` as MSVC's STL `std::string` can also be thought of a pointer+size pair. I named this kind of string "string buffer". This PR picks that change, so the MSVC PR can be smaller. Unfortunately, libstdc++'s `std::string` does not fit this (it also uses a different string printer function). This resolves two FIXMEs in the libc++ tests, where empty u16 and u32 strings didn't have any prefix (u/U).
1 parent 0c60817 commit b14e03d

File tree

5 files changed

+148
-146
lines changed

5 files changed

+148
-146
lines changed

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

Lines changed: 78 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,7 @@ bool lldb_private::formatters::WCharStringSummaryProvider(
116116
return false;
117117

118118
// Get a wchar_t basic type from the current type system
119-
CompilerType wchar_compiler_type =
120-
valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
121-
122-
if (!wchar_compiler_type)
123-
return false;
124-
125-
// Safe to pass nullptr for exe_scope here.
126-
std::optional<uint64_t> size =
127-
llvm::expectedToOptional(wchar_compiler_type.GetBitSize(nullptr));
119+
std::optional<uint64_t> size = GetWCharByteSize(valobj);
128120
if (!size)
129121
return false;
130122
const uint32_t wchar_size = *size;
@@ -136,13 +128,13 @@ bool lldb_private::formatters::WCharStringSummaryProvider(
136128
options.SetPrefixToken("L");
137129

138130
switch (wchar_size) {
139-
case 8:
131+
case 1:
140132
return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF8>(
141133
options);
142-
case 16:
134+
case 2:
143135
return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF16>(
144136
options);
145-
case 32:
137+
case 4:
146138
return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF32>(
147139
options);
148140
default:
@@ -177,15 +169,7 @@ bool lldb_private::formatters::WCharSummaryProvider(
177169
return false;
178170

179171
// Get a wchar_t basic type from the current type system
180-
CompilerType wchar_compiler_type =
181-
valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
182-
183-
if (!wchar_compiler_type)
184-
return false;
185-
186-
// Safe to pass nullptr for exe_scope here.
187-
std::optional<uint64_t> size =
188-
llvm::expectedToOptional(wchar_compiler_type.GetBitSize(nullptr));
172+
std::optional<uint64_t> size = GetWCharByteSize(valobj);
189173
if (!size)
190174
return false;
191175
const uint32_t wchar_size = *size;
@@ -199,13 +183,13 @@ bool lldb_private::formatters::WCharSummaryProvider(
199183
options.SetBinaryZeroIsTerminator(false);
200184

201185
switch (wchar_size) {
202-
case 8:
186+
case 1:
203187
return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF8>(
204188
options);
205-
case 16:
189+
case 2:
206190
return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF16>(
207191
options);
208-
case 32:
192+
case 4:
209193
return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF32>(
210194
options);
211195
default:
@@ -214,3 +198,73 @@ bool lldb_private::formatters::WCharSummaryProvider(
214198
}
215199
return true;
216200
}
201+
202+
std::optional<uint64_t>
203+
lldb_private::formatters::GetWCharByteSize(ValueObject &valobj) {
204+
return llvm::expectedToOptional(
205+
valobj.GetCompilerType()
206+
.GetBasicTypeFromAST(lldb::eBasicTypeWChar)
207+
.GetByteSize(nullptr));
208+
}
209+
210+
template <StringPrinter::StringElementType element_type>
211+
bool lldb_private::formatters::StringBufferSummaryProvider(
212+
Stream &stream, const TypeSummaryOptions &summary_options,
213+
lldb::ValueObjectSP location_sp, uint64_t size, std::string prefix_token) {
214+
215+
if (size == 0) {
216+
stream.PutCString(prefix_token);
217+
stream.PutCString("\"\"");
218+
return true;
219+
}
220+
221+
if (!location_sp)
222+
return false;
223+
224+
StringPrinter::ReadBufferAndDumpToStreamOptions options(*location_sp);
225+
226+
if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
227+
const auto max_size =
228+
location_sp->GetTargetSP()->GetMaximumSizeOfStringSummary();
229+
if (size > max_size) {
230+
size = max_size;
231+
options.SetIsTruncated(true);
232+
}
233+
}
234+
235+
{
236+
DataExtractor extractor;
237+
const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
238+
if (bytes_read < size)
239+
return false;
240+
241+
options.SetData(std::move(extractor));
242+
}
243+
options.SetStream(&stream);
244+
if (prefix_token.empty())
245+
options.SetPrefixToken(nullptr);
246+
else
247+
options.SetPrefixToken(prefix_token);
248+
options.SetQuote('"');
249+
options.SetSourceSize(size);
250+
options.SetBinaryZeroIsTerminator(false);
251+
return StringPrinter::ReadBufferAndDumpToStream<element_type>(options);
252+
}
253+
254+
// explicit instantiations for all string element types
255+
template bool
256+
lldb_private::formatters::StringBufferSummaryProvider<StringElementType::ASCII>(
257+
Stream &, const TypeSummaryOptions &, lldb::ValueObjectSP, uint64_t,
258+
std::string);
259+
template bool
260+
lldb_private::formatters::StringBufferSummaryProvider<StringElementType::UTF8>(
261+
Stream &, const TypeSummaryOptions &, lldb::ValueObjectSP, uint64_t,
262+
std::string);
263+
template bool
264+
lldb_private::formatters::StringBufferSummaryProvider<StringElementType::UTF16>(
265+
Stream &, const TypeSummaryOptions &, lldb::ValueObjectSP, uint64_t,
266+
std::string);
267+
template bool
268+
lldb_private::formatters::StringBufferSummaryProvider<StringElementType::UTF32>(
269+
Stream &, const TypeSummaryOptions &, lldb::ValueObjectSP, uint64_t,
270+
std::string);

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CXXSTRINGTYPES_H
1111
#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CXXSTRINGTYPES_H
1212

13+
#include "lldb/DataFormatters/StringPrinter.h"
1314
#include "lldb/DataFormatters/TypeSummary.h"
1415
#include "lldb/Utility/Stream.h"
1516
#include "lldb/ValueObject/ValueObject.h"
@@ -43,6 +44,34 @@ bool Char32SummaryProvider(ValueObject &valobj, Stream &stream,
4344
bool WCharSummaryProvider(ValueObject &valobj, Stream &stream,
4445
const TypeSummaryOptions &options); // wchar_t
4546

47+
std::optional<uint64_t> GetWCharByteSize(ValueObject &valobj);
48+
49+
/// Print a summary for a string buffer to \a stream.
50+
///
51+
/// \param[in] stream
52+
/// The output stream to print the summary to.
53+
///
54+
/// \param[in] summary_options
55+
/// Options for printing the string contents. This function respects the
56+
/// capping.
57+
///
58+
/// \param[in] location_sp
59+
/// ValueObject of a pointer to the string being printed.
60+
///
61+
/// \param[in] size
62+
/// The size of the buffer pointed to by \a location_sp.
63+
///
64+
/// \param[in] prefix_token
65+
/// A prefix before the double quotes (e.g. 'u' results in u"...").
66+
///
67+
/// \return
68+
/// Returns whether the string buffer was successfully printed.
69+
template <StringPrinter::StringElementType element_type>
70+
bool StringBufferSummaryProvider(Stream &stream,
71+
const TypeSummaryOptions &summary_options,
72+
lldb::ValueObjectSP location_sp, uint64_t size,
73+
std::string prefix_token);
74+
4675
} // namespace formatters
4776
} // namespace lldb_private
4877

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

Lines changed: 34 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "lldb/ValueObject/ValueObject.h"
2525
#include "lldb/ValueObject/ValueObjectConstResult.h"
2626

27+
#include "Plugins/Language/CPlusPlus/CxxStringTypes.h"
2728
#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
2829
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
2930
#include "lldb/lldb-enumerations.h"
@@ -535,70 +536,6 @@ ExtractLibcxxStringInfo(ValueObject &valobj) {
535536
return std::make_pair(size, location_sp);
536537
}
537538

538-
static bool
539-
LibcxxWStringSummaryProvider(ValueObject &valobj, Stream &stream,
540-
const TypeSummaryOptions &summary_options,
541-
ValueObjectSP location_sp, size_t size) {
542-
if (size == 0) {
543-
stream.Printf("L\"\"");
544-
return true;
545-
}
546-
if (!location_sp)
547-
return false;
548-
549-
StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
550-
if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
551-
const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
552-
if (size > max_size) {
553-
size = max_size;
554-
options.SetIsTruncated(true);
555-
}
556-
}
557-
558-
DataExtractor extractor;
559-
const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
560-
if (bytes_read < size)
561-
return false;
562-
563-
// std::wstring::size() is measured in 'characters', not bytes
564-
TypeSystemClangSP scratch_ts_sp =
565-
ScratchTypeSystemClang::GetForTarget(*valobj.GetTargetSP());
566-
if (!scratch_ts_sp)
567-
return false;
568-
569-
auto wchar_t_size =
570-
scratch_ts_sp->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr);
571-
if (!wchar_t_size)
572-
return false;
573-
574-
options.SetData(std::move(extractor));
575-
options.SetStream(&stream);
576-
options.SetPrefixToken("L");
577-
options.SetQuote('"');
578-
options.SetSourceSize(size);
579-
options.SetBinaryZeroIsTerminator(false);
580-
581-
switch (*wchar_t_size) {
582-
case 1:
583-
return StringPrinter::ReadBufferAndDumpToStream<
584-
lldb_private::formatters::StringPrinter::StringElementType::UTF8>(
585-
options);
586-
break;
587-
588-
case 2:
589-
return StringPrinter::ReadBufferAndDumpToStream<
590-
lldb_private::formatters::StringPrinter::StringElementType::UTF16>(
591-
options);
592-
break;
593-
594-
case 4:
595-
return StringPrinter::ReadBufferAndDumpToStream<
596-
lldb_private::formatters::StringPrinter::StringElementType::UTF32>(
597-
options);
598-
}
599-
return false;
600-
}
601-
602539
bool lldb_private::formatters::LibcxxWStringSummaryProvider(
603540
ValueObject &valobj, Stream &stream,
604541
const TypeSummaryOptions &summary_options) {
@@ -609,52 +546,22 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider(
609546
ValueObjectSP location_sp;
610547
std::tie(size, location_sp) = *string_info;
611548

612-
return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,
613-
location_sp, size);
614-
}
615-
616-
template <StringPrinter::StringElementType element_type>
617-
static bool
618-
LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream,
619-
const TypeSummaryOptions &summary_options,
620-
std::string prefix_token, ValueObjectSP location_sp,
621-
uint64_t size) {
622-
623-
if (size == 0) {
624-
stream.Printf("\"\"");
625-
return true;
626-
}
627-
628-
if (!location_sp)
549+
auto wchar_t_size = GetWCharByteSize(valobj);
550+
if (!wchar_t_size)
629551
return false;
630552

631-
StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
632-
633-
if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
634-
const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
635-
if (size > max_size) {
636-
size = max_size;
637-
options.SetIsTruncated(true);
638-
}
639-
}
640-
641-
{
642-
DataExtractor extractor;
643-
const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
644-
if (bytes_read < size)
645-
return false;
646-
647-
options.SetData(std::move(extractor));
553+
switch (*wchar_t_size) {
554+
case 1:
555+
return StringBufferSummaryProvider<StringPrinter::StringElementType::UTF8>(
556+
stream, summary_options, location_sp, size, "L");
557+
case 2:
558+
return StringBufferSummaryProvider<StringPrinter::StringElementType::UTF16>(
559+
stream, summary_options, location_sp, size, "L");
560+
case 4:
561+
return StringBufferSummaryProvider<StringPrinter::StringElementType::UTF32>(
562+
stream, summary_options, location_sp, size, "L");
648563
}
649-
options.SetStream(&stream);
650-
if (prefix_token.empty())
651-
options.SetPrefixToken(nullptr);
652-
else
653-
options.SetPrefixToken(prefix_token);
654-
options.SetQuote('"');
655-
options.SetSourceSize(size);
656-
options.SetBinaryZeroIsTerminator(false);
657-
return StringPrinter::ReadBufferAndDumpToStream<element_type>(options);
564+
return false;
658565
}
659566

660567
template <StringPrinter::StringElementType element_type>
@@ -669,8 +576,8 @@ LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream,
669576
ValueObjectSP location_sp;
670577
std::tie(size, location_sp) = *string_info;
671578

672-
return LibcxxStringSummaryProvider<element_type>(
673-
valobj, stream, summary_options, prefix_token, location_sp, size);
579+
return StringBufferSummaryProvider<element_type>(
580+
stream, summary_options, location_sp, size, prefix_token);
674581
}
675582
template <StringPrinter::StringElementType element_type>
676583
static bool formatStringImpl(ValueObject &valobj, Stream &stream,
@@ -742,8 +649,8 @@ static bool formatStringViewImpl(ValueObject &valobj, Stream &stream,
742649
return true;
743650
}
744651

745-
return LibcxxStringSummaryProvider<element_type>(
746-
valobj, stream, summary_options, prefix_token, dataobj, size);
652+
return StringBufferSummaryProvider<element_type>(stream, summary_options,
653+
dataobj, size, prefix_token);
747654
}
748655

749656
bool lldb_private::formatters::LibcxxStringViewSummaryProviderASCII(
@@ -781,8 +688,22 @@ bool lldb_private::formatters::LibcxxWStringViewSummaryProvider(
781688
return true;
782689
}
783690

784-
return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,
785-
dataobj, size);
691+
auto wchar_t_size = GetWCharByteSize(valobj);
692+
if (!wchar_t_size)
693+
return false;
694+
695+
switch (*wchar_t_size) {
696+
case 1:
697+
return StringBufferSummaryProvider<StringPrinter::StringElementType::UTF8>(
698+
stream, summary_options, dataobj, size, "L");
699+
case 2:
700+
return StringBufferSummaryProvider<StringPrinter::StringElementType::UTF16>(
701+
stream, summary_options, dataobj, size, "L");
702+
case 4:
703+
return StringBufferSummaryProvider<StringPrinter::StringElementType::UTF32>(
704+
stream, summary_options, dataobj, size, "L");
705+
}
706+
return false;
786707
}
787708

788709
static bool

lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,9 @@ def cleanup():
6565
'(%s::wstring) IHaveEmbeddedZerosToo = L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"'
6666
% ns,
6767
'(%s::u16string) u16_string = u"ß水氶"' % ns,
68-
# FIXME: This should have a 'u' prefix.
69-
'(%s::u16string) u16_empty = ""' % ns,
68+
'(%s::u16string) u16_empty = u""' % ns,
7069
'(%s::u32string) u32_string = U"🍄🍅🍆🍌"' % ns,
71-
# FIXME: This should have a 'U' prefix.
72-
'(%s::u32string) u32_empty = ""' % ns,
70+
'(%s::u32string) u32_empty = U""' % ns,
7371
"(%s::string *) null_str = nullptr" % ns,
7472
],
7573
)
@@ -123,7 +121,7 @@ def cleanup():
123121
% ns,
124122
'(%s::u16string) u16_string = u"ß水氶"' % ns,
125123
'(%s::u32string) u32_string = U"🍄🍅🍆🍌"' % ns,
126-
'(%s::u32string) u32_empty = ""' % ns,
124+
'(%s::u32string) u32_empty = U""' % ns,
127125
"(%s::string *) null_str = nullptr" % ns,
128126
],
129127
)

0 commit comments

Comments
 (0)