[patch/rfc] An opt-in warning for functions whose availability(introduced) is newer than the deployment target
Nico Weber
thakis at chromium.org
Sun Mar 1 19:52:52 PST 2015
On Mon, Feb 2, 2015 at 10:26 PM, Douglas Gregor <dgregor at apple.com> wrote:
> Hi Nico,
>
> On Jan 8, 2015, at 6:14 PM, Nico Weber <thakis at chromium.org> wrote:
>
> Hi,
>
> the Mac OS X and iOS SDKs add new functions in new releases. Apple
> recommends using the newest SDK and setting the deployment target to
> whatever old OS version one wants to support, and only calling new
> functions after checking that they are available at runtime.
>
> In practice, we (Chromium) get this wrong. Others who support old OS X
> versions get this wrong too. Hence, we (Chromium) use a very old SDK and
> then manually declare new functions when we want to call them – this
> reduces the chance of us forgetting if they are available at runtime
> considerably, in practice. But using an old SDK has its problems –
> sometimes the frameworks check which SDK an app was linked against and only
> then activate bug fixes, and newer Xcodes don't ship include old SDKs.
>
>
> That’s an interesting approach to handling the availability problem; I
> hadn’t heard of it before, but I see the logic there.
>
> Ideally, we could use a new SDK but get a warning when we use a new API
> without a manual redeclaration – this protects us against new APIs the same
> way using an old SDK does without the drawbacks that this brings.
>
> The attached patch is a sketch how such a warning might work. How
> repulsive is this idea? Are there other approaches to this problem? If the
> basic idea is ok:
>
>
> This is a drastically different approach than I’d imagined. Whenever I’ve
> thought about this problem, I’ve always come back to some form of dataflow
> analysis that checks whether uses of “not-yet-introduced” API is used in a
> sane way: is it dominated by some check that implies the availability,
> e.g., a -respondsToSelector: check on a method with at least that
> availability, or checking whether “[NSFoo class]” is non-null when the
> class has availability. I suspect that’s the idea behind Deploymate (
> http://www.deploymateapp.com), although I’ve never used it, and it has
> the benefit that it should make idiomatic code (that does the right
> checking) just work.
>
> It’s also a heck of a lot more work to implement than the approach you’re
> using.
>
Right :-)
>
> Any comments on the implementation?
>
>
> The implementation generally looks fine. One minor comment:
>
> + case AR_NotYetIntroduced: {
> + // don't do this for enums, they can't be redeclared.
> + if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D))
> + break;
> + bool FoundRedecl = false;
> + for (Decl *Redecl = D->getMostRecentDecl(); Redecl && !FoundRedecl;
> + Redecl = Redecl->getPreviousDecl()) {
> + if (Redecl->getAttr<AvailabilityAttr>()->isInherited())
> + FoundRedecl = true;
> + }
> + if (!FoundRedecl)
> + S.EmitAvailabilityWarning(Sema::AD_Partial, D, Message, Loc,
> + UnknownObjCClass, ObjCPDecl,
> + ObjCPropertyAccess);
> + break;
> + }
>
> Generally speaking, name lookup will always find the most recent
> declaration, so you might be able to skip the D->getMostRecentDecl() bit
> entirely and just check that the availability attribute was inherited.
>
That worked, done.
I also had to add some explicit code for handling redeclarations in
@interfaces, as these aren't modeled as redeclarations in the AST. I also
added the property note used in the other availability warnings, and I
added lots of tests.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150301/86566eeb/attachment.html>
-------------- next part --------------
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td (revision 230929)
+++ include/clang/Basic/DiagnosticGroups.td (working copy)
@@ -80,6 +80,7 @@
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">;
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td (revision 230929)
+++ include/clang/Basic/DiagnosticSemaKinds.td (working copy)
@@ -731,7 +731,7 @@
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 :
@@ -3871,6 +3871,15 @@
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<PartialAvailability>, DefaultIgnore;
+def note_partial_availability_silence : Note<
+ "explicitly redeclare %0 to silence this warning">;
+def warn_partial_message : Warning<"%0 is partial: %1">,
+ InGroup<PartialAvailability>, DefaultIgnore;
+def warn_partial_fwdclass_message : Warning<
+ "%0 may be partial because the receiver type is unknown">,
+ InGroup<PartialAvailability>, DefaultIgnore;
def warn_deprecated : Warning<"%0 is deprecated">,
InGroup<DeprecatedDeclarations>;
def warn_property_method_deprecated :
@@ -3896,7 +3905,7 @@
InGroup<UnavailableDeclarations>;
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<
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h (revision 230929)
+++ include/clang/Sema/Sema.h (working copy)
@@ -3355,7 +3355,7 @@
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,
Index: lib/Sema/DelayedDiagnostic.cpp
===================================================================
--- lib/Sema/DelayedDiagnostic.cpp (revision 230929)
+++ lib/Sema/DelayedDiagnostic.cpp (working copy)
@@ -35,6 +35,8 @@
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;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp (revision 230929)
+++ lib/Sema/SemaExpr.cpp (working copy)
@@ -82,10 +82,26 @@
}
}
-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<ObjCMethodDecl>(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<AvailabilityAttr>())
+ 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 @@
}
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<ObjCMethodDecl>(D)) {
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
@@ -115,9 +132,26 @@
switch (Result) {
case AR_Available:
- case AR_NotYetIntroduced:
break;
-
+
+ case AR_NotYetIntroduced: {
+ // Don't do this for enums, they can't be redeclared.
+ if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D))
+ break;
+ bool Warn = !D->getAttr<AvailabilityAttr>()->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;
+
+ if (Warn)
+ S.EmitAvailabilityWarning(Sema::AD_Partial, D, Message, Loc,
+ UnknownObjCClass, ObjCPDecl,
+ ObjCPropertyAccess);
+ break;
+ }
+
case AR_Deprecated:
if (S.getCurContextAvailability() != AR_Deprecated)
S.EmitAvailabilityWarning(Sema::AD_Deprecation,
@@ -307,7 +341,8 @@
DeduceReturnType(FD, Loc))
return true;
}
- DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass, ObjCPropertyAccess);
+ DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass,
+ ObjCPropertyAccess);
DiagnoseUnusedOfDecl(*this, D, Loc);
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp (revision 230929)
+++ lib/Sema/SemaDeclAttr.cpp (working copy)
@@ -5105,7 +5105,7 @@
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,
@@ -5122,7 +5122,7 @@
// 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
@@ -5133,7 +5133,7 @@
available_here_select_kind = /* deprecated */ 2;
break;
- case DelayedDiagnostic::Unavailable:
+ case Sema::AD_Unavailable:
if (isDeclUnavailable(Ctx))
return;
diag = !ObjCPropertyAccess ? diag::err_unavailable
@@ -5144,8 +5144,13 @@
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()) {
@@ -5165,15 +5170,21 @@
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) {
@@ -5239,7 +5250,7 @@
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));
@@ -5247,16 +5258,6 @@
}
Decl *Ctx = cast<Decl>(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);
}
Index: test/Sema/attr-availability.c
===================================================================
--- test/Sema/attr-availability.c (revision 230929)
+++ test/Sema/attr-availability.c (working copy)
@@ -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,11 +15,34 @@
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 at +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 at +2 {{is partial: introduced in OS X 10.8}} expected-note at +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
__attribute__((availability(macos, unavailable))) // expected-warning {{attribute 'availability' is ignored}}
enum {
Index: test/SemaObjC/attr-availability.m
===================================================================
--- test/SemaObjC/attr-availability.m (revision 230929)
+++ test/SemaObjC/attr-availability.m (working copy)
@@ -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 at +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 <P>
- (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 at +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,8 +42,34 @@
[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 at +2 {{'partialMethod' is partial: introduced in OS X 10.8}} expected-note at +2 {{explicitly redeclare 'partialMethod' to silence this warning}}
+#endif
+ [a partialMethod];
+ [b partialMethod]; // no warning
+#if defined(WARN_PARTIAL)
+ // expected-warning at +2 {{'partial_proto_method' is partial: introduced in OS X 10.8}} expected-note at +2 {{explicitly redeclare 'partial_proto_method' to silence this warning}}
+#endif
+ [a partial_proto_method];
+#if defined(WARN_PARTIAL)
+ // expected-warning at +2 {{'partial_proto_method' is partial: introduced in OS X 10.8}} expected-note at +2 {{explicitly redeclare 'partial_proto_method' to silence this warning}}
+#endif
+ [b partial_proto_method];
}
+ at interface A (NewAPI)
+- (void)partialMethod;
+- (void)partial_proto_method;
+ at 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 <rdar://problem/11627873>. Warn about
// using a deprecated method when that method is re-implemented in a
// subclass where the redeclared method is not deprecated.
@@ -87,3 +124,52 @@
}
@end
+
+ at protocol PartialProt
+- (void)ppartialMethod __attribute__((availability(macosx,introduced=10.8)));
++ (void)ppartialMethod __attribute__((availability(macosx,introduced=10.8)));
+ at end
+
+ at interface PartialI <PartialProt>
+- (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
++ (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
+ at end
+
+ at interface PartialI ()
+- (void)ipartialMethod1 __attribute__((availability(macosx,introduced=10.8)));
+#if defined(WARN_PARTIAL)
+ // expected-note at +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 at +2 {{'ipartialMethod2' has been explicitly marked partial here}}
+#endif
++ (void)ipartialMethod2 __attribute__((availability(macosx,introduced=10.8)));
+ at end
+
+ at interface PartialI (Redecls)
+- (void)partialMethod;
+- (void)ipartialMethod1;
+- (void)ppartialMethod;
++ (void)partialMethod;
++ (void)ipartialMethod1;
++ (void)ppartialMethod;
+ at end
+
+void partialfun(PartialI* a) {
+ [a partialMethod]; // no warning
+ [a ipartialMethod1]; // no warning
+#if defined(WARN_PARTIAL)
+ // expected-warning at +2 {{'ipartialMethod2' is partial: introduced in OS X 10.8}} expected-note at +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 at +2 {{'ipartialMethod2' is partial: introduced in OS X 10.8}} expected-note at +2 {{explicitly redeclare 'ipartialMethod2' to silence this warning}}
+#endif
+ [PartialI ipartialMethod2];
+ [PartialI ppartialMethod]; // no warning
+}
Index: test/SemaObjC/property-deprecated-warning.m
===================================================================
--- test/SemaObjC/property-deprecated-warning.m (revision 230929)
+++ test/SemaObjC/property-deprecated-warning.m (working copy)
@@ -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 @@
@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 at +2 {{property 'partialPtarget' is declared partial here}} expected-note at +2 {{'partialPtarget' has been explicitly marked partial here}}
+#endif
+ at property(nonatomic,assign) id partialPtarget __attribute__((availability(ios,introduced=5.0)));
@end
@protocol P1<P>
- (void)setPtarget:(id)arg;
+- (void)setPartialPtarget:(id)arg;
@end
@interface UITableViewCell<P1>
@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 at +2 {{property 'partialTarget' is declared partial here}} expected-note at +2 {{'setPartialTarget:' has been explicitly marked partial here}}
+#endif
+ at 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 at +2 4 {{property 'partial_dep_target' is declared partial here}} expected-note at +2 2 {{'partial_dep_target' has been explicitly marked partial here}} expected-note at +2 2 {{'setPartial_dep_target:' has been explicitly marked partial here}}
+#endif
+ at 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 @@
// 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 at +2 {{'partial_dep_target' is partial: introduced in iOS 5.0}} expected-warning at +2 {{'setPartial_dep_target:' is partial: introduced in iOS 5.0}} expected-note at +2 {{explicitly redeclare 'partial_dep_target' to silence this warning}} expected-note at +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;
+ at synthesize partialTarget;
@synthesize ptarget;
+ at 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 at +2 {{'setPartialTarget:' is partial: introduced in iOS 5.0}} expected-note at +2 {{explicitly redeclare 'setPartialTarget:' to silence this warning}}
+#endif
+ [self setPartialTarget: (id)0];
+#if defined(WARN_PARTIAL)
+ // expected-warning at +2 {{'partial_dep_target' is partial: introduced in iOS 5.0}} expected-warning at +2 {{'setPartial_dep_target:' is partial: introduced in iOS 5.0}} expected-note at +2 {{explicitly redeclare 'partial_dep_target' to silence this warning}} expected-note at +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 @@
@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 at +2 {{property 'partialEnabled' is declared partial here}} expected-note at +2 {{'partialIsEnabled' has been explicitly marked partial here}}
+#endif
+ at property(getter=partialIsEnabled,assign) BOOL partialEnabled __attribute__((availability(ios,introduced=5.0)));
+
+#if defined(WARN_PARTIAL)
+// expected-note at +2 {{property 'partialDelegate' is declared partial here}} expected-note at +2 {{'partialSetNewDelegate:' has been explicitly marked partial here}}
+#endif
+ at 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 at +2 {{'partialIsEnabled' is partial: introduced in iOS 5.0}} expected-warning at +3 {{'partialSetNewDelegate:' is partial: introduced in iOS 5.0}} expected-note at +2 {{explicitly redeclare 'partialIsEnabled' to silence this warning}} expected-note at +3 {{explicitly redeclare 'partialSetNewDelegate:' to silence this warning}}
+#endif
+ if ([obj partialIsEnabled])
+ [obj partialSetNewDelegate:0];
}
@@ -71,12 +127,20 @@
@interface ProtocolInCategory (TheCategory) <P1>
- (id)ptarget;
+- (id)partialPtarget;
@end
id useDeprecatedProperty(ProtocolInCategory *obj, id<P> 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 at +2 {{'partialPtarget' is partial: introduced in iOS 5.0}} expected-note at +2 {{explicitly redeclare 'partialPtarget' to silence this warning}}
+#endif
+ return [obj2 partialPtarget];
}
// rdar://15951801
More information about the cfe-commits
mailing list