mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Warn on uses of deprecated APIs
Emit a warning when the developer uses an API that has been marked deprecated with an availability attribute. Following the Clang behavior, we will only warn if the API is deprecated on all deployment targets. For example, if an API is deprecated as of OS X 10.11 but the minimum deployment target is 10.10 then no warning will be emitted. rdar://problem/17406050 Swift SVN r25288
This commit is contained in:
@@ -1052,6 +1052,10 @@ public:
|
|||||||
/// a declaration is unavailable, or null otherwise.
|
/// a declaration is unavailable, or null otherwise.
|
||||||
const AvailabilityAttr *getUnavailable(const ASTContext &ctx) const;
|
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 dump() const;
|
||||||
void print(ASTPrinter &Printer, const PrintOptions &Options) const;
|
void print(ASTPrinter &Printer, const PrintOptions &Options) const;
|
||||||
|
|
||||||
|
|||||||
@@ -1900,6 +1900,14 @@ NOTE(availability_obsoleted, sema_avail, none,
|
|||||||
"%0 was obsoleted in %1 version %2",
|
"%0 was obsoleted in %1 version %2",
|
||||||
(DeclName, StringRef, clang::VersionTuple))
|
(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,
|
ERROR(availability_decl_only_version_greater, sema_avail, none,
|
||||||
"%0 is only available on %1 version %2 or greater",
|
"%0 is only available on %1 version %2 or greater",
|
||||||
(DeclName, StringRef, clang::VersionTuple))
|
(DeclName, StringRef, clang::VersionTuple))
|
||||||
|
|||||||
@@ -94,6 +94,33 @@ const AvailabilityAttr *DeclAttributes::getUnavailable(
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AvailabilityAttr *
|
||||||
|
DeclAttributes::getDeprecated(const ASTContext &ctx) const {
|
||||||
|
for (auto Attr : *this) {
|
||||||
|
if (auto AvAttr = dyn_cast<AvailabilityAttr>(Attr)) {
|
||||||
|
if (AvAttr->isInvalid() || !AvAttr->isActivePlatform(ctx))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Optional<clang::VersionTuple> 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 {
|
void DeclAttributes::dump() const {
|
||||||
StreamPrinter P(llvm::errs());
|
StreamPrinter P(llvm::errs());
|
||||||
PrintOptions PO = PrintOptions::printEverything();
|
PrintOptions PO = PrintOptions::printEverything();
|
||||||
|
|||||||
@@ -540,6 +540,11 @@ static bool diagAvailability(TypeChecker &TC, const ValueDecl *D,
|
|||||||
}
|
}
|
||||||
return true;
|
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
|
// We only diagnose potentially unavailability here if availability checking
|
||||||
// is turned on, but we are not treating unavailable symbols as having
|
// is turned on, but we are not treating unavailable symbols as having
|
||||||
|
|||||||
@@ -891,7 +891,11 @@ static bool checkTypeDeclAvailability(Decl *TypeDecl, IdentTypeRepr *IdType,
|
|||||||
CI->getIdentifier()).highlight(Attr->getRange());
|
CI->getIdentifier()).highlight(Attr->getRange());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auto *Attr = TypeDecl->getAttrs().getDeprecated(TC.Context)) {
|
||||||
|
TC.diagnoseDeprecated(Loc, Attr, CI->getIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
// Check for potential unavailability because of the minimum
|
// Check for potential unavailability because of the minimum
|
||||||
// deployment version.
|
// deployment version.
|
||||||
// We should probably unify this checking for deployment-version API
|
// We should probably unify this checking for deployment-version API
|
||||||
|
|||||||
@@ -1199,6 +1199,22 @@ void TypeChecker::diagnosePotentialAccessorUnavailability(
|
|||||||
Reason.getRequiredOSVersionRange().getLowerEndpoint());
|
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.
|
// checkForForbiddenPrefix is for testing purposes.
|
||||||
|
|
||||||
void TypeChecker::checkForForbiddenPrefix(const Decl *D) {
|
void TypeChecker::checkForForbiddenPrefix(const Decl *D) {
|
||||||
|
|||||||
@@ -1273,6 +1273,10 @@ public:
|
|||||||
void diagnosePotentialAccessorUnavailability(
|
void diagnosePotentialAccessorUnavailability(
|
||||||
FuncDecl *Accessor, SourceLoc referenceLoc,
|
FuncDecl *Accessor, SourceLoc referenceLoc,
|
||||||
const UnavailabilityReason &Reason, bool ForInout);
|
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
|
/// If LangOptions::DebugForbidTypecheckPrefix is set and the given decl
|
||||||
|
|||||||
@@ -25,3 +25,30 @@ func doSomethingReallyOld() { }
|
|||||||
// expected-note @-1{{'doSomethingReallyOld()' was obsoleted in OS X version 10}}
|
// expected-note @-1{{'doSomethingReallyOld()' was obsoleted in OS X version 10}}
|
||||||
|
|
||||||
doSomethingReallyOld() // expected-error{{'doSomethingReallyOld()' is unavailable}}
|
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) { }
|
||||||
|
|||||||
Reference in New Issue
Block a user