@@ -958,6 +958,13 @@ TypeChecker::checkDeclarationAvailability(const Decl *D,
958
958
return UnavailabilityReason::requiresVersionRange (version);
959
959
}
960
960
961
+ Optional<UnavailabilityReason>
962
+ TypeChecker::checkConformanceAvailability (const RootProtocolConformance *conf,
963
+ const ExtensionDecl *ext,
964
+ const ExportContext &where) {
965
+ return checkDeclarationAvailability (ext, where);
966
+ }
967
+
961
968
// / A class that walks the AST to find the innermost (i.e., deepest) node that
962
969
// / contains a target SourceRange and matches a particular criterion.
963
970
// / This class finds the innermost nodes of interest by walking
@@ -1638,6 +1645,37 @@ void TypeChecker::diagnosePotentialAccessorUnavailability(
1638
1645
fixAvailability (ReferenceRange, ReferenceDC, RequiredRange, Context);
1639
1646
}
1640
1647
1648
+ void TypeChecker::diagnosePotentialUnavailability (
1649
+ const RootProtocolConformance *rootConf,
1650
+ const ExtensionDecl *ext,
1651
+ SourceLoc loc,
1652
+ const DeclContext *dc,
1653
+ const UnavailabilityReason &reason) {
1654
+ ASTContext &ctx = dc->getASTContext ();
1655
+
1656
+ auto requiredRange = reason.getRequiredOSVersionRange ();
1657
+ {
1658
+ auto type = rootConf->getType ();
1659
+ auto proto = rootConf->getProtocol ()->getDeclaredInterfaceType ();
1660
+
1661
+ auto diagID = (ctx.LangOpts .EnableConformanceAvailabilityErrors
1662
+ ? diag::conformance_availability_only_version_newer
1663
+ : diag::conformance_availability_only_version_newer_warn);
1664
+ auto err =
1665
+ ctx.Diags .diagnose (
1666
+ loc, diagID,
1667
+ type, proto, prettyPlatformString (targetPlatform (ctx.LangOpts )),
1668
+ reason.getRequiredOSVersionRange ().getLowerEndpoint ());
1669
+
1670
+ // Direct a fixit to the error if an existing guard is nearly-correct
1671
+ if (fixAvailabilityByNarrowingNearbyVersionCheck (loc, dc,
1672
+ requiredRange, ctx, err))
1673
+ return ;
1674
+ }
1675
+
1676
+ fixAvailability (loc, dc, requiredRange, ctx);
1677
+ }
1678
+
1641
1679
const AvailableAttr *TypeChecker::getDeprecated (const Decl *D) {
1642
1680
if (auto *Attr = D->getAttrs ().getDeprecated (D->getASTContext ()))
1643
1681
return Attr;
@@ -1655,7 +1693,7 @@ const AvailableAttr *TypeChecker::getDeprecated(const Decl *D) {
1655
1693
// / Returns true if the reference or any of its parents is an
1656
1694
// / unconditional unavailable declaration for the same platform.
1657
1695
static bool isInsideCompatibleUnavailableDeclaration (
1658
- const ValueDecl *D, const ExportContext &where,
1696
+ const Decl *D, const ExportContext &where,
1659
1697
const AvailableAttr *attr) {
1660
1698
auto referencedPlatform = where.getUnavailablePlatformKind ();
1661
1699
if (!referencedPlatform)
@@ -2134,6 +2172,60 @@ void TypeChecker::diagnoseIfDeprecated(SourceRange ReferenceRange,
2134
2172
}
2135
2173
}
2136
2174
2175
+ void TypeChecker::diagnoseIfDeprecated (
2176
+ SourceLoc loc,
2177
+ const RootProtocolConformance *rootConf,
2178
+ const ExtensionDecl *ext,
2179
+ const ExportContext &where) {
2180
+ const AvailableAttr *attr = TypeChecker::getDeprecated (ext);
2181
+ if (!attr)
2182
+ return ;
2183
+
2184
+ // We match the behavior of clang to not report deprecation warnings
2185
+ // inside declarations that are themselves deprecated on all deployment
2186
+ // targets.
2187
+ if (where.isDeprecated ()) {
2188
+ return ;
2189
+ }
2190
+
2191
+ auto *dc = where.getDeclContext ();
2192
+ auto &ctx = dc->getASTContext ();
2193
+ if (!ctx.LangOpts .DisableAvailabilityChecking ) {
2194
+ AvailabilityContext runningOSVersion = where.getAvailabilityContext ();
2195
+ if (runningOSVersion.isKnownUnreachable ()) {
2196
+ // Suppress a deprecation warning if the availability checking machinery
2197
+ // thinks the reference program location will not execute on any
2198
+ // deployment target for the current platform.
2199
+ return ;
2200
+ }
2201
+ }
2202
+
2203
+ auto type = rootConf->getType ();
2204
+ auto proto = rootConf->getProtocol ()->getDeclaredInterfaceType ();
2205
+
2206
+ StringRef platform = attr->prettyPlatformString ();
2207
+ llvm::VersionTuple deprecatedVersion;
2208
+ if (attr->Deprecated )
2209
+ deprecatedVersion = attr->Deprecated .getValue ();
2210
+
2211
+ if (attr->Message .empty ()) {
2212
+ ctx.Diags .diagnose (
2213
+ loc, diag::conformance_availability_deprecated,
2214
+ type, proto, attr->hasPlatform (), platform,
2215
+ attr->Deprecated .hasValue (), deprecatedVersion,
2216
+ /* message*/ StringRef ())
2217
+ .highlight (attr->getRange ());
2218
+ return ;
2219
+ }
2220
+
2221
+ EncodedDiagnosticMessage encodedMessage (attr->Message );
2222
+ ctx.Diags .diagnose (
2223
+ loc, diag::conformance_availability_deprecated,
2224
+ type, proto, attr->hasPlatform (), platform,
2225
+ attr->Deprecated .hasValue (), deprecatedVersion,
2226
+ encodedMessage.Message )
2227
+ .highlight (attr->getRange ());
2228
+ }
2137
2229
2138
2230
void swift::diagnoseUnavailableOverride (ValueDecl *override ,
2139
2231
const ValueDecl *base,
@@ -2198,6 +2290,102 @@ bool swift::diagnoseExplicitUnavailability(const ValueDecl *D,
2198
2290
});
2199
2291
}
2200
2292
2293
+ // / Emit a diagnostic for references to declarations that have been
2294
+ // / marked as unavailable, either through "unavailable" or "obsoleted:".
2295
+ bool swift::diagnoseExplicitUnavailability (SourceLoc loc,
2296
+ const RootProtocolConformance *rootConf,
2297
+ const ExtensionDecl *ext,
2298
+ const ExportContext &where) {
2299
+ auto *attr = AvailableAttr::isUnavailable (ext);
2300
+ if (!attr)
2301
+ return false ;
2302
+
2303
+ // Calling unavailable code from within code with the same
2304
+ // unavailability is OK -- the eventual caller can't call the
2305
+ // enclosing code in the same situations it wouldn't be able to
2306
+ // call this code.
2307
+ if (isInsideCompatibleUnavailableDeclaration (ext, where, attr))
2308
+ return false ;
2309
+
2310
+ ASTContext &ctx = ext->getASTContext ();
2311
+ auto &diags = ctx.Diags ;
2312
+
2313
+ auto type = rootConf->getType ();
2314
+ auto proto = rootConf->getProtocol ()->getDeclaredInterfaceType ();
2315
+
2316
+ StringRef platform;
2317
+ switch (attr->getPlatformAgnosticAvailability ()) {
2318
+ case PlatformAgnosticAvailabilityKind::Deprecated:
2319
+ llvm_unreachable (" shouldn't see deprecations in explicit unavailability" );
2320
+
2321
+ case PlatformAgnosticAvailabilityKind::None:
2322
+ case PlatformAgnosticAvailabilityKind::Unavailable:
2323
+ if (attr->Platform != PlatformKind::none) {
2324
+ // This was platform-specific; indicate the platform.
2325
+ platform = attr->prettyPlatformString ();
2326
+ break ;
2327
+ }
2328
+ LLVM_FALLTHROUGH;
2329
+
2330
+ case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific:
2331
+ case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific:
2332
+ // We don't want to give further detail about these.
2333
+ platform = " " ;
2334
+ break ;
2335
+
2336
+ case PlatformAgnosticAvailabilityKind::UnavailableInSwift:
2337
+ // This API is explicitly unavailable in Swift.
2338
+ platform = " Swift" ;
2339
+ break ;
2340
+ }
2341
+
2342
+ EncodedDiagnosticMessage EncodedMessage (attr->Message );
2343
+ diags.diagnose (loc, diag::conformance_availability_unavailable,
2344
+ type, proto,
2345
+ platform.empty (), platform, EncodedMessage.Message );
2346
+
2347
+ switch (attr->getVersionAvailability (ctx)) {
2348
+ case AvailableVersionComparison::Available:
2349
+ case AvailableVersionComparison::PotentiallyUnavailable:
2350
+ llvm_unreachable (" These aren't considered unavailable" );
2351
+
2352
+ case AvailableVersionComparison::Unavailable:
2353
+ if ((attr->isLanguageVersionSpecific () ||
2354
+ attr->isPackageDescriptionVersionSpecific ())
2355
+ && attr->Introduced .hasValue ())
2356
+ diags.diagnose (ext, diag::conformance_availability_introduced_in_version,
2357
+ type, proto,
2358
+ (attr->isLanguageVersionSpecific () ?
2359
+ " Swift" : " PackageDescription" ),
2360
+ *attr->Introduced )
2361
+ .highlight (attr->getRange ());
2362
+ else
2363
+ diags.diagnose (ext, diag::conformance_availability_marked_unavailable,
2364
+ type, proto)
2365
+ .highlight (attr->getRange ());
2366
+ break ;
2367
+
2368
+ case AvailableVersionComparison::Obsoleted:
2369
+ // FIXME: Use of the platformString here is non-awesome for application
2370
+ // extensions.
2371
+
2372
+ StringRef platformDisplayString;
2373
+ if (attr->isLanguageVersionSpecific ()) {
2374
+ platformDisplayString = " Swift" ;
2375
+ } else if (attr->isPackageDescriptionVersionSpecific ()) {
2376
+ platformDisplayString = " PackageDescription" ;
2377
+ } else {
2378
+ platformDisplayString = platform;
2379
+ }
2380
+
2381
+ diags.diagnose (ext, diag::conformance_availability_obsoleted,
2382
+ type, proto, platformDisplayString, *attr->Obsoleted )
2383
+ .highlight (attr->getRange ());
2384
+ break ;
2385
+ }
2386
+ return true ;
2387
+ }
2388
+
2201
2389
// / Check if this is a subscript declaration inside String or
2202
2390
// / Substring that returns String, and if so return true.
2203
2391
bool isSubscriptReturningString (const ValueDecl *D, ASTContext &Context) {
@@ -3187,19 +3375,42 @@ bool
3187
3375
swift::diagnoseConformanceAvailability (SourceLoc loc,
3188
3376
ProtocolConformanceRef conformance,
3189
3377
const ExportContext &where) {
3378
+ assert (!where.isImplicit ());
3379
+
3190
3380
if (!conformance.isConcrete ())
3191
3381
return false ;
3382
+
3192
3383
const ProtocolConformance *concreteConf = conformance.getConcrete ();
3384
+ const RootProtocolConformance *rootConf = concreteConf->getRootConformance ();
3193
3385
3194
3386
auto *DC = where.getDeclContext ();
3387
+
3388
+ if (auto *ext = dyn_cast<ExtensionDecl>(rootConf->getDeclContext ())) {
3389
+ if (TypeChecker::diagnoseConformanceExportability (loc, rootConf, ext, where))
3390
+ return true ;
3391
+
3392
+ if (diagnoseExplicitUnavailability (loc, rootConf, ext, where))
3393
+ return true ;
3394
+
3395
+ // Diagnose for deprecation
3396
+ TypeChecker::diagnoseIfDeprecated (loc, rootConf, ext, where);
3397
+
3398
+ // Diagnose (and possibly signal) for potential unavailability
3399
+ auto maybeUnavail = TypeChecker::checkConformanceAvailability (
3400
+ rootConf, ext, where);
3401
+ if (maybeUnavail.hasValue ()) {
3402
+ TypeChecker::diagnosePotentialUnavailability (rootConf, ext, loc, DC,
3403
+ maybeUnavail.getValue ());
3404
+ }
3405
+ }
3406
+
3407
+ // Now, check associated conformances.
3195
3408
SubstitutionMap subConformanceSubs =
3196
3409
concreteConf->getSubstitutions (DC->getParentModule ());
3197
- diagnoseSubstitutionMapAvailability (loc, subConformanceSubs, where);
3198
- const RootProtocolConformance *rootConf =
3199
- concreteConf->getRootConformance ();
3410
+ if (diagnoseSubstitutionMapAvailability (loc, subConformanceSubs, where))
3411
+ return true ;
3200
3412
3201
- return TypeChecker::diagnoseConformanceExportability (
3202
- loc, rootConf, where);
3413
+ return false ;
3203
3414
}
3204
3415
3205
3416
bool
0 commit comments