mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
AST: Introduce queries on Decl for active @available attrs.
Use these queries to replace some duplicated code. Also, move the `attr_inlinable_available.swift` test to the `Availability` sub-directory since the test has more to do with availability checking than it has to do specifically with the `@inlinable` attr.
This commit is contained in:
@@ -260,6 +260,12 @@ public:
|
||||
/// universal domain (`*`) is the bottom element.
|
||||
bool contains(const AvailabilityDomain &other) const;
|
||||
|
||||
/// Returns true if availability in `other` is a subset of availability in
|
||||
/// this domain or vice-versa.
|
||||
bool isRelated(const AvailabilityDomain &other) const {
|
||||
return contains(other) || other.contains(*this);
|
||||
}
|
||||
|
||||
/// Returns true for domains that are not contained by any domain other than
|
||||
/// the universal domain.
|
||||
bool isRoot() const;
|
||||
|
||||
@@ -1464,6 +1464,27 @@ public:
|
||||
std::optional<SemanticAvailableAttr>
|
||||
getAvailableAttrForPlatformIntroduction(bool checkExtension = true) const;
|
||||
|
||||
/// Returns true if `decl` has any active `@available` attribute attached to
|
||||
/// it.
|
||||
bool hasAnyActiveAvailableAttr() const {
|
||||
return hasAnyMatchingActiveAvailableAttr(
|
||||
[](SemanticAvailableAttr attr) -> bool { return true; });
|
||||
}
|
||||
|
||||
/// Returns true if `predicate` returns true for any active availability
|
||||
/// attribute attached to `decl`. The predicate function should accept a
|
||||
/// `SemanticAvailableAttr`.
|
||||
template <typename F>
|
||||
bool hasAnyMatchingActiveAvailableAttr(F predicate) const {
|
||||
auto &ctx = getASTContext();
|
||||
auto decl = getAbstractSyntaxDeclForAttributes();
|
||||
for (auto attr : decl->getSemanticAvailableAttrs()) {
|
||||
if (attr.isActive(ctx) && predicate(attr))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Returns true if the declaration is deprecated at the current deployment
|
||||
/// target.
|
||||
bool isDeprecated() const { return getDeprecatedAttr().has_value(); }
|
||||
|
||||
@@ -30,20 +30,6 @@
|
||||
|
||||
using namespace swift;
|
||||
|
||||
/// Returns true if there is any availability attribute on the declaration
|
||||
/// that is active.
|
||||
// FIXME: [availability] De-duplicate this with TypeCheckAvailability.cpp.
|
||||
static bool hasActiveAvailableAttribute(const Decl *decl, ASTContext &ctx) {
|
||||
decl = decl->getAbstractSyntaxDeclForAttributes();
|
||||
|
||||
for (auto attr : decl->getSemanticAvailableAttrs()) {
|
||||
if (attr.isActive(ctx))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool computeContainedByDeploymentTarget(AvailabilityScope *scope,
|
||||
ASTContext &ctx) {
|
||||
return scope->getPlatformAvailabilityRange().isContainedIn(
|
||||
@@ -397,7 +383,7 @@ private:
|
||||
return nullptr;
|
||||
|
||||
// Declarations with explicit availability attributes always get a scope.
|
||||
if (hasActiveAvailableAttribute(decl, Context)) {
|
||||
if (decl->hasAnyActiveAvailableAttr()) {
|
||||
return AvailabilityScope::createForDecl(
|
||||
Context, decl, getCurrentScope(),
|
||||
getEffectiveAvailabilityForDeclSignature(decl),
|
||||
@@ -423,16 +409,20 @@ private:
|
||||
getEffectiveAvailabilityForDeclSignature(const Decl *decl) {
|
||||
auto effectiveIntroduction = AvailabilityRange::alwaysAvailable();
|
||||
|
||||
// Availability attributes are found abstract syntax decls.
|
||||
// Availability attributes are found on abstract syntax decls.
|
||||
decl = decl->getAbstractSyntaxDeclForAttributes();
|
||||
|
||||
// As a special case, extension decls are treated as effectively as
|
||||
// available as the nominal type they extend, up to the deployment target.
|
||||
// This rule is a convenience for library authors who have written
|
||||
// extensions without specifying availabilty on the extension itself.
|
||||
// extensions without specifying platform availabilty on the extension
|
||||
// itself.
|
||||
if (auto *extension = dyn_cast<ExtensionDecl>(decl)) {
|
||||
auto extendedType = extension->getExtendedType();
|
||||
if (extendedType && !hasActiveAvailableAttribute(decl, Context)) {
|
||||
if (extendedType && !decl->hasAnyMatchingActiveAvailableAttr(
|
||||
[](SemanticAvailableAttr attr) -> bool {
|
||||
return attr.getDomain().isPlatform();
|
||||
})) {
|
||||
effectiveIntroduction.intersectWith(
|
||||
swift::AvailabilityInference::inferForType(extendedType));
|
||||
|
||||
|
||||
@@ -241,20 +241,6 @@ ExportContext::getExportabilityReason() const {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/// Returns true if there is any availability attribute on the declaration
|
||||
/// that is active.
|
||||
// FIXME: [availability] De-duplicate this with AvailabilityScopeBuilder.cpp.
|
||||
static bool hasActiveAvailableAttribute(const Decl *D, ASTContext &ctx) {
|
||||
D = D->getAbstractSyntaxDeclForAttributes();
|
||||
|
||||
for (auto Attr : D->getSemanticAvailableAttrs()) {
|
||||
if (Attr.isActive(ctx))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool shouldAllowReferenceToUnavailableInSwiftDeclaration(
|
||||
const Decl *D, const ExportContext &where) {
|
||||
auto *DC = where.getDeclContext();
|
||||
@@ -639,15 +625,18 @@ static void fixAvailabilityForDecl(
|
||||
const AvailabilityRange &RequiredAvailability, ASTContext &Context) {
|
||||
assert(D);
|
||||
|
||||
// Don't suggest adding an @available() to a declaration where we would
|
||||
// Don't suggest adding an @available to a declaration where we would
|
||||
// emit a diagnostic saying it is not allowed.
|
||||
if (TypeChecker::diagnosticIfDeclCannotBePotentiallyUnavailable(D).has_value())
|
||||
return;
|
||||
|
||||
if (hasActiveAvailableAttribute(D, Context)) {
|
||||
// For QoI, in future should emit a fixit to update the existing attribute.
|
||||
// Don't suggest adding an @available attribute to a declaration that already
|
||||
// has one that is active for the given domain.
|
||||
// FIXME: Emit a fix-it to adjust the existing attribute instead.
|
||||
if (D->hasAnyMatchingActiveAvailableAttr([&](SemanticAvailableAttr attr) {
|
||||
return attr.getDomain().isRelated(Domain);
|
||||
}))
|
||||
return;
|
||||
}
|
||||
|
||||
// For some declarations (variables, enum elements), the location in concrete
|
||||
// syntax to suggest the Fix-It may differ from the declaration to which
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// RUN: %target-swift-frontend -typecheck -dump-availability-scopes %s -target %target-cpu-apple-macos50 > %t.dump 2>&1
|
||||
// RUN: %target-swift-frontend -typecheck -dump-availability-scopes %s -target %target-cpu-apple-macos50 -swift-version 5 > %t.dump 2>&1
|
||||
// RUN: %FileCheck --strict-whitespace %s < %t.dump
|
||||
|
||||
// REQUIRES: OS=macosx
|
||||
@@ -454,6 +454,23 @@ func deprecatedOnMacOS() {
|
||||
let x = 1
|
||||
}
|
||||
|
||||
// Since availableOniOS() doesn't have any active @available attributes it
|
||||
// shouldn't create a scope.
|
||||
// CHECK-NOT: availableOniOS
|
||||
|
||||
@available(iOS, introduced: 53)
|
||||
func availableOniOS() { }
|
||||
|
||||
// CHECK-NEXT: {{^}} (decl version=50 decl=availableInSwift5
|
||||
|
||||
@available(swift 5)
|
||||
func availableInSwift5() { }
|
||||
|
||||
// CHECK-NEXT: {{^}} (decl version=50 unavailable=swift decl=availableInSwift6
|
||||
|
||||
@available(swift 6)
|
||||
func availableInSwift6() { }
|
||||
|
||||
// CHECK-NEXT: {{^}} (decl version=51 decl=FinalDecl
|
||||
|
||||
@available(OSX 51, *)
|
||||
|
||||
@@ -1292,6 +1292,30 @@ extension BetweenTargets { // expected-note 2 {{add '@available' attribute to en
|
||||
) {}
|
||||
}
|
||||
|
||||
@available(iOS 8.0, *)
|
||||
extension BetweenTargets { // expected-note 2 {{add '@available' attribute to enclosing extension}}
|
||||
public func publicFuncInExtensionWithExplicitiOSAvailability( // expected-note 2 {{add '@available' attribute to enclosing instance method}}
|
||||
_: NoAvailable,
|
||||
_: BeforeInliningTarget,
|
||||
_: AtInliningTarget,
|
||||
_: BetweenTargets,
|
||||
_: AtDeploymentTarget, // expected-error {{'AtDeploymentTarget' is only available in macOS 10.15 or newer; clients of 'Test' may have a lower deployment target}}
|
||||
_: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}}
|
||||
) {}
|
||||
}
|
||||
|
||||
@available(swift 5)
|
||||
extension BetweenTargets { // expected-note 2 {{add '@available' attribute to enclosing extension}}
|
||||
public func publicFuncInExtensionWithExplicitSwiftAvailability( // expected-note 2 {{add '@available' attribute to enclosing instance method}}
|
||||
_: NoAvailable,
|
||||
_: BeforeInliningTarget,
|
||||
_: AtInliningTarget,
|
||||
_: BetweenTargets,
|
||||
_: AtDeploymentTarget, // expected-error {{'AtDeploymentTarget' is only available in macOS 10.15 or newer; clients of 'Test' may have a lower deployment target}}
|
||||
_: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}}
|
||||
) {}
|
||||
}
|
||||
|
||||
@available(macOS 10.15, *)
|
||||
extension BetweenTargets {
|
||||
public func publicFuncInExtensionWithExplicitAvailability( // expected-note {{add '@available' attribute to enclosing instance method}}
|
||||
Reference in New Issue
Block a user