diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h index 36a536e991df0..116dc109f68d2 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h @@ -376,7 +376,9 @@ class SwiftLanguageRuntime : public LanguageRuntime { /// Ask Remote Mirrors about the children of a composite type. llvm::Expected GetNumChildren(CompilerType type, - ExecutionContextScope *exe_scope); + ExecutionContextScope *exe_scope, + bool include_superclass = true, + bool include_clang_types = true); /// Determine the enum case name for the \p data value of the enum \p type. /// This is performed using Swift reflection. @@ -422,7 +424,7 @@ class SwiftLanguageRuntime : public LanguageRuntime { uint64_t &language_flags); /// Ask Remote Mirrors about the fields of a composite type. - std::optional GetNumFields(CompilerType type, + llvm::Expected GetNumFields(CompilerType type, ExecutionContext *exe_ctx); /// Ask Remote Mirrors for the size of a Swift type. diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp index 90f2c8356d97e..69166955f39a1 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp +++ b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp @@ -709,8 +709,17 @@ CompilerType GetTypedefedTypeRecursive(CompilerType type) { } // namespace llvm::Expected -SwiftLanguageRuntime::GetNumChildren(CompilerType type, - ExecutionContextScope *exe_scope) { +SwiftLanguageRuntime::GetNumFields(CompilerType type, + ExecutionContext *exe_ctx) { + if (exe_ctx) + return GetNumChildren(type, exe_ctx->GetBestExecutionContextScope(), false, + false); + return llvm::createStringError("no execution context"); +} + +llvm::Expected SwiftLanguageRuntime::GetNumChildren( + CompilerType type, ExecutionContextScope *exe_scope, + bool include_superclass, bool include_clang_types) { LLDB_SCOPED_TIMER(); auto ts_sp = type.GetTypeSystem().dyn_cast_or_null(); @@ -726,7 +735,7 @@ SwiftLanguageRuntime::GetNumChildren(CompilerType type, return pack_type->count; // Deal with Clang types. - { + if (include_clang_types) { CompilerType clang_type = LookupAnonymousClangType(type.GetMangledTypeName().AsCString()); if (!clang_type) @@ -806,7 +815,7 @@ SwiftLanguageRuntime::GetNumChildren(CompilerType type, if (GetWeakReferent(ts, type)) return 1; break; - default: + case swift::reflection::ReferenceKind::Strong: break; } @@ -838,7 +847,8 @@ SwiftLanguageRuntime::GetNumChildren(CompilerType type, type.GetMangledTypeName(), rti->getNumFields()); // The superclass, if any, is an extra child. - if (reflection_ctx->LookupSuperclass(*tr, ts.GetDescriptorFinder())) + if (include_superclass && + reflection_ctx->LookupSuperclass(*tr, ts.GetDescriptorFinder())) return rti->getNumFields() + 1; return rti->getNumFields(); } @@ -867,91 +877,6 @@ SwiftLanguageRuntime::GetNumChildren(CompilerType type, type.GetMangledTypeName().GetString()); } -std::optional -SwiftLanguageRuntime::GetNumFields(CompilerType type, - ExecutionContext *exe_ctx) { - auto ts_sp = type.GetTypeSystem().dyn_cast_or_null(); - if (!ts_sp) - return {}; - auto &ts = *ts_sp; - - using namespace swift::reflection; - // Try the static type metadata. - const TypeRef *tr = nullptr; - auto ti_or_err = GetSwiftRuntimeTypeInfo( - type, exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr, &tr); - if (!ti_or_err) { - LLDB_LOG_ERRORV(GetLog(LLDBLog::Types), ti_or_err.takeError(), "{0}"); - return {}; - } - auto *ti = &*ti_or_err; - - // Structs and Tuples. - switch (ti->getKind()) { - case TypeInfoKind::Record: { - // Structs and Tuples. - auto *rti = llvm::cast(ti); - switch (rti->getRecordKind()) { - case RecordKind::ExistentialMetatype: - case RecordKind::ThickFunction: - // There are two fields, `function` and `context`, but they're not exposed - // by lldb. - return 0; - case RecordKind::OpaqueExistential: - // `OpaqueExistential` is documented as: - // An existential is a three-word buffer followed by value metadata... - // The buffer is exposed as fields named `payload_data_{0,1,2}`, and - // the number of fields are increased to match. - return rti->getNumFields() + 3; - default: - return rti->getNumFields(); - } - } - case TypeInfoKind::Builtin: { - // Clang types without debug info may present themselves like this. - return {}; - } - case TypeInfoKind::Enum: { - auto *eti = llvm::cast(ti); - return eti->getNumPayloadCases(); - } - case TypeInfoKind::Reference: { - // Objects. - auto *rti = llvm::cast(ti); - switch (rti->getReferenceKind()) { - case ReferenceKind::Weak: - case ReferenceKind::Unowned: - case ReferenceKind::Unmanaged: - if (auto referent = GetWeakReferent(ts, type)) - return referent.GetNumFields(exe_ctx); - return 0; - case ReferenceKind::Strong: - ThreadSafeReflectionContext reflection_ctx = GetReflectionContext(); - if (!reflection_ctx) - return {}; - if (!tr) - return {}; - - LLDBTypeInfoProvider tip(*this, ts); - auto cti_or_err = reflection_ctx->GetClassInstanceTypeInfo( - *tr, &tip, ts.GetDescriptorFinder()); - if (!cti_or_err) { - LLDB_LOG_ERRORV(GetLog(LLDBLog::Types), cti_or_err.takeError(), - "GetNumFields failed: {0}"); - return {}; - } - if (auto *rti = llvm::dyn_cast_or_null(&*cti_or_err)) - return rti->getNumFields(); - - return {}; - } - } - default: - LogUnimplementedTypeKind(__FUNCTION__, type); - return {}; - } -} - static std::pair> findFieldWithName(const std::vector &fields, const swift::reflection::TypeRef *tr, llvm::StringRef name, diff --git a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp index 26117864a3793..8649156be370e 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp @@ -3782,10 +3782,15 @@ uint32_t TypeSystemSwiftTypeRef::GetNumFields(opaque_compiler_type_t type, LLDB_SCOPED_TIMER(); auto impl = [&]() -> std::optional { if (exe_ctx) - if (auto *runtime = SwiftLanguageRuntime::Get(exe_ctx->GetProcessSP())) - if (auto num_fields = - runtime->GetNumFields(GetCanonicalType(type), exe_ctx)) - return num_fields; + if (auto *runtime = SwiftLanguageRuntime::Get(exe_ctx->GetProcessSP())) { + auto num_fields_or_err = + runtime->GetNumFields(GetCanonicalType(type), exe_ctx); + if (num_fields_or_err) + return *num_fields_or_err; + LLDB_LOG_ERROR(GetLog(LLDBLog::Types), num_fields_or_err.takeError(), + "GetNumFields failed for type {1}: {0}", + AsMangledName(type)); + } bool is_imported = false; if (auto clang_type = GetAsClangTypeOrNull(type, &is_imported)) { @@ -4983,6 +4988,8 @@ bool TypeSystemSwiftTypeRef::DumpTypeValue( is_base_class); return false; } + case Node::Kind::ProtocolList: + return false; default: assert(false && "Unhandled node kind"); LLDB_LOGF(GetLog(LLDBLog::Types), diff --git a/lldb/test/API/lang/swift/clangimporter/objc_protocol/Makefile b/lldb/test/API/lang/swift/clangimporter/objc_protocol/Makefile new file mode 100644 index 0000000000000..25665993c2e78 --- /dev/null +++ b/lldb/test/API/lang/swift/clangimporter/objc_protocol/Makefile @@ -0,0 +1,4 @@ +SWIFT_SOURCES := main.swift +SWIFTFLAGS_EXTRAS = -Xcc -I$(SRCDIR) + +include Makefile.rules diff --git a/lldb/test/API/lang/swift/clangimporter/objc_protocol/P.h b/lldb/test/API/lang/swift/clangimporter/objc_protocol/P.h new file mode 100644 index 0000000000000..88da034e3273a --- /dev/null +++ b/lldb/test/API/lang/swift/clangimporter/objc_protocol/P.h @@ -0,0 +1,2 @@ +@protocol P +@end diff --git a/lldb/test/API/lang/swift/clangimporter/objc_protocol/TestSwiftObjCProtocol.py b/lldb/test/API/lang/swift/clangimporter/objc_protocol/TestSwiftObjCProtocol.py new file mode 100644 index 0000000000000..fa454ea6e49d5 --- /dev/null +++ b/lldb/test/API/lang/swift/clangimporter/objc_protocol/TestSwiftObjCProtocol.py @@ -0,0 +1,16 @@ +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +import lldbsuite.test.lldbutil as lldbutil + +class TestSwiftObjCProtocol(TestBase): + @skipUnlessDarwin + @swiftTest + def test(self): + """Test printing an Objective-C protocol existential member.""" + self.build() + lldbutil.run_to_source_breakpoint( + self, 'break here', lldb.SBFileSpec('main.swift') + ) + + self.expect("v self", substrs=["obj", "0x"]) diff --git a/lldb/test/API/lang/swift/clangimporter/objc_protocol/main.swift b/lldb/test/API/lang/swift/clangimporter/objc_protocol/main.swift new file mode 100644 index 0000000000000..3c1d8568319d5 --- /dev/null +++ b/lldb/test/API/lang/swift/clangimporter/objc_protocol/main.swift @@ -0,0 +1,14 @@ +import P + +class ImplementsP : P {} + +class C { + init(p: P) { x = p } + weak var x : P? + + func f() { + print("break here") + } +} + +C(p: ImplementsP()).f() diff --git a/lldb/test/API/lang/swift/clangimporter/objc_protocol/module.modulemap b/lldb/test/API/lang/swift/clangimporter/objc_protocol/module.modulemap new file mode 100644 index 0000000000000..52817f4e2ed9f --- /dev/null +++ b/lldb/test/API/lang/swift/clangimporter/objc_protocol/module.modulemap @@ -0,0 +1 @@ +module P { header "P.h" }