Skip to content

Commit b3aa2dd

Browse files
committed
[lldb] Implement identification of generic Swift types in C++
The mangled name generated for generic Swift types contain unbound generics. Implement substituting those generic types in by consulting the C++ generated type's templates, and recursively resolving those to their Swift counterpart.
1 parent ac6ccfa commit b3aa2dd

File tree

8 files changed

+207
-54
lines changed

8 files changed

+207
-54
lines changed

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

Lines changed: 80 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,84 @@ SwiftLanguage::GetHardcodedSummaries() {
733733
return g_formatters;
734734
}
735735

736+
static CompilerType
737+
ExtractSwiftTypeFromCxxInteropType(CompilerType type, TypeSystemSwift &ts,
738+
SwiftLanguageRuntime &runtime) {
739+
// Try to recognize a Swift type wrapped in a C++ interop wrapper class.
740+
// These types have a typedef from a char to the swift mangled name, and a
741+
// static constexpr char field whose type is the typedef, and whose name
742+
// is __swift_mangled_name.
743+
// These classes will look something like:
744+
// class CxxBridgedClass {
745+
// [Layout specific variables]
746+
// typedef char $sClassMangledNameHere;
747+
// static inline constexpr $sClassMangledNameHere __swift_mangled_name = 0;
748+
// }
749+
750+
751+
Log *log(GetLog(LLDBLog::DataFormatters));
752+
// This only makes sense for Clang types.
753+
auto tsc = type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
754+
if (!tsc)
755+
return {};
756+
757+
// We operate directly on the qualified type because the TypeSystem
758+
// interface doesn't allow us to check for static constexpr members.
759+
auto qual_type = TypeSystemClang::GetQualType(type.GetOpaqueQualType());
760+
auto *record_type =
761+
llvm::dyn_cast_or_null<clang::RecordType>(qual_type.getTypePtrOrNull());
762+
if (!record_type) {
763+
LLDB_LOGV(log, "[ExtractSwiftTypeFromCxxInteropType] "
764+
"Type is not a record type.");
765+
return {};
766+
}
767+
768+
const clang::RecordDecl *record_decl = record_type->getDecl();
769+
CompilerType swift_type;
770+
771+
for (auto *child_decl : record_decl->decls()) {
772+
auto *var_decl = llvm::dyn_cast<clang::VarDecl>(child_decl);
773+
if (!var_decl)
774+
continue;
775+
776+
auto name = var_decl->getName();
777+
if (name != "__swift_mangled_name")
778+
continue;
779+
780+
const auto *typedef_type =
781+
llvm::dyn_cast<clang::TypedefType>(var_decl->getType());
782+
if (!typedef_type)
783+
break;
784+
785+
auto *decl = typedef_type->getDecl();
786+
if (!decl)
787+
break;
788+
789+
auto swift_name = decl->getName();
790+
if (!swift::Demangle::isMangledName(swift_name))
791+
break;
792+
793+
swift_type = ts.GetTypeFromMangledTypename(ConstString(swift_name));
794+
break;
795+
}
796+
797+
if (swift_type) {
798+
auto bound_type = runtime.BindGenericTypeParameters(
799+
swift_type, [&](unsigned depth, unsigned index) -> CompilerType {
800+
assert(depth == 0 && "Unexpected depth! C++ interop does not support "
801+
"nested generic parameters");
802+
if (depth > 0)
803+
return {};
804+
805+
auto templated_type = type.GetTypeTemplateArgument(index);
806+
return ExtractSwiftTypeFromCxxInteropType(templated_type, ts,
807+
runtime);
808+
});
809+
return bound_type;
810+
}
811+
return {};
812+
}
813+
736814
HardcodedFormatters::HardcodedSyntheticFinder
737815
SwiftLanguage::GetHardcodedSynthetics() {
738816
static std::once_flag g_initialize;
@@ -862,11 +940,6 @@ SwiftLanguage::GetHardcodedSynthetics() {
862940
lldb::DynamicValueType dyn_type,
863941
FormatManager &format_manager)
864942
-> lldb::SyntheticChildrenSP {
865-
// Try to recognize a Swift type wrapped in a C++ interop wrapper class.
866-
// These types have a typedef from a char to the swift mangled name, and a
867-
// static constexpr char field whose type is the typedef, and whose name
868-
// is $__swift_mangled_name.
869-
870943
Log *log(GetLog(LLDBLog::DataFormatters));
871944

872945
ProcessSP process_sp(valobj.GetProcessSP());
@@ -885,56 +958,10 @@ SwiftLanguage::GetHardcodedSynthetics() {
885958
}
886959
auto &type_system_swift = **scratch_ctx;
887960

888-
// This only makes sense for Clang types.
889961
auto type = valobj.GetCompilerType();
890-
auto tsc = type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
891-
if (!tsc) {
892-
LLDB_LOGV(log, "[Matching CxxBridgedSyntheticChildProvider] - "
893-
"Type is not a clang type.");
894-
return nullptr;
895-
}
896-
897-
// We operate directly on the qualified type because the TypeSystem
898-
// interface doesn't allow us to check for static constexpr members.
899-
auto qual_type = TypeSystemClang::GetQualType(type.GetOpaqueQualType());
900-
auto *record_type = llvm::dyn_cast_or_null<clang::RecordType>(
901-
qual_type.getTypePtrOrNull());
902-
if (!record_type) {
903-
LLDB_LOGV(log, "[Matching CxxBridgedSyntheticChildProvider] - "
904-
"Type is not a record type.");
905-
return nullptr;
906-
}
907-
908-
const clang::RecordDecl *record_decl = record_type->getDecl();
909-
CompilerType swift_type;
910-
911-
for (auto *child_decl : record_decl->decls()) {
912-
auto *var_decl = llvm::dyn_cast<clang::VarDecl>(child_decl);
913-
if (!var_decl)
914-
continue;
915-
916-
auto name = var_decl->getName();
917-
if (name != "__swift_mangled_name")
918-
continue;
919-
920-
const auto *typedef_type =
921-
llvm::dyn_cast<clang::TypedefType>(var_decl->getType());
922-
if (!typedef_type)
923-
break;
924-
925-
auto *decl = typedef_type->getDecl();
926-
if (!decl)
927-
break;
928-
929-
auto swift_name = decl->getName();
930-
if (!swift::Demangle::isMangledName(swift_name))
931-
break;
932-
933-
swift_type = type_system_swift.GetTypeFromMangledTypename(
934-
ConstString(swift_name));
935-
break;
936-
}
937962

963+
auto swift_type = ExtractSwiftTypeFromCxxInteropType(
964+
type, type_system_swift, *swift_runtime);
938965
if (!swift_type) {
939966
LLDB_LOGV(log, "[Matching CxxBridgedSyntheticChildProvider] - "
940967
"Did not find Swift type.");

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,13 @@ class SwiftLanguageRuntimeStub {
346346
return {};
347347
}
348348

349+
CompilerType BindGenericTypeParameters(
350+
CompilerType unbound_type,
351+
std::function<CompilerType(unsigned, unsigned)> type_finder) {
352+
STUB_LOG();
353+
return {};
354+
}
355+
349356
CompilerType GetConcreteType(ExecutionContextScope *exe_scope,
350357
ConstString abstract_type_name) {
351358
STUB_LOG();
@@ -1818,6 +1825,20 @@ lldb::ValueObjectSP SwiftLanguageRuntime::ExtractSwiftValueObjectFromCxxWrapper(
18181825

18191826
auto opaque_ptr_valobj = child_valobj->GetChildAtIndex(0, true);
18201827
swift_valobj = opaque_ptr_valobj;
1828+
} else if (child_type.GetMangledTypeName() == "swift::_impl::OpaqueStorage") {
1829+
if (child_valobj->GetNumChildren() != 1)
1830+
return swift_valobj;
1831+
1832+
auto opaque_ptr_valobj = child_valobj->GetChildAtIndex(0, true);
1833+
1834+
Status error;
1835+
opaque_ptr_valobj = opaque_ptr_valobj->Dereference(error);
1836+
if (error.Success())
1837+
swift_valobj = opaque_ptr_valobj;
1838+
else
1839+
LLDB_LOGF(GetLog(LLDBLog::Types),
1840+
"Could not dereference opaque storage value object, error: %s",
1841+
error.AsCString());
18211842
} else {
18221843
CompilerType element_type;
18231844
if (child_type.IsArrayType(&element_type)) {
@@ -2378,6 +2399,12 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress(
23782399
address, value_type);
23792400
}
23802401

2402+
CompilerType SwiftLanguageRuntime::BindGenericTypeParameters(
2403+
CompilerType unbound_type,
2404+
std::function<CompilerType(unsigned, unsigned)> type_resolver) {
2405+
FORWARD(BindGenericTypeParameters, unbound_type, type_resolver);
2406+
}
2407+
23812408
void SwiftLanguageRuntime::DumpTyperef(CompilerType type,
23822409
TypeSystemSwiftTypeRef *module_holder,
23832410
Stream *s) {

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,12 @@ class SwiftLanguageRuntime : public LanguageRuntime {
219219
Address &address,
220220
Value::ValueType &value_type) override;
221221

222+
CompilerType BindGenericTypeParameters(
223+
CompilerType unbound_type,
224+
std::function<CompilerType(unsigned, unsigned)> finder);
225+
222226
/// Extract the value object which contains the Swift type's "contents".
223-
/// Returns null if this is not a C++ wrapping a Swift type.
227+
/// Returns null if this is not a C++ wrapping a Swift type.
224228
static lldb::ValueObjectSP
225229
ExtractSwiftValueObjectFromCxxWrapper(ValueObject &valobj);
226230

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

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,6 +2005,75 @@ ForEachGenericParameter(swift::Demangle::NodePointer node,
20052005
}
20062006
}
20072007

2008+
CompilerType SwiftLanguageRuntimeImpl::BindGenericTypeParameters(
2009+
CompilerType unbound_type,
2010+
std::function<CompilerType(unsigned, unsigned)> type_resolver) {
2011+
LLDB_SCOPED_TIMER();
2012+
using namespace swift::Demangle;
2013+
2014+
auto ts =
2015+
unbound_type.GetTypeSystem().dyn_cast_or_null<TypeSystemSwift>();
2016+
Status error;
2017+
auto *reflection_ctx = GetReflectionContext();
2018+
if (!reflection_ctx) {
2019+
LLDB_LOG(GetLog(LLDBLog::Types),
2020+
"No reflection context available.");
2021+
return unbound_type;
2022+
}
2023+
2024+
Demangler dem;
2025+
NodePointer unbound_node =
2026+
dem.demangleSymbol(unbound_type.GetMangledTypeName().GetStringRef());
2027+
auto type_ref_or_err =
2028+
decodeMangledType(reflection_ctx->getBuilder(), unbound_node);
2029+
if (type_ref_or_err.isError()) {
2030+
LLDB_LOG(GetLog(LLDBLog::Expressions | LLDBLog::Types),
2031+
"Couldn't get TypeRef of unbound type.");
2032+
return {};
2033+
}
2034+
2035+
swift::reflection::GenericArgumentMap substitutions;
2036+
bool failure = false;
2037+
ForEachGenericParameter(unbound_node, [&](unsigned depth, unsigned index) {
2038+
if (failure)
2039+
return;
2040+
if (substitutions.count({depth, index}))
2041+
return;
2042+
2043+
auto type = type_resolver(depth, index);
2044+
if (!type) {
2045+
LLDB_LOG(GetLog(LLDBLog::Expressions | LLDBLog::Types),
2046+
"type_finder function failed to find type.");
2047+
failure = true;
2048+
return;
2049+
}
2050+
2051+
NodePointer child_node =
2052+
dem.demangleSymbol(type.GetMangledTypeName().GetStringRef());
2053+
auto type_ref_or_err =
2054+
decodeMangledType(reflection_ctx->getBuilder(), child_node);
2055+
if (type_ref_or_err.isError()) {
2056+
LLDB_LOG(GetLog(LLDBLog::Expressions | LLDBLog::Types),
2057+
"Couldn't get TypeRef when binding generic type parameters.");
2058+
failure = true;
2059+
return;
2060+
}
2061+
2062+
substitutions.insert({{depth, index}, type_ref_or_err.getType()});
2063+
});
2064+
2065+
if (failure)
2066+
return {};
2067+
2068+
const swift::reflection::TypeRef *type_ref = type_ref_or_err.getType();
2069+
2070+
// Apply the substitutions.
2071+
const swift::reflection::TypeRef *bound_type_ref =
2072+
type_ref->subst(reflection_ctx->getBuilder(), substitutions);
2073+
NodePointer node = bound_type_ref->getDemangling(dem);
2074+
return ts->GetTypeSystemSwiftTypeRef().RemangleAsType(dem, node);
2075+
}
2076+
20082077
CompilerType
20092078
SwiftLanguageRuntimeImpl::BindGenericTypeParameters(StackFrame &stack_frame,
20102079
TypeSystemSwiftTypeRef &ts,

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ class SwiftLanguageRuntimeImpl {
145145
bool &child_is_deref_of_parent, ValueObject *valobj,
146146
uint64_t &language_flags);
147147

148+
CompilerType BindGenericTypeParameters(
149+
CompilerType unbound_type,
150+
std::function<CompilerType(unsigned, unsigned)> type_resolver);
151+
148152
/// Like \p BindGenericTypeParameters but for TypeSystemSwiftTypeRef.
149153
CompilerType BindGenericTypeParameters(StackFrame &stack_frame,
150154
TypeSystemSwiftTypeRef &ts,

lldb/test/API/lang/swift/cxx_interop/backward/test-format-swift-types-in-cxx/TestSwiftFormatSwiftTypesInCxx.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,9 @@ def test_class(self):
3434
self.expect('p swiftStruct', substrs=['SwiftStruct', 'str = "Hello this is a big string"',
3535
'boolean = true'])
3636

37+
self.expect('v wrapper', substrs=['a.GenericPair<a.SwiftClass, a.SwiftStruct>',
38+
'field = 42', 'arr = 4 values', '[0] = "An"', '[1] = "array"', '[2] = "of"',
39+
'[3] = "strings"', 'str = "Hello this is a big string"', 'boolean = true'])
40+
self.expect('p wrapper', substrs=['a.GenericPair<a.SwiftClass, a.SwiftStruct>',
41+
'field = 42', 'arr = 4 values', '[0] = "An"', '[1] = "array"', '[2] = "of"',
42+
'[3] = "strings"', 'str = "Hello this is a big string"', 'boolean = true'])

lldb/test/API/lang/swift/cxx_interop/backward/test-format-swift-types-in-cxx/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ int main() {
55
auto swiftClass = returnSwiftClass();
66
auto swiftSublass = returnSwiftSubclassAsClass();
77
auto swiftStruct = returnSwiftStruct();
8+
auto wrapper = returnPair(swiftClass, swiftStruct);
89
return 0; // Set breakpoint here.
910
}

lldb/test/API/lang/swift/cxx_interop/backward/test-format-swift-types-in-cxx/swift-types.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@ public struct SwiftStruct {
1313
var boolean = true
1414
}
1515

16+
@frozen
17+
public struct GenericPair<T, T2> {
18+
var x: T
19+
var y: T2
20+
21+
init(x: T, y: T2) {
22+
self.x = x
23+
self.y = y
24+
}
25+
}
26+
1627
public func returnSwiftClass() -> SwiftClass {
1728
return SwiftClass()
1829
}
@@ -24,3 +35,7 @@ public func returnSwiftSubclassAsClass() -> SwiftClass {
2435
public func returnSwiftStruct() -> SwiftStruct {
2536
return SwiftStruct()
2637
}
38+
39+
public func returnPair<T, U>(t: T, u: U) -> GenericPair<T, U> {
40+
return GenericPair<T, U>(x: t, y: u)
41+
}

0 commit comments

Comments
 (0)