[patch/rfc] An opt-in warning for functions whose availability(introduced) is newer than the deployment target
Nico Weber
thakis at chromium.org
Mon Mar 2 14:25:01 PST 2015
One more tweak: Apparently for `@interface A @end @class A;`, a lookup for
A finds the @interface decl, not the @class redecl. So for
ObjCInterfaceDecls, the explicit loop is necessary – this patch adds it
back for that case. With this change, I can build most of chrome with this
warning enabled (and some declaration tweaks in chrome). (Only "most of"
because the build is still running – no known bugs).
On Sun, Mar 1, 2015 at 7:52 PM, Nico Weber <thakis at chromium.org> wrote:
> 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/20150302/7be9e7f3/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,36 @@
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;
+ // 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<ObjCInterfaceDecl>(D))
+ for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn;
+ Redecl = Redecl->getPreviousDecl())
+ if (!Redecl->hasAttr<AvailabilityAttr>() ||
+ Redecl->getAttr<AvailabilityAttr>()->isInherited())
+ 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 +351,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,69 @@
}
@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
+}
+
+#if defined(WARN_PARTIAL)
+ // expected-note at +2 {{'PartialI2' has been explicitly marked partial here}}
+#endif
+__attribute__((availability(macosx, introduced = 10.8))) @interface PartialI2
+ at end
+
+#if defined(WARN_PARTIAL)
+ // expected-warning at +2 {{'PartialI2' is partial: introduced in OS X 10.8}} expected-note at +2 {{explicitly redeclare 'PartialI2' to silence this warning}}
+#endif
+void partialinter1(PartialI2* p) {
+}
+
+ at class PartialI2;
+
+void partialinter2(PartialI2* p) { // 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