Skip to content

Commit 6f3e9e7

Browse files
committed
Add @objc @implementation tests for custom availability domains.
These tests reveal that the `@objc @implementation` checker does not verify the availability of implementations. It should reject implementations where the extension or its members are more or less available than the class or method that they implement. Fixing this is tracked by rdar://156564928.
1 parent 58bf087 commit 6f3e9e7

File tree

2 files changed

+142
-0
lines changed

2 files changed

+142
-0
lines changed

test/ClangImporter/Inputs/availability_domains_bridging_header.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,65 @@ static struct __AvailabilityDomain bay_bridge
66
static struct __AvailabilityDomain golden_gate_bridge
77
__attribute__((availability_domain(GoldenGateBridge))) = {
88
__AVAILABILITY_DOMAIN_DISABLED, 0};
9+
10+
#define AVAIL 0
11+
#define UNAVAIL 1
12+
13+
14+
#if __OBJC__
15+
@import Foundation;
16+
17+
__attribute__((availability(domain:BayBridge, AVAIL)))
18+
@interface BayBridgeAvailable : NSObject
19+
- (instancetype)init;
20+
@end
21+
22+
__attribute__((availability(domain:BayBridge, UNAVAIL)))
23+
@interface BayBridgeUnavailable : NSObject
24+
- (instancetype)init;
25+
@end
26+
27+
@interface ImplementMe : NSObject
28+
- (instancetype)init;
29+
- (void)availableInBayBridge __attribute__((availability(domain:BayBridge, AVAIL)));
30+
- (void)unavailableInBayBridge __attribute__((availability(domain:BayBridge, UNAVAIL)));
31+
32+
- (void)availableInGoldenGateBridge __attribute__((availability(domain:GoldenGateBridge, AVAIL)));
33+
- (void)unavailableInGoldenGateBridge __attribute__((availability(domain:GoldenGateBridge, UNAVAIL)));
34+
35+
@end
36+
37+
__attribute__((availability(domain:BayBridge, AVAIL)))
38+
@interface ImplementMeBayBridgeAvailable : NSObject
39+
- (instancetype)init;
40+
@end
41+
42+
__attribute__((availability(domain:BayBridge, UNAVAIL)))
43+
@interface ImplementMeBayBridgeUnavailable : NSObject
44+
- (instancetype)init;
45+
@end
46+
47+
__attribute__((availability(domain:GoldenGateBridge, AVAIL)))
48+
@interface ImplementMeGoldenGateBridgeAvailable : NSObject
49+
- (instancetype)init;
50+
@end
51+
52+
__attribute__((availability(domain:GoldenGateBridge, AVAIL)))
53+
@interface ImplementMeGoldenGateBridgeAvailable2 : NSObject
54+
- (instancetype)init;
55+
@end
56+
57+
__attribute__((availability(domain:GoldenGateBridge, AVAIL)))
58+
@interface ImplementMeGoldenGateBridgeAvailable3 : NSObject
59+
- (instancetype)init;
60+
@end
61+
62+
__attribute__((availability(domain:GoldenGateBridge, UNAVAIL)))
63+
@interface ImplementMeGoldenGateBridgeUnavailable : NSObject
64+
- (instancetype)init;
65+
@end
66+
67+
#endif // __OBJC__
68+
69+
#undef UNAVAIL
70+
#undef AVAIL
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify \
4+
// RUN: -import-objc-header %S/Inputs/availability_domains_bridging_header.h \
5+
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
6+
// RUN: -enable-experimental-feature CustomAvailability \
7+
// RUN: %s %S/Inputs/availability_custom_domains_other.swift
8+
9+
// Re-test with the bridging header precompiled into a .pch.
10+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-pch \
11+
// RUN: -o %t/bridging-header.pch %S/Inputs/availability_domains_bridging_header.h
12+
13+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify \
14+
// RUN: -import-objc-header %t/bridging-header.pch \
15+
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
16+
// RUN: -enable-experimental-feature CustomAvailability \
17+
// RUN: %s %S/Inputs/availability_custom_domains_other.swift
18+
19+
// REQUIRES: swift_feature_CustomAvailability
20+
// REQUIRES: objc_interop
21+
22+
import Oceans // re-exports Rivers
23+
24+
func testObjCClasses( // expected-note {{add '@available' attribute to enclosing global function}}
25+
_ bayBridgeAvailable: BayBridgeAvailable, // expected-error {{'BayBridgeAvailable' is only available in BayBridge}}
26+
_ bayBridgeUnavailable: BayBridgeUnavailable, // expected-error {{'BayBridgeUnavailable' is unavailable}}
27+
) { }
28+
29+
@objc @implementation
30+
extension ImplementMe {
31+
// FIXME: [availability] @available(BayBridge) should be required
32+
func availableInBayBridge() { }
33+
34+
// FIXME: [availability] Should match and suggest @available(BayBridge, unavailable)
35+
func unavailableInBayBridge() { } // expected-error {{instance method 'unavailableInBayBridge()' does not match any instance method declared in the headers for 'ImplementMe'}}
36+
// expected-note@-1 {{add 'private' or 'fileprivate'}}
37+
// expected-note@-2 {{add 'final' to define a Swift-only instance method}}
38+
39+
@available(GoldenGateBridge)
40+
func availableInGoldenGateBridge() { }
41+
42+
// FIXME: [availability] This should be accepted
43+
@available(GoldenGateBridge, unavailable)
44+
func unavailableInGoldenGateBridge() { } // expected-error {{instance method 'unavailableInGoldenGateBridge()' does not match any instance method declared in the headers for 'ImplementMe'}}
45+
// expected-note@-1 {{add 'private' or 'fileprivate'}}
46+
// expected-note@-2 {{add 'final' to define a Swift-only instance method}}
47+
}
48+
49+
@objc @implementation
50+
extension ImplementMeBayBridgeAvailable { // expected-error {{'ImplementMeBayBridgeAvailable' is only available in BayBridge}}
51+
// expected-note@-1 {{add '@available' attribute to enclosing extension}}
52+
}
53+
54+
@objc @implementation
55+
extension ImplementMeBayBridgeUnavailable { // expected-error {{'ImplementMeBayBridgeUnavailable' is unavailable}}
56+
}
57+
58+
@available(GoldenGateBridge)
59+
@objc @implementation
60+
extension ImplementMeGoldenGateBridgeAvailable {
61+
}
62+
63+
@available(BayBridge)
64+
@objc @implementation
65+
extension ImplementMeGoldenGateBridgeAvailable2 { // expected-error {{'ImplementMeGoldenGateBridgeAvailable2' is only available in GoldenGateBridge}}
66+
// expected-note@-1 {{add '@available' attribute to enclosing extension}}
67+
}
68+
69+
// FIXME: [availability] This implementation should be rejected because its less
70+
// available than the original class declaration.
71+
@available(BayBridge)
72+
@available(GoldenGateBridge)
73+
@objc @implementation
74+
extension ImplementMeGoldenGateBridgeAvailable3 {
75+
}
76+
77+
@available(GoldenGateBridge, unavailable)
78+
@objc @implementation
79+
extension ImplementMeGoldenGateBridgeUnavailable {
80+
}

0 commit comments

Comments
 (0)