From 0055a19926b7b23cfc49b5b645769698ba5aa129 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Thu, 19 Mar 2015 19:18:22 +0000 Subject: [PATCH] Add -Wpartial-availability. This warns when using decls that are not available on all deployment targets. For example, a call to - (void)ppartialMethod __attribute__((availability(macosx,introduced=10.8))); will warn if -mmacosx-version-min is set to less than 10.8. To silence the warning, one has to explicitly redeclare the method like so: @interface Whatever(MountainLionAPI) - (void)ppartialMethod; @end This way, one cannot accidentally call a function that isn't available everywhere. Having to add the redeclaration will hopefully remind the user to add an explicit respondsToSelector: call as well. Some projects build against old SDKs to get this effect, but building against old SDKs suppresses some bug fixes -- see http://crbug.com/463171 for examples. The hope is that SDK headers are annotated well enough with availability attributes that new SDK + this warning offers the same amount of protection as using an old SDK. llvm-svn: 232750 --- clang/include/clang/Basic/DiagnosticGroups.td | 1 + clang/include/clang/Basic/DiagnosticSemaKinds.td | 13 ++- clang/include/clang/Sema/Sema.h | 2 +- clang/lib/Sema/DelayedDiagnostic.cpp | 2 + clang/lib/Sema/SemaDeclAttr.cpp | 45 +++++----- clang/lib/Sema/SemaExpr.cpp | 59 +++++++++++-- clang/test/Sema/attr-availability.c | 25 ++++++ clang/test/SemaObjC/attr-availability.m | 103 ++++++++++++++++++++++ clang/test/SemaObjC/property-deprecated-warning.m | 66 +++++++++++++- 9 files changed, 283 insertions(+), 33 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 5affa28..6f4cce7 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -80,6 +80,7 @@ def CXX11CompatDeprecatedWritableStr : def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">; def UnavailableDeclarations : DiagGroup<"unavailable-declarations">; +def PartialAvailability : DiagGroup<"partial-availability">; def DeprecatedImplementations :DiagGroup<"deprecated-implementations">; def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">; def DeprecatedRegister : DiagGroup<"deprecated-register">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b7ab489..3fb3774 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -731,7 +731,7 @@ def warn_accessor_property_type_mismatch : Warning< def not_conv_function_declared_at : Note<"type conversion function declared here">; def note_method_declared_at : Note<"method %0 declared here">; def note_property_attribute : Note<"property %0 is declared " - "%select{deprecated|unavailable}1 here">; + "%select{deprecated|unavailable|partial}1 here">; def err_setter_type_void : Error<"type of setter must be void">; def err_duplicate_method_decl : Error<"duplicate declaration of method %0">; def warn_duplicate_method_decl : @@ -3867,6 +3867,15 @@ def err_not_found_by_two_phase_lookup : Error<"call to function %0 that is neith def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to the " "call site%select{| or in %2| or in an associated namespace of one of its arguments}1">; def err_undeclared_use : Error<"use of undeclared %0">; +def warn_partial_availability : Warning<"%0 is only available conditionally">, + InGroup, DefaultIgnore; +def note_partial_availability_silence : Note< + "explicitly redeclare %0 to silence this warning">; +def warn_partial_message : Warning<"%0 is partial: %1">, + InGroup, DefaultIgnore; +def warn_partial_fwdclass_message : Warning< + "%0 may be partial because the receiver type is unknown">, + InGroup, DefaultIgnore; def warn_deprecated : Warning<"%0 is deprecated">, InGroup; def warn_property_method_deprecated : @@ -3892,7 +3901,7 @@ def warn_unavailable_fwdclass_message : Warning< InGroup; def note_availability_specified_here : Note< "%0 has been explicitly marked " - "%select{unavailable|deleted|deprecated}1 here">; + "%select{unavailable|deleted|deprecated|partial}1 here">; def note_implicitly_deleted : Note< "explicitly defaulted function was implicitly deleted here">; def note_inherited_deleted_here : Note< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 7671ab3..6f6faf4 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3272,7 +3272,7 @@ public: void redelayDiagnostics(sema::DelayedDiagnosticPool &pool); - enum AvailabilityDiagnostic { AD_Deprecation, AD_Unavailable }; + enum AvailabilityDiagnostic { AD_Deprecation, AD_Unavailable, AD_Partial }; void EmitAvailabilityWarning(AvailabilityDiagnostic AD, NamedDecl *D, StringRef Message, diff --git a/clang/lib/Sema/DelayedDiagnostic.cpp b/clang/lib/Sema/DelayedDiagnostic.cpp index 664a6b1..ceea04f 100644 --- a/clang/lib/Sema/DelayedDiagnostic.cpp +++ b/clang/lib/Sema/DelayedDiagnostic.cpp @@ -35,6 +35,8 @@ DelayedDiagnostic::makeAvailability(Sema::AvailabilityDiagnostic AD, case Sema::AD_Unavailable: DD.Kind = Unavailable; break; + case Sema::AD_Partial: + llvm_unreachable("AD_Partial diags should not be delayed"); } DD.Triggered = false; DD.Loc = Loc; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 86aaf3a..336d222 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5117,7 +5117,7 @@ static bool isDeclUnavailable(Decl *D) { return false; } -static void DoEmitAvailabilityWarning(Sema &S, DelayedDiagnostic::DDKind K, +static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, Decl *Ctx, const NamedDecl *D, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, @@ -5134,7 +5134,7 @@ static void DoEmitAvailabilityWarning(Sema &S, DelayedDiagnostic::DDKind K, // Don't warn if our current context is deprecated or unavailable. switch (K) { - case DelayedDiagnostic::Deprecation: + case Sema::AD_Deprecation: if (isDeclDeprecated(Ctx)) return; diag = !ObjCPropertyAccess ? diag::warn_deprecated @@ -5145,7 +5145,7 @@ static void DoEmitAvailabilityWarning(Sema &S, DelayedDiagnostic::DDKind K, available_here_select_kind = /* deprecated */ 2; break; - case DelayedDiagnostic::Unavailable: + case Sema::AD_Unavailable: if (isDeclUnavailable(Ctx)) return; diag = !ObjCPropertyAccess ? diag::err_unavailable @@ -5156,8 +5156,13 @@ static void DoEmitAvailabilityWarning(Sema &S, DelayedDiagnostic::DDKind K, available_here_select_kind = /* unavailable */ 0; break; - default: - llvm_unreachable("Neither a deprecation or unavailable kind"); + case Sema::AD_Partial: + diag = diag::warn_partial_availability; + diag_message = diag::warn_partial_message; + diag_fwdclass_message = diag::warn_partial_fwdclass_message; + property_note_select = /* partial */ 2; + available_here_select_kind = /* partial */ 3; + break; } if (!Message.empty()) { @@ -5177,15 +5182,21 @@ static void DoEmitAvailabilityWarning(Sema &S, DelayedDiagnostic::DDKind K, S.Diag(D->getLocation(), diag::note_availability_specified_here) << D << available_here_select_kind; + if (K == Sema::AD_Partial) + S.Diag(Loc, diag::note_partial_availability_silence) << D; } static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, Decl *Ctx) { + assert(DD.Kind == DelayedDiagnostic::Deprecation || + DD.Kind == DelayedDiagnostic::Unavailable); + Sema::AvailabilityDiagnostic AD = DD.Kind == DelayedDiagnostic::Deprecation + ? Sema::AD_Deprecation + : Sema::AD_Unavailable; DD.Triggered = true; - DoEmitAvailabilityWarning(S, (DelayedDiagnostic::DDKind)DD.Kind, Ctx, - DD.getDeprecationDecl(), DD.getDeprecationMessage(), - DD.Loc, DD.getUnknownObjCClass(), - DD.getObjCProperty(), false); + DoEmitAvailabilityWarning( + S, AD, Ctx, DD.getDeprecationDecl(), DD.getDeprecationMessage(), DD.Loc, + DD.getUnknownObjCClass(), DD.getObjCProperty(), false); } void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { @@ -5251,7 +5262,7 @@ void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { // Delay if we're currently parsing a declaration. - if (DelayedDiagnostics.shouldDelayDiagnostics()) { + if (DelayedDiagnostics.shouldDelayDiagnostics() && AD != AD_Partial) { DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability( AD, Loc, D, UnknownObjCClass, ObjCProperty, Message, ObjCPropertyAccess)); @@ -5259,16 +5270,6 @@ void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD, } Decl *Ctx = cast(getCurLexicalContext()); - DelayedDiagnostic::DDKind K; - switch (AD) { - case AD_Deprecation: - K = DelayedDiagnostic::Deprecation; - break; - case AD_Unavailable: - K = DelayedDiagnostic::Unavailable; - break; - } - - DoEmitAvailabilityWarning(*this, K, Ctx, D, Message, Loc, - UnknownObjCClass, ObjCProperty, ObjCPropertyAccess); + DoEmitAvailabilityWarning(*this, AD, Ctx, D, Message, Loc, UnknownObjCClass, + ObjCProperty, ObjCPropertyAccess); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 35a0e39..c061e06 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -82,10 +82,26 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { } } -static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, - NamedDecl *D, SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass, - bool ObjCPropertyAccess) { +static bool HasRedeclarationWithoutAvailabilityInCategory(const Decl *D) { + const auto *OMD = dyn_cast(D); + if (!OMD) + return false; + const ObjCInterfaceDecl *OID = OMD->getClassInterface(); + if (!OID) + return false; + + for (const ObjCCategoryDecl *Cat : OID->visible_categories()) + if (ObjCMethodDecl *CatMeth = + Cat->getMethod(OMD->getSelector(), OMD->isInstanceMethod())) + if (!CatMeth->hasAttr()) + return true; + return false; +} + +static AvailabilityResult +DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, + const ObjCInterfaceDecl *UnknownObjCClass, + bool ObjCPropertyAccess) { // See if this declaration is unavailable or deprecated. std::string Message; @@ -103,7 +119,8 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, } const ObjCPropertyDecl *ObjCPDecl = nullptr; - if (Result == AR_Deprecated || Result == AR_Unavailable) { + if (Result == AR_Deprecated || Result == AR_Unavailable || + AR_NotYetIntroduced) { if (const ObjCMethodDecl *MD = dyn_cast(D)) { if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { AvailabilityResult PDeclResult = PD->getAvailability(nullptr); @@ -115,7 +132,6 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, switch (Result) { case AR_Available: - case AR_NotYetIntroduced: break; case AR_Deprecated: @@ -125,6 +141,34 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, ObjCPropertyAccess); break; + case AR_NotYetIntroduced: { + // Don't do this for enums, they can't be redeclared. + if (isa(D) || isa(D)) + break; + + bool Warn = !D->getAttr()->isInherited(); + // Objective-C method declarations in categories are not modelled as + // redeclarations, so manually look for a redeclaration in a category + // if necessary. + if (Warn && HasRedeclarationWithoutAvailabilityInCategory(D)) + Warn = false; + // In general, D will point to the most recent redeclaration. However, + // for `@class A;` decls, this isn't true -- manually go through the + // redecl chain in that case. + if (Warn && isa(D)) + for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn; + Redecl = Redecl->getPreviousDecl()) + if (!Redecl->hasAttr() || + Redecl->getAttr()->isInherited()) + Warn = false; + + if (Warn) + S.EmitAvailabilityWarning(Sema::AD_Partial, D, Message, Loc, + UnknownObjCClass, ObjCPDecl, + ObjCPropertyAccess); + break; + } + case AR_Unavailable: if (S.getCurContextAvailability() != AR_Unavailable) S.EmitAvailabilityWarning(Sema::AD_Unavailable, @@ -307,7 +351,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, DeduceReturnType(FD, Loc)) return true; } - DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass, ObjCPropertyAccess); + DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass, + ObjCPropertyAccess); DiagnoseUnusedOfDecl(*this, D, Loc); diff --git a/clang/test/Sema/attr-availability.c b/clang/test/Sema/attr-availability.c index b7a8e6e..48bdf26 100644 --- a/clang/test/Sema/attr-availability.c +++ b/clang/test/Sema/attr-availability.c @@ -1,4 +1,6 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -fblocks -verify %s +// RUN: %clang_cc1 -D WARN_PARTIAL -Wpartial-availability -triple x86_64-apple-darwin9 -fsyntax-only -fblocks -verify %s +// void f0() __attribute__((availability(macosx,introduced=10.4,deprecated=10.2))); // expected-warning{{feature cannot be deprecated in OS X version 10.2 before it was introduced in version 10.4; attribute ignored}} void f1() __attribute__((availability(ios,obsoleted=2.1,deprecated=3.0))); // expected-warning{{feature cannot be obsoleted in iOS version 2.1 before it was deprecated in version 3.0; attribute ignored}} @@ -13,9 +15,32 @@ ATSFontGetName(const char *oName) __attribute__((availability(macosx,introduced= extern void ATSFontGetPostScriptName(int flags) __attribute__((availability(macosx,introduced=8.0,obsoleted=9.0, message="use ATSFontGetFullPostScriptName"))); // expected-note {{'ATSFontGetPostScriptName' has been explicitly marked unavailable here}} +#if defined(WARN_PARTIAL) +// expected-note@+3 {{has been explicitly marked partial here}} +#endif +extern void +PartiallyAvailable() __attribute__((availability(macosx,introduced=10.8))); + +enum __attribute__((availability(macosx,introduced=10.8))) PartialEnum { + kPartialEnumConstant, +}; + void test_10095131() { ATSFontGetName("Hello"); // expected-warning {{'ATSFontGetName' is deprecated: first deprecated in OS X 9.0 - use CTFontCopyFullName}} ATSFontGetPostScriptName(100); // expected-error {{'ATSFontGetPostScriptName' is unavailable: obsoleted in OS X 9.0 - use ATSFontGetFullPostScriptName}} + +#if defined(WARN_PARTIAL) + // expected-warning@+2 {{is partial: introduced in OS X 10.8}} expected-note@+2 {{explicitly redeclare 'PartiallyAvailable' to silence this warning}} +#endif + PartiallyAvailable(); +} + +extern void PartiallyAvailable() ; +void with_redeclaration() { + PartiallyAvailable(); // Don't warn. + + // enums should never warn. + enum PartialEnum p = kPartialEnumConstant; } // rdar://10711037 diff --git a/clang/test/SemaObjC/attr-availability.m b/clang/test/SemaObjC/attr-availability.m index c455bc7..bac4be2 100644 --- a/clang/test/SemaObjC/attr-availability.m +++ b/clang/test/SemaObjC/attr-availability.m @@ -1,11 +1,21 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin9.0.0 -fsyntax-only -verify %s +// RUN: %clang_cc1 -D WARN_PARTIAL -Wpartial-availability -triple x86_64-apple-darwin9.0.0 -fsyntax-only -verify %s @protocol P - (void)proto_method __attribute__((availability(macosx,introduced=10.1,deprecated=10.2))); // expected-note 2 {{'proto_method' has been explicitly marked deprecated here}} + +#if defined(WARN_PARTIAL) + // expected-note@+2 2 {{'partial_proto_method' has been explicitly marked partial here}} +#endif +- (void)partial_proto_method __attribute__((availability(macosx,introduced=10.8))); @end @interface A

- (void)method __attribute__((availability(macosx,introduced=10.1,deprecated=10.2))); // expected-note {{'method' has been explicitly marked deprecated here}} +#if defined(WARN_PARTIAL) + // expected-note@+2 {{'partialMethod' has been explicitly marked partial here}} +#endif +- (void)partialMethod __attribute__((availability(macosx,introduced=10.8))); - (void)overridden __attribute__((availability(macosx,introduced=10.3))); // expected-note{{overridden method is here}} - (void)overridden2 __attribute__((availability(macosx,introduced=10.3))); @@ -18,6 +28,7 @@ // rdar://11475360 @interface B : A - (void)method; // NOTE: we expect 'method' to *not* inherit availability. +- (void)partialMethod; // Likewise. - (void)overridden __attribute__((availability(macosx,introduced=10.4))); // expected-warning{{overriding method introduced after overridden method on OS X (10.4 vs. 10.3)}} - (void)overridden2 __attribute__((availability(macosx,introduced=10.2))); - (void)overridden3 __attribute__((availability(macosx,deprecated=10.4))); @@ -31,6 +42,32 @@ void f(A *a, B *b) { [b method]; // no-warning [a proto_method]; // expected-warning{{'proto_method' is deprecated: first deprecated in OS X 10.2}} [b proto_method]; // expected-warning{{'proto_method' is deprecated: first deprecated in OS X 10.2}} + +#if defined(WARN_PARTIAL) + // expected-warning@+2 {{'partialMethod' is partial: introduced in OS X 10.8}} expected-note@+2 {{explicitly redeclare 'partialMethod' to silence this warning}} +#endif + [a partialMethod]; + [b partialMethod]; // no warning +#if defined(WARN_PARTIAL) + // expected-warning@+2 {{'partial_proto_method' is partial: introduced in OS X 10.8}} expected-note@+2 {{explicitly redeclare 'partial_proto_method' to silence this warning}} +#endif + [a partial_proto_method]; +#if defined(WARN_PARTIAL) + // expected-warning@+2 {{'partial_proto_method' is partial: introduced in OS X 10.8}} expected-note@+2 {{explicitly redeclare 'partial_proto_method' to silence this warning}} +#endif + [b partial_proto_method]; +} + +@interface A (NewAPI) +- (void)partialMethod; +- (void)partial_proto_method; +@end + +void f_after_redecl(A *a, B *b) { + [a partialMethod]; // no warning + [b partialMethod]; // no warning + [a partial_proto_method]; // no warning + [b partial_proto_method]; // no warning } // Test case for . Warn about @@ -87,3 +124,69 @@ id NSNibOwner, topNibObjects; } @end + +@protocol PartialProt +- (void)ppartialMethod __attribute__((availability(macosx,introduced=10.8))); ++ (void)ppartialMethod __attribute__((availability(macosx,introduced=10.8))); +@end + +@interface PartialI +- (void)partialMethod __attribute__((availability(macosx,introduced=10.8))); ++ (void)partialMethod __attribute__((availability(macosx,introduced=10.8))); +@end + +@interface PartialI () +- (void)ipartialMethod1 __attribute__((availability(macosx,introduced=10.8))); +#if defined(WARN_PARTIAL) + // expected-note@+2 {{'ipartialMethod2' has been explicitly marked partial here}} +#endif +- (void)ipartialMethod2 __attribute__((availability(macosx,introduced=10.8))); ++ (void)ipartialMethod1 __attribute__((availability(macosx,introduced=10.8))); +#if defined(WARN_PARTIAL) + // expected-note@+2 {{'ipartialMethod2' has been explicitly marked partial here}} +#endif ++ (void)ipartialMethod2 __attribute__((availability(macosx,introduced=10.8))); +@end + +@interface PartialI (Redecls) +- (void)partialMethod; +- (void)ipartialMethod1; +- (void)ppartialMethod; ++ (void)partialMethod; ++ (void)ipartialMethod1; ++ (void)ppartialMethod; +@end + +void partialfun(PartialI* a) { + [a partialMethod]; // no warning + [a ipartialMethod1]; // no warning +#if defined(WARN_PARTIAL) + // expected-warning@+2 {{'ipartialMethod2' is partial: introduced in OS X 10.8}} expected-note@+2 {{explicitly redeclare 'ipartialMethod2' to silence this warning}} +#endif + [a ipartialMethod2]; + [a ppartialMethod]; // no warning + [PartialI partialMethod]; // no warning + [PartialI ipartialMethod1]; // no warning +#if defined(WARN_PARTIAL) + // expected-warning@+2 {{'ipartialMethod2' is partial: introduced in OS X 10.8}} expected-note@+2 {{explicitly redeclare 'ipartialMethod2' to silence this warning}} +#endif + [PartialI ipartialMethod2]; + [PartialI ppartialMethod]; // no warning +} + +#if defined(WARN_PARTIAL) + // expected-note@+2 {{'PartialI2' has been explicitly marked partial here}} +#endif +__attribute__((availability(macosx, introduced = 10.8))) @interface PartialI2 +@end + +#if defined(WARN_PARTIAL) + // expected-warning@+2 {{'PartialI2' is partial: introduced in OS X 10.8}} expected-note@+2 {{explicitly redeclare 'PartialI2' to silence this warning}} +#endif +void partialinter1(PartialI2* p) { +} + +@class PartialI2; + +void partialinter2(PartialI2* p) { // no warning +} diff --git a/clang/test/SemaObjC/property-deprecated-warning.m b/clang/test/SemaObjC/property-deprecated-warning.m index 4beb23a..cec3768 100644 --- a/clang/test/SemaObjC/property-deprecated-warning.m +++ b/clang/test/SemaObjC/property-deprecated-warning.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -triple thumbv6-apple-ios3.0 -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -D WARN_PARTIAL -Wpartial-availability -fsyntax-only -triple thumbv6-apple-ios3.0 -verify -Wno-objc-root-class %s // RUN: %clang_cc1 -x objective-c++ -fsyntax-only -triple thumbv6-apple-ios3.0 -verify -Wno-objc-root-class %s // rdar://12324295 @@ -6,29 +7,47 @@ typedef signed char BOOL; @protocol P @property(nonatomic,assign) id ptarget __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{property 'ptarget' is declared deprecated here}} expected-note {{'ptarget' has been explicitly marked deprecated here}} + +#if defined(WARN_PARTIAL) +// expected-note@+2 {{property 'partialPtarget' is declared partial here}} expected-note@+2 {{'partialPtarget' has been explicitly marked partial here}} +#endif +@property(nonatomic,assign) id partialPtarget __attribute__((availability(ios,introduced=5.0))); @end @protocol P1

- (void)setPtarget:(id)arg; +- (void)setPartialPtarget:(id)arg; @end @interface UITableViewCell @property(nonatomic,assign) id target __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{property 'target' is declared deprecated here}} expected-note {{'setTarget:' has been explicitly marked deprecated here}} + +#if defined(WARN_PARTIAL) +// expected-note@+2 {{property 'partialTarget' is declared partial here}} expected-note@+2 {{'setPartialTarget:' has been explicitly marked partial here}} +#endif +@property(nonatomic,assign) id partialTarget __attribute__((availability(ios,introduced=5.0))); @end @interface PSTableCell : UITableViewCell - (void)setTarget:(id)target; + - (void)setPartialTarget:(id)target; @end @interface UITableViewCell(UIDeprecated) @property(nonatomic,assign) id dep_target __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note 2 {{'dep_target' has been explicitly marked deprecated here}} \ // expected-note 4 {{property 'dep_target' is declared deprecated here}} \ // expected-note 2 {{'setDep_target:' has been explicitly marked deprecated here}} + +#if defined(WARN_PARTIAL) +// expected-note@+2 4 {{property 'partial_dep_target' is declared partial here}} expected-note@+2 2 {{'partial_dep_target' has been explicitly marked partial here}} expected-note@+2 2 {{'setPartial_dep_target:' has been explicitly marked partial here}} +#endif +@property(nonatomic,assign) id partial_dep_target __attribute__((availability(ios,introduced=5.0))); @end @implementation PSTableCell - (void)setTarget:(id)target {}; +- (void)setPartialTarget:(id)target {}; - (void)setPtarget:(id)val {}; - (void) Meth { [self setTarget: (id)0]; // no-warning @@ -36,20 +55,41 @@ typedef signed char BOOL; // expected-warning {{'setDep_target:' is deprecated: first deprecated in iOS 3.0}} [self setPtarget: (id)0]; // no-warning + [self setPartialTarget: (id)0]; // no-warning +#if defined(WARN_PARTIAL) + // expected-warning@+2 {{'partial_dep_target' is partial: introduced in iOS 5.0}} expected-warning@+2 {{'setPartial_dep_target:' is partial: introduced in iOS 5.0}} expected-note@+2 {{explicitly redeclare 'partial_dep_target' to silence this warning}} expected-note@+2 {{explicitly redeclare 'setPartial_dep_target:' to silence this warning}} +#endif + [self setPartial_dep_target: [self partial_dep_target]]; + + [self setPartialPtarget: (id)0]; // no-warning } @end @implementation UITableViewCell @synthesize target; +@synthesize partialTarget; @synthesize ptarget; +@synthesize partialPtarget; - (void)setPtarget:(id)val {}; +- (void)setPartialPtarget:(id)val {}; - (void)setTarget:(id)target {}; +- (void)setPartialTarget:(id)target {}; - (void) Meth { [self setTarget: (id)0]; // expected-warning {{'setTarget:' is deprecated: first deprecated in iOS 3.0}} [self setDep_target: [self dep_target]]; // expected-warning {{'dep_target' is deprecated: first deprecated in iOS 3.0}} \ // expected-warning {{'setDep_target:' is deprecated: first deprecated in iOS 3.0}} - + [self setPtarget: (id)0]; // no-warning + +#if defined(WARN_PARTIAL) + // expected-warning@+2 {{'setPartialTarget:' is partial: introduced in iOS 5.0}} expected-note@+2 {{explicitly redeclare 'setPartialTarget:' to silence this warning}} +#endif + [self setPartialTarget: (id)0]; +#if defined(WARN_PARTIAL) + // expected-warning@+2 {{'partial_dep_target' is partial: introduced in iOS 5.0}} expected-warning@+2 {{'setPartial_dep_target:' is partial: introduced in iOS 5.0}} expected-note@+2 {{explicitly redeclare 'partial_dep_target' to silence this warning}} expected-note@+2 {{explicitly redeclare 'setPartial_dep_target:' to silence this warning}} +#endif + [self setPartial_dep_target: [self partial_dep_target]]; + [self setPartialPtarget: (id)0]; // no-warning } @end @@ -58,11 +98,27 @@ typedef signed char BOOL; @property(getter=isEnabled,assign) BOOL enabled __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{'isEnabled' has been explicitly marked deprecated here}} expected-note {{property 'enabled' is declared deprecated here}} @property(setter=setNewDelegate:,assign) id delegate __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{'setNewDelegate:' has been explicitly marked deprecated here}} expected-note {{property 'delegate' is declared deprecated here}} + +#if defined(WARN_PARTIAL) +// expected-note@+2 {{property 'partialEnabled' is declared partial here}} expected-note@+2 {{'partialIsEnabled' has been explicitly marked partial here}} +#endif +@property(getter=partialIsEnabled,assign) BOOL partialEnabled __attribute__((availability(ios,introduced=5.0))); + +#if defined(WARN_PARTIAL) +// expected-note@+2 {{property 'partialDelegate' is declared partial here}} expected-note@+2 {{'partialSetNewDelegate:' has been explicitly marked partial here}} +#endif +@property(setter=partialSetNewDelegate:,assign) id partialDelegate __attribute__((availability(ios,introduced=5.0))); @end void testCustomAccessorNames(CustomAccessorNames *obj) { if ([obj isEnabled]) // expected-warning {{'isEnabled' is deprecated: first deprecated in iOS 3.0}} [obj setNewDelegate:0]; // expected-warning {{'setNewDelegate:' is deprecated: first deprecated in iOS 3.0}} + +#if defined(WARN_PARTIAL) +// expected-warning@+2 {{'partialIsEnabled' is partial: introduced in iOS 5.0}} expected-warning@+3 {{'partialSetNewDelegate:' is partial: introduced in iOS 5.0}} expected-note@+2 {{explicitly redeclare 'partialIsEnabled' to silence this warning}} expected-note@+3 {{explicitly redeclare 'partialSetNewDelegate:' to silence this warning}} +#endif + if ([obj partialIsEnabled]) + [obj partialSetNewDelegate:0]; } @@ -71,12 +127,20 @@ void testCustomAccessorNames(CustomAccessorNames *obj) { @interface ProtocolInCategory (TheCategory) - (id)ptarget; +- (id)partialPtarget; @end id useDeprecatedProperty(ProtocolInCategory *obj, id

obj2, int flag) { if (flag) return [obj ptarget]; // no-warning return [obj2 ptarget]; // expected-warning {{'ptarget' is deprecated: first deprecated in iOS 3.0}} + + if (flag) + return [obj partialPtarget]; // no-warning +#if defined(WARN_PARTIAL) +// expected-warning@+2 {{'partialPtarget' is partial: introduced in iOS 5.0}} expected-note@+2 {{explicitly redeclare 'partialPtarget' to silence this warning}} +#endif + return [obj2 partialPtarget]; } // rdar://15951801 -- 2.7.4