Skip to content

Commit 106fe98

Browse files
Merge pull request #10905 from swiftlang/dl/lldb-Add-formatters-for-Swift.Span
[lldb] Add formatters for Swift.Span
2 parents 3d8aa19 + 58dfa69 commit 106fe98

File tree

5 files changed

+166
-66
lines changed

5 files changed

+166
-66
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,12 @@ static void LoadSwiftFormatters(lldb::TypeCategoryImplSP swift_category_sp) {
344344
ConstString("^Swift.Unsafe(Mutable)?(Raw)?(Buffer)?Pointer(<.+>)?$"),
345345
summary_flags, true);
346346

347+
AddCXXSummary(swift_category_sp,
348+
lldb_private::formatters::swift::UnsafeTypeSummaryProvider,
349+
"Swift.[Mutable]Span",
350+
ConstString("^Swift\\.(Mutable)?Span<.+>$"), summary_flags,
351+
true);
352+
347353
DictionaryConfig::Get().RegisterSummaryProviders(swift_category_sp,
348354
summary_flags);
349355
SetConfig::Get().RegisterSummaryProviders(swift_category_sp, summary_flags);
@@ -395,6 +401,12 @@ static void LoadSwiftFormatters(lldb::TypeCategoryImplSP swift_category_sp) {
395401
ConstString("^Swift.Unsafe(Mutable)?(Raw)?(Buffer)?Pointer(<.+>)?$"),
396402
synth_flags, true);
397403

404+
AddCXXSynthetic(
405+
swift_category_sp,
406+
lldb_private::formatters::swift::UnsafeTypeSyntheticFrontEndCreator,
407+
"Swift.[Mutable]Span", ConstString("^Swift\\.(Mutable)?Span<.+>?"),
408+
synth_flags, true);
409+
398410
DictionaryConfig::Get().RegisterSyntheticChildrenCreators(swift_category_sp,
399411
synth_flags);
400412
SetConfig::Get().RegisterSyntheticChildrenCreators(swift_category_sp,

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

Lines changed: 112 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33

44
#include "Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h"
55
#include "lldb/DataFormatters/TypeSynthetic.h"
6+
#include "lldb/Symbol/CompilerType.h"
67
#include "lldb/Utility/LLDBLog.h"
78
#include "lldb/Utility/Log.h"
9+
#include "lldb/ValueObject/ValueObject.h"
810
#include "lldb/lldb-enumerations.h"
11+
#include "llvm/ADT/StringRef.h"
912

1013
#include <utility>
1114

@@ -38,6 +41,8 @@ class SwiftUnsafeType {
3841
protected:
3942
SwiftUnsafeType(ValueObject &valobj, UnsafePointerKind kind);
4043
addr_t GetAddress(llvm::StringRef child_name);
44+
std::optional<size_t> GetCountValue(llvm::StringRef child_name);
45+
CompilerType GetArgumentType();
4146

4247
ValueObject &m_valobj;
4348
const UnsafePointerKind m_kind;
@@ -133,6 +138,70 @@ lldb::addr_t SwiftUnsafeType::GetAddress(llvm::StringRef child_name) {
133138
return pointer_value_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
134139
}
135140

141+
std::optional<size_t>
142+
SwiftUnsafeType::GetCountValue(llvm::StringRef child_name) {
143+
ValueObjectSP count_value_sp(
144+
m_valobj.GetChildMemberWithName(child_name, true));
145+
if (!count_value_sp) {
146+
LLDB_LOG(GetLog(LLDBLog::DataFormatters),
147+
"{0}: Couldn't find ValueObject child member named '{1}'.",
148+
__FUNCTION__, child_name);
149+
return std::nullopt;
150+
}
151+
152+
ValueObjectSP value_provided_child_sp;
153+
154+
// Implement Swift's 'value-providing synthetic children' workaround.
155+
// Depending on whether the ValueObject type is a primitive or a structure,
156+
// lldb should prioritize the synthetic value children.
157+
// If it has no synthetic children then fallback to non synthetic children.
158+
ValueObjectSP synthetic = count_value_sp->GetSyntheticValue();
159+
if (synthetic)
160+
value_provided_child_sp = synthetic->GetChildAtIndex(0, true);
161+
if (!value_provided_child_sp)
162+
value_provided_child_sp = count_value_sp->GetChildAtIndex(0, true);
163+
164+
// If neither child exists, fail.
165+
if (!value_provided_child_sp) {
166+
LLDB_LOG(GetLog(LLDBLog::DataFormatters),
167+
"{0}: Couldn't extract 'value-providing synthetic children' from "
168+
"ValueObject '{1}'.",
169+
__FUNCTION__, child_name);
170+
return std::nullopt;
171+
}
172+
173+
size_t count = value_provided_child_sp->GetValueAsUnsigned(UINT64_MAX);
174+
175+
if (count == UINT64_MAX) {
176+
LLDB_LOG(GetLog(LLDBLog::DataFormatters),
177+
"{0}: Couldn't get a valid value for ValueObject '{1}'.",
178+
__FUNCTION__, child_name);
179+
return std::nullopt;
180+
}
181+
182+
return count;
183+
}
184+
185+
CompilerType SwiftUnsafeType::GetArgumentType() {
186+
CompilerType type = m_valobj.GetCompilerType();
187+
if (!type.IsValid()) {
188+
LLDB_LOG(GetLog(LLDBLog::DataFormatters),
189+
"{0}: Couldn't get the compiler type for the '{1}' ValueObject.",
190+
__FUNCTION__, type.GetTypeName());
191+
return {};
192+
}
193+
194+
auto type_system = type.GetTypeSystem().dyn_cast_or_null<TypeSystemSwift>();
195+
if (!type_system) {
196+
LLDB_LOG(GetLog(LLDBLog::DataFormatters),
197+
"{0}: Couldn't get {1} type system.", __FUNCTION__,
198+
type.GetTypeName());
199+
return {};
200+
}
201+
202+
return type_system->GetGenericArgumentType(type.GetOpaqueQualType(), 0);
203+
}
204+
136205
class SwiftUnsafeBufferPointer final : public SwiftUnsafeType {
137206
public:
138207
SwiftUnsafeBufferPointer(ValueObject &valobj);
@@ -162,46 +231,10 @@ lldb::ChildCacheState SwiftUnsafeBufferPointer::Update() {
162231
// pointer address, lldb unfolds every ValueObject child until reaching
163232
// `pointerValue`.
164233

165-
static ConstString g_count("count");
166-
ValueObjectSP count_value_sp(m_valobj.GetChildMemberWithName(g_count, true));
167-
if (!count_value_sp) {
168-
LLDB_LOG(GetLog(LLDBLog::DataFormatters),
169-
"{0}: Couldn't find ValueObject child member named '{1}'.",
170-
__FUNCTION__, g_count);
171-
return ChildCacheState::eRefetch;
172-
}
173-
174-
ValueObjectSP value_provided_child_sp = nullptr;
175-
176-
// Implement Swift's 'value-providing synthetic children' workaround.
177-
// Depending on whether the ValueObject type is a primitive or a structure,
178-
// lldb should prioritize the synthetic value children.
179-
// If it has no synthetic children then fallback to non synthetic children.
180-
ValueObjectSP synthetic = count_value_sp->GetSyntheticValue();
181-
if (synthetic)
182-
value_provided_child_sp = synthetic->GetChildAtIndex(0, true);
183-
if (!value_provided_child_sp)
184-
value_provided_child_sp = count_value_sp->GetChildAtIndex(0, true);
185-
186-
// If neither child exists, fail.
187-
if (!value_provided_child_sp) {
188-
LLDB_LOG(GetLog(LLDBLog::DataFormatters),
189-
"{0}: Couldn't extract 'value-providing synthetic children' from "
190-
"ValueObject 'count'.",
191-
__FUNCTION__);
192-
return lldb::ChildCacheState::eRefetch;
193-
}
194-
195-
size_t count = value_provided_child_sp->GetValueAsUnsigned(UINT64_MAX);
196-
197-
if (count == UINT64_MAX) {
198-
LLDB_LOG(GetLog(LLDBLog::DataFormatters),
199-
"{0}: Couldn't get a valid value for ValueObject 'count'.",
200-
__FUNCTION__);
234+
if (auto count = GetCountValue("count"))
235+
m_count = *count;
236+
else
201237
return ChildCacheState::eRefetch;
202-
}
203-
204-
m_count = count;
205238

206239
addr_t start_addr = GetAddress("_position");
207240

@@ -332,35 +365,10 @@ lldb::ChildCacheState SwiftUnsafePointer::Update() {
332365
// - pointerValue : Int
333366
//
334367

335-
CompilerType type = m_valobj.GetCompilerType();
336-
if (!type.IsValid()) {
337-
LLDB_LOG(GetLog(LLDBLog::DataFormatters),
338-
"{0}: Couldn't get the compiler type for the "
339-
"'Swift.UnsafePointer' ValueObject.",
340-
__FUNCTION__, type.GetTypeName());
341-
return ChildCacheState::eRefetch;
342-
}
343-
344-
auto type_system = type.GetTypeSystem().dyn_cast_or_null<TypeSystemSwift>();
345-
if (!type_system) {
346-
LLDB_LOG(GetLog(LLDBLog::DataFormatters),
347-
"{0}: Couldn't get {1} type system.", __FUNCTION__,
348-
type.GetTypeName());
349-
return ChildCacheState::eRefetch;
350-
}
351-
352-
CompilerType argument_type =
353-
type_system->GetGenericArgumentType(type.GetOpaqueQualType(), 0);
354-
368+
CompilerType argument_type = GetArgumentType();
355369
if (argument_type.IsValid())
356370
m_elem_type = argument_type;
357371

358-
if (type.GetTypeInfo() & eTypeIsEnumeration) {
359-
CompilerType argument_type =
360-
type_system->GetGenericArgumentType(type.GetOpaqueQualType(), 0);
361-
if (argument_type.IsValid())
362-
m_elem_type = argument_type;
363-
}
364372
assert(
365373
!m_elem_type.GetTypeName().GetStringRef().starts_with("Swift.Optional"));
366374

@@ -384,6 +392,40 @@ lldb::ChildCacheState SwiftUnsafePointer::Update() {
384392
return ChildCacheState::eReuse;
385393
}
386394

395+
class SwiftSpan final : public SwiftUnsafeType {
396+
public:
397+
SwiftSpan(ValueObject &valobj);
398+
lldb::ChildCacheState Update() override;
399+
};
400+
401+
SwiftSpan::SwiftSpan(ValueObject &valobj)
402+
: SwiftUnsafeType(valobj, UnsafePointerKind::eSwiftUnsafeRawBufferPointer) {
403+
}
404+
405+
lldb::ChildCacheState SwiftSpan::Update() {
406+
if (auto count = GetCountValue("_count"))
407+
m_count = *count;
408+
else
409+
return ChildCacheState::eRefetch;
410+
411+
addr_t start_addr = GetAddress("_pointer");
412+
if (!start_addr || start_addr == LLDB_INVALID_ADDRESS) {
413+
LLDB_LOG(GetLog(LLDBLog::DataFormatters),
414+
"{0}: Couldn't get a valid address for ValueObject '_pointer'.",
415+
__FUNCTION__);
416+
return ChildCacheState::eRefetch;
417+
}
418+
m_start_addr = start_addr;
419+
420+
CompilerType argument_type = GetArgumentType();
421+
if (argument_type.IsValid())
422+
m_elem_type = argument_type;
423+
else
424+
return ChildCacheState::eRefetch;
425+
426+
return ChildCacheState::eReuse;
427+
}
428+
387429
std::unique_ptr<SwiftUnsafeType> SwiftUnsafeType::Create(ValueObject &valobj) {
388430
CompilerType type = valobj.GetCompilerType();
389431
if (!type.IsValid()) {
@@ -424,8 +466,12 @@ std::unique_ptr<SwiftUnsafeType> SwiftUnsafeType::Create(ValueObject &valobj) {
424466

425467
llvm::StringRef valobj_type_name(type.GetTypeName().GetCString());
426468
valobj_type_name.consume_front("Swift.");
427-
valobj_type_name.consume_front("Unsafe");
469+
bool is_unsafe = valobj_type_name.consume_front("Unsafe");
428470
valobj_type_name.consume_front("Mutable");
471+
472+
if (!is_unsafe && valobj_type_name.consume_front("Span"))
473+
return std::make_unique<SwiftSpan>(valobj);
474+
429475
bool is_raw = valobj_type_name.consume_front("Raw");
430476
bool is_buffer_ptr = valobj_type_name.consume_front("Buffer");
431477
UnsafePointerKind kind =
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SWIFT_SOURCES := main.swift
2+
SWIFTFLAGS_EXTRAS := -parse-as-library -Xfrontend -disable-availability-checking
3+
include Makefile.rules
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import lldb
2+
from lldbsuite.test.decorators import *
3+
from lldbsuite.test.lldbtest import *
4+
from lldbsuite.test import lldbutil
5+
6+
7+
class TestCase(TestBase):
8+
9+
@swiftTest
10+
def test(self):
11+
self.build()
12+
lldbutil.run_to_source_breakpoint(
13+
self, "break here", lldb.SBFileSpec("main.swift")
14+
)
15+
16+
self.expect("frame var ints_span", substrs=["[0] = 6", "[1] = 7"])
17+
self.expect("frame var strings_span", substrs=['[0] = "six"', '[1] = "seven"'])
18+
self.expect("frame var things_span", substrs=["[0] = (id = 67, odd = true)"])
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
struct Thing {
2+
var id: Int
3+
var odd: Bool
4+
5+
init(_ n: Int) {
6+
id = n
7+
odd = n % 2 == 1
8+
}
9+
}
10+
11+
@main struct Entry {
12+
static func main() {
13+
let ints = [6, 7]
14+
let ints_span = ints.span
15+
let strings = ["six", "seven"]
16+
let strings_span = strings.span
17+
let things = [Thing(67)]
18+
let things_span = things.span
19+
print("break here")
20+
}
21+
}

0 commit comments

Comments
 (0)