Skip to content

[Cherry-pick into next] [lldb] Unify implementation of GetNumChildren and GetNumFields #10488

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,9 @@ class SwiftLanguageRuntime : public LanguageRuntime {

/// Ask Remote Mirrors about the children of a composite type.
llvm::Expected<uint32_t> 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.
Expand Down Expand Up @@ -422,7 +424,7 @@ class SwiftLanguageRuntime : public LanguageRuntime {
uint64_t &language_flags);

/// Ask Remote Mirrors about the fields of a composite type.
std::optional<unsigned> GetNumFields(CompilerType type,
llvm::Expected<unsigned> GetNumFields(CompilerType type,
ExecutionContext *exe_ctx);

/// Ask Remote Mirrors for the size of a Swift type.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -709,8 +709,17 @@ CompilerType GetTypedefedTypeRecursive(CompilerType type) {
} // namespace

llvm::Expected<uint32_t>
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<uint32_t> 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<TypeSystemSwiftTypeRef>();
Expand All @@ -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)
Expand Down Expand Up @@ -806,7 +815,7 @@ SwiftLanguageRuntime::GetNumChildren(CompilerType type,
if (GetWeakReferent(ts, type))
return 1;
break;
default:
case swift::reflection::ReferenceKind::Strong:
break;
}

Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -867,91 +877,6 @@ SwiftLanguageRuntime::GetNumChildren(CompilerType type,
type.GetMangledTypeName().GetString());
}

std::optional<unsigned>
SwiftLanguageRuntime::GetNumFields(CompilerType type,
ExecutionContext *exe_ctx) {
auto ts_sp = type.GetTypeSystem().dyn_cast_or_null<TypeSystemSwiftTypeRef>();
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<RecordTypeInfo>(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<EnumTypeInfo>(ti);
return eti->getNumPayloadCases();
}
case TypeInfoKind::Reference: {
// Objects.
auto *rti = llvm::cast<ReferenceTypeInfo>(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<RecordTypeInfo>(&*cti_or_err))
return rti->getNumFields();

return {};
}
}
default:
LogUnimplementedTypeKind(__FUNCTION__, type);
return {};
}
}

static std::pair<SwiftLanguageRuntime::LookupResult, std::optional<size_t>>
findFieldWithName(const std::vector<swift::reflection::FieldInfo> &fields,
const swift::reflection::TypeRef *tr, llvm::StringRef name,
Expand Down
15 changes: 11 additions & 4 deletions lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3819,10 +3819,15 @@ uint32_t TypeSystemSwiftTypeRef::GetNumFields(opaque_compiler_type_t type,
LLDB_SCOPED_TIMER();
auto impl = [&]() -> std::optional<uint32_t> {
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)) {
Expand Down Expand Up @@ -5020,6 +5025,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),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
SWIFT_SOURCES := main.swift
SWIFTFLAGS_EXTRAS = -Xcc -I$(SRCDIR)

include Makefile.rules
2 changes: 2 additions & 0 deletions lldb/test/API/lang/swift/clangimporter/objc_protocol/P.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@protocol P
@end
Original file line number Diff line number Diff line change
@@ -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"])
14 changes: 14 additions & 0 deletions lldb/test/API/lang/swift/clangimporter/objc_protocol/main.swift
Original file line number Diff line number Diff line change
@@ -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()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module P { header "P.h" }