Skip to content

Commit 5a093c7

Browse files
committed
Sema: Refactor unavailable declaration diagnostics.
Consolidate code related to determining which kinds of diagnostics to emit and platform names to display so that it is not duplicated between regular declaration diagnostics and conformance diagnostics. NFC.
1 parent d47c50e commit 5a093c7

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)