Skip to content

Commit b68ae2e

Browse files
ChristopherRogersjrose-apple
authored andcommitted
Preserve availability on ObjC subscript getters and setters (#17105)
This resolves SR-7398.
1 parent 13e1c83 commit b68ae2e

File tree

3 files changed

+119
-6
lines changed

3 files changed

+119
-6
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6530,18 +6530,24 @@ SwiftDeclConverter::importSubscript(Decl *decl,
65306530

65316531
// Determine the selector of the counterpart.
65326532
FuncDecl *getter = nullptr, *setter = nullptr;
6533+
const clang::ObjCMethodDecl *getterObjCMethod = nullptr,
6534+
*setterObjCMethod = nullptr;
65336535
clang::Selector counterpartSelector;
65346536
if (objcMethod->getSelector() == Impl.objectAtIndexedSubscript) {
65356537
getter = cast<FuncDecl>(decl);
6538+
getterObjCMethod = objcMethod;
65366539
counterpartSelector = Impl.setObjectAtIndexedSubscript;
65376540
} else if (objcMethod->getSelector() == Impl.setObjectAtIndexedSubscript) {
65386541
setter = cast<FuncDecl>(decl);
6542+
setterObjCMethod = objcMethod;
65396543
counterpartSelector = Impl.objectAtIndexedSubscript;
65406544
} else if (objcMethod->getSelector() == Impl.objectForKeyedSubscript) {
65416545
getter = cast<FuncDecl>(decl);
6546+
getterObjCMethod = objcMethod;
65426547
counterpartSelector = Impl.setObjectForKeyedSubscript;
65436548
} else if (objcMethod->getSelector() == Impl.setObjectForKeyedSubscript) {
65446549
setter = cast<FuncDecl>(decl);
6550+
setterObjCMethod = objcMethod;
65456551
counterpartSelector = Impl.objectForKeyedSubscript;
65466552
} else {
65476553
llvm_unreachable("Unknown getter/setter selector");
@@ -6552,24 +6558,29 @@ SwiftDeclConverter::importSubscript(Decl *decl,
65526558
clang::ObjCMethodDecl::Optional);
65536559

65546560
if (auto *counterpart = findCounterpart(counterpartSelector)) {
6561+
const clang::ObjCMethodDecl *counterpartMethod = nullptr;
6562+
65556563
// If the counterpart to the method we're attempting to import has the
65566564
// swift_private attribute, don't import as a subscript.
65576565
if (auto importedFrom = counterpart->getClangDecl()) {
65586566
if (importedFrom->hasAttr<clang::SwiftPrivateAttr>())
65596567
return nullptr;
65606568

6561-
auto counterpartMethod = dyn_cast<clang::ObjCMethodDecl>(importedFrom);
6569+
counterpartMethod = cast<clang::ObjCMethodDecl>(importedFrom);
65626570
if (optionalMethods)
65636571
optionalMethods = (counterpartMethod->getImplementationControl() ==
65646572
clang::ObjCMethodDecl::Optional);
65656573
}
65666574

65676575
assert(!counterpart || !counterpart->isStatic());
65686576

6569-
if (getter)
6577+
if (getter) {
65706578
setter = counterpart;
6571-
else
6579+
setterObjCMethod = counterpartMethod;
6580+
} else {
65726581
getter = counterpart;
6582+
getterObjCMethod = counterpartMethod;
6583+
}
65736584
}
65746585

65756586
// Swift doesn't have write-only subscripting.
@@ -6657,6 +6668,7 @@ SwiftDeclConverter::importSubscript(Decl *decl,
66576668
// Otherwise, just forget we had a setter.
66586669
// FIXME: This feels very, very wrong.
66596670
setter = nullptr;
6671+
setterObjCMethod = nullptr;
66606672
setterIndex = nullptr;
66616673
}
66626674

@@ -6717,9 +6729,14 @@ SwiftDeclConverter::importSubscript(Decl *decl,
67176729
buildSubscriptSetterDecl(Impl, subscript, setter, elementTy,
67186730
dc, setterIndex);
67196731

6720-
/// Record the subscript as an alternative declaration.
6732+
// Record the subscript as an alternative declaration.
67216733
Impl.addAlternateDecl(associateWithSetter ? setter : getter, subscript);
67226734

6735+
// Import attributes for the accessors if there is a pair.
6736+
Impl.importAttributes(getterObjCMethod, getterThunk);
6737+
if (setterObjCMethod)
6738+
Impl.importAttributes(setterObjCMethod, setterThunk);
6739+
67236740
subscript->setGenericEnvironment(dc->getGenericEnvironmentOfContext());
67246741

67256742
subscript->setIsSetterMutating(false);
@@ -7374,6 +7391,11 @@ void ClangImporter::Implementation::importAttributes(
73747391
Decl *MappedDecl,
73757392
const clang::ObjCContainerDecl *NewContext)
73767393
{
7394+
// Subscripts are special-cased since there isn't a 1:1 mapping
7395+
// from its accessor(s) to the subscript declaration.
7396+
if (isa<SubscriptDecl>(MappedDecl))
7397+
return;
7398+
73777399
ASTContext &C = SwiftContext;
73787400

73797401
if (auto maybeDefinition = getDefinitionForClangTypeDecl(ClangDecl))

test/ClangImporter/Inputs/custom-modules/AvailabilityExtras.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ typedef NS_ENUM(NSInteger, NSEnumAddedCasesIn2017) {
9797
@interface AccessorDeprecations: NSObject
9898
@property int fullyDeprecated __attribute__((deprecated));
9999

100+
@property NSInteger fullyDeprecatedOnAccessors;
101+
- (NSInteger)fullyDeprecatedOnAccessors __attribute__((deprecated));
102+
- (void)setFullyDeprecatedOnAccessors:(NSInteger)fullyDeprecatedOnAccessors __attribute__((deprecated));
103+
100104
@property int getterDeprecated;
101105
- (int)getterDeprecated __attribute__((deprecated));
102106
@property (class) int getterDeprecatedClass;
@@ -112,6 +116,10 @@ typedef NS_ENUM(NSInteger, NSEnumAddedCasesIn2017) {
112116
@interface UnavailableAccessors: NSObject
113117
@property NSInteger fullyUnavailable __attribute__((unavailable));
114118

119+
@property NSInteger fullyUnavailableOnAccessors;
120+
- (NSInteger)fullyUnavailableOnAccessors __attribute__((unavailable));
121+
- (void)setFullyUnavailableOnAccessors:(NSInteger)fullyUnavailableOnAccessors __attribute__((unavailable));
122+
115123
@property NSInteger getterUnavailable;
116124
- (NSInteger)getterUnavailable __attribute__((unavailable));
117125
@property (class) NSInteger getterUnavailableClass;
@@ -122,3 +130,42 @@ typedef NS_ENUM(NSInteger, NSEnumAddedCasesIn2017) {
122130
@property (class) NSInteger setterUnavailableClass;
123131
+ (void)setSetterUnavailableClass:(NSInteger)setterUnavailable __attribute__((unavailable));
124132
@end
133+
134+
135+
@interface UnavailableSubscript: NSObject
136+
- (nonnull NSString *)objectAtIndexedSubscript:(NSInteger)i __attribute__((unavailable("bad subscript getter")));
137+
- (void)setObject:(nonnull NSString *)obj atIndexedSubscript:(NSInteger)i __attribute__((unavailable("bad subscript setter")));
138+
@end
139+
140+
@interface UnavailableGetterSubscript: NSObject
141+
- (nonnull NSString *)objectAtIndexedSubscript:(NSInteger)i __attribute__((unavailable("bad subscript getter")));
142+
- (void)setObject:(nonnull NSString *)obj atIndexedSubscript:(NSInteger)i;
143+
@end
144+
145+
@interface UnavailableSetterSubscript: NSObject
146+
- (nonnull NSString *)objectAtIndexedSubscript:(NSInteger)i;
147+
- (void)setObject:(nonnull NSString *)obj atIndexedSubscript:(NSInteger)i __attribute__((unavailable("bad subscript setter")));
148+
@end
149+
150+
@interface UnavailableReadOnlySubscript: NSObject
151+
- (nonnull NSString *)objectAtIndexedSubscript:(NSInteger)i __attribute__((unavailable));
152+
@end
153+
154+
@interface DeprecatedSubscript: NSObject
155+
- (nonnull NSString *)objectAtIndexedSubscript:(NSInteger)i __attribute__((deprecated("bad subscript getter")));
156+
- (void)setObject:(nonnull NSString *)obj atIndexedSubscript:(NSInteger)i __attribute__((deprecated("bad subscript setter")));
157+
@end
158+
159+
@interface DeprecatedGetterSubscript: NSObject
160+
- (nonnull NSString *)objectAtIndexedSubscript:(NSInteger)i __attribute__((deprecated("bad subscript getter")));
161+
- (void)setObject:(nonnull NSString *)obj atIndexedSubscript:(NSInteger)i;
162+
@end
163+
164+
@interface DeprecatedSetterSubscript: NSObject
165+
- (nonnull NSString *)objectAtIndexedSubscript:(NSInteger)i;
166+
- (void)setObject:(nonnull NSString *)obj atIndexedSubscript:(NSInteger)i __attribute__((deprecated("bad subscript setter")));
167+
@end
168+
169+
@interface DeprecatedReadOnlySubscript: NSObject
170+
- (nonnull NSString *)objectAtIndexedSubscript:(NSInteger)i __attribute__((deprecated));
171+
@end

test/ClangImporter/availability.swift

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,19 @@ func test_unavailable_func(_ x : NSObject) {
2525
NSDeallocateObject(x) // expected-error {{'NSDeallocateObject' is unavailable}}
2626
}
2727

28-
func test_unavailable_accessors(_ obj: UnavailableAccessors) {
28+
func test_unavailable_accessors(_ obj: UnavailableAccessors,
29+
_ sub: UnavailableSubscript,
30+
_ subGetter: UnavailableGetterSubscript,
31+
_ subSetter: UnavailableSetterSubscript,
32+
_ subReadOnly: UnavailableReadOnlySubscript) {
2933
_ = obj.fullyUnavailable // expected-error {{'fullyUnavailable' is unavailable}}
3034
obj.fullyUnavailable = 0 // expected-error {{'fullyUnavailable' is unavailable}}
3135
obj.fullyUnavailable += 1 // expected-error {{'fullyUnavailable' is unavailable}}
3236

37+
_ = obj.fullyUnavailableOnAccessors // expected-error {{getter for 'fullyUnavailableOnAccessors' is unavailable}}
38+
obj.fullyUnavailableOnAccessors = 0 // expected-error {{setter for 'fullyUnavailableOnAccessors' is unavailable}}
39+
obj.fullyUnavailableOnAccessors += 1 // expected-error {{getter for 'fullyUnavailableOnAccessors' is unavailable}} expected-error {{setter for 'fullyUnavailableOnAccessors' is unavailable}}
40+
3341
_ = obj.getterUnavailable // expected-error {{getter for 'getterUnavailable' is unavailable}}
3442
obj.getterUnavailable = 0
3543
obj.getterUnavailable += 1 // expected-error {{getter for 'getterUnavailable' is unavailable}}
@@ -45,15 +53,37 @@ func test_unavailable_accessors(_ obj: UnavailableAccessors) {
4553
_ = UnavailableAccessors.setterUnavailableClass
4654
UnavailableAccessors.setterUnavailableClass = 0 // expected-error {{setter for 'setterUnavailableClass' is unavailable}}
4755
UnavailableAccessors.setterUnavailableClass += 1 // expected-error {{setter for 'setterUnavailableClass' is unavailable}}
56+
57+
_ = sub[0] // expected-error {{getter for 'subscript' is unavailable: bad subscript getter}}
58+
sub[0] = "" // expected-error {{setter for 'subscript' is unavailable: bad subscript setter}}
59+
sub[0] += "" // expected-error {{getter for 'subscript' is unavailable: bad subscript getter}} expected-error {{setter for 'subscript' is unavailable: bad subscript setter}}
60+
61+
_ = subGetter[0] // expected-error {{getter for 'subscript' is unavailable: bad subscript getter}}
62+
subGetter[0] = ""
63+
subGetter[0] += "" // expected-error {{getter for 'subscript' is unavailable: bad subscript getter}}
64+
65+
_ = subSetter[0]
66+
subSetter[0] = "" // expected-error {{setter for 'subscript' is unavailable: bad subscript setter}}
67+
subSetter[0] += "" // expected-error {{setter for 'subscript' is unavailable: bad subscript setter}}
68+
69+
_ = subReadOnly[0] // expected-error {{getter for 'subscript' is unavailable}}
4870
}
4971

50-
func test_deprecated(_ s:UnsafeMutablePointer<CChar>, _ obj: AccessorDeprecations) {
72+
func test_deprecated(_ s:UnsafeMutablePointer<CChar>, _ obj: AccessorDeprecations,
73+
_ sub: DeprecatedSubscript,
74+
_ subGetter: DeprecatedGetterSubscript,
75+
_ subSetter: DeprecatedSetterSubscript,
76+
_ subReadOnly: DeprecatedReadOnlySubscript) {
5177
_ = tmpnam(s) // expected-warning {{'tmpnam' is deprecated: Due to security concerns inherent in the design of tmpnam(3), it is highly recommended that you use mkstemp(3) instead.}}
5278

5379
_ = obj.fullyDeprecated // expected-warning {{'fullyDeprecated' is deprecated}}
5480
obj.fullyDeprecated = 0 // expected-warning {{'fullyDeprecated' is deprecated}}
5581
obj.fullyDeprecated += 1 // expected-warning {{'fullyDeprecated' is deprecated}}
5682

83+
_ = obj.fullyDeprecatedOnAccessors // expected-warning {{getter for 'fullyDeprecatedOnAccessors' is deprecated}}
84+
obj.fullyDeprecatedOnAccessors = 0 // expected-warning {{setter for 'fullyDeprecatedOnAccessors' is deprecated}}
85+
obj.fullyDeprecatedOnAccessors += 1 // expected-warning {{getter for 'fullyDeprecatedOnAccessors' is deprecated}} expected-warning {{setter for 'fullyDeprecatedOnAccessors' is deprecated}}
86+
5787
_ = obj.getterDeprecated // expected-warning {{getter for 'getterDeprecated' is deprecated}}
5888
obj.getterDeprecated = 0
5989
obj.getterDeprecated += 1 // expected-warning {{getter for 'getterDeprecated' is deprecated}}
@@ -69,6 +99,20 @@ func test_deprecated(_ s:UnsafeMutablePointer<CChar>, _ obj: AccessorDeprecation
6999
_ = AccessorDeprecations.setterDeprecatedClass
70100
AccessorDeprecations.setterDeprecatedClass = 0 // expected-warning {{setter for 'setterDeprecatedClass' is deprecated}}
71101
AccessorDeprecations.setterDeprecatedClass += 1 // expected-warning {{setter for 'setterDeprecatedClass' is deprecated}}
102+
103+
_ = sub[0] // expected-warning {{getter for 'subscript' is deprecated: bad subscript getter}}
104+
sub[0] = "" // expected-warning {{setter for 'subscript' is deprecated: bad subscript setter}}
105+
sub[0] += "" // expected-warning {{getter for 'subscript' is deprecated: bad subscript getter}} expected-warning {{setter for 'subscript' is deprecated: bad subscript setter}}
106+
107+
_ = subGetter[0] // expected-warning {{getter for 'subscript' is deprecated: bad subscript getter}}
108+
subGetter[0] = ""
109+
subGetter[0] += "" // expected-warning {{getter for 'subscript' is deprecated: bad subscript getter}}
110+
111+
_ = subSetter[0]
112+
subSetter[0] = "" // expected-warning {{setter for 'subscript' is deprecated: bad subscript setter}}
113+
subSetter[0] += "" // expected-warning {{setter for 'subscript' is deprecated: bad subscript setter}}
114+
115+
_ = subReadOnly[0] // expected-warning {{getter for 'subscript' is deprecated}}
72116
}
73117

74118
func test_NSInvocation(_ x: NSInvocation, // expected-error {{'NSInvocation' is unavailable}}

0 commit comments

Comments
 (0)