Skip to content

Commit cbb922c

Browse files
committed
[lldb] Fix Swift.Optional formatter behavior when types cannot be resolved
Previously this formatter would print "nil" as the summary of an optional whose payload could not be resolved in the typesystem, which is very misleading. rdar://143358292
1 parent 2c16566 commit cbb922c

File tree

6 files changed

+90
-14
lines changed

6 files changed

+90
-14
lines changed

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

Lines changed: 34 additions & 14 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 ValueObjectSP
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

6168
ValueObjectSP value_sp(
6269
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 = ValueObjectSP(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
}
@@ -121,7 +128,11 @@ ExtractSomeIfAny(ValueObject *optional,
121128
static bool
122129
SwiftOptional_SummaryProvider_Impl(ValueObject &valobj, Stream &stream,
123130
const TypeSummaryOptions &options) {
124-
ValueObjectSP 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;
@@ -172,8 +183,12 @@ bool lldb_private::formatters::swift::SwiftOptionalSummaryProvider::
172183
if (!target_valobj)
173184
return false;
174185

175-
ValueObjectSP 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

@@ -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;
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)