Skip to content

Commit da5383c

Browse files
committedSep 19, 2024
Better support CoreFoundation types in RemoteMirror
This plugs a hole where we failed to recognize a CF type when it appeared as the payload of an enum stored as a property. Curiously, RemoteMirror is able to reflect this when the enum appears by itself, just not when it's stored as a property. The simplest fix is to hook into the TypeInfo calculation which computes a TypeInfo (basically, the tree of fields) from a TypeRef (basically, the name of the type, including generic context). Specifically, we sometimes end up here with a "type alias" that none of the lookup support seems to be able to handle. Fortunately, these aliases demangle into a pretty predictable shape, so this just pattern-matches the specific demangle tree shape to recognize these as "type aliases in the `__C` module whose name starts with `CF` and ends with `Ref`". Resolves rdar://82465109

File tree

2 files changed

+138
-0
lines changed

2 files changed

+138
-0
lines changed
 

‎stdlib/public/RemoteInspection/TypeLowering.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -2196,6 +2196,34 @@ class LowerType
21962196
TypeConverter &TC;
21972197
remote::TypeInfoProvider *ExternalTypeInfo;
21982198

2199+
const TypeInfo *CFRefTypeInfo(const TypeRef *TR) {
2200+
if (auto N = dyn_cast<NominalTypeRef>(TR)) {
2201+
Demangler Dem;
2202+
auto Node = N->getDemangling(Dem);
2203+
if (Node->getKind() == Node::Kind::Type && Node->getNumChildren() == 1) {
2204+
auto Alias = Node->getChild(0);
2205+
if (Alias->getKind() == Node::Kind::TypeAlias && Alias->getNumChildren() == 2) {
2206+
auto Module = Alias->getChild(0);
2207+
auto Name = Alias->getChild(1);
2208+
if (Module->getKind() == Node::Kind::Module
2209+
&& Module->hasText()
2210+
&& Module->getText() == "__C"
2211+
&& Name->getKind() == Node::Kind::Identifier
2212+
&& Name->hasText()) {
2213+
auto CName = Name->getText();
2214+
// Heuristic: Hopefully good enough.
2215+
if (CName.starts_with("CF") && CName.ends_with("Ref")) {
2216+
// A CF reference is essentially the same as a Strong ObjC reference
2217+
return TC.getReferenceTypeInfo(ReferenceKind::Strong,
2218+
ReferenceCounting::Unknown);
2219+
}
2220+
}
2221+
}
2222+
}
2223+
}
2224+
return nullptr;
2225+
}
2226+
21992227
public:
22002228
using TypeRefVisitor<LowerType, const TypeInfo *>::visit;
22012229

@@ -2265,6 +2293,11 @@ class LowerType
22652293
if (auto External = QueryExternalTypeInfoProvider())
22662294
return External;
22672295

2296+
// CoreFoundation types require some special handling
2297+
if (auto CFTypeInfo = CFRefTypeInfo(TR))
2298+
return CFTypeInfo;
2299+
2300+
22682301
// If the external provider also fails we're out of luck.
22692302
DEBUG_LOG(fprintf(stderr, "No TypeInfo for nominal type: "); TR->dump());
22702303
return nullptr;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -lswiftSwiftReflectionTest %s -o %t/reflect_Enum_CF
3+
// RUN: %target-codesign %t/reflect_Enum_CF
4+
5+
// RUN: %target-run %target-swift-reflection-test %t/reflect_Enum_CF | tee /dev/stderr | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK%target-ptrsize --dump-input=fail %add_num_extra_inhabitants
6+
7+
// REQUIRES: objc_interop
8+
// REQUIRES: executable_test
9+
// REQUIRES: reflection_test_support
10+
// UNSUPPORTED: use_os_stdlib
11+
// UNSUPPORTED: asan
12+
13+
import SwiftReflectionTest
14+
import Foundation
15+
16+
enum MyPair<T,U> {
17+
case a(T)
18+
case b(U)
19+
}
20+
21+
reflect(enum: MyPair<Void,CFNumber>.b(kCFNumberPositiveInfinity))
22+
23+
// CHECK: Reflecting an enum.
24+
// CHECK-NEXT: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
25+
// CHECK-NEXT: Type reference:
26+
// CHECK-NEXT: (bound_generic_enum reflect_Enum_CF.MyPair
27+
// CHECK-NEXT: (tuple)
28+
// CHECK-NEXT: (foreign name=So11CFNumberRefa))
29+
30+
// CHECK: Type info:
31+
// CHECK64-NEXT: (multi_payload_enum size=9 alignment=8 stride=16 num_extra_inhabitants=254 bitwise_takable=1
32+
// CHECK64-NEXT: (case name=a index=0 offset=0
33+
// CHECK64-NEXT: (tuple size=0 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1))
34+
// CHECK64-NEXT: (case name=b index=1 offset=0
35+
// CHECK64-NEXT: (reference kind=strong refcounting=unknown)))
36+
37+
// CHECK: Mangled name: $s15reflect_Enum_CF6MyPairOyytSo11CFNumberRefaG
38+
// CHECK-NEXT: Demangled name: reflect_Enum_CF.MyPair<(), __C.CFNumberRef>
39+
40+
// CHECK: Enum value:
41+
// CHECK-NEXT: (enum_value name=b index=1
42+
// CHECK-NEXT: (foreign name=So11CFNumberRefa)
43+
// CHECK-NEXT: )
44+
45+
struct StructA {
46+
let field1 = MyPair<Void,CFNumber>.b(kCFNumberPositiveInfinity)
47+
let field2 = 7
48+
}
49+
50+
enum T {
51+
case a
52+
case b(MyPair<Void,CFNumber>)
53+
}
54+
55+
reflect(enum: StructA().field1)
56+
57+
// CHECK: Reflecting an enum.
58+
// CHECK-NEXT: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
59+
// CHECK-NEXT: Type reference:
60+
// CHECK-NEXT: (bound_generic_enum reflect_Enum_CF.MyPair
61+
// CHECK-NEXT: (tuple)
62+
// CHECK-NEXT: (foreign name=So11CFNumberRefa))
63+
64+
// CHECK: Type info:
65+
// CHECK-NEXT: (multi_payload_enum size=9 alignment=8 stride=16 num_extra_inhabitants=254 bitwise_takable=1
66+
// CHECK-NEXT: (case name=a index=0 offset=0
67+
// CHECK-NEXT: (tuple size=0 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1))
68+
// CHECK-NEXT: (case name=b index=1 offset=0
69+
// CHECK-NEXT: (reference kind=strong refcounting=unknown)))
70+
71+
// CHECK: Mangled name: $s15reflect_Enum_CF6MyPairOyytSo11CFNumberRefaG
72+
// CHECK-NEXT: Demangled name: reflect_Enum_CF.MyPair<(), __C.CFNumberRef>
73+
74+
// CHECK: Enum value:
75+
// CHECK-NEXT: (enum_value name=b index=1
76+
// CHECK-NEXT: (foreign name=So11CFNumberRefa)
77+
// CHECK-NEXT: )
78+
79+
reflect(enum: T.a)
80+
81+
// CHECK: Reflecting an enum.
82+
// CHECK-NEXT: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
83+
// CHECK-NEXT: Type reference:
84+
// CHECK-NEXT: (enum reflect_Enum_CF.T)
85+
86+
// CHECK: Type info:
87+
// CHECK-NEXT: (single_payload_enum size=9 alignment=8 stride=16 num_extra_inhabitants=253 bitwise_takable=1
88+
// CHECK-NEXT: (case name=b index=0 offset=0
89+
// CHECK-NEXT: (multi_payload_enum size=9 alignment=8 stride=16 num_extra_inhabitants=254 bitwise_takable=1
90+
// CHECK-NEXT: (case name=a index=0 offset=0
91+
// CHECK-NEXT: (tuple size=0 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1))
92+
// CHECK-NEXT: (case name=b index=1 offset=0
93+
// CHECK-NEXT: (reference kind=strong refcounting=unknown))))
94+
// CHECK-NEXT: (case name=a index=1))
95+
// CHECK-NEXT: Mangled name: $s15reflect_Enum_CF1TO
96+
// CHECK-NEXT: Demangled name: reflect_Enum_CF.T
97+
98+
99+
// CHECK: Enum value:
100+
// CHECK-NEXT: (enum_value name=a index=1)
101+
102+
doneReflecting()
103+
104+
// CHECKALL: Done.
105+

0 commit comments

Comments
 (0)
Please sign in to comment.