Skip to content

Commit 646d2f3

Browse files
committed
[LLDB] Add ObjC object typeref support to SwiftRuntimeTypeVisitor
This is done by defering to the Objective-C runtime. This functionality is implemented in the visitor because ObjC object typerefs are fully valid reference types in the Swift reflection descriptors already and only LLDB wants to look inside them. rdar://154450536
1 parent 03bec58 commit 646d2f3

File tree

6 files changed

+137
-3
lines changed

6 files changed

+137
-3
lines changed

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

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "LLDBMemoryReader.h"
14+
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
1415
#include "Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h"
1516
#include "ReflectionContextInterface.h"
1617
#include "SwiftLanguageRuntime.h"
@@ -800,9 +801,7 @@ class SwiftRuntimeTypeVisitor {
800801

801802
llvm::Expected<unsigned>
802803
SwiftRuntimeTypeVisitor::VisitImpl(std::optional<unsigned> visit_only,
803-
VisitCallback visit_callback)
804-
805-
{
804+
VisitCallback visit_callback) {
806805
if (!m_type)
807806
return llvm::createStringError("invalid type");
808807

@@ -1113,6 +1112,77 @@ SwiftRuntimeTypeVisitor::VisitImpl(std::optional<unsigned> visit_only,
11131112
if (ts.IsBuiltinType(m_type))
11141113
return 0;
11151114

1115+
// Resolve ObjC references via the ObjC runtime.
1116+
auto visit_objcclass = [&](const swift::reflection::ObjCClassTypeRef &tr)
1117+
-> llvm::Expected<unsigned> {
1118+
auto process = m_exe_ctx.GetProcessPtr();
1119+
if (!process)
1120+
return llvm::createStringError(
1121+
"cannot resolve objc type without process");
1122+
auto objc_runtime = SwiftLanguageRuntime::GetObjCRuntime(*process);
1123+
if (!process)
1124+
return llvm::createStringError("no Objective-C runtime");
1125+
const std::string &name = tr.getName();
1126+
AppleObjCRuntime::ObjCISA isa = objc_runtime->GetISA(ConstString(name));
1127+
if (!isa)
1128+
return llvm::createStringError("no Objective-C class " + name);
1129+
AppleObjCRuntime::ClassDescriptorSP desc_sp =
1130+
objc_runtime->GetClassDescriptorFromISA(isa);
1131+
if (!desc_sp)
1132+
return llvm::createStringError("no class descriptor for " + name);
1133+
unsigned n = desc_sp->GetNumIVars();
1134+
if (count_only) {
1135+
if (!m_hide_superclass && desc_sp->GetSuperclass())
1136+
return n + 1;
1137+
return n;
1138+
}
1139+
unsigned depth = 0;
1140+
if (!m_hide_superclass)
1141+
if (AppleObjCRuntime::ClassDescriptorSP superclass_desc_sp =
1142+
desc_sp->GetSuperclass()) {
1143+
auto get_name = [&]() -> std::string {
1144+
return superclass_desc_sp->GetClassName().GetString();
1145+
};
1146+
auto get_info = [&]() -> llvm::Expected<ChildInfo> {
1147+
return ChildInfo();
1148+
};
1149+
CompilerType type;
1150+
if (TypeSP type_sp = superclass_desc_sp->GetType())
1151+
type = type_sp->GetForwardCompilerType();
1152+
if (auto err = visit_callback(type, depth, get_name, get_info))
1153+
return err;
1154+
if (visit_only)
1155+
return success;
1156+
}
1157+
1158+
for (unsigned i = 0; i < n; ++i) {
1159+
auto ivar = desc_sp->GetIVarAtIndex(i);
1160+
if (!visit_only || *visit_only == i) {
1161+
auto get_name = [&]() -> std::string {
1162+
return ivar.m_name.GetString();
1163+
};
1164+
auto get_info = [&]() -> llvm::Expected<ChildInfo> {
1165+
ChildInfo child;
1166+
child.byte_size = ivar.m_size;
1167+
child.byte_offset = ivar.m_offset;
1168+
child.bitfield_bit_size = 0;
1169+
child.bitfield_bit_offset = 0;
1170+
child.is_base_class = false;
1171+
child.is_deref_of_parent = false;
1172+
child.language_flags = 0;
1173+
return child;
1174+
};
1175+
if (auto err =
1176+
visit_callback(ivar.m_type, depth, get_name, get_info))
1177+
return err;
1178+
}
1179+
}
1180+
return success;
1181+
};
1182+
if (auto *obj_tr =
1183+
llvm::dyn_cast_or_null<swift::reflection::ObjCClassTypeRef>(tr))
1184+
return visit_objcclass(*obj_tr);
1185+
11161186
LLDBTypeInfoProvider tip(m_runtime, ts);
11171187
auto cti_or_err = reflection_ctx->GetClassInstanceTypeInfo(
11181188
*tr, &tip, ts.GetDescriptorFinder());
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
#include <Foundation/Foundation.h>
3+
4+
@protocol ObjcProtocol <NSObject>
5+
@end
6+
7+
@interface ObjcClass : NSObject <ObjcProtocol>
8+
@property NSString *someString;
9+
- (instancetype)init;
10+
@end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
SWIFT_SOURCES := main.swift
2+
SWIFT_BRIDGING_HEADER := Header.h
3+
OBJC_SOURCES := objc.m
4+
SWIFT_OBJC_INTEROP := 1
5+
6+
include Makefile.rules
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import lldb
2+
from lldbsuite.test.lldbtest import *
3+
from lldbsuite.test.decorators import *
4+
import lldbsuite.test.lldbutil as lldbutil
5+
6+
7+
class TestCase(TestBase):
8+
9+
@swiftTest
10+
@skipUnlessDarwin
11+
def test(self):
12+
self.build()
13+
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
14+
self, "break here", lldb.SBFileSpec("main.swift")
15+
)
16+
frame = thread.frames[0]
17+
self.expect('settings set symbols.swift-enable-ast-context false')
18+
c = frame.FindVariable("c")
19+
self.assertEqual(c.GetNumChildren(), 1)
20+
obj = c.GetChildAtIndex(0)
21+
self.assertEqual(obj.GetNumChildren(), 2)
22+
base = obj.GetChildAtIndex(0)
23+
self.assertEqual(base.GetName(), "ObjectiveC.NSObject")
24+
string = obj.GetChildAtIndex(1)
25+
self.assertEqual(string.GetSummary(), '"The objc string"')
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class C {
2+
let objcClass = ObjcClass()!
3+
}
4+
5+
func f(_ c: C) {
6+
print("break here")
7+
}
8+
9+
f(C())
10+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include "Header.h"
2+
3+
@implementation ObjcClass
4+
5+
- (instancetype)init {
6+
self = [super init];
7+
if (self) {
8+
self.someString = @"The objc string";
9+
}
10+
return self;
11+
}
12+
13+
@end

0 commit comments

Comments
 (0)