Skip to content

Commit

Permalink
[Sema] Improve some -Wunguarded-availability diagnostics
Browse files Browse the repository at this point in the history
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
  • Loading branch information
epilk committed Aug 14, 2017
1 parent 430fd9e commit edee035
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 106 deletions.
18 changes: 2 additions & 16 deletions include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2896,25 +2896,11 @@ def warn_unguarded_availability :
def warn_unguarded_availability_new :
Warning<warn_unguarded_availability.Text>,
InGroup<UnguardedAvailabilityNew>;
def warn_partial_availability : Warning<"%0 is only available conditionally">,
InGroup<UnguardedAvailability>, DefaultIgnore;
def warn_partial_availability_new : Warning<warn_partial_availability.Text>,
InGroup<UnguardedAvailabilityNew>;
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<UnguardedAvailability>, DefaultIgnore;
def warn_partial_message_new : Warning<warn_partial_message.Text>,
InGroup<UnguardedAvailabilityNew>;
def warn_partial_fwdclass_message : Warning<
"%0 may be partial because the receiver type is unknown">,
InGroup<UnguardedAvailability>, DefaultIgnore;
def warn_partial_fwdclass_message_new :
Warning<warn_partial_fwdclass_message.Text>,
InGroup<UnguardedAvailabilityNew>;
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">,
Expand Down
153 changes: 78 additions & 75 deletions lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<TagDecl>(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<AvailabilityAttr>())
return;
if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE"))
return;
Optional<AttributeInsertion> 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;
Expand Down Expand Up @@ -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?");
}
Expand Down Expand Up @@ -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<TagDecl>(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<AvailabilityAttr>())
return;
if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE"))
return;
Optional<AttributeInsertion> 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,
Expand Down
4 changes: 2 additions & 2 deletions test/SemaObjC/attr-availability.m
Original file line number Diff line number Diff line change
Expand Up @@ -196,15 +196,15 @@ void partialfun(PartialI* a) {
@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) {
}

@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) {
}
Expand Down
8 changes: 4 additions & 4 deletions test/SemaObjC/unguarded-availability-new.m
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,16 @@
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

Expand Down
18 changes: 9 additions & 9 deletions test/SemaObjC/unguarded-availability.m
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -238,29 +238,29 @@ void f() {
#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}}
};
}

Expand All @@ -273,7 +273,7 @@ @protocol NewProtocol // expected-note {{'NewProtocol' has been explicitly marke

@protocol ProtocolWithNewProtocolRequirement <NewProtocol> // expected-note {{annotate 'ProtocolWithNewProtocolRequirement' with an availability attribute to silence}}

@property(copy) id<NewProtocol> prop; // expected-warning {{'NewProtocol' is partial: introduced in macOS 10.12}}
@property(copy) id<NewProtocol> prop; // expected-warning {{'NewProtocol' is only available on macOS 10.12 or newer}}

@end

Expand Down

0 comments on commit edee035

Please sign in to comment.