mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
AST: Warn for non-existent platform versions in @available attributes.
This commit is contained in:
@@ -209,6 +209,10 @@ public:
|
||||
/// version ranges.
|
||||
bool isVersioned() const;
|
||||
|
||||
/// Returns true if the given version is a valid version number for this
|
||||
/// domain. It is an error to call this on an un-versioned domain.
|
||||
bool isVersionValid(const llvm::VersionTuple &version) const;
|
||||
|
||||
/// Returns true if availability of the domain can be refined using
|
||||
/// `@available` attributes and `if #available` queries. If not, then the
|
||||
/// domain's availability is fixed by compilation settings. For example,
|
||||
|
||||
@@ -6929,6 +6929,9 @@ GROUPED_ERROR(availability_suggest_platform_name,
|
||||
(Identifier, StringRef))
|
||||
WARNING(availability_unsupported_version_number, none,
|
||||
"'%0' is not a supported version number", (llvm::VersionTuple))
|
||||
WARNING(availability_invalid_version_number_for_domain, none,
|
||||
"'%0' is not a valid version number for %1",
|
||||
(llvm::VersionTuple, AvailabilityDomain))
|
||||
|
||||
WARNING(attr_availability_expected_deprecated_version, none,
|
||||
"expected version number with 'deprecated' in '%0' attribute for %1",
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "swift/Config.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/VersionTuple.h"
|
||||
#include "llvm/TargetParser/Triple.h"
|
||||
#include <optional>
|
||||
|
||||
namespace swift {
|
||||
@@ -91,6 +92,10 @@ PlatformKind targetVariantPlatform(const LangOptions &LangOpts);
|
||||
/// an explicit attribute for the child.
|
||||
bool inheritsAvailabilityFromPlatform(PlatformKind Child, PlatformKind Parent);
|
||||
|
||||
/// Returns the LLVM triple OS type for the given platform, if there is one.
|
||||
std::optional<llvm::Triple::OSType>
|
||||
tripleOSTypeForPlatform(PlatformKind platform);
|
||||
|
||||
llvm::VersionTuple canonicalizePlatformVersion(
|
||||
PlatformKind platform, const llvm::VersionTuple &version);
|
||||
|
||||
|
||||
@@ -832,7 +832,10 @@ SemanticAvailableAttrRequest::evaluate(swift::Evaluator &evaluator,
|
||||
|
||||
auto checkVersion = [&](std::optional<llvm::VersionTuple> version,
|
||||
SourceRange sourceRange) {
|
||||
if (version && !VersionRange::isValidVersion(*version)) {
|
||||
if (!version)
|
||||
return false;
|
||||
|
||||
if (!VersionRange::isValidVersion(*version)) {
|
||||
diags
|
||||
.diagnose(attrLoc, diag::availability_unsupported_version_number,
|
||||
*version)
|
||||
@@ -840,6 +843,16 @@ SemanticAvailableAttrRequest::evaluate(swift::Evaluator &evaluator,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Warn if the version is not a valid one for the domain. For example, macOS
|
||||
// 17 will never exist.
|
||||
if (domain->isVersioned() && !domain->isVersionValid(*version)) {
|
||||
diags
|
||||
.diagnose(attrLoc,
|
||||
diag::availability_invalid_version_number_for_domain,
|
||||
*version, *domain)
|
||||
.highlight(sourceRange);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
@@ -109,6 +109,26 @@ bool AvailabilityDomain::isVersioned() const {
|
||||
}
|
||||
}
|
||||
|
||||
bool AvailabilityDomain::isVersionValid(
|
||||
const llvm::VersionTuple &version) const {
|
||||
ASSERT(isVersioned());
|
||||
|
||||
switch (getKind()) {
|
||||
case Kind::Universal:
|
||||
case Kind::Embedded:
|
||||
llvm_unreachable("unexpected domain kind");
|
||||
case Kind::SwiftLanguage:
|
||||
case Kind::PackageDescription:
|
||||
return true;
|
||||
case Kind::Platform:
|
||||
if (auto osType = tripleOSTypeForPlatform(getPlatformKind()))
|
||||
return llvm::Triple::isValidVersionForOS(*osType, version);
|
||||
return true;
|
||||
case Kind::Custom:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool AvailabilityDomain::supportsContextRefinement() const {
|
||||
switch (getKind()) {
|
||||
case Kind::Universal:
|
||||
|
||||
@@ -263,8 +263,8 @@ bool swift::inheritsAvailabilityFromPlatform(PlatformKind Child,
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::optional<llvm::Triple::OSType>
|
||||
tripleOSTypeForPlatform(PlatformKind platform) {
|
||||
std::optional<llvm::Triple::OSType>
|
||||
swift::tripleOSTypeForPlatform(PlatformKind platform) {
|
||||
switch (platform) {
|
||||
case PlatformKind::macOS:
|
||||
case PlatformKind::macOSApplicationExtension:
|
||||
@@ -296,8 +296,11 @@ tripleOSTypeForPlatform(PlatformKind platform) {
|
||||
llvm::VersionTuple
|
||||
swift::canonicalizePlatformVersion(PlatformKind platform,
|
||||
const llvm::VersionTuple &version) {
|
||||
if (auto osType = tripleOSTypeForPlatform(platform))
|
||||
return llvm::Triple::getCanonicalVersionForOS(*osType, version);
|
||||
if (auto osType = tripleOSTypeForPlatform(platform)) {
|
||||
bool isInValidRange = llvm::Triple::isValidVersionForOS(*osType, version);
|
||||
return llvm::Triple::getCanonicalVersionForOS(*osType, version,
|
||||
isInValidRange);
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-swift-frontend -typecheck -verify %s
|
||||
// RUN: %target-swift-frontend -typecheck %s
|
||||
// RUN: %target-swift-ide-test -skip-deinit=false -print-ast-typechecked -source-filename %s -function-definitions=false -prefer-type-repr=false -print-implicit-attrs=true > %t.printed.txt
|
||||
// RUN: %FileCheck %s -check-prefix=PASS_COMMON -strict-whitespace < %t.printed.txt
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
// RUN: %target-typecheck-verify-swift -target %target-swift-5.1-abi-triple
|
||||
// RUN: %swift -typecheck %s -verify -parse-stdlib -module-name Swift -target x86_64-apple-macosx10.15 -verify-additional-prefix macos-
|
||||
// RUN: %swift -typecheck %s -verify -parse-stdlib -module-name Swift -target arm64-apple-ios13 -verify-additional-prefix ios-
|
||||
// RUN: %swift -typecheck %s -verify -parse-stdlib -module-name Swift -target arm64-apple-watchos6 -verify-additional-prefix watchos-
|
||||
// RUN: %swift -typecheck %s -verify -parse-stdlib -module-name Swift -target arm64-apple-tvos13 -verify-additional-prefix tvos-
|
||||
// RUN: %swift -typecheck %s -verify -parse-stdlib -module-name Swift -target arm64-apple-xros1 -verify-additional-prefix visionos-
|
||||
|
||||
@available(OSX 10.16, *)
|
||||
func introducedOnMacOS10_16() { }
|
||||
@@ -12,7 +16,59 @@ func introducedInVersionsMappingTo26_0() { }
|
||||
@available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0, *)
|
||||
func introducedIn26_0() { }
|
||||
|
||||
@available(macOS 17.0, iOS 20.0, watchOS 13.0, tvOS 20.0, visionOS 4.0, *)
|
||||
// expected-warning@-1 {{'17.0' is not a valid version number for macOS}}
|
||||
// expected-warning@-2 {{'20.0' is not a valid version number for iOS}}
|
||||
// expected-warning@-3 {{'13.0' is not a valid version number for watchOS}}
|
||||
// expected-warning@-4 {{'20.0' is not a valid version number for tvOS}}
|
||||
// expected-warning@-5 {{'4.0' is not a valid version number for visionOS}}
|
||||
func introducedInVersionsMappingTo27_0() { }
|
||||
|
||||
@available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
|
||||
func introducedIn27_0() { }
|
||||
|
||||
func useUnderPoundAvailable() {
|
||||
// expected-note@-1 * {{add '@available' attribute to enclosing global function}}
|
||||
introducedOnMacOS10_16()
|
||||
// expected-macos-error@-1 {{'introducedOnMacOS10_16()' is only available in macOS 11.0 or newer}}
|
||||
// expected-macos-note@-2 {{add 'if #available' version check}}
|
||||
|
||||
introducedOnMacOS11_0()
|
||||
// expected-macos-error@-1 {{'introducedOnMacOS11_0()' is only available in macOS 11.0 or newer}}
|
||||
// expected-macos-note@-2 {{add 'if #available' version check}}
|
||||
|
||||
introducedInVersionsMappingTo26_0()
|
||||
// expected-macos-error@-1 {{'introducedInVersionsMappingTo26_0()' is only available in macOS 26.0 or newer}}
|
||||
// expected-ios-error@-2 {{'introducedInVersionsMappingTo26_0()' is only available in iOS 26.0 or newer}}
|
||||
// expected-watchos-error@-3 {{'introducedInVersionsMappingTo26_0()' is only available in watchOS 26.0 or newer}}
|
||||
// expected-tvos-error@-4 {{'introducedInVersionsMappingTo26_0()' is only available in tvOS 26.0 or newer}}
|
||||
// expected-visionos-error@-5 {{'introducedInVersionsMappingTo26_0()' is only available in visionOS 26.0 or newer}}
|
||||
// expected-note@-6 {{add 'if #available' version check}}
|
||||
|
||||
introducedIn26_0()
|
||||
// expected-macos-error@-1 {{'introducedIn26_0()' is only available in macOS 26.0 or newer}}
|
||||
// expected-ios-error@-2 {{'introducedIn26_0()' is only available in iOS 26.0 or newer}}
|
||||
// expected-watchos-error@-3 {{'introducedIn26_0()' is only available in watchOS 26.0 or newer}}
|
||||
// expected-tvos-error@-4 {{'introducedIn26_0()' is only available in tvOS 26.0 or newer}}
|
||||
// expected-visionos-error@-5 {{'introducedIn26_0()' is only available in visionOS 26.0 or newer}}
|
||||
// expected-note@-6 {{add 'if #available' version check}}
|
||||
|
||||
introducedInVersionsMappingTo27_0()
|
||||
// expected-macos-error@-1 {{'introducedInVersionsMappingTo27_0()' is only available in macOS 27.0 or newer}}
|
||||
// expected-ios-error@-2 {{'introducedInVersionsMappingTo27_0()' is only available in iOS 27.0 or newer}}
|
||||
// expected-watchos-error@-3 {{'introducedInVersionsMappingTo27_0()' is only available in watchOS 27.0 or newer}}
|
||||
// expected-tvos-error@-4 {{'introducedInVersionsMappingTo27_0()' is only available in tvOS 27.0 or newer}}
|
||||
// expected-visionos-error@-5 {{'introducedInVersionsMappingTo27_0()' is only available in visionOS 27.0 or newer}}
|
||||
// expected-note@-6 {{add 'if #available' version check}}
|
||||
|
||||
introducedIn27_0()
|
||||
// expected-macos-error@-1 {{'introducedIn27_0()' is only available in macOS 27.0 or newer}}
|
||||
// expected-ios-error@-2 {{'introducedIn27_0()' is only available in iOS 27.0 or newer}}
|
||||
// expected-watchos-error@-3 {{'introducedIn27_0()' is only available in watchOS 27.0 or newer}}
|
||||
// expected-tvos-error@-4 {{'introducedIn27_0()' is only available in tvOS 27.0 or newer}}
|
||||
// expected-visionos-error@-5 {{'introducedIn27_0()' is only available in visionOS 27.0 or newer}}
|
||||
// expected-note@-6 {{add 'if #available' version check}}
|
||||
|
||||
if #available(OSX 10.16, *) {
|
||||
introducedOnMacOS10_16()
|
||||
introducedOnMacOS11_0()
|
||||
@@ -21,5 +77,24 @@ func useUnderPoundAvailable() {
|
||||
if #available(macOS 16.0, iOS 19.0, watchOS 12.0, tvOS 19.0, visionOS 3.0, *) {
|
||||
introducedInVersionsMappingTo26_0()
|
||||
introducedIn26_0()
|
||||
introducedInVersionsMappingTo27_0()
|
||||
// expected-macos-error@-1 {{'introducedInVersionsMappingTo27_0()' is only available in macOS 27.0 or newer}}
|
||||
// expected-ios-error@-2 {{'introducedInVersionsMappingTo27_0()' is only available in iOS 27.0 or newer}}
|
||||
// expected-watchos-error@-3 {{'introducedInVersionsMappingTo27_0()' is only available in watchOS 27.0 or newer}}
|
||||
// expected-tvos-error@-4 {{'introducedInVersionsMappingTo27_0()' is only available in tvOS 27.0 or newer}}
|
||||
// expected-visionos-error@-5 {{'introducedInVersionsMappingTo27_0()' is only available in visionOS 27.0 or newer}}
|
||||
// expected-note@-6 {{add 'if #available' version check}}
|
||||
introducedIn27_0()
|
||||
// expected-macos-error@-1 {{'introducedIn27_0()' is only available in macOS 27.0 or newer}}
|
||||
// expected-ios-error@-2 {{'introducedIn27_0()' is only available in iOS 27.0 or newer}}
|
||||
// expected-watchos-error@-3 {{'introducedIn27_0()' is only available in watchOS 27.0 or newer}}
|
||||
// expected-tvos-error@-4 {{'introducedIn27_0()' is only available in tvOS 27.0 or newer}}
|
||||
// expected-visionos-error@-5 {{'introducedIn27_0()' is only available in visionOS 27.0 or newer}}
|
||||
// expected-note@-6 {{add 'if #available' version check}}
|
||||
}
|
||||
|
||||
if #available(macOS 17.0, iOS 20.0, watchOS 13.0, tvOS 20.0, visionOS 4.0, *) {
|
||||
introducedInVersionsMappingTo27_0()
|
||||
introducedIn27_0()
|
||||
}
|
||||
}
|
||||
|
||||
34
test/attr/attr_availability_invalid_platform_versions.swift
Normal file
34
test/attr/attr_availability_invalid_platform_versions.swift
Normal file
@@ -0,0 +1,34 @@
|
||||
// RUN: %target-swift-frontend -typecheck -verify -parse-stdlib -module-name Swift %s
|
||||
|
||||
@available(macOS, introduced: 17) // expected-warning {{'17' is not a valid version number for macOS}}
|
||||
@available(iOS, introduced: 20) // expected-warning {{'20' is not a valid version number for iOS}}
|
||||
@available(macCatalyst, introduced: 20) // expected-warning {{'20' is not a valid version number for Mac Catalyst}}
|
||||
@available(watchOS, introduced: 13) // expected-warning {{'13' is not a valid version number for watchOS}}
|
||||
@available(tvOS, introduced: 20) // expected-warning {{'20' is not a valid version number for tvOS}}
|
||||
@available(visionOS, introduced: 4) // expected-warning {{'4' is not a valid version number for visionOS}}
|
||||
func invalidIntroduced() { }
|
||||
|
||||
@available(macOS, deprecated: 17) // expected-warning {{'17' is not a valid version number for macOS}}
|
||||
@available(iOS, deprecated: 20) // expected-warning {{'20' is not a valid version number for iOS}}
|
||||
@available(macCatalyst, deprecated: 20) // expected-warning {{'20' is not a valid version number for Mac Catalyst}}
|
||||
@available(watchOS, deprecated: 13) // expected-warning {{'13' is not a valid version number for watchOS}}
|
||||
@available(tvOS, deprecated: 20) // expected-warning {{'20' is not a valid version number for tvOS}}
|
||||
@available(visionOS, deprecated: 4) // expected-warning {{'4' is not a valid version number for visionOS}}
|
||||
func invalidDeprecated() { }
|
||||
|
||||
@available(macOS, obsoleted: 17) // expected-warning {{'17' is not a valid version number for macOS}}
|
||||
@available(iOS, obsoleted: 20) // expected-warning {{'20' is not a valid version number for iOS}}
|
||||
@available(macCatalyst, obsoleted: 20) // expected-warning {{'20' is not a valid version number for Mac Catalyst}}
|
||||
@available(watchOS, obsoleted: 13) // expected-warning {{'13' is not a valid version number for watchOS}}
|
||||
@available(tvOS, obsoleted: 20) // expected-warning {{'20' is not a valid version number for tvOS}}
|
||||
@available(visionOS, obsoleted: 4) // expected-warning {{'4' is not a valid version number for visionOS}}
|
||||
func invalidObsoleted() { }
|
||||
|
||||
@available(macOS 18, iOS 21, macCatalyst 22, watchOS 14, tvOS 23, visionOS 7, *)
|
||||
// expected-warning@-1 {{'18' is not a valid version number for macOS}}
|
||||
// expected-warning@-2 {{'21' is not a valid version number for iOS}}
|
||||
// expected-warning@-3 {{'22' is not a valid version number for Mac Catalyst}}
|
||||
// expected-warning@-4 {{'14' is not a valid version number for watchOS}}
|
||||
// expected-warning@-5 {{'23' is not a valid version number for tvOS}}
|
||||
// expected-warning@-6 {{'7' is not a valid version number for visionOS}}
|
||||
func invalidIntroducedShort() { }
|
||||
Reference in New Issue
Block a user