Skip to content

Commit 21b0c97

Browse files
committed
[lldb] Add type summary for String.Index (#5515)
Implement a type summary for Swift's `String.Index`. The summary string follows the following: 1. Original proposal: https://forums.swift.org/t/improving-string-index-s-printed-descriptions/57027 2. Proposed implementation: swiftlang/swift#58479 3. Temporary(ish) near-`CustomStringConvertible` implementation: swiftlang/swift#61548 The associated test cases are taken from the test cases in swiftlang/swift#58479. rdar://99211823 (cherry picked from commit c7146a3)
1 parent 284c281 commit 21b0c97

File tree

7 files changed

+258
-0
lines changed

7 files changed

+258
-0
lines changed

lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "SwiftFormatters.h"
14+
#include "Plugins/Language/Swift/SwiftStringIndex.h"
1415
#include "Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h"
1516
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
1617
#include "lldb/DataFormatters/FormattersHelpers.h"
1718
#include "lldb/DataFormatters/StringPrinter.h"
1819
#include "lldb/Target/Process.h"
20+
#include "lldb/Utility/ConstString.h"
1921
#include "lldb/Utility/DataBufferHeap.h"
2022
#include "lldb/Utility/Status.h"
2123
#include "lldb/Utility/Timer.h"
@@ -368,6 +370,26 @@ bool lldb_private::formatters::swift::String_SummaryProvider(
368370
return false;
369371
}
370372

373+
bool lldb_private::formatters::swift::StringIndex_SummaryProvider(
374+
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
375+
static ConstString g__rawBits("_rawBits");
376+
auto raw_bits_sp = valobj.GetChildMemberWithName(g__rawBits, true);
377+
if (!raw_bits_sp)
378+
return false;
379+
380+
bool success = false;
381+
StringIndex index =
382+
raw_bits_sp->GetSyntheticValue()->GetValueAsUnsigned(0, &success);
383+
if (!success)
384+
return false;
385+
386+
stream.Printf("%llu[%s]", index.encodedOffset(), index.encodingName());
387+
if (index.transcodedOffset() != 0)
388+
stream.Printf("+%u", index.transcodedOffset());
389+
390+
return true;
391+
}
392+
371393
bool lldb_private::formatters::swift::StaticString_SummaryProvider(
372394
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
373395
return StaticString_SummaryProvider(

lldb/source/Plugins/Language/Swift/SwiftFormatters.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ bool String_SummaryProvider(ValueObject &valobj, Stream &stream,
5454
const TypeSummaryOptions &,
5555
StringPrinter::ReadStringAndDumpToStreamOptions);
5656

57+
bool StringIndex_SummaryProvider(ValueObject &valobj, Stream &stream,
58+
const TypeSummaryOptions &options);
59+
5760
bool StaticString_SummaryProvider(ValueObject &valobj, Stream &stream,
5861
const TypeSummaryOptions &options);
5962

lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,10 @@ static void LoadSwiftFormatters(lldb::TypeCategoryImplSP swift_category_sp) {
418418
AddCXXSummary(swift_category_sp, string_summary_provider,
419419
"Swift.String summary provider", ConstString("Swift.String"),
420420
summary_flags);
421+
AddCXXSummary(swift_category_sp,
422+
lldb_private::formatters::swift::StringIndex_SummaryProvider,
423+
"Swift String.Index summary provider",
424+
ConstString("Swift.String.Index"), summary_flags);
421425
bool (*staticstring_summary_provider)(ValueObject &, Stream &,
422426
const TypeSummaryOptions &) =
423427
lldb_private::formatters::swift::StaticString_SummaryProvider;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//===-- SwiftStringIndex.h --------------------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef liblldb_SwiftStringIndex_h
14+
#define liblldb_SwiftStringIndex_h
15+
16+
#include "lldb/lldb-forward.h"
17+
18+
namespace lldb_private {
19+
namespace formatters {
20+
namespace swift {
21+
22+
// From SwiftIndex.swift
23+
// ┌──────────┬────────────────╥────────────────┬───────╥───────┐
24+
// │ b63:b16 │ b15:b14 ║ b13:b8 │ b7:b4 ║ b3:b0 │
25+
// ├──────────┼────────────────╫────────────────┼───────╫───────┤
26+
// │ position │ transc. offset ║ grapheme cache │ rsvd ║ flags │
27+
// └──────────┴────────────────╨────────────────┴───────╨───────┘
28+
// └────── resilient ───────┘
29+
class StringIndex {
30+
uint64_t _rawBits;
31+
32+
enum Flags : uint8_t {
33+
IsScalarAligned = 1 << 0,
34+
IsCharacterAligned = 1 << 1,
35+
CanBeUTF8 = 1 << 2,
36+
CanBeUTF16 = 1 << 3,
37+
};
38+
39+
public:
40+
StringIndex(uint64_t rawBits) : _rawBits(rawBits) {}
41+
42+
uint64_t encodedOffset() { return _rawBits >> 16; }
43+
44+
const char *encodingName() {
45+
uint8_t flags = _rawBits & 0b1111;
46+
bool canBeUTF8 = flags & Flags::CanBeUTF8;
47+
bool canBeUTF16 = flags & Flags::CanBeUTF16;
48+
if (canBeUTF8 && canBeUTF16)
49+
return "any";
50+
else if (canBeUTF8)
51+
return "utf8";
52+
else if (canBeUTF16)
53+
return "utf16";
54+
else
55+
return "unknown";
56+
}
57+
58+
uint8_t transcodedOffset() { return (_rawBits >> 14) & 0b11; }
59+
};
60+
61+
}; // namespace swift
62+
}; // namespace formatters
63+
}; // namespace lldb_private
64+
65+
#endif
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SWIFT_SOURCES := main.swift
2+
3+
include Makefile.rules
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
"""
2+
Test String.Index summary strings.
3+
4+
The test cases are LLDB versions of the original Swift tests, see
5+
https://github.com/apple/swift/pull/58479
6+
"""
7+
import lldb
8+
from lldbsuite.test.lldbtest import *
9+
from lldbsuite.test.decorators import *
10+
import lldbsuite.test.lldbutil as lldbutil
11+
12+
13+
class TestCase(TestBase):
14+
@skipUnlessFoundation
15+
@swiftTest
16+
def test_swift_string_index_formatters(self):
17+
"""Test String.Index summary strings."""
18+
self.build()
19+
_, process, _, _ = lldbutil.run_to_source_breakpoint(
20+
self, "break here", lldb.SBFileSpec("main.swift")
21+
)
22+
23+
#
24+
# The first breakpoint stop tests a native (non-bridged) String.
25+
#
26+
27+
self.expect(
28+
"v nativeIndices",
29+
substrs=[
30+
"0[any]",
31+
"1[utf8]",
32+
"9[utf8]",
33+
"10[utf8]",
34+
],
35+
)
36+
37+
self.expect(
38+
"v unicodeScalarIndices",
39+
substrs=[
40+
"0[any]",
41+
"1[utf8]",
42+
"5[utf8]",
43+
"9[utf8]",
44+
"10[utf8]",
45+
],
46+
)
47+
48+
self.expect(
49+
"v utf8Indices",
50+
substrs=[
51+
"0[any]",
52+
"1[utf8]",
53+
"2[utf8]",
54+
"3[utf8]",
55+
"4[utf8]",
56+
"5[utf8]",
57+
"6[utf8]",
58+
"7[utf8]",
59+
"8[utf8]",
60+
"9[utf8]",
61+
"10[utf8]",
62+
],
63+
)
64+
65+
self.expect(
66+
"v utf16Indices",
67+
substrs=[
68+
"0[any]",
69+
"1[utf8]",
70+
"1[utf8]+1",
71+
"5[utf8]",
72+
"5[utf8]+1",
73+
"9[utf8]",
74+
"10[utf8]",
75+
],
76+
)
77+
78+
#
79+
# The second breakpoint stop tests a bridged String.
80+
#
81+
82+
process.Continue()
83+
84+
self.expect(
85+
"v nativeIndices",
86+
substrs=[
87+
"0[any]",
88+
"1[utf16]",
89+
"5[utf16]",
90+
"6[utf16]",
91+
],
92+
)
93+
94+
self.expect(
95+
"v unicodeScalarIndices",
96+
substrs=[
97+
"0[any]",
98+
"1[utf16]",
99+
"3[utf16]",
100+
"5[utf16]",
101+
"6[utf16]",
102+
],
103+
)
104+
105+
self.expect(
106+
"v utf8Indices",
107+
substrs=[
108+
"0[any]",
109+
"1[utf16]",
110+
"1[utf16]+1",
111+
"1[utf16]+2",
112+
"1[utf16]+3",
113+
"3[utf16]",
114+
"3[utf16]+1",
115+
"3[utf16]+2",
116+
"3[utf16]+3",
117+
"5[utf16]",
118+
"6[utf16]",
119+
],
120+
)
121+
122+
self.expect(
123+
"v utf16Indices",
124+
substrs=[
125+
"0[any]",
126+
"1[utf16]",
127+
"2[utf16]",
128+
"3[utf16]",
129+
"4[utf16]",
130+
"5[utf16]",
131+
"6[utf16]",
132+
],
133+
)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import Foundation
2+
3+
func main() {
4+
exerciseNative()
5+
exerciseBridged()
6+
}
7+
8+
func exerciseNative() {
9+
exercise("a👉🏼b")
10+
}
11+
12+
func exerciseBridged() {
13+
exercise("a👉🏼b" as NSString as String)
14+
}
15+
16+
func exercise(_ string: String) {
17+
let nativeIndices = allIndices(string)
18+
let unicodeScalarIndices = allIndices(string.unicodeScalars)
19+
let utf8Indices = allIndices(string.utf8)
20+
let utf16Indices = allIndices(string.utf16)
21+
// break here
22+
}
23+
24+
func allIndices<T: Collection>(_ collection: T) -> [T.Index] {
25+
return Array(collection.indices) + [collection.endIndex]
26+
}
27+
28+
main()

0 commit comments

Comments
 (0)