2828#include " swift/AST/AvailabilityScope.h"
2929#include " swift/AST/AvailabilitySpec.h"
3030#include " swift/AST/ClangModuleLoader.h"
31+ #include " swift/AST/DeclExportabilityVisitor.h"
3132#include " swift/AST/DiagnosticsParse.h"
3233#include " swift/AST/GenericEnvironment.h"
3334#include " swift/AST/Initializer.h"
@@ -97,88 +98,6 @@ ExportContext::ExportContext(DeclContext *DC,
9798 Reason = unsigned (ExportabilityReason::General);
9899}
99100
100- bool swift::isExported (const ValueDecl *VD) {
101- if (VD->getAttrs ().hasAttribute <ImplementationOnlyAttr>())
102- return false ;
103- if (VD->isObjCMemberImplementation ())
104- return false ;
105-
106- // Is this part of the module's API or ABI?
107- AccessScope accessScope =
108- VD->getFormalAccessScope (nullptr ,
109- /* treatUsableFromInlineAsPublic*/ true );
110- if (accessScope.isPublic ())
111- return true ;
112-
113- // Is this a stored property in a @frozen struct or class?
114- if (auto *property = dyn_cast<VarDecl>(VD))
115- if (property->isLayoutExposedToClients ())
116- return true ;
117-
118- return false ;
119- }
120-
121- static bool hasConformancesToPublicProtocols (const ExtensionDecl *ED) {
122- auto nominal = ED->getExtendedNominal ();
123- if (!nominal)
124- return false ;
125-
126- // Extensions of protocols cannot introduce additional conformances.
127- if (isa<ProtocolDecl>(nominal))
128- return false ;
129-
130- auto protocols = ED->getLocalProtocols (ConformanceLookupKind::OnlyExplicit);
131- for (const ProtocolDecl *PD : protocols) {
132- AccessScope scope =
133- PD->getFormalAccessScope (/* useDC*/ nullptr ,
134- /* treatUsableFromInlineAsPublic*/ true );
135- if (scope.isPublic ())
136- return true ;
137- }
138-
139- return false ;
140- }
141-
142- bool swift::isExported (const ExtensionDecl *ED) {
143- // An extension can only be exported if it extends an exported type.
144- if (auto *NTD = ED->getExtendedNominal ()) {
145- if (!isExported (NTD))
146- return false ;
147- }
148-
149- // If there are any exported members then the extension is exported.
150- for (const Decl *D : ED->getMembers ()) {
151- if (isExported (D))
152- return true ;
153- }
154-
155- // If the extension declares a conformance to a public protocol then the
156- // extension is exported.
157- if (hasConformancesToPublicProtocols (ED))
158- return true ;
159-
160- return false ;
161- }
162-
163- bool swift::isExported (const Decl *D) {
164- if (auto *VD = dyn_cast<ValueDecl>(D)) {
165- return isExported (VD);
166- }
167- if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
168- for (unsigned i = 0 , e = PBD->getNumPatternEntries (); i < e; ++i) {
169- if (auto *VD = PBD->getAnchoringVarDecl (i))
170- return isExported (VD);
171- }
172-
173- return false ;
174- }
175- if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
176- return isExported (ED);
177- }
178-
179- return true ;
180- }
181-
182101template <typename Fn>
183102static void forEachOuterDecl (DeclContext *DC, Fn fn) {
184103 for (; !DC->isModuleScopeContext (); DC = DC->getParent ()) {
@@ -4803,12 +4722,7 @@ void swift::checkExplicitAvailability(Decl *decl) {
48034722 !isa<ExtensionDecl>(decl->getDeclContext ())) return ;
48044723
48054724 if (auto extension = dyn_cast<ExtensionDecl>(decl)) {
4806- // decl should be either a ValueDecl or an ExtensionDecl.
4807- auto extended = extension->getExtendedNominal ();
4808- if (!extended || !extended->getFormalAccessScope ().isPublic ())
4809- return ;
4810-
4811- // Skip extensions without public members or conformances.
4725+ // Skip extensions when none of their members need availability.
48124726 auto members = extension->getMembers ();
48134727 auto hasMembers = std::any_of (members.begin (), members.end (),
48144728 [](const Decl *D) -> bool {
@@ -4818,10 +4732,8 @@ void swift::checkExplicitAvailability(Decl *decl) {
48184732 return false ;
48194733 });
48204734
4821- auto hasProtocols = hasConformancesToPublicProtocols (extension);
4822-
4823- if (!hasMembers && !hasProtocols) return ;
4824-
4735+ if (!hasMembers && !isExported (extension))
4736+ return ;
48254737 } else if (auto pbd = dyn_cast<PatternBindingDecl>(decl)) {
48264738 // Check the first var instead.
48274739 if (pbd->getNumPatternEntries () == 0 )
0 commit comments