|
22 | 22 | #include "swift/AST/AvailabilityInference.h"
|
23 | 23 | #include "swift/AST/AvailabilityRange.h"
|
24 | 24 | #include "swift/AST/Decl.h"
|
| 25 | +#include "swift/AST/DeclExportabilityVisitor.h" |
25 | 26 | // FIXME: [availability] Remove this when possible
|
26 | 27 | #include "swift/AST/DiagnosticsParse.h"
|
27 | 28 | #include "swift/AST/DiagnosticsSema.h"
|
@@ -382,7 +383,7 @@ static std::optional<SemanticAvailableAttr>
|
382 | 383 | getDeclAvailableAttrForPlatformIntroduction(const Decl *D) {
|
383 | 384 | std::optional<SemanticAvailableAttr> bestAvailAttr;
|
384 | 385 |
|
385 |
| - D = abstractSyntaxDeclForAvailableAttribute(D); |
| 386 | + D = D->getAbstractSyntaxDeclForAttributes(); |
386 | 387 |
|
387 | 388 | for (auto attr : D->getSemanticAvailableAttrs(/*includingInactive=*/false)) {
|
388 | 389 | if (!attr.isPlatformSpecific() || !attr.getIntroduced())
|
@@ -1053,32 +1054,84 @@ bool ASTContext::supportsVersionedAvailability() const {
|
1053 | 1054 | return minimumAvailableOSVersionForTriple(LangOpts.Target).has_value();
|
1054 | 1055 | }
|
1055 | 1056 |
|
1056 |
| -// FIXME: Rename abstractSyntaxDeclForAvailableAttribute since it's useful |
1057 |
| -// for more attributes than `@available`. |
1058 |
| -const Decl * |
1059 |
| -swift::abstractSyntaxDeclForAvailableAttribute(const Decl *ConcreteSyntaxDecl) { |
1060 |
| - // This function needs to be kept in sync with its counterpart, |
1061 |
| - // concreteSyntaxDeclForAvailableAttribute(). |
1062 |
| - |
1063 |
| - if (auto *PBD = dyn_cast<PatternBindingDecl>(ConcreteSyntaxDecl)) { |
1064 |
| - // Existing @available attributes in the AST are attached to VarDecls |
1065 |
| - // rather than PatternBindingDecls, so we return the first VarDecl for |
1066 |
| - // the pattern binding declaration. |
1067 |
| - // This is safe, even though there may be multiple VarDecls, because |
1068 |
| - // all parsed attribute that appear in the concrete syntax upon on the |
1069 |
| - // PatternBindingDecl are added to all of the VarDecls for the pattern |
1070 |
| - // binding. |
1071 |
| - for (auto index : range(PBD->getNumPatternEntries())) { |
1072 |
| - if (auto VD = PBD->getAnchoringVarDecl(index)) |
1073 |
| - return VD; |
1074 |
| - } |
1075 |
| - } else if (auto *ECD = dyn_cast<EnumCaseDecl>(ConcreteSyntaxDecl)) { |
1076 |
| - // Similar to the PatternBindingDecl case above, we return the |
1077 |
| - // first EnumElementDecl. |
1078 |
| - if (auto *Elem = ECD->getFirstElement()) { |
1079 |
| - return Elem; |
| 1057 | +bool swift::isExported(const Decl *D) { |
| 1058 | + if (auto *VD = dyn_cast<ValueDecl>(D)) { |
| 1059 | + return isExported(VD); |
| 1060 | + } |
| 1061 | + if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) { |
| 1062 | + for (unsigned i = 0, e = PBD->getNumPatternEntries(); i < e; ++i) { |
| 1063 | + if (auto *VD = PBD->getAnchoringVarDecl(i)) |
| 1064 | + return isExported(VD); |
1080 | 1065 | }
|
| 1066 | + |
| 1067 | + return false; |
| 1068 | + } |
| 1069 | + if (auto *ED = dyn_cast<ExtensionDecl>(D)) { |
| 1070 | + return isExported(ED); |
| 1071 | + } |
| 1072 | + |
| 1073 | + return true; |
| 1074 | +} |
| 1075 | + |
| 1076 | +bool swift::isExported(const ValueDecl *VD) { |
| 1077 | + if (VD->getAttrs().hasAttribute<ImplementationOnlyAttr>()) |
| 1078 | + return false; |
| 1079 | + if (VD->isObjCMemberImplementation()) |
| 1080 | + return false; |
| 1081 | + |
| 1082 | + // Is this part of the module's API or ABI? |
| 1083 | + AccessScope accessScope = |
| 1084 | + VD->getFormalAccessScope(nullptr, |
| 1085 | + /*treatUsableFromInlineAsPublic*/ true); |
| 1086 | + if (accessScope.isPublic()) |
| 1087 | + return true; |
| 1088 | + |
| 1089 | + // Is this a stored property in a @frozen struct or class? |
| 1090 | + if (auto *property = dyn_cast<VarDecl>(VD)) |
| 1091 | + if (property->isLayoutExposedToClients()) |
| 1092 | + return true; |
| 1093 | + |
| 1094 | + return false; |
| 1095 | +} |
| 1096 | + |
| 1097 | +static bool hasConformancesToPublicProtocols(const ExtensionDecl *ED) { |
| 1098 | + auto nominal = ED->getExtendedNominal(); |
| 1099 | + if (!nominal) |
| 1100 | + return false; |
| 1101 | + |
| 1102 | + // Extensions of protocols cannot introduce additional conformances. |
| 1103 | + if (isa<ProtocolDecl>(nominal)) |
| 1104 | + return false; |
| 1105 | + |
| 1106 | + auto protocols = ED->getLocalProtocols(ConformanceLookupKind::OnlyExplicit); |
| 1107 | + for (const ProtocolDecl *PD : protocols) { |
| 1108 | + AccessScope scope = |
| 1109 | + PD->getFormalAccessScope(/*useDC*/ nullptr, |
| 1110 | + /*treatUsableFromInlineAsPublic*/ true); |
| 1111 | + if (scope.isPublic()) |
| 1112 | + return true; |
| 1113 | + } |
| 1114 | + |
| 1115 | + return false; |
| 1116 | +} |
| 1117 | + |
| 1118 | +bool swift::isExported(const ExtensionDecl *ED) { |
| 1119 | + // An extension can only be exported if it extends an exported type. |
| 1120 | + if (auto *NTD = ED->getExtendedNominal()) { |
| 1121 | + if (!isExported(NTD)) |
| 1122 | + return false; |
| 1123 | + } |
| 1124 | + |
| 1125 | + // If there are any exported members then the extension is exported. |
| 1126 | + for (const Decl *D : ED->getMembers()) { |
| 1127 | + if (isExported(D)) |
| 1128 | + return true; |
1081 | 1129 | }
|
1082 | 1130 |
|
1083 |
| - return ConcreteSyntaxDecl; |
| 1131 | + // If the extension declares a conformance to a public protocol then the |
| 1132 | + // extension is exported. |
| 1133 | + if (hasConformancesToPublicProtocols(ED)) |
| 1134 | + return true; |
| 1135 | + |
| 1136 | + return false; |
1084 | 1137 | }
|
0 commit comments