Skip to content

Commit 306fe85

Browse files
Merge pull request #9909 from adrian-prantl/143358292
[lldb] Fix Swift.Optional formatter behavior when types cannot be res
2 parents aee4d34 + cbb922c commit 306fe85

File tree

8 files changed

+100
-56
lines changed

8 files changed

+100
-56
lines changed

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

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,38 +38,45 @@ std::string lldb_private::formatters::swift::SwiftOptionalSummaryProvider::
3838
return sstr.GetString().str();
3939
}
4040

41-
// if this ValueObject is an Optional<T> with the Some(T) case selected,
42-
// retrieve the value of the Some case..
43-
static PointerOrSP
41+
/// If this ValueObject is an Optional<T> with the Some(T) case selected,
42+
/// retrieve the value of the Some case.
43+
///
44+
/// Returns {} on error, nullptr on .none, and a ValueObject on .some.
45+
/// None of the callees can pass on errors messages, so this function
46+
/// doesn't return them either.
47+
static std::optional<ValueObjectSP>
4448
ExtractSomeIfAny(ValueObject *optional,
4549
bool synthetic_value = false) {
4650
if (!optional)
47-
return nullptr;
51+
return {};
4852

4953
static ConstString g_Some("some");
5054
static ConstString g_None("none");
5155

5256
ValueObjectSP non_synth_valobj = optional->GetNonSyntheticValue();
5357
if (!non_synth_valobj)
54-
return nullptr;
58+
return {};
5559

5660
ConstString value(non_synth_valobj->GetValueAsCString());
5761

58-
if (!value || value == g_None)
62+
if (!value)
63+
return {};
64+
65+
if (value == g_None)
5966
return nullptr;
6067

61-
PointerOrSP value_sp(
62-
non_synth_valobj->GetChildMemberWithName(g_Some, true).get());
68+
ValueObjectSP value_sp(
69+
non_synth_valobj->GetChildMemberWithName(g_Some, true));
6370
if (!value_sp)
64-
return nullptr;
71+
return {};
6572

6673
auto process_sp = optional->GetProcessSP();
6774
auto *swift_runtime = SwiftLanguageRuntime::Get(process_sp);
6875

6976
CompilerType type = non_synth_valobj->GetCompilerType();
7077
auto type_system = type.GetTypeSystem().dyn_cast_or_null<TypeSystemSwift>();
7178
if (!type_system)
72-
return nullptr;
79+
return {};
7380
if (auto kind = type_system->GetNonTriviallyManagedReferenceKind(
7481
type.GetOpaqueQualType())) {
7582
if (*kind == TypeSystemSwift::NonTriviallyManagedReferenceKind::eWeak) {
@@ -86,10 +93,10 @@ ExtractSomeIfAny(ValueObject *optional,
8693
DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(),
8794
process_sp->GetAddressByteSize());
8895
ExecutionContext exe_ctx(process_sp);
89-
value_sp = PointerOrSP(ValueObject::CreateValueObjectFromData(
90-
value_sp->GetName().AsCString(), extractor, exe_ctx, value_type));
96+
value_sp = ValueObject::CreateValueObjectFromData(
97+
value_sp->GetName().AsCString(), extractor, exe_ctx, value_type);
9198
if (!value_sp)
92-
return nullptr;
99+
return {};
93100
else
94101
value_sp->SetSyntheticChildrenGenerated(true);
95102
}
@@ -116,12 +123,16 @@ ExtractSomeIfAny(ValueObject *optional,
116123
value_sp = value_sp->GetSyntheticValue();
117124

118125
return value_sp;
119-
}
126+
}
120127

121128
static bool
122129
SwiftOptional_SummaryProvider_Impl(ValueObject &valobj, Stream &stream,
123130
const TypeSummaryOptions &options) {
124-
PointerOrSP some = ExtractSomeIfAny(&valobj, true);
131+
std::optional<ValueObjectSP> maybe_some = ExtractSomeIfAny(&valobj, true);
132+
if (!maybe_some)
133+
return false;
134+
135+
ValueObjectSP some = *maybe_some;
125136
if (!some) {
126137
stream.Printf("nil");
127138
return true;
@@ -145,7 +156,7 @@ SwiftOptional_SummaryProvider_Impl(ValueObject &valobj, Stream &stream,
145156
.SetSkipReferences(false);
146157
StringSummaryFormat oneliner(oneliner_flags, "");
147158
std::string buffer;
148-
oneliner.FormatObject(some, buffer, options);
159+
oneliner.FormatObject(some.get(), buffer, options);
149160
stream.Printf("%s", buffer.c_str());
150161
}
151162

@@ -172,8 +183,12 @@ bool lldb_private::formatters::swift::SwiftOptionalSummaryProvider::
172183
if (!target_valobj)
173184
return false;
174185

175-
PointerOrSP some = ExtractSomeIfAny(target_valobj, true);
186+
std::optional<ValueObjectSP> maybe_some =
187+
ExtractSomeIfAny(target_valobj, true);
188+
if (!maybe_some)
189+
return false;
176190

191+
ValueObjectSP some = *maybe_some;
177192
if (!some)
178193
return true;
179194

@@ -191,7 +206,7 @@ bool lldb_private::formatters::swift::SwiftOptionalSummaryProvider::
191206
return false;
192207
return some->HasChildren();
193208
}
194-
return some->HasChildren() && summary_sp->DoesPrintChildren(some);
209+
return some->HasChildren() && summary_sp->DoesPrintChildren(some.get());
195210
}
196211

197212
bool lldb_private::formatters::swift::SwiftOptionalSummaryProvider::
@@ -231,7 +246,12 @@ lldb::ChildCacheState lldb_private::formatters::swift::SwiftOptionalSyntheticFro
231246
m_is_none = true;
232247
m_children = false;
233248

234-
m_some = ExtractSomeIfAny(&m_backend, true);
249+
std::optional<ValueObjectSP> maybe_some =
250+
ExtractSomeIfAny(&m_backend, true);
251+
if (!maybe_some)
252+
return ChildCacheState::eRefetch;
253+
254+
m_some = *maybe_some;
235255

236256
if (!m_some) {
237257
m_is_none = true;

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

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -22,42 +22,6 @@
2222

2323
namespace lldb_private {
2424
namespace formatters {
25-
// ExtractSomeIfAny() can return EITHER a child member or some other long-lived
26-
// ValueObject
27-
// OR an entirely consed-up ValueObject
28-
// The lifetime of these two is radically different, and there is no trivial way
29-
// to do the right
30-
// thing for both cases - except have a class that can wrap either and is safe
31-
// to store and pass around
32-
class PointerOrSP {
33-
public:
34-
PointerOrSP(std::nullptr_t) : m_raw_ptr(nullptr), m_shared_ptr(nullptr) {}
35-
36-
PointerOrSP(ValueObject *valobj) : m_raw_ptr(valobj), m_shared_ptr(nullptr) {}
37-
38-
PointerOrSP(lldb::ValueObjectSP valobj_sp)
39-
: m_raw_ptr(nullptr), m_shared_ptr(valobj_sp) {}
40-
41-
ValueObject *operator->() {
42-
if (m_shared_ptr)
43-
return m_shared_ptr.get();
44-
return m_raw_ptr;
45-
}
46-
47-
ValueObject &operator*() { return *(this->operator->()); }
48-
49-
operator ValueObject *() { return this->operator->(); }
50-
51-
explicit operator bool() const {
52-
return (m_shared_ptr.get() != nullptr) || (m_raw_ptr != nullptr);
53-
}
54-
55-
bool operator==(std::nullptr_t) const { return !(this->operator bool()); }
56-
57-
protected:
58-
ValueObject *m_raw_ptr;
59-
lldb::ValueObjectSP m_shared_ptr;
60-
};
6125

6226
namespace swift {
6327
struct SwiftOptionalSummaryProvider : public TypeSummaryImpl {
@@ -92,7 +56,7 @@ class SwiftOptionalSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
9256
private:
9357
bool m_is_none;
9458
bool m_children;
95-
PointerOrSP m_some;
59+
lldb::ValueObjectSP m_some;
9660

9761
bool IsEmpty() const;
9862
};

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,10 @@ SwiftLanguageRuntime::GetNumFields(CompilerType type,
866866
return rti->getNumFields();
867867
}
868868
}
869+
case TypeInfoKind::Builtin: {
870+
// Clang types without debug info may present themselves like this.
871+
return {};
872+
}
869873
case TypeInfoKind::Enum: {
870874
auto *eti = llvm::cast<EnumTypeInfo>(ti);
871875
return eti->getNumPayloadCases();
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public struct WithOpaqueType {
2+
public init() {}
3+
let opaqueSome : FromC? = FromC(i: 23)
4+
let opaqueNone : FromC? = nil
5+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
SWIFT_SOURCES := main.swift
2+
SWIFTFLAGS_EXTRAS = -I.
3+
LD_EXTRAS = -L. -lLibrary
4+
5+
6+
all: Library $(EXE)
7+
8+
include Makefile.rules
9+
10+
.PHONY: Library
11+
Library:
12+
$(MAKE) MAKE_DSYM=NO CC=$(CC) SWIFTC=$(SWIFTC) \
13+
ARCH=$(ARCH) DSYMUTIL=$(DSYMUTIL) \
14+
VPATH=$(SRCDIR) -I $(SRCDIR) SRCDIR=$(SRCDIR) \
15+
-f $(THIS_FILE_DIR)/Makefile.rules \
16+
DYLIB_SWIFT_SOURCES=Library.swift \
17+
SWIFT_BRIDGING_HEADER=bridging.h \
18+
SWIFT_PRECOMPILE_BRIDGING_HEADER=NO \
19+
DYLIB_NAME=Library \
20+
DYLIB_ONLY=YES \
21+
DEBUG_INFO_FLAG= \
22+
all
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import lldb
2+
from lldbsuite.test.lldbtest import *
3+
from lldbsuite.test.decorators import *
4+
import lldbsuite.test.lldbutil as lldbutil
5+
6+
class TestSwiftOptionalErrorHandling(TestBase):
7+
NO_DEBUG_INFO_TESTCASE = True
8+
9+
@swiftTest
10+
def test(self):
11+
"""Test that errors are surfaced"""
12+
self.build()
13+
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
14+
self, "break here", lldb.SBFileSpec("main.swift"),
15+
extra_images=['Library'])
16+
self.expect('settings set symbols.use-swift-clangimporter false')
17+
self.expect('frame variable x', substrs=[
18+
'opaqueSome', 'missing debug info for Clang type', 'FromC',
19+
'opaqueNone', 'nil',
20+
])
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
struct FromC {
2+
int i;
3+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import Library
2+
func main() {
3+
let x = WithOpaqueType()
4+
print(x) // break here
5+
}
6+
main()

0 commit comments

Comments
 (0)