Skip to content

Commit 9c31e14

Browse files
committed
Be more flexible when handling bridged Swift/ObjC CoreFoundation types.
Foundation, for example, generates new Objective-C classes on the fly (such as instances of _DictionaryStorage<T1, T2>) and LLDB's ObjC runtime implementation isn't set up to recognize these. As a workaround, this patch tries to resolve (id) types in Swift as Swift types when doing dynamic type resolution. rdar://73216083+73842894
1 parent 34458dc commit 9c31e14

File tree

9 files changed

+70
-11
lines changed

9 files changed

+70
-11
lines changed

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -889,8 +889,15 @@ std::vector<ConstString> SwiftLanguage::GetPossibleFormattersMatches(
889889

890890
const bool check_cpp = false;
891891
const bool check_objc = false;
892-
bool canBeSwiftDynamic = compiler_type.IsPossibleDynamicType(
893-
nullptr, check_cpp, check_objc);
892+
bool canBeSwiftDynamic =
893+
compiler_type.IsPossibleDynamicType(nullptr, check_cpp, check_objc) ||
894+
// Foundation (but really any library) may create new
895+
// Objective-C classes at runtime and LLDB's ObjC runtime
896+
// implementation doesn't yet get notified about this. As a
897+
// workaround we try to interpret ObjC id pointers as Swift
898+
// classes to make them available.
899+
(compiler_type.GetCanonicalType().GetTypeClass() ==
900+
eTypeClassObjCObjectPointer);
894901

895902
if (canBeSwiftDynamic) {
896903
do {

lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4795,6 +4795,12 @@ CompilerType SwiftASTContext::GetErrorType() {
47954795
return {};
47964796
}
47974797

4798+
CompilerType SwiftASTContext::GetObjCObjectType() {
4799+
// FIXME: ClangImporter::Implementation stores this type, but it's not
4800+
// exposed.
4801+
return GetCompilerType(ConstString("$sSo8NSObjectCD"));
4802+
}
4803+
47984804
SwiftASTContext *SwiftASTContext::GetSwiftASTContext(swift::ASTContext *ast) {
47994805
SwiftASTContext *swift_ast = GetASTMap().Lookup(ast);
48004806
return swift_ast;

lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ class SwiftASTContext : public TypeSystemSwift {
356356
CreateTupleType(const std::vector<TupleElement> &elements) override;
357357

358358
CompilerType GetErrorType() override;
359+
CompilerType GetObjCObjectType() override;
359360

360361
bool HasErrors();
361362

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwift.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ class TypeSystemSwift : public TypeSystem {
116116
virtual bool IsImportedType(lldb::opaque_compiler_type_t type,
117117
CompilerType *original_type) = 0;
118118
virtual CompilerType GetErrorType() = 0;
119+
virtual CompilerType GetObjCObjectType() = 0;
119120
virtual CompilerType GetReferentType(lldb::opaque_compiler_type_t type) = 0;
120121
static CompilerType GetInstanceType(CompilerType ct);
121122
virtual CompilerType GetInstanceType(lldb::opaque_compiler_type_t type) = 0;

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2752,6 +2752,23 @@ CompilerType TypeSystemSwiftTypeRef::GetErrorType() {
27522752
VALIDATE_AND_RETURN_STATIC(impl, GetErrorType);
27532753
}
27542754

2755+
CompilerType TypeSystemSwiftTypeRef::GetObjCObjectType() {
2756+
auto impl = [&]() {
2757+
using namespace swift::Demangle;
2758+
Demangler dem;
2759+
auto *obj_type = dem.createNode(Node::Kind::Type);
2760+
NodePointer s = dem.createNode(Node::Kind::Structure);
2761+
NodePointer m =
2762+
dem.createNode(Node::Kind::Module, swift::MANGLING_MODULE_OBJC);
2763+
NodePointer ident = dem.createNode(Node::Kind::Identifier, "NSObject");
2764+
s->addChild(m, dem);
2765+
s->addChild(ident, dem);
2766+
obj_type->addChild(s, dem);
2767+
return RemangleAsType(dem, obj_type);
2768+
};
2769+
VALIDATE_AND_RETURN_STATIC(impl, GetObjCObjectType);
2770+
}
2771+
27552772
CompilerType
27562773
TypeSystemSwiftTypeRef::GetReferentType(opaque_compiler_type_t type) {
27572774
auto impl = [&]() -> CompilerType {

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift {
233233
/// builtins (int <-> Swift.Int) as Clang types.
234234
CompilerType GetAsClangTypeOrNull(lldb::opaque_compiler_type_t type);
235235
CompilerType GetErrorType() override;
236+
CompilerType GetObjCObjectType() override;
236237
CompilerType GetReferentType(lldb::opaque_compiler_type_t type) override;
237238
CompilerType GetInstanceType(lldb::opaque_compiler_type_t type) override;
238239
TypeAllocationStrategy

lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2486,7 +2486,8 @@ static bool CouldHaveDynamicValue(ValueObject &in_value) {
24862486
// disable it.
24872487
return !in_value.IsBaseClass();
24882488
}
2489-
return var_type.IsPossibleDynamicType(nullptr, false, false);
2489+
bool check_objc = true;
2490+
return var_type.IsPossibleDynamicType(nullptr, false, check_objc);
24902491
}
24912492

24922493
bool SwiftLanguageRuntimeImpl::GetDynamicTypeAndAddress(
@@ -2497,10 +2498,6 @@ bool SwiftLanguageRuntimeImpl::GetDynamicTypeAndAddress(
24972498
if (use_dynamic == lldb::eNoDynamicValues)
24982499
return false;
24992500

2500-
// Try to import a Clang type into Swift.
2501-
if (in_value.GetObjectRuntimeLanguage() == eLanguageTypeObjC)
2502-
return GetDynamicTypeAndAddress_ClangType(
2503-
in_value, use_dynamic, class_type_or_name, address, value_type);
25042501

25052502
if (!CouldHaveDynamicValue(in_value))
25062503
return false;
@@ -2509,11 +2506,33 @@ bool SwiftLanguageRuntimeImpl::GetDynamicTypeAndAddress(
25092506
// use the scratch context where such operations are legal and safe.
25102507
assert(IsScratchContextLocked(in_value.GetTargetSP()) &&
25112508
"Swift scratch context not locked ahead of dynamic type resolution");
2509+
CompilerType val_type(in_value.GetCompilerType());
2510+
25122511
llvm::Optional<SwiftASTContextReader> maybe_scratch_ctx =
25132512
in_value.GetScratchSwiftASTContext();
2513+
2514+
// Try to import a Clang type into Swift.
2515+
if (in_value.GetObjectRuntimeLanguage() == eLanguageTypeObjC) {
2516+
if (GetDynamicTypeAndAddress_ClangType(
2517+
in_value, use_dynamic, class_type_or_name, address, value_type))
2518+
return true;
2519+
// If the type couldn't be resolved by the Clang runtime:
2520+
// Foundation, for example, generates new Objective-C classes on
2521+
// the fly (such as instances of _DictionaryStorage<T1, T2>) and
2522+
// LLDB's ObjC runtime implementation isn't set up to recognize
2523+
// these. As a workaround, try to resolve them as Swift types.
2524+
if (val_type.GetCanonicalType().GetTypeClass() ==
2525+
eTypeClassObjCObjectPointer)
2526+
if (maybe_scratch_ctx)
2527+
if (auto *scratch_ctx = maybe_scratch_ctx->get())
2528+
val_type = scratch_ctx->GetObjCObjectType();
2529+
}
2530+
25142531
if (!maybe_scratch_ctx)
25152532
return false;
25162533
SwiftASTContextForExpressions *scratch_ctx = maybe_scratch_ctx->get();
2534+
if (!scratch_ctx)
2535+
return false;
25172536

25182537
auto retry_once = [&]() {
25192538
// Retry exactly once using the per-module fallback scratch context.
@@ -2536,7 +2555,6 @@ bool SwiftLanguageRuntimeImpl::GetDynamicTypeAndAddress(
25362555

25372556
// Import the type into the scratch context. Any form of dynamic
25382557
// type resolution may trigger a cross-module import.
2539-
CompilerType val_type(in_value.GetCompilerType());
25402558
Flags type_info(val_type.GetTypeInfo());
25412559
if (!type_info.AnySet(eTypeIsSwift))
25422560
return false;

lldb/test/Shell/SwiftREPL/DictBridging.test

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Test formatters on bridged dictionaries in the REPL.
33
// REQUIRES: system-darwin
44
// REQUIRES: swift
5-
// REQUIRES: rdar73216083
65

76
// RUN: %lldb --repl < %s | FileCheck %s --check-prefix=DICT
87

@@ -68,7 +67,17 @@ let d_objc2 = NSArray(object: [1: 2] as [NSNumber: NSNumber] as NSDictionary)
6867
let d_objc3 = NSArray(object: [1: 2] as [Int: Int] as NSDictionary)
6968
// DICT-LABEL: d_objc3: NSArray = 1 element {
7069
// DICT-NEXT: [0] = 1 key/value pair {
71-
// DICT-NEXT: [0] = (key = 1, value = 2)
70+
//
71+
// Allowing for both multi-line and single-line
72+
// formatting, depending on CoreFoundation
73+
// implementation:
74+
//
75+
// DICT-NOT: }
76+
// DICT: [0] =
77+
// DICT-NOT: }
78+
// DICT: key = 1
79+
// DICT-NOT: }
80+
// DICT: value = 2
7281
// DICT-NEXT: }
7382
// DICT-NEXT: }
7483

lldb/test/Shell/SwiftREPL/SetBridging.test

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Test formatters on bridged sets in the REPL.
33
// REQUIRES: system-darwin
44
// REQUIRES: swift
5-
// REQUIRES: rdar73216234
65

76
// RUN: %lldb --repl < %s | FileCheck %s --check-prefix=SET
87

0 commit comments

Comments
 (0)