From 0900716ae20ebeb4a40ccfa892148d7e55df2ae6 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Thu, 22 Jun 2017 17:02:24 +0000 Subject: [PATCH] [Sema] Add -Wunguarded-availability-new The new compiler warning -Wunguarded-availability-new is a subset of -Wunguarded-availability. It is on by default. It only warns about uses of APIs that have been introduced in macOS >= 10.13, iOS >= 11, watchOS >= 4 and tvOS >= 11. We decided to use this kind of solution as we didn't want to turn on -Wunguarded-availability by default, because we didn't want our users to get warnings about uses of old APIs in their existing projects. rdar://31054725 Differential Revision: https://reviews.llvm.org/D34264 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@306033 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticGroups.td | 4 +- include/clang/Basic/DiagnosticSemaKinds.td | 10 ++ lib/Sema/SemaDeclAttr.cpp | 60 +++++++- test/SemaObjC/unguarded-availability-new.m | 160 +++++++++++++++++++++ 4 files changed, 228 insertions(+), 6 deletions(-) create mode 100644 test/SemaObjC/unguarded-availability-new.m diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 36b64a1252..464c2425a1 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -98,7 +98,9 @@ def CXX11CompatDeprecatedWritableStr : def DeprecatedAttributes : DiagGroup<"deprecated-attributes">; def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">; def UnavailableDeclarations : DiagGroup<"unavailable-declarations">; -def UnguardedAvailability : DiagGroup<"unguarded-availability">; +def UnguardedAvailabilityNew : DiagGroup<"unguarded-availability-new">; +def UnguardedAvailability : DiagGroup<"unguarded-availability", + [UnguardedAvailabilityNew]>; // partial-availability is an alias of unguarded-availability. def : DiagGroup<"partial-availability", [UnguardedAvailability]>; def DeprecatedDynamicExceptionSpec diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 0dd151cbd9..62faadcc5f 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2870,8 +2870,13 @@ def note_protocol_method : Note< def warn_unguarded_availability : Warning<"%0 is only available on %1 %2 or newer">, InGroup, DefaultIgnore; +def warn_unguarded_availability_new : + Warning, + InGroup; def warn_partial_availability : Warning<"%0 is only available conditionally">, InGroup, DefaultIgnore; +def warn_partial_availability_new : Warning, + InGroup; def note_partial_availability_silence : Note< "explicitly redeclare %0 to silence this warning">; def note_unguarded_available_silence : Note< @@ -2879,9 +2884,14 @@ def note_unguarded_available_silence : Note< " this warning">; def warn_partial_message : Warning<"%0 is partial: %1">, InGroup, DefaultIgnore; +def warn_partial_message_new : Warning, + InGroup; def warn_partial_fwdclass_message : Warning< "%0 may be partial because the receiver type is unknown">, InGroup, DefaultIgnore; +def warn_partial_fwdclass_message_new : + Warning, + InGroup; def warn_at_available_unchecked_use : Warning< "%select{@available|__builtin_available}0 does not guard availability here; " "use if (%select{@available|__builtin_available}0) instead">, diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index b43642f549..e850342753 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -6903,6 +6903,32 @@ static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, return true; } +static bool +shouldDiagnoseAvailabilityByDefault(const ASTContext &Context, + const VersionTuple &DeploymentVersion, + const VersionTuple &DeclVersion) { + const auto &Triple = Context.getTargetInfo().getTriple(); + VersionTuple ForceAvailabilityFromVersion; + switch (Triple.getOS()) { + case llvm::Triple::IOS: + case llvm::Triple::TvOS: + ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11); + break; + case llvm::Triple::WatchOS: + ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4); + break; + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13); + break; + default: + // New targets should always warn about availability. + return Triple.getVendor() == llvm::Triple::Apple; + } + return DeploymentVersion >= ForceAvailabilityFromVersion || + DeclVersion >= ForceAvailabilityFromVersion; +} + static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, Decl *Ctx, const NamedDecl *D, StringRef Message, SourceLocation Loc, @@ -6991,13 +7017,26 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, } break; - case AR_NotYetIntroduced: - diag = diag::warn_partial_availability; - diag_message = diag::warn_partial_message; - diag_fwdclass_message = diag::warn_partial_fwdclass_message; + case AR_NotYetIntroduced: { + // We would like to emit the diagnostic even if -Wunguarded-availability is + // not specified for deployment targets >= to iOS 11 or equivalent or + // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or + // later. + const AvailabilityAttr *AA = getAttrForPlatform(S.getASTContext(), D); + VersionTuple Introduced = AA->getIntroduced(); + bool NewWarning = shouldDiagnoseAvailabilityByDefault( + S.Context, S.Context.getTargetInfo().getPlatformMinVersion(), + Introduced); + diag = NewWarning ? diag::warn_partial_availability_new + : diag::warn_partial_availability; + diag_message = NewWarning ? diag::warn_partial_message_new + : diag::warn_partial_message; + diag_fwdclass_message = NewWarning ? diag::warn_partial_fwdclass_message_new + : diag::warn_partial_fwdclass_message; property_note_select = /* partial */ 2; available_here_select_kind = /* partial */ 3; break; + } case AR_Available: llvm_unreachable("Warning for availability of available declaration?"); @@ -7317,7 +7356,18 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx)) return; - SemaRef.Diag(Range.getBegin(), diag::warn_unguarded_availability) + // We would like to emit the diagnostic even if -Wunguarded-availability is + // not specified for deployment targets >= to iOS 11 or equivalent or + // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or + // later. + unsigned DiagKind = + shouldDiagnoseAvailabilityByDefault( + SemaRef.Context, + SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced) + ? diag::warn_unguarded_availability_new + : diag::warn_unguarded_availability; + + SemaRef.Diag(Range.getBegin(), DiagKind) << Range << D << AvailabilityAttr::getPrettyPlatformName( SemaRef.getASTContext().getTargetInfo().getPlatformName()) diff --git a/test/SemaObjC/unguarded-availability-new.m b/test/SemaObjC/unguarded-availability-new.m new file mode 100644 index 0000000000..33baedebc2 --- /dev/null +++ b/test/SemaObjC/unguarded-availability-new.m @@ -0,0 +1,160 @@ +// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -xobjective-c++ -DMAC -triple x86_64-apple-macosx10.13 -fblocks -fsyntax-only -verify %s + +// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -Wunguarded-availability-new -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -Wno-unguarded-availability-new -DNO_WARNING -fblocks -fsyntax-only -verify %s + +// unguarded-availability implies unguarded-availability-new: +// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -Wunguarded-availability -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.11 -Wunguarded-availability -Wno-unguarded-availability-new -DNO_WARNING -DWARN_PREV -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -Wno-unguarded-availability -DNO_WARNING -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -Wno-unguarded-availability -Wunguarded-availability-new -fblocks -fsyntax-only -verify %s + +// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -D TEST_FUNC_CURRENT -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -D TEST_FUNC_NEXT -DNO_WARNING -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DMAC -triple x86_64-apple-ios11 -DNO_WARNING -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.12 -DWARN_CURRENT -fblocks -fsyntax-only -verify %s + +// RUN: %clang_cc1 -DIOS -triple x86_64-apple-ios11 -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DIOS -triple x86_64-apple-ios11 -D TEST_FUNC_CURRENT -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DIOS -triple x86_64-apple-ios11 -D TEST_FUNC_NEXT -DNO_WARNING -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DIOS -triple x86_64-apple-ios10.3 -DWARN_CURRENT -fblocks -fsyntax-only -verify %s + +// RUN: %clang_cc1 -DTVOS -triple x86_64-apple-tvos11 -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DTVOS -triple x86_64-apple-tvos11 -D TEST_FUNC_CURRENT -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DTVOS -triple x86_64-apple-tvos11 -D TEST_FUNC_NEXT -DNO_WARNING -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DTVOS -triple x86_64-apple-tvos10 -DWARN_CURRENT -fblocks -fsyntax-only -verify %s + +// RUN: %clang_cc1 -DWATCHOS -triple i386-apple-watchos4 -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DWATCHOS -triple i386-apple-watchos4 -D TEST_FUNC_CURRENT -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DWATCHOS -triple i386-apple-watchos4 -D TEST_FUNC_NEXT -DNO_WARNING -fblocks -fsyntax-only -verify %s +// RUN: %clang_cc1 -DWATCHOS -triple i386-apple-watchos3 -DWARN_CURRENT -fblocks -fsyntax-only -verify %s + +#ifdef MAC +#define PLATFORM macos +#define NEXT 10.14 + +#define AVAILABLE_PREV __attribute__((availability(macos, introduced = 10.12))) +#define AVAILABLE_CURRENT __attribute__((availability(macos, introduced = 10.13))) +#define AVAILABLE_NEXT __attribute__((availability(macos, introduced = 10.14))) +#endif + +#ifdef IOS +#define PLATFORM ios +#define NEXT 12 + +#define AVAILABLE_PREV __attribute__((availability(ios, introduced = 10))) +#define AVAILABLE_CURRENT __attribute__((availability(ios, introduced = 11))) +#define AVAILABLE_NEXT __attribute__((availability(ios, introduced = 12))) +#endif + +#ifdef TVOS +#define PLATFORM tvos +#define NEXT 13 + +#define AVAILABLE_PREV __attribute__((availability(tvos, introduced = 10))) +#define AVAILABLE_CURRENT __attribute__((availability(tvos, introduced = 11))) +#define AVAILABLE_NEXT __attribute__((availability(tvos, introduced = 13))) +#endif + +#ifdef WATCHOS +#define PLATFORM watchos +#define NEXT 5 + +#define AVAILABLE_PREV __attribute__((availability(watchos, introduced = 3))) +#define AVAILABLE_CURRENT __attribute__((availability(watchos, introduced = 4))) +#define AVAILABLE_NEXT __attribute__((availability(watchos, introduced = 5))) +#endif + +void previouslyAvailable() AVAILABLE_PREV; +#ifdef WARN_PREV + // expected-note@-2 {{'previouslyAvailable' has been explicitly marked partial here}} +#endif +void currentlyAvailable() AVAILABLE_CURRENT; +#ifdef WARN_CURRENT + // expected-note@-2 {{'currentlyAvailable' has been explicitly marked partial here}} +#endif +void willBeAvailabile() AVAILABLE_NEXT; +#ifndef NO_WARNING + // expected-note@-2 {{'willBeAvailabile' has been explicitly marked partial here}} +#endif + +#ifdef TEST_FUNC_CURRENT +#define FUNC_AVAILABLE AVAILABLE_CURRENT +#endif +#ifdef TEST_FUNC_NEXT +#define FUNC_AVAILABLE AVAILABLE_NEXT +#endif +#ifndef FUNC_AVAILABLE +#define FUNC_AVAILABLE +#endif + +typedef int AVAILABLE_NEXT new_int; +#ifndef NO_WARNING + // expected-note@-2 {{'new_int' has been explicitly marked partial here}} +#endif +FUNC_AVAILABLE new_int x; +#ifndef NO_WARNING +#ifdef MAC + // expected-warning@-3 {{'new_int' is partial: introduced in macOS 10.14}} expected-note@-3 {{explicitly redeclare 'new_int' to silence this warning}} +#endif +#ifdef IOS + // expected-warning@-6 {{'new_int' is partial: introduced in iOS 12}} expected-note@-6 {{explicitly redeclare 'new_int' to silence this warning}} +#endif +#ifdef TVOS + // expected-warning@-9 {{'new_int' is partial: introduced in tvOS 13}} expected-note@-9 {{explicitly redeclare 'new_int' to silence this warning}} +#endif +#ifdef WATCHOS + // expected-warning@-12 {{'new_int' is partial: introduced in watchOS 5}} expected-note@-12 {{explicitly redeclare 'new_int' to silence this warning}} +#endif +#endif + +void test() FUNC_AVAILABLE { + previouslyAvailable(); +#ifdef WARN_PREV +#ifdef MAC + // expected-warning@-3 {{'previouslyAvailable' is only available on macOS 10.12 or newer}} +#endif + // expected-note@-5 {{enclose 'previouslyAvailable' in an @available check to silence this warning}} +#endif + currentlyAvailable(); +#ifdef WARN_CURRENT +#ifdef MAC + // expected-warning@-3 {{'currentlyAvailable' is only available on macOS 10.13 or newer}} +#endif +#ifdef IOS + // expected-warning@-6 {{'currentlyAvailable' is only available on iOS 11 or newer}} +#endif +#ifdef TVOS + // expected-warning@-9 {{'currentlyAvailable' is only available on tvOS 11 or newer}} +#endif +#ifdef WATCHOS + // expected-warning@-12 {{'currentlyAvailable' is only available on watchOS 4 or newer}} +#endif + // expected-note@-14 {{enclose 'currentlyAvailable' in an @available check to silence this warning}} +#endif + willBeAvailabile(); +#ifndef NO_WARNING +#ifdef MAC + // expected-warning@-3 {{'willBeAvailabile' is only available on macOS 10.14 or newer}} +#endif +#ifdef IOS + // expected-warning@-6 {{'willBeAvailabile' is only available on iOS 12 or newer}} +#endif +#ifdef TVOS + // expected-warning@-9 {{'willBeAvailabile' is only available on tvOS 13 or newer}} +#endif +#ifdef WATCHOS + // expected-warning@-12 {{'willBeAvailabile' is only available on watchOS 5 or newer}} +#endif + // expected-note@-14 {{enclose 'willBeAvailabile' in an @available check to silence this warning}} +#endif + if (@available(PLATFORM NEXT, *)) + willBeAvailabile(); // OK +} + +#ifdef NO_WARNING +#ifndef WARN_PREV +// expected-no-diagnostics +#endif +#endif -- 2.40.0