Skip to content

Commit 0473e99

Browse files
lilyballtkremenek
authored andcommitted
[PrintAsObjC] Add unavailable attribute to unavailable obj-c initializers (#3852)
* [PrintAsObjC] Add unavailable attribute to non-inherited initializers Initializers that aren't inherited by subclasses cannot be called, so we should make this visible to Obj-C. Due to SR-2211, non-inherited convenience initializers do not get this same treatment. * [PrintAsObjC] Add unavailable initializers for private overrides When a public initializer is overridden with a private one, we need to mark these as unavailable to Obj-C as they're not supposed to be callable even though they do exist.
1 parent acc5fd5 commit 0473e99

File tree

3 files changed

+59
-7
lines changed

3 files changed

+59
-7
lines changed

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,19 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
137137
visit(const_cast<Decl *>(D));
138138
}
139139

140-
bool shouldInclude(const ValueDecl *VD) {
141-
return (VD->isObjC() || VD->getAttrs().hasAttribute<CDeclAttr>()) &&
142-
VD->getFormalAccess() >= minRequiredAccess &&
143-
!(isa<ConstructorDecl>(VD) &&
144-
cast<ConstructorDecl>(VD)->hasStubImplementation());
140+
bool shouldInclude(const ValueDecl *VD, bool checkParent = true) {
141+
if (!(VD->isObjC() || VD->getAttrs().hasAttribute<CDeclAttr>()))
142+
return false;
143+
if (VD->getFormalAccess() >= minRequiredAccess) {
144+
return true;
145+
} else if (checkParent) {
146+
if (auto ctor = dyn_cast<ConstructorDecl>(VD)) {
147+
// Check if we're overriding an initializer that is visible to obj-c
148+
if (auto parent = ctor->getOverriddenDecl())
149+
return shouldInclude(parent, false);
150+
}
151+
}
152+
return false;
145153
}
146154

147155
private:
@@ -479,7 +487,12 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
479487

480488
// Swift designated initializers are Objective-C designated initializers.
481489
if (auto ctor = dyn_cast<ConstructorDecl>(AFD)) {
482-
if (ctor->isDesignatedInit() &&
490+
if (ctor->hasStubImplementation()
491+
|| ctor->getFormalAccess() < minRequiredAccess) {
492+
// This will only be reached if the overridden initializer has the
493+
// required access
494+
os << " SWIFT_UNAVAILABLE";
495+
} else if (ctor->isDesignatedInit() &&
483496
!isa<ProtocolDecl>(ctor->getDeclContext())) {
484497
os << " OBJC_DESIGNATED_INITIALIZER";
485498
}
@@ -1961,6 +1974,9 @@ class ModuleWriter {
19611974
"SWIFT_ENUM(_type, _name)\n"
19621975
"# endif\n"
19631976
"#endif\n"
1977+
"#if !defined(SWIFT_UNAVAILABLE)\n"
1978+
"# define SWIFT_UNAVAILABLE __attribute__((unavailable))\n"
1979+
"#endif\n"
19641980
;
19651981
static_assert(SWIFT_MAX_IMPORTED_SIMD_ELEMENTS == 4,
19661982
"need to add SIMD typedefs here if max elements is increased");

test/PrintAsObjC/classes.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ class ClassWithCustomNameSub : ClassWithCustomName {}
108108
// CHECK-NEXT: - (nonnull instancetype)initWithString:(NSString * _Nonnull)s boolean:(BOOL)b;
109109
// CHECK-NEXT: - (nullable instancetype)initWithBoolean:(BOOL)b;
110110
// CHECK-NEXT: - (nonnull instancetype)initForFun OBJC_DESIGNATED_INITIALIZER;
111+
// CHECK-NEXT: - (nonnull instancetype)initWithMoreFun OBJC_DESIGNATED_INITIALIZER;
112+
// CHECK-NEXT: - (nonnull instancetype)initWithEvenMoreFun OBJC_DESIGNATED_INITIALIZER;
111113
// CHECK-NEXT: @end
112114
@objc class Initializers {
113115
init() {}
@@ -120,6 +122,39 @@ class ClassWithCustomNameSub : ClassWithCustomName {}
120122
convenience init?(boolean b: ObjCBool) { self.init() }
121123

122124
init(forFun: ()) { }
125+
126+
init(moreFun: ()) { }
127+
128+
init(evenMoreFun: ()) { }
129+
}
130+
131+
// CHECK-LABEL: @interface InheritedInitializers
132+
// CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
133+
// CHECK-NEXT: - (nonnull instancetype)initWithFloat:(float)f SWIFT_UNAVAILABLE;
134+
// CHECK-NEXT: - (nonnull instancetype)initWithMoreFun SWIFT_UNAVAILABLE;
135+
// CHECK-NEXT: - (nonnull instancetype)initForFun SWIFT_UNAVAILABLE;
136+
// CHECK-NEXT: - (nonnull instancetype)initWithEvenMoreFun SWIFT_UNAVAILABLE;
137+
// CHECK-NEXT: @end
138+
@objc class InheritedInitializers : Initializers {
139+
override init() {
140+
super.init()
141+
}
142+
143+
private convenience init(float f: Float) { self.init() }
144+
145+
private override init(moreFun: ()) { super.init() }
146+
}
147+
148+
// CHECK-LABEL: @interface InheritedInitializersAgain
149+
// CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
150+
// CHECK-NEXT: - (nonnull instancetype)initWithEvenMoreFun OBJC_DESIGNATED_INITIALIZER;
151+
// CHECK-NEXT: @end
152+
@objc class InheritedInitializersAgain : InheritedInitializers {
153+
override init() {
154+
super.init()
155+
}
156+
157+
init(evenMoreFun: ()) { super.init() }
123158
}
124159

125160
// NEGATIVE-NOT: NotObjC

test/PrintAsObjC/protocols.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ protocol CustomNameType2 {}
7575
}
7676

7777
// CHECK-LABEL: @interface MyObject : NSObject <NSCoding>
78-
// CHECK-NEXT: init
78+
// CHECK-NEXT: initWithCoder
79+
// CHECK-NEXT: init SWIFT_UNAVAILABLE
7980
// CHECK-NEXT: @end
8081
// NEGATIVE-NOT: @protocol NSCoding
8182
class MyObject : NSObject, NSCoding {

0 commit comments

Comments
 (0)