From edee0359a81664531e0e5482a837cb41f7cee2e5 Mon Sep 17 00:00:00 2001 From: Erik Pilkington Date: Mon, 14 Aug 2017 19:49:12 +0000 Subject: [PATCH] [Sema] Improve some -Wunguarded-availability diagnostics rdar://33543523 Differential revision: https://reviews.llvm.org/D36200 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@310874 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 18 +-- lib/Sema/SemaDeclAttr.cpp | 153 +++++++++++---------- test/SemaObjC/attr-availability.m | 4 +- test/SemaObjC/unguarded-availability-new.m | 8 +- test/SemaObjC/unguarded-availability.m | 18 +-- 5 files changed, 95 insertions(+), 106 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 25bc6508e1..27ffef02fe 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2896,25 +2896,11 @@ def warn_unguarded_availability : 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< - "annotate %select{%1|anonymous %1}0 with an availability attribute to silence">; +def note_decl_unguarded_availability_silence : Note< + "annotate %select{%1|anonymous %1}0 with an availability attribute to silence this warning">; def note_unguarded_available_silence : Note< "enclose %0 in %select{an @available|a __builtin_available}1 check to silence" " 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 0086e643c1..41f8f9f0bc 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -7128,7 +7128,83 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx)) return; + // The declaration can have multiple availability attributes, we are looking + // at one of them. + const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl); + if (A && A->isInherited()) { + for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl; + Redecl = Redecl->getPreviousDecl()) { + const AvailabilityAttr *AForRedecl = + getAttrForPlatform(S.Context, Redecl); + if (AForRedecl && !AForRedecl->isInherited()) { + // If D is a declaration with inherited attributes, the note should + // point to the declaration with actual attributes. + NoteLocation = Redecl->getLocation(); + break; + } + } + } + switch (K) { + 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(), OffendingDecl); + VersionTuple Introduced = AA->getIntroduced(); + + bool UseNewWarning = shouldDiagnoseAvailabilityByDefault( + S.Context, S.Context.getTargetInfo().getPlatformMinVersion(), + Introduced); + unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new + : diag::warn_unguarded_availability; + + S.Diag(Loc, Warning) + << OffendingDecl + << AvailabilityAttr::getPrettyPlatformName( + S.getASTContext().getTargetInfo().getPlatformName()) + << Introduced.getAsString(); + + S.Diag(OffendingDecl->getLocation(), diag::note_availability_specified_here) + << OffendingDecl << /* partial */ 3; + + if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { + if (auto *TD = dyn_cast(Enclosing)) + if (TD->getDeclName().isEmpty()) { + S.Diag(TD->getLocation(), + diag::note_decl_unguarded_availability_silence) + << /*Anonymous*/ 1 << TD->getKindName(); + return; + } + auto FixitNoteDiag = + S.Diag(Enclosing->getLocation(), + diag::note_decl_unguarded_availability_silence) + << /*Named*/ 0 << Enclosing; + // Don't offer a fixit for declarations with availability attributes. + if (Enclosing->hasAttr()) + return; + if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE")) + return; + Optional Insertion = createAttributeInsertion( + Enclosing, S.getSourceManager(), S.getLangOpts()); + if (!Insertion) + return; + std::string PlatformName = + AvailabilityAttr::getPlatformNameSourceSpelling( + S.getASTContext().getTargetInfo().getPlatformName()) + .lower(); + std::string Introduced = + OffendingDecl->getVersionIntroduced().getAsString(); + FixitNoteDiag << FixItHint::CreateInsertion( + Insertion->Loc, + (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName + + "(" + Introduced + "))" + Insertion->Suffix) + .str()); + } + return; + } case AR_Deprecated: diag = !ObjCPropertyAccess ? diag::warn_deprecated : diag::warn_property_method_deprecated; @@ -7193,28 +7269,6 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, } break; - 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(), OffendingDecl); - 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?"); } @@ -7253,59 +7307,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); } - // The declaration can have multiple availability attributes, we are looking - // at one of them. - const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl); - if (A && A->isInherited()) { - for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl; - Redecl = Redecl->getPreviousDecl()) { - const AvailabilityAttr *AForRedecl = getAttrForPlatform(S.Context, - Redecl); - if (AForRedecl && !AForRedecl->isInherited()) { - // If D is a declaration with inherited attributes, the note should - // point to the declaration with actual attributes. - S.Diag(Redecl->getLocation(), diag_available_here) << OffendingDecl - << available_here_select_kind; - break; - } - } - } - else - S.Diag(NoteLocation, diag_available_here) - << OffendingDecl << available_here_select_kind; - - if (K == AR_NotYetIntroduced) - if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { - if (auto *TD = dyn_cast(Enclosing)) - if (TD->getDeclName().isEmpty()) { - S.Diag(TD->getLocation(), diag::note_partial_availability_silence) - << /*Anonymous*/1 << TD->getKindName(); - return; - } - auto FixitNoteDiag = S.Diag(Enclosing->getLocation(), - diag::note_partial_availability_silence) - << /*Named*/ 0 << Enclosing; - // Don't offer a fixit for declarations with availability attributes. - if (Enclosing->hasAttr()) - return; - if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE")) - return; - Optional Insertion = createAttributeInsertion( - Enclosing, S.getSourceManager(), S.getLangOpts()); - if (!Insertion) - return; - std::string PlatformName = - AvailabilityAttr::getPlatformNameSourceSpelling( - S.getASTContext().getTargetInfo().getPlatformName()) - .lower(); - std::string Introduced = - OffendingDecl->getVersionIntroduced().getAsString(); - FixitNoteDiag << FixItHint::CreateInsertion( - Insertion->Loc, - (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName + - "(" + Introduced + "))" + Insertion->Suffix) - .str()); - } + S.Diag(NoteLocation, diag_available_here) + << OffendingDecl << available_here_select_kind; } static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, diff --git a/test/SemaObjC/attr-availability.m b/test/SemaObjC/attr-availability.m index 1245ac7409..da1a664e91 100644 --- a/test/SemaObjC/attr-availability.m +++ b/test/SemaObjC/attr-availability.m @@ -196,7 +196,7 @@ __attribute__((availability(macosx, introduced = 10.8))) @interface PartialI2 @end #if defined(WARN_PARTIAL) -// expected-warning@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+2 {{annotate 'partialinter1' with an availability attribute to silence}} +// expected-warning@+2 {{'PartialI2' is only available on macOS 10.8 or newer}} expected-note@+2 {{annotate 'partialinter1' with an availability attribute to silence}} #endif void partialinter1(PartialI2* p) { } @@ -204,7 +204,7 @@ void partialinter1(PartialI2* p) { @class PartialI2; #ifdef WARN_PARTIAL -// expected-warning@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+2 {{annotate 'partialinter2' with an availability attribute to silence}} +// expected-warning@+2 {{'PartialI2' is only available on macOS 10.8 or newer}} expected-note@+2 {{annotate 'partialinter2' with an availability attribute to silence}} #endif void partialinter2(PartialI2* p) { } diff --git a/test/SemaObjC/unguarded-availability-new.m b/test/SemaObjC/unguarded-availability-new.m index 9c44b164d5..474730f0d3 100644 --- a/test/SemaObjC/unguarded-availability-new.m +++ b/test/SemaObjC/unguarded-availability-new.m @@ -96,16 +96,16 @@ typedef int AVAILABLE_NEXT new_int; 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 {{annotate 'x' with an availability attribute to silence}} + // expected-warning@-3 {{'new_int' is only available on macOS 10.14 or newer}} expected-note@-3 {{annotate 'x' with an availability attribute to silence this warning}} #endif #ifdef IOS - // expected-warning@-6 {{'new_int' is partial: introduced in iOS 12}} expected-note@-6 {{annotate 'x' with an availability attribute to silence}} + // expected-warning@-6 {{'new_int' is only available on iOS 12 or newer}} expected-note@-6 {{annotate 'x' with an availability attribute to silence this warning}} #endif #ifdef TVOS - // expected-warning@-9 {{'new_int' is partial: introduced in tvOS 13}} expected-note@-9 {{annotate 'x' with an availability attribute to silence}} + // expected-warning@-9 {{'new_int' is only available on tvOS 13 or newer}} expected-note@-9 {{annotate 'x' with an availability attribute to silence this warning}} #endif #ifdef WATCHOS - // expected-warning@-12 {{'new_int' is partial: introduced in watchOS 5}} expected-note@-12 {{annotate 'x' with an availability attribute to silence}} + // expected-warning@-12 {{'new_int' is only available on watchOS 5}} expected-note@-12 {{annotate 'x' with an availability attribute to silence this warning}} #endif #endif diff --git a/test/SemaObjC/unguarded-availability.m b/test/SemaObjC/unguarded-availability.m index 139b79158a..f94d1425fe 100644 --- a/test/SemaObjC/unguarded-availability.m +++ b/test/SemaObjC/unguarded-availability.m @@ -74,7 +74,7 @@ void use_typedef() { __attribute__((objc_root_class)) AVAILABLE_10_11 @interface Class_10_11 { // expected-note{{annotate 'Class_10_11' with an availability attribute to silence}} int_10_11 foo; - int_10_12 bar; // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} + int_10_12 bar; // expected-warning {{'int_10_12' is only available on macOS 10.12 or newer}} } - (void)method1; - (void)method2; @@ -127,7 +127,7 @@ void test_blocks() { }; } -void test_params(int_10_12 x); // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{annotate 'test_params' with an availability attribute to silence}} +void test_params(int_10_12 x); // expected-warning {{'int_10_12' is only available on macOS 10.12 or newer}} expected-note{{annotate 'test_params' with an availability attribute to silence this warning}} void test_params2(int_10_12 x) AVAILABLE_10_12; // no warn @@ -238,29 +238,29 @@ void functionInFunction() { #endif struct InStruct { // expected-note{{annotate 'InStruct' with an availability attribute to silence}} - new_int mem; // expected-warning{{'new_int' is partial}} + new_int mem; // expected-warning{{'new_int' is only available on macOS 10.12 or newer}} - struct { new_int mem; } anon; // expected-warning{{'new_int' is partial}} expected-note{{annotate anonymous struct with an availability attribute}} + struct { new_int mem; } anon; // expected-warning{{'new_int' is only available on macOS 10.12 or newer}} expected-note{{annotate anonymous struct with an availability attribute to silence}} }; #ifdef OBJCPP static constexpr int AVAILABLE_10_12 SomeConstexprValue = 2; // expected-note{{marked partial here}} typedef enum { // expected-note{{annotate anonymous enum with an availability attribute}} - SomeValue = SomeConstexprValue // expected-warning{{'SomeConstexprValue' is partial}} + SomeValue = SomeConstexprValue // expected-warning{{'SomeConstexprValue' is only available on macOS 10.12 or newer}} } SomeEnum; #endif @interface InInterface --(new_int)meth; // expected-warning{{'new_int' is partial}} expected-note{{annotate 'meth' with an availability attribute}} +-(new_int)meth; // expected-warning{{'new_int' is only available on macOS 10.12 or newer}} expected-note{{annotate 'meth' with an availability attribute}} @end @interface Proper // expected-note{{annotate 'Proper' with an availability attribute}} -@property (class) new_int x; // expected-warning{{'new_int' is partial}} +@property (class) new_int x; // expected-warning{{'new_int' is only available}} @end void with_local_struct() { struct local { // expected-note{{annotate 'local' with an availability attribute}} - new_int x; // expected-warning{{'new_int' is partial}} + new_int x; // expected-warning{{'new_int' is only available}} }; } @@ -273,7 +273,7 @@ AVAILABLE_10_12 @protocol ProtocolWithNewProtocolRequirement // expected-note {{annotate 'ProtocolWithNewProtocolRequirement' with an availability attribute to silence}} -@property(copy) id prop; // expected-warning {{'NewProtocol' is partial: introduced in macOS 10.12}} +@property(copy) id prop; // expected-warning {{'NewProtocol' is only available on macOS 10.12 or newer}} @end -- 2.40.0