Skip to content

Commit a50350e

Browse files
committed
[lldb] Change the representation of Swift enums
(Payload-carrying) Swift enums are a challenging datastructure to support in LLDB; this patch makes an attempt to clean up a problem with the previous implementation, namely the dynamic nature of the children of an enum, which has, in the past, lead to caching bugs when displaying the children of enums. The new scheme is as follows: - The static value of an enum is its discriminator (its case). - An enum has no static children. - The synthtic value of an enum is its projected case's payload. - A synthetic child provider for all Swift enums provides synthetic children, which are the children of the projected case's payload. For example: ``` enum E { case a case b(Int, (Int, Int)) } let a : E= .a let b : E= .b(1, (2, 3)) ``` The value of `a` is `.a`. The value of `b` is `.b`. The synthtic value of `b` is (1, (2, 3)). The synthetic child 0 of `b` is 1. The synthetic child 1 of `b` is (2, 3). The number of (non-synthetic) children of `b` is 0. The Swift Optional formatter behaves similarly. Known Issues: - SwiftRuntimeTypeVisitor does currently not visit the children of Objective-C types; this also needs to get fixed, and is surfaced by the new synthtic child providers in 1 test. Implementation Notes: This removes a lot of enum-handling code from SwiftLanguageRuntime; simplifying the type visitor and dynamic type resolution, adn moves it into the Enum/Optional synthetic frontends.
1 parent cf4a54e commit a50350e

34 files changed

+703
-509
lines changed

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

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -745,9 +745,9 @@ class EnumSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
745745
size_t GetIndexOfChildWithName(ConstString name) override;
746746

747747
private:
748-
ExecutionContextRef m_exe_ctx_ref;
749-
ConstString m_element_name;
750-
size_t m_child_index;
748+
ValueObjectSP m_projected;
749+
lldb::DynamicValueType m_dynamic = eNoDynamicValues;
750+
bool m_indirect = false;
751751
};
752752

753753
static std::string mangledTypenameForTasksTuple(size_t count) {
@@ -1511,46 +1511,83 @@ class ActorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
15111511

15121512
lldb_private::formatters::swift::EnumSyntheticFrontEnd::EnumSyntheticFrontEnd(
15131513
lldb::ValueObjectSP valobj_sp)
1514-
: SyntheticChildrenFrontEnd(*valobj_sp.get()), m_exe_ctx_ref(),
1515-
m_element_name(nullptr), m_child_index(UINT32_MAX) {
1514+
: SyntheticChildrenFrontEnd(*valobj_sp.get()) {
15161515
if (valobj_sp)
15171516
Update();
15181517
}
15191518

15201519
llvm::Expected<uint32_t>
15211520
lldb_private::formatters::swift::EnumSyntheticFrontEnd::CalculateNumChildren() {
1522-
return m_child_index != UINT32_MAX ? 1 : 0;
1521+
if (m_indirect && m_projected)
1522+
return m_projected->GetNumChildren();
1523+
return m_projected ? 1 : 0;
15231524
}
15241525

15251526
lldb::ValueObjectSP
15261527
lldb_private::formatters::swift::EnumSyntheticFrontEnd::GetChildAtIndex(
15271528
uint32_t idx) {
1528-
if (idx)
1529-
return ValueObjectSP();
1530-
if (m_child_index == UINT32_MAX)
1531-
return ValueObjectSP();
1532-
return m_backend.GetChildAtIndex(m_child_index, true);
1529+
ValueObjectSP value_sp;
1530+
// Hide the indirection.
1531+
if (m_indirect && m_projected) {
1532+
value_sp = m_projected->GetChildAtIndex(idx);
1533+
} else {
1534+
if (idx != 0)
1535+
return {};
1536+
value_sp = m_projected;
1537+
}
1538+
if (!value_sp)
1539+
return {};
1540+
1541+
return value_sp;
15331542
}
15341543

15351544
lldb::ChildCacheState
15361545
lldb_private::formatters::swift::EnumSyntheticFrontEnd::Update() {
1537-
m_element_name.Clear();
1538-
m_child_index = UINT32_MAX;
1539-
m_exe_ctx_ref = m_backend.GetExecutionContextRef();
1540-
m_element_name.SetCString(m_backend.GetValueAsCString());
1541-
m_child_index = m_backend.GetIndexOfChildWithName(m_element_name);
1546+
auto *runtime = SwiftLanguageRuntime::Get(m_backend.GetProcessSP());
1547+
if (!runtime)
1548+
return ChildCacheState::eRefetch;
1549+
1550+
llvm::Expected<ValueObjectSP> projected =
1551+
runtime->SwiftLanguageRuntime::ProjectEnum(m_backend);
1552+
if (!projected) {
1553+
LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), projected.takeError(),
1554+
"{0}");
1555+
return ChildCacheState::eRefetch;
1556+
}
1557+
1558+
m_dynamic = m_backend.GetDynamicValueType();
1559+
m_projected = *projected;
1560+
if (m_projected &&
1561+
m_projected->GetName().GetStringRef().starts_with("$indirect."))
1562+
m_indirect = true;
1563+
else
1564+
m_indirect = false;
1565+
1566+
if (!m_projected)
1567+
return ChildCacheState::eRefetch;
1568+
1569+
if ((m_projected->GetCompilerType().GetTypeInfo() & eTypeIsEnumeration))
1570+
if (auto synthetic_sp = m_projected->GetSyntheticValue())
1571+
m_projected = synthetic_sp;
1572+
1573+
if (m_dynamic != eNoDynamicValues)
1574+
if (auto dynamic_sp = m_projected->GetDynamicValue(m_dynamic))
1575+
m_projected = dynamic_sp;
15421576
return ChildCacheState::eRefetch;
15431577
}
15441578

15451579
bool lldb_private::formatters::swift::EnumSyntheticFrontEnd::
15461580
MightHaveChildren() {
1547-
return m_child_index != UINT32_MAX;
1581+
return m_projected ? true : false;
15481582
}
15491583

15501584
size_t
15511585
lldb_private::formatters::swift::EnumSyntheticFrontEnd::GetIndexOfChildWithName(
15521586
ConstString name) {
1553-
if (name == m_element_name)
1587+
// Hide the indirection.
1588+
if (m_indirect && m_projected)
1589+
return m_projected->GetIndexOfChildWithName(name);
1590+
if (m_projected && name == m_projected->GetName())
15541591
return 0;
15551592
return UINT32_MAX;
15561593
}

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

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -522,9 +522,9 @@ static void LoadSwiftFormatters(lldb::TypeCategoryImplSP swift_category_sp) {
522522

523523
TypeSummaryImpl::Flags optional_summary_flags;
524524
optional_summary_flags.SetCascades(true)
525-
.SetDontShowChildren(false) // this one will actually be calculated at
526-
// runtime, what you pass here doesn't matter
527-
.SetDontShowValue(true)
525+
.SetDontShowChildren(true) // this one will actually be calculated at
526+
// runtime, what you pass here doesn't matter
527+
.SetDontShowValue(false)
528528
.SetHideItemNames(false)
529529
.SetShowMembersOneLiner(false)
530530
.SetSkipPointers(true)
@@ -968,10 +968,6 @@ SwiftLanguage::GetHardcodedSynthetics() {
968968
CompilerType type(valobj.GetCompilerType());
969969
Flags type_flags(type.GetTypeInfo());
970970
if (type_flags.AllSet(eTypeIsSwift | eTypeIsEnumeration)) {
971-
// FIXME: The classification of clang-imported enums may
972-
// change based on whether a Swift module is present or not.
973-
if (!valobj.GetValueAsCString())
974-
return nullptr;
975971
if (!swift_enum_synth)
976972
swift_enum_synth = lldb::SyntheticChildrenSP(new CXXSyntheticChildren(
977973
SyntheticChildren::Flags()

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,15 +199,16 @@ bool lldb_private::formatters::swift::SwiftOptionSetSummaryProvider::
199199
}
200200
}
201201

202-
if (!any_match)
203-
return false;
204-
205202
if (matched_value != value) {
206203
// Print the unaccounted-for bits separately.
207204
llvm::APInt residual = value & ~matched_value;
208205
llvm::SmallString<24> string;
209206
residual.toString(string, 16, false);
210-
ss << ", 0x" << string;
207+
if (any_match)
208+
ss << ", ";
209+
else
210+
ss << "rawValue = ";
211+
ss << "0x" << string;
211212
}
212213
ss << ']';
213214

0 commit comments

Comments
 (0)