Skip to content

Commit 7296909

Browse files
authored
Merge pull request #75936 from tshortli/refactor-unavailable-decl-diags
Sema: Refactor unavailable declaration diagnostics
2 parents ba63b9f + 5a093c7 commit 7296909

File tree

1 file changed

+150
-141
lines changed

1 file changed

+150
-141
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 150 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -2841,36 +2841,72 @@ bool swift::diagnoseExplicitUnavailability(const ValueDecl *D, SourceRange R,
28412841
});
28422842
}
28432843

2844-
/// Emit a diagnostic for references to declarations that have been
2845-
/// marked as unavailable, either through "unavailable" or "obsoleted:".
2846-
bool swift::diagnoseExplicitUnavailability(SourceLoc loc,
2847-
const RootProtocolConformance *rootConf,
2848-
const ExtensionDecl *ext,
2849-
const ExportContext &where,
2850-
bool warnIfConformanceUnavailablePreSwift6) {
2851-
auto *attr = AvailableAttr::isUnavailable(ext);
2844+
/// Represents common information needed to emit diagnostics about explicitly
2845+
/// unavailable declarations.
2846+
class UnavailabilityDiagnosticInfo {
2847+
public:
2848+
enum class Status {
2849+
/// The declaration is marked `unavailable`, potentially on a specific
2850+
/// platform.
2851+
AlwaysUnavailable,
2852+
2853+
/// The declaration is not available until, for example, a later Swift
2854+
/// language mode.
2855+
IntroducedInVersion,
2856+
2857+
/// The declaration was obsoleted in a previous version.
2858+
Obsoleted,
2859+
};
2860+
2861+
private:
2862+
Status DiagnosticStatus;
2863+
const AvailableAttr *Attr;
2864+
StringRef Platform;
2865+
StringRef VersionedPlatform;
2866+
2867+
public:
2868+
UnavailabilityDiagnosticInfo(Status status, const AvailableAttr *attr,
2869+
StringRef platform, StringRef versionedPlatform)
2870+
: DiagnosticStatus(status), Attr(attr), Platform(platform),
2871+
VersionedPlatform(versionedPlatform) {
2872+
assert(attr);
2873+
assert(status == Status::AlwaysUnavailable || !VersionedPlatform.empty());
2874+
};
2875+
2876+
Status getStatus() const { return DiagnosticStatus; }
2877+
const AvailableAttr *getAttr() const { return Attr; }
2878+
2879+
/// Returns the platform name (or "Swift" for a declaration that is
2880+
/// unavailable in Swift) to print in the main unavailability diangostic. May
2881+
/// be empty.
2882+
StringRef getPlatform() const { return Platform; }
2883+
2884+
/// Returns the platform name to print in diagnostic notes about the version
2885+
/// in which a declaration either will become available or previously became
2886+
/// obsoleted.
2887+
StringRef getVersionedPlatform() const {
2888+
assert(DiagnosticStatus != Status::AlwaysUnavailable);
2889+
return VersionedPlatform;
2890+
}
2891+
};
2892+
2893+
static std::optional<UnavailabilityDiagnosticInfo>
2894+
getExplicitUnavailabilityDiagnosticInfo(const Decl *decl,
2895+
const ExportContext &where) {
2896+
auto *attr = AvailableAttr::isUnavailable(decl);
28522897
if (!attr)
2853-
return false;
2898+
return std::nullopt;
28542899

28552900
// Calling unavailable code from within code with the same
28562901
// unavailability is OK -- the eventual caller can't call the
28572902
// enclosing code in the same situations it wouldn't be able to
28582903
// call this code.
2859-
if (isInsideCompatibleUnavailableDeclaration(ext, where, attr))
2860-
return false;
2861-
2862-
// Invertible protocols are never unavailable.
2863-
if (rootConf->getProtocol()->getInvertibleProtocolKind())
2864-
return false;
2865-
2866-
ASTContext &ctx = ext->getASTContext();
2867-
auto &diags = ctx.Diags;
2868-
2869-
auto type = rootConf->getType();
2870-
auto proto = rootConf->getProtocol()->getDeclaredInterfaceType();
2904+
if (isInsideCompatibleUnavailableDeclaration(decl, where, attr))
2905+
return std::nullopt;
28712906

2872-
StringRef platform;
2873-
auto behavior = DiagnosticBehavior::Unspecified;
2907+
ASTContext &ctx = decl->getASTContext();
2908+
StringRef platform = "";
2909+
StringRef versionedPlatform = "";
28742910
switch (attr->getPlatformAgnosticAvailability()) {
28752911
case PlatformAgnosticAvailabilityKind::Deprecated:
28762912
llvm_unreachable("shouldn't see deprecations in explicit unavailability");
@@ -2881,73 +2917,96 @@ bool swift::diagnoseExplicitUnavailability(SourceLoc loc,
28812917
case PlatformAgnosticAvailabilityKind::None:
28822918
case PlatformAgnosticAvailabilityKind::Unavailable:
28832919
if (attr->Platform != PlatformKind::none) {
2884-
// This was platform-specific; indicate the platform.
28852920
platform = attr->prettyPlatformString();
2886-
break;
2921+
versionedPlatform = platform;
28872922
}
2888-
2889-
// Downgrade unavailable Sendable conformance diagnostics where
2890-
// appropriate.
2891-
behavior = behaviorLimitForExplicitUnavailability(
2892-
rootConf, where.getDeclContext());
2893-
LLVM_FALLTHROUGH;
2894-
2923+
break;
28952924
case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific:
2925+
versionedPlatform = "Swift";
2926+
break;
28962927
case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific:
2897-
// We don't want to give further detail about these.
2898-
platform = "";
2928+
versionedPlatform = "PackageDescription";
28992929
break;
2900-
29012930
case PlatformAgnosticAvailabilityKind::UnavailableInSwift:
2902-
// This API is explicitly unavailable in Swift.
29032931
platform = "Swift";
29042932
break;
29052933
}
29062934

2907-
EncodedDiagnosticMessage EncodedMessage(attr->Message);
2908-
diags.diagnose(loc, diag::conformance_availability_unavailable,
2909-
type, proto,
2910-
platform.empty(), platform, EncodedMessage.Message)
2911-
.limitBehaviorUntilSwiftVersion(behavior, 6)
2912-
.warnUntilSwiftVersionIf(warnIfConformanceUnavailablePreSwift6, 6);
2913-
29142935
switch (attr->getVersionAvailability(ctx)) {
29152936
case AvailableVersionComparison::Available:
29162937
case AvailableVersionComparison::PotentiallyUnavailable:
29172938
llvm_unreachable("These aren't considered unavailable");
29182939

29192940
case AvailableVersionComparison::Unavailable:
29202941
if ((attr->isLanguageVersionSpecific() ||
2921-
attr->isPackageDescriptionVersionSpecific())
2922-
&& attr->Introduced.has_value())
2923-
diags.diagnose(ext, diag::conformance_availability_introduced_in_version,
2924-
type, proto,
2925-
(attr->isLanguageVersionSpecific() ?
2926-
"Swift" : "PackageDescription"),
2927-
*attr->Introduced)
2928-
.highlight(attr->getRange());
2929-
else
2930-
diags.diagnose(ext, diag::conformance_availability_marked_unavailable,
2931-
type, proto)
2932-
.highlight(attr->getRange());
2942+
attr->isPackageDescriptionVersionSpecific()) &&
2943+
attr->Introduced.has_value()) {
2944+
return UnavailabilityDiagnosticInfo(
2945+
UnavailabilityDiagnosticInfo::Status::IntroducedInVersion, attr,
2946+
platform, versionedPlatform);
2947+
} else {
2948+
return UnavailabilityDiagnosticInfo(
2949+
UnavailabilityDiagnosticInfo::Status::AlwaysUnavailable, attr,
2950+
platform, versionedPlatform);
2951+
}
29332952
break;
29342953

29352954
case AvailableVersionComparison::Obsoleted:
2936-
// FIXME: Use of the platformString here is non-awesome for application
2937-
// extensions.
2938-
2939-
StringRef platformDisplayString;
2940-
if (attr->isLanguageVersionSpecific()) {
2941-
platformDisplayString = "Swift";
2942-
} else if (attr->isPackageDescriptionVersionSpecific()) {
2943-
platformDisplayString = "PackageDescription";
2944-
} else {
2945-
platformDisplayString = platform;
2946-
}
2955+
return UnavailabilityDiagnosticInfo(
2956+
UnavailabilityDiagnosticInfo::Status::Obsoleted, attr, platform,
2957+
versionedPlatform);
2958+
}
2959+
}
29472960

2948-
diags.diagnose(ext, diag::conformance_availability_obsoleted,
2949-
type, proto, platformDisplayString, *attr->Obsoleted)
2950-
.highlight(attr->getRange());
2961+
bool swift::diagnoseExplicitUnavailability(
2962+
SourceLoc loc, const RootProtocolConformance *rootConf,
2963+
const ExtensionDecl *ext, const ExportContext &where,
2964+
bool warnIfConformanceUnavailablePreSwift6) {
2965+
// Invertible protocols are never unavailable.
2966+
if (rootConf->getProtocol()->getInvertibleProtocolKind())
2967+
return false;
2968+
2969+
auto diagnosticInfo = getExplicitUnavailabilityDiagnosticInfo(ext, where);
2970+
if (!diagnosticInfo)
2971+
return false;
2972+
2973+
ASTContext &ctx = ext->getASTContext();
2974+
auto &diags = ctx.Diags;
2975+
2976+
auto type = rootConf->getType();
2977+
auto proto = rootConf->getProtocol()->getDeclaredInterfaceType();
2978+
StringRef platform = diagnosticInfo->getPlatform();
2979+
const AvailableAttr *attr = diagnosticInfo->getAttr();
2980+
2981+
// Downgrade unavailable Sendable conformance diagnostics where
2982+
// appropriate.
2983+
auto behavior =
2984+
behaviorLimitForExplicitUnavailability(rootConf, where.getDeclContext());
2985+
2986+
EncodedDiagnosticMessage EncodedMessage(attr->Message);
2987+
diags
2988+
.diagnose(loc, diag::conformance_availability_unavailable, type, proto,
2989+
platform.empty(), platform, EncodedMessage.Message)
2990+
.limitBehaviorUntilSwiftVersion(behavior, 6)
2991+
.warnUntilSwiftVersionIf(warnIfConformanceUnavailablePreSwift6, 6);
2992+
2993+
switch (diagnosticInfo->getStatus()) {
2994+
case UnavailabilityDiagnosticInfo::Status::AlwaysUnavailable:
2995+
diags
2996+
.diagnose(ext, diag::conformance_availability_marked_unavailable, type,
2997+
proto)
2998+
.highlight(attr->getRange());
2999+
break;
3000+
case UnavailabilityDiagnosticInfo::Status::IntroducedInVersion:
3001+
diags.diagnose(ext, diag::conformance_availability_introduced_in_version,
3002+
type, proto, diagnosticInfo->getVersionedPlatform(),
3003+
*attr->Introduced);
3004+
break;
3005+
case UnavailabilityDiagnosticInfo::Status::Obsoleted:
3006+
diags
3007+
.diagnose(ext, diag::conformance_availability_obsoleted, type, proto,
3008+
diagnosticInfo->getVersionedPlatform(), *attr->Obsoleted)
3009+
.highlight(attr->getRange());
29513010
break;
29523011
}
29533012
return true;
@@ -3282,52 +3341,21 @@ bool swift::diagnoseExplicitUnavailability(
32823341
const ExportContext &Where,
32833342
DeclAvailabilityFlags Flags,
32843343
llvm::function_ref<void(InFlightDiagnostic &)> attachRenameFixIts) {
3285-
auto *Attr = AvailableAttr::isUnavailable(D);
3286-
if (!Attr)
3344+
auto diagnosticInfo = getExplicitUnavailabilityDiagnosticInfo(D, Where);
3345+
if (!diagnosticInfo)
32873346
return false;
32883347

3289-
// Calling unavailable code from within code with the same
3290-
// unavailability is OK -- the eventual caller can't call the
3291-
// enclosing code in the same situations it wouldn't be able to
3292-
// call this code.
3293-
if (isInsideCompatibleUnavailableDeclaration(D, Where, Attr))
3294-
return false;
3348+
auto *Attr = diagnosticInfo->getAttr();
3349+
if (Attr->getPlatformAgnosticAvailability() ==
3350+
PlatformAgnosticAvailabilityKind::UnavailableInSwift) {
3351+
if (shouldAllowReferenceToUnavailableInSwiftDeclaration(D, Where))
3352+
return false;
3353+
}
32953354

32963355
SourceLoc Loc = R.Start;
3297-
32983356
ASTContext &ctx = D->getASTContext();
32993357
auto &diags = ctx.Diags;
3300-
3301-
StringRef platform;
3302-
switch (Attr->getPlatformAgnosticAvailability()) {
3303-
case PlatformAgnosticAvailabilityKind::Deprecated:
3304-
llvm_unreachable("shouldn't see deprecations in explicit unavailability");
3305-
3306-
case PlatformAgnosticAvailabilityKind::NoAsync:
3307-
llvm_unreachable("shouldn't see noasync with explicit unavailability");
3308-
3309-
case PlatformAgnosticAvailabilityKind::None:
3310-
case PlatformAgnosticAvailabilityKind::Unavailable:
3311-
if (Attr->Platform != PlatformKind::none) {
3312-
// This was platform-specific; indicate the platform.
3313-
platform = Attr->prettyPlatformString();
3314-
break;
3315-
}
3316-
LLVM_FALLTHROUGH;
3317-
3318-
case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific:
3319-
case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific:
3320-
// We don't want to give further detail about these.
3321-
platform = "";
3322-
break;
3323-
3324-
case PlatformAgnosticAvailabilityKind::UnavailableInSwift:
3325-
if (shouldAllowReferenceToUnavailableInSwiftDeclaration(D, Where))
3326-
return true;
3327-
3328-
platform = "Swift";
3329-
break;
3330-
}
3358+
StringRef platform = diagnosticInfo->getPlatform();
33313359

33323360
// TODO: Consider removing this.
33333361
// ObjC keypaths components weren't checked previously, so errors are demoted
@@ -3372,41 +3400,22 @@ bool swift::diagnoseExplicitUnavailability(
33723400
.limitBehavior(limit);
33733401
}
33743402

3375-
switch (Attr->getVersionAvailability(ctx)) {
3376-
case AvailableVersionComparison::Available:
3377-
case AvailableVersionComparison::PotentiallyUnavailable:
3378-
llvm_unreachable("These aren't considered unavailable");
3379-
3380-
case AvailableVersionComparison::Unavailable:
3381-
if ((Attr->isLanguageVersionSpecific() ||
3382-
Attr->isPackageDescriptionVersionSpecific())
3383-
&& Attr->Introduced.has_value())
3384-
diags.diagnose(D, diag::availability_introduced_in_version, D,
3385-
(Attr->isLanguageVersionSpecific() ?
3386-
"Swift" : "PackageDescription"),
3387-
*Attr->Introduced)
3403+
switch (diagnosticInfo->getStatus()) {
3404+
case UnavailabilityDiagnosticInfo::Status::AlwaysUnavailable:
3405+
diags.diagnose(D, diag::availability_marked_unavailable, D)
33883406
.highlight(Attr->getRange());
3389-
else
3390-
diags.diagnose(D, diag::availability_marked_unavailable, D)
3407+
break;
3408+
case UnavailabilityDiagnosticInfo::Status::IntroducedInVersion:
3409+
diags
3410+
.diagnose(D, diag::availability_introduced_in_version, D,
3411+
diagnosticInfo->getVersionedPlatform(), *Attr->Introduced)
33913412
.highlight(Attr->getRange());
33923413
break;
3393-
3394-
case AvailableVersionComparison::Obsoleted:
3395-
// FIXME: Use of the platformString here is non-awesome for application
3396-
// extensions.
3397-
3398-
StringRef platformDisplayString;
3399-
if (Attr->isLanguageVersionSpecific()) {
3400-
platformDisplayString = "Swift";
3401-
} else if (Attr->isPackageDescriptionVersionSpecific()) {
3402-
platformDisplayString = "PackageDescription";
3403-
} else {
3404-
platformDisplayString = platform;
3405-
}
3406-
3407-
diags.diagnose(D, diag::availability_obsoleted, D, platformDisplayString,
3408-
*Attr->Obsoleted)
3409-
.highlight(Attr->getRange());
3414+
case UnavailabilityDiagnosticInfo::Status::Obsoleted:
3415+
diags
3416+
.diagnose(D, diag::availability_obsoleted, D,
3417+
diagnosticInfo->getVersionedPlatform(), *Attr->Obsoleted)
3418+
.highlight(Attr->getRange());
34103419
break;
34113420
}
34123421
return true;

0 commit comments

Comments
 (0)