|
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