diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index c0e553bd653..9aee41034a9 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -1052,6 +1052,10 @@ public: /// a declaration is unavailable, or null otherwise. const AvailabilityAttr *getUnavailable(const ASTContext &ctx) const; + /// Returns the first @availability attribute that indicates + /// a declaration is deprecated on all deployment targets, or null otherwise. + const AvailabilityAttr *getDeprecated(const ASTContext &ctx) const; + void dump() const; void print(ASTPrinter &Printer, const PrintOptions &Options) const; diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index d10b1db23bc..7346d16ac13 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1900,6 +1900,14 @@ NOTE(availability_obsoleted, sema_avail, none, "%0 was obsoleted in %1 version %2", (DeclName, StringRef, clang::VersionTuple)) +WARNING(availability_deprecated, sema_avail, none, + "%0 was deprecated in %1 version %2", + (DeclName, StringRef, clang::VersionTuple)) + +WARNING(availability_deprecated_msg, sema_avail, none, + "%0 was deprecated in %1 version %2: %3", + (DeclName, StringRef, clang::VersionTuple, StringRef)) + ERROR(availability_decl_only_version_greater, sema_avail, none, "%0 is only available on %1 version %2 or greater", (DeclName, StringRef, clang::VersionTuple)) diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index ee3f708bac3..1281da0cc6d 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -94,6 +94,33 @@ const AvailabilityAttr *DeclAttributes::getUnavailable( return nullptr; } +const AvailabilityAttr * +DeclAttributes::getDeprecated(const ASTContext &ctx) const { + for (auto Attr : *this) { + if (auto AvAttr = dyn_cast(Attr)) { + if (AvAttr->isInvalid() || !AvAttr->isActivePlatform(ctx)) + continue; + + Optional DeprecatedVersion = AvAttr->Deprecated; + if (!DeprecatedVersion.hasValue()) + continue; + + auto MinVersion = ctx.LangOpts.getMinPlatformVersion(); + + // We treat the declaration as deprecated if it is deprecated on + // all deployment targets. + // Once availability checking is enabled by default, we should + // query the type refinement context hierarchy to determine + // whether a declaration is deprecated on all versions + // allowed by the context containing the reference. + if (DeprecatedVersion.getValue() <= MinVersion) { + return AvAttr; + } + } + } + return nullptr; +} + void DeclAttributes::dump() const { StreamPrinter P(llvm::errs()); PrintOptions PO = PrintOptions::printEverything(); diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 3ed2336d8bc..7aec120c769 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -540,6 +540,11 @@ static bool diagAvailability(TypeChecker &TC, const ValueDecl *D, } return true; } + + // Diagnose for deprecation + if (const AvailabilityAttr *Attr = D->getAttrs().getDeprecated(TC.Context)) { + TC.diagnoseDeprecated(R.Start, Attr, D->getFullName()); + } // We only diagnose potentially unavailability here if availability checking // is turned on, but we are not treating unavailable symbols as having diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 4dfadb3ad5a..f64febd6c3c 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -891,7 +891,11 @@ static bool checkTypeDeclAvailability(Decl *TypeDecl, IdentTypeRepr *IdType, CI->getIdentifier()).highlight(Attr->getRange()); return true; } - + + if (auto *Attr = TypeDecl->getAttrs().getDeprecated(TC.Context)) { + TC.diagnoseDeprecated(Loc, Attr, CI->getIdentifier()); + } + // Check for potential unavailability because of the minimum // deployment version. // We should probably unify this checking for deployment-version API diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index cd12f2526ca..6dd970f9d44 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -1199,6 +1199,22 @@ void TypeChecker::diagnosePotentialAccessorUnavailability( Reason.getRequiredOSVersionRange().getLowerEndpoint()); } +void TypeChecker::diagnoseDeprecated(SourceLoc ReferenceLoc, + const AvailabilityAttr *Attr, + DeclName Name) { + StringRef Platform = Attr->prettyPlatformString(); + clang::VersionTuple DeprecatedVersion = Attr->Deprecated.getValue(); + + if (Attr->Message.empty()) { + diagnose(ReferenceLoc, diag::availability_deprecated, Name, Platform, + DeprecatedVersion).highlight(Attr->getRange()); + return; + } + + diagnose(ReferenceLoc, diag::availability_deprecated_msg, Name, Platform, + DeprecatedVersion, Attr->Message).highlight(Attr->getRange()); +} + // checkForForbiddenPrefix is for testing purposes. void TypeChecker::checkForForbiddenPrefix(const Decl *D) { diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index b09f7f3414d..342fc1ff61a 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1273,6 +1273,10 @@ public: void diagnosePotentialAccessorUnavailability( FuncDecl *Accessor, SourceLoc referenceLoc, const UnavailabilityReason &Reason, bool ForInout); + + /// Emits a diagnostic for a reference to a declaration that is deprecated. + void diagnoseDeprecated(SourceLoc ReferenceLoc, const AvailabilityAttr *Attr, + DeclName Name); /// @} /// If LangOptions::DebugForbidTypecheckPrefix is set and the given decl diff --git a/test/attr/attr_availability_osx.swift b/test/attr/attr_availability_osx.swift index 5843c71e767..bd2ca0d7de5 100644 --- a/test/attr/attr_availability_osx.swift +++ b/test/attr/attr_availability_osx.swift @@ -25,3 +25,30 @@ func doSomethingReallyOld() { } // expected-note @-1{{'doSomethingReallyOld()' was obsoleted in OS X version 10}} doSomethingReallyOld() // expected-error{{'doSomethingReallyOld()' is unavailable}} + +// Test deprecations in 10.10 and later + +@availability(OSX, introduced=10.5, deprecated=10.10, + message="Use another function") +func deprecatedFunctionWithMessage() { } + +deprecatedFunctionWithMessage() // expected-warning{{'deprecatedFunctionWithMessage()' was deprecated in OS X version 10.10: Use another function}} + + +@availability(OSX, introduced=10.5, deprecated=10.10) +func deprecatedFunctionWithoutMessage() { } + +deprecatedFunctionWithoutMessage() // expected-warning{{'deprecatedFunctionWithoutMessage()' was deprecated in OS X version 10.10}} + +@availability(OSX, introduced=10.5, deprecated=10.10, + message="Use BetterClass instead") +class DeprecatedClass { } + +func functionWithDeprecatedParameter(p: DeprecatedClass) { } // expected-warning{{'DeprecatedClass' was deprecated in OS X version 10.10: Use BetterClass instead}} + +@availability(OSX, introduced=10.5, deprecated=10.11, + message="Use BetterClass instead") +class DeprecatedClassIn10_11 { } + +// Elements deprecated later than the minimum deployment target (which is 10.10, in this case) should not generate warnings +func functionWithDeprecatedLaterParameter(p: DeprecatedClassIn10_11) { }