Skip to content

Commit 58bf087

Browse files
committed
PrintAsClang: Add support for availability attrs with custom domains.
Resolves rdar://154510571.
1 parent 49febcd commit 58bf087

File tree

8 files changed

+282
-11
lines changed

8 files changed

+282
-11
lines changed

include/swift/PrintAsClang/ClangMacros.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ CLANG_MACRO("SWIFT_UNAVAILABLE", , "__attribute__((unavailable))")
220220
CLANG_MACRO("SWIFT_UNAVAILABLE_MSG", "(msg)", "__attribute__((unavailable(msg)))")
221221

222222
CLANG_MACRO("SWIFT_AVAILABILITY", "(plat, ...)", "__attribute__((availability(plat, __VA_ARGS__)))")
223+
CLANG_MACRO("SWIFT_AVAILABILITY_DOMAIN", "(dom, ...)", "__attribute__((availability(domain: dom, __VA_ARGS__)))")
223224

224225
CLANG_MACRO("SWIFT_WEAK_IMPORT", , "__attribute__((weak_import))")
225226

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1702,9 +1702,24 @@ class DeclAndTypePrinter::Implementation
17021702
};
17031703

17041704
for (auto AvAttr : D->getSemanticAvailableAttrs()) {
1705-
if (AvAttr.getPlatform() == PlatformKind::none) {
1706-
if (AvAttr.isUnconditionallyUnavailable() &&
1707-
!AvAttr.getDomain().isSwiftLanguage()) {
1705+
auto domain = AvAttr.getDomain();
1706+
if (auto domainDecl = domain.getDecl()) {
1707+
// If the domain is defined in a Clang module then the attr can be
1708+
// printed.
1709+
if (domainDecl->hasClangNode()) {
1710+
// Versioned custom domains aren't supported yet.
1711+
ASSERT(!domain.isVersioned());
1712+
1713+
maybePrintLeadingSpace();
1714+
os << "SWIFT_AVAILABILITY_DOMAIN("
1715+
<< domain.getNameForAttributePrinting() << ","
1716+
<< (AvAttr.isUnconditionallyUnavailable() ? "1" : "0") << ")";
1717+
}
1718+
continue;
1719+
}
1720+
1721+
if (domain.isUniversal()) {
1722+
if (AvAttr.isUnconditionallyUnavailable()) {
17081723
// Availability for *
17091724
if (!AvAttr.getRename().empty() && isa<ValueDecl>(D)) {
17101725
// rename
@@ -1749,6 +1764,9 @@ class DeclAndTypePrinter::Implementation
17491764
}
17501765

17511766
// Availability for a specific platform
1767+
if (!domain.isPlatform())
1768+
continue;
1769+
17521770
if (!AvAttr.getIntroduced().has_value() &&
17531771
!AvAttr.getDeprecated().has_value() &&
17541772
!AvAttr.getObsoleted().has_value() &&

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,8 @@ class ModuleWriter {
684684
continue;
685685
}
686686

687+
addImportsForReferencedAvailabilityDomains(member);
688+
687689
bool needsToBeIndividuallyDelayed = false;
688690
ReferencedTypeFinder::walk(VD->getInterfaceType(),
689691
[&](ReferencedTypeFinder &finder,
@@ -745,6 +747,15 @@ class ModuleWriter {
745747
return !hadAnyDelayedMembers;
746748
}
747749

750+
void addImportsForReferencedAvailabilityDomains(const Decl *D) {
751+
for (auto attr : D->getSemanticAvailableAttrs()) {
752+
if (auto *domainDecl = attr.getDomain().getDecl()) {
753+
if (domainDecl->hasClangNode())
754+
addImport(domainDecl);
755+
}
756+
}
757+
}
758+
748759
bool writeClass(const ClassDecl *CD) {
749760
if (addImport(CD))
750761
return true;
@@ -777,6 +788,7 @@ class ModuleWriter {
777788
if (outputLangMode == OutputLanguageMode::Cxx &&
778789
(inserted || !it->second.second))
779790
ClangValueTypePrinter::forwardDeclType(os, CD, printer);
791+
addImportsForReferencedAvailabilityDomains(CD);
780792
it->second = {EmissionState::Defined, true};
781793
printer.print(CD);
782794
return true;
@@ -795,6 +807,7 @@ class ModuleWriter {
795807
TD);
796808
forwardDeclareType(TD);
797809
});
810+
addImportsForReferencedAvailabilityDomains(FD);
798811

799812
printer.print(FD);
800813
return true;
@@ -811,6 +824,7 @@ class ModuleWriter {
811824
}
812825
forwardDeclareCxxValueTypeIfNeeded(SD);
813826
}
827+
addImportsForReferencedAvailabilityDomains(SD);
814828
printer.print(SD);
815829
return true;
816830
}
@@ -837,6 +851,8 @@ class ModuleWriter {
837851
if (!forwardDeclareMemberTypes(PD->getAllMembers(), PD))
838852
return false;
839853

854+
addImportsForReferencedAvailabilityDomains(PD);
855+
840856
seenTypes[PD] = { EmissionState::Defined, true };
841857
printer.print(PD);
842858
return true;
@@ -863,6 +879,8 @@ class ModuleWriter {
863879
if (!forwardDeclareMemberTypes(ED->getAllMembers(), ED))
864880
return false;
865881

882+
addImportsForReferencedAvailabilityDomains(ED);
883+
866884
printer.print(ED);
867885
return true;
868886
}
@@ -882,7 +900,9 @@ class ModuleWriter {
882900

883901
if (seenTypes[ED].first == EmissionState::Defined)
884902
return true;
885-
903+
904+
addImportsForReferencedAvailabilityDomains(ED);
905+
886906
seenTypes[ED] = {EmissionState::Defined, true};
887907
printer.print(ED);
888908

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#include <feature-availability.h>
22

3-
static struct __AvailabilityDomain __BayBridge
3+
static struct __AvailabilityDomain bay_bridge
44
__attribute__((availability_domain(BayBridge))) = {
55
__AVAILABILITY_DOMAIN_ENABLED, 0};
6-
static struct __AvailabilityDomain __GoldenGateBridge
6+
static struct __AvailabilityDomain golden_gate_bridge
77
__attribute__((availability_domain(GoldenGateBridge))) = {
88
__AVAILABILITY_DOMAIN_DISABLED, 0};

test/Inputs/custom-modules/availability-domains/Oceans.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
int arctic_pred(void);
55
int pacific_pred(void);
66

7-
static struct __AvailabilityDomain __Arctic
7+
static struct __AvailabilityDomain arctic_domain
88
__attribute__((availability_domain(Arctic))) = {
99
__AVAILABILITY_DOMAIN_DYNAMIC, arctic_pred};
10-
static struct __AvailabilityDomain __Pacific
10+
static struct __AvailabilityDomain pacific_domain
1111
__attribute__((availability_domain(Pacific))) = {
1212
__AVAILABILITY_DOMAIN_DYNAMIC, pacific_pred};
1313

test/Inputs/custom-modules/availability-domains/Rivers.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include <feature-availability.h>
22

3-
static struct __AvailabilityDomain __Colorado __attribute__((
3+
static struct __AvailabilityDomain colorado_domain __attribute__((
44
availability_domain(Colorado))) = {__AVAILABILITY_DOMAIN_DISABLED, 0};
55

66
#define AVAIL 0

test/Inputs/custom-modules/availability-domains/Seas.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#include <feature-availability.h>
22

3-
static struct __AvailabilityDomain __Baltic __attribute__((
3+
static struct __AvailabilityDomain baltic_domain __attribute__((
44
availability_domain(Baltic))) = {__AVAILABILITY_DOMAIN_ENABLED, 0};
5-
static struct __AvailabilityDomain __Mediterranean __attribute__((
5+
static struct __AvailabilityDomain _mediterranean __attribute__((
66
availability_domain(Mediterranean))) = {__AVAILABILITY_DOMAIN_ENABLED, 0};
77

88
#define AVAIL 0
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -typecheck \
4+
// RUN: -verify -disable-objc-attr-requires-foundation-module \
5+
// RUN: -enable-experimental-feature CustomAvailability \
6+
// RUN: -import-objc-header %S/../Inputs/empty.h \
7+
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
8+
// RUN: -emit-objc-header-path %t/func.h -DFUNC
9+
10+
// RUN: %FileCheck %s --check-prefixes=CHECK-FUNC --input-file %t/func.h
11+
// RUN: %check-in-clang -I %S/../Inputs/custom-modules/availability-domains %t/func.h
12+
13+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -typecheck \
14+
// RUN: -verify -disable-objc-attr-requires-foundation-module \
15+
// RUN: -enable-experimental-feature CustomAvailability \
16+
// RUN: -import-objc-header %S/../Inputs/empty.h \
17+
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
18+
// RUN: -emit-objc-header-path %t/class.h -DCLASS
19+
20+
// RUN: %FileCheck %s --check-prefixes=CHECK-CLASS --input-file %t/class.h
21+
// RUN: %check-in-clang -I %S/../Inputs/custom-modules/availability-domains %t/class.h
22+
23+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -typecheck \
24+
// RUN: -verify -disable-objc-attr-requires-foundation-module \
25+
// RUN: -enable-experimental-feature CustomAvailability \
26+
// RUN: -import-objc-header %S/../Inputs/empty.h \
27+
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
28+
// RUN: -emit-objc-header-path %t/class_member.h -DCLASS_MEMBER
29+
30+
// RUN: %FileCheck %s --check-prefixes=CHECK-CLASS-MEMBER --input-file %t/class_member.h
31+
// RUN: %check-in-clang -I %S/../Inputs/custom-modules/availability-domains %t/class_member.h
32+
33+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -typecheck \
34+
// RUN: -verify -disable-objc-attr-requires-foundation-module \
35+
// RUN: -enable-experimental-feature CustomAvailability \
36+
// RUN: -import-objc-header %S/../Inputs/empty.h \
37+
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
38+
// RUN: -emit-objc-header-path %t/protocol.h -DPROTOCOL
39+
40+
// RUN: %FileCheck %s --check-prefixes=CHECK-PROTOCOL --input-file %t/protocol.h
41+
// RUN: %check-in-clang -I %S/../Inputs/custom-modules/availability-domains %t/protocol.h
42+
43+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -typecheck \
44+
// RUN: -verify -disable-objc-attr-requires-foundation-module \
45+
// RUN: -enable-experimental-feature CustomAvailability \
46+
// RUN: -import-objc-header %S/../Inputs/empty.h \
47+
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
48+
// RUN: -emit-objc-header-path %t/protocol_member.h -DPROTOCOL_MEMBER
49+
50+
// RUN: %FileCheck %s --check-prefixes=CHECK-PROTOCOL-MEMBER --input-file %t/protocol_member.h
51+
// RUN: %check-in-clang -I %S/../Inputs/custom-modules/availability-domains %t/protocol_member.h
52+
53+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -typecheck \
54+
// RUN: -verify -disable-objc-attr-requires-foundation-module \
55+
// RUN: -enable-experimental-feature CustomAvailability \
56+
// RUN: -import-objc-header %S/../Inputs/empty.h \
57+
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
58+
// RUN: -emit-objc-header-path %t/extension.h -DEXTENSION
59+
60+
// RUN: %FileCheck %s --check-prefixes=CHECK-EXTENSION --input-file %t/extension.h
61+
// RUN: %check-in-clang -I %S/../Inputs/custom-modules/availability-domains %t/extension.h
62+
63+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -typecheck \
64+
// RUN: -verify -disable-objc-attr-requires-foundation-module \
65+
// RUN: -enable-experimental-feature CustomAvailability \
66+
// RUN: -import-objc-header %S/../Inputs/empty.h \
67+
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
68+
// RUN: -emit-objc-header-path %t/extension_member.h -DEXTENSION_MEMBER
69+
70+
// RUN: %FileCheck %s --check-prefixes=CHECK-EXTENSION-MEMBER --input-file %t/extension_member.h
71+
// RUN: %check-in-clang -I %S/../Inputs/custom-modules/availability-domains %t/extension_member.h
72+
73+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -typecheck \
74+
// RUN: -verify -disable-objc-attr-requires-foundation-module \
75+
// RUN: -enable-experimental-feature CustomAvailability \
76+
// RUN: -import-objc-header %S/../Inputs/empty.h \
77+
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
78+
// RUN: -emit-objc-header-path %t/enum.h -DENUM
79+
80+
// RUN: %FileCheck %s --check-prefixes=CHECK-ENUM --input-file %t/enum.h
81+
// RUN: %check-in-clang -I %S/../Inputs/custom-modules/availability-domains %t/enum.h
82+
83+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -typecheck \
84+
// RUN: -verify -disable-objc-attr-requires-foundation-module \
85+
// RUN: -enable-experimental-feature CustomAvailability \
86+
// RUN: -import-objc-header %S/../Inputs/empty.h \
87+
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
88+
// RUN: -emit-objc-header-path %t/enum_member.h -DENUM_MEMBER
89+
90+
// RUN: %FileCheck %s --check-prefixes=CHECK-ENUM-MEMBER --input-file %t/enum_member.h
91+
// RUN: %check-in-clang -I %S/../Inputs/custom-modules/availability-domains %t/enum_member.h
92+
93+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -typecheck \
94+
// RUN: -verify -disable-objc-attr-requires-foundation-module \
95+
// RUN: -enable-experimental-feature CustomAvailability \
96+
// RUN: -import-objc-header %S/../Inputs/empty.h \
97+
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
98+
// RUN: -emit-objc-header-path %t/private.h -DPRIVATE
99+
100+
// RUN: %FileCheck %s --check-prefix=CHECK-PRIVATE --input-file %t/private.h
101+
// RUN: %check-in-clang -I %S/../Inputs/custom-modules/availability-domains %t/private.h
102+
103+
// REQUIRES: swift_feature_CustomAvailability
104+
// REQUIRES: objc_interop
105+
106+
import Oceans
107+
108+
#if FUNC
109+
110+
// CHECK-FUNC: SWIFT_EXTERN void arctic_func(void) SWIFT_NOEXCEPT SWIFT_AVAILABILITY_DOMAIN(Arctic,0);
111+
@available(Arctic)
112+
@_cdecl("arctic_func") func arcticFunc() { }
113+
114+
#elseif CLASS
115+
116+
// CHECK-CLASS: SWIFT_AVAILABILITY_DOMAIN(Arctic,0)
117+
// CHECK-CLASS-LABEL: @interface ArcticClass{{$}}
118+
@available(Arctic)
119+
@objc class ArcticClass {
120+
// CHECK-CLASS-NEXT: - (void)alwaysAvailable;
121+
@objc func alwaysAvailable() { }
122+
}
123+
// CHECK-CLASS-LABEL: @end
124+
125+
#elseif CLASS_MEMBER
126+
127+
// CHECK-CLASS-MEMBER-LABEL: @interface AvailableClass{{$}}
128+
@objc class AvailableClass {
129+
// CHECK-CLASS-MEMBER-NEXT: - (void)availableInArctic SWIFT_AVAILABILITY_DOMAIN(Arctic,0);
130+
@available(Arctic)
131+
@objc func availableInArctic() { }
132+
133+
// CHECK-CLASS-MEMBER-NEXT: @property (nonatomic) NSInteger unavailableInArctic SWIFT_AVAILABILITY_DOMAIN(Arctic,1);
134+
@available(Arctic, unavailable)
135+
@objc var unavailableInArctic: Int {
136+
get { 0 }
137+
set { }
138+
}
139+
}
140+
// CHECK-CLASS-MEMBER-LABEL: @end
141+
142+
#elseif PROTOCOL
143+
144+
// CHECK-PROTOCOL: SWIFT_AVAILABILITY_DOMAIN(Arctic,0)
145+
// CHECK-PROTOCOL-LABEL: @protocol ArcticProtocol{{$}}
146+
@available(Arctic)
147+
@objc protocol ArcticProtocol {
148+
// CHECK-PROTOCOL-NEXT: - (void)requirement;
149+
func requirement()
150+
}
151+
// CHECK-PROTOCOL-LABEL: @end
152+
153+
#elseif PROTOCOL_MEMBER
154+
155+
// CHECK-PROTOCOL-MEMBER-LABEL: @protocol AvailableProtocol{{$}}
156+
@objc protocol AvailableProtocol {
157+
// CHECK-PROTOCOL-MEMBER-NEXT: - (void)availableInArctic SWIFT_AVAILABILITY_DOMAIN(Arctic,0);
158+
@available(Arctic)
159+
func availableInArctic()
160+
161+
func requirement()
162+
}
163+
// CHECK-PROTOCOL-MEMBER-LABEL: @end
164+
165+
#elseif EXTENSION
166+
167+
// CHECK-EXTENSION-LABEL: @interface AvailableClass{{$}}
168+
@objc class AvailableClass {
169+
}
170+
// CHECK-EXTENSION-LABEL: @end
171+
172+
// CHECK-EXTENSION-LABEL: SWIFT_AVAILABILITY_DOMAIN(Arctic,0)
173+
// CHECK-EXTENSION-NEXT: @interface AvailableClass (SWIFT_EXTENSION(availability_custom_domains))
174+
@available(Arctic)
175+
extension AvailableClass {
176+
// CHECK-EXTENSION-NEXT: - (void)alwaysAvailable;
177+
@objc func alwaysAvailable() { }
178+
}
179+
// CHECK-EXTENSION-LABEL: @end
180+
181+
#elseif EXTENSION_MEMBER
182+
183+
// CHECK-EXTENSION-MEMBER-LABEL: @interface AvailableClass{{$}}
184+
@objc class AvailableClass {
185+
}
186+
// CHECK-EXTENSION-MEMBER-LABEL: @end
187+
188+
// CHECK-EXTENSION-MEMBER-LABEL: @interface AvailableClass (SWIFT_EXTENSION(availability_custom_domains))
189+
extension AvailableClass {
190+
// CHECK-EXTENSION-MEMBER-NEXT: - (void)availableInArctic SWIFT_AVAILABILITY_DOMAIN(Arctic,0);
191+
@available(Arctic)
192+
@objc func availableInArctic() { }
193+
}
194+
// CHECK-EXTENSION-MEMBER-LABEL: @end
195+
196+
#elseif ENUM
197+
198+
// FIXME: [availability] Availability attribute is missing
199+
// CHECK-ENUM-LABEL: typedef SWIFT_ENUM(NSInteger, ArcticEnum, closed)
200+
@available(Arctic)
201+
@objc enum ArcticEnum: Int {
202+
// CHECK-ENUM-NEXT: ArcticEnumAvailable = 0,
203+
case available
204+
}
205+
// CHECK-ENUM-NEXT: };
206+
207+
#elseif ENUM_MEMBER
208+
209+
// FIXME: [availability] Availability attribute is missing
210+
// CHECK-ENUM-MEMBER-LABEL: typedef SWIFT_ENUM(NSInteger, AvailableEnum, closed)
211+
@objc enum AvailableEnum: Int {
212+
// CHECK-ENUM-MEMBER-NEXT: AvailableEnumAvailableInArctic = 0,
213+
@available(Arctic)
214+
case availableInArctic
215+
}
216+
// CHECK-ENUM-MEMBER-NEXT: };
217+
218+
#elseif PRIVATE
219+
220+
// CHECK-PRIVATE-NOT: @import Oceans;
221+
// CHECK-PRIVATE-NOT: @interface PrivateClass
222+
@available(Arctic)
223+
@objc private class PrivateClass { }
224+
225+
// CHECK-PRIVATE-LABEL: @interface ClassWithPrivateMember{{$}}
226+
@objc class ClassWithPrivateMember {
227+
// CHECK-PRIVATE-NOT: - (void)member;
228+
@available(Arctic)
229+
@objc private func member() { }
230+
}
231+
232+
#endif

0 commit comments

Comments
 (0)