Files
clang-p2996/clang/test/ARCMT/checking.m
Ted Kremenek b79ee57080 Implemented delayed processing of 'unavailable' checking, just like with 'deprecated'.
Fixes <rdar://problem/15584219> and <rdar://problem/12241361>.

This change looks large, but all it does is reuse and consolidate
the delayed diagnostic logic for deprecation warnings with unavailability
warnings.  By doing so, it showed various inconsistencies between the
diagnostics, which were close, but not consistent.  It also revealed
some missing "note:"'s in the deprecated diagnostics that were showing
up in the unavailable diagnostics, etc.

This change also changes the wording of the core deprecation diagnostics.
Instead of saying "function has been explicitly marked deprecated"
we now saw "'X' has been been explicitly marked deprecated".  It
turns out providing a bit more context is useful, and often we
got the actual term wrong or it was not very precise
 (e.g., "function" instead of "destructor").  By just saying the name
of the thing that is deprecated/deleted/unavailable we define
this issue away.  This diagnostic can likely be further wordsmithed
to be shorter.

llvm-svn: 197627
2013-12-18 23:30:06 +00:00

356 lines
14 KiB
Objective-C

// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fblocks -Werror %s
#if __has_feature(objc_arc)
#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
#else
#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE
#endif
typedef const void * CFTypeRef;
CFTypeRef CFBridgingRetain(id X);
id CFBridgingRelease(CFTypeRef);
typedef int BOOL;
typedef unsigned NSUInteger;
@protocol NSObject
- (id)retain NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
- (NSUInteger)retainCount NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
- (id)autorelease NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
@end
@interface NSObject <NSObject> {}
- (id)init;
+ (id)new;
+ (id)alloc;
- (void)dealloc;
- (void)finalize;
- (id)copy;
- (id)mutableCopy;
@end
typedef const struct __CFString * CFStringRef;
extern const CFStringRef kUTTypePlainText;
extern const CFStringRef kUTTypeRTF;
@class NSString;
@class A;
struct UnsafeS {
A *__unsafe_unretained unsafeObj;
};
@interface A : NSObject
- (id)retain; // expected-note {{'retain' has been explicitly marked unavailable here}}
- (id)retainCount; // expected-note {{'retainCount' has been explicitly marked unavailable here}}
- (id)autorelease; // expected-note 2 {{'autorelease' has been explicitly marked unavailable here}}
- (id)init;
- (oneway void)release;
- (void)dealloc;
-(void)test;
-(id)delegate;
@end
@implementation A
-(void)test {
[super dealloc];
}
-(void)dealloc {
[super dealloc];
}
- (id)retain { return self; } // expected-error {{ARC forbids implementation}}
- (id)retainCount { return self; } // expected-error {{ARC forbids implementation}}
- (id)autorelease { return self; } // expected-error {{ARC forbids implementation}}
- (oneway void)release { } // expected-error {{ARC forbids implementation}}
-(id)delegate { return self; }
@end
id global_foo;
void test1(A *a, BOOL b, struct UnsafeS *unsafeS) {
[[a delegate] release]; // expected-error {{it is not safe to remove 'retain' message on the result of a 'delegate' message; the object that was passed to 'setDelegate:' may not be properly retained}} \
// expected-error {{ARC forbids explicit message send}}
[a.delegate release]; // expected-error {{it is not safe to remove 'retain' message on the result of a 'delegate' message; the object that was passed to 'setDelegate:' may not be properly retained}} \
// expected-error {{ARC forbids explicit message send}}
[unsafeS->unsafeObj retain]; // expected-error {{it is not safe to remove 'retain' message on an __unsafe_unretained type}} \
// expected-error {{ARC forbids explicit message send}} \
// expected-error {{'retain' is unavailable}}
id foo = [unsafeS->unsafeObj retain]; // no warning.
[global_foo retain]; // expected-error {{it is not safe to remove 'retain' message on a global variable}} \
// expected-error {{ARC forbids explicit message send}}
[global_foo release]; // expected-error {{it is not safe to remove 'release' message on a global variable}} \
// expected-error {{ARC forbids explicit message send}}
[a dealloc];
[a retain];
[a retainCount]; // expected-error {{ARC forbids explicit message send of 'retainCount'}} \
// expected-error {{'retainCount' is unavailable}}
[a release];
[a autorelease]; // expected-error {{it is not safe to remove an unused 'autorelease' message; its receiver may be destroyed immediately}} \
// expected-error {{ARC forbids explicit message send}} \
// expected-error {{'autorelease' is unavailable}}
[a autorelease]; // expected-error {{it is not safe to remove an unused 'autorelease' message; its receiver may be destroyed immediately}} \
// expected-error {{ARC forbids explicit message send}} \
// expected-error {{'autorelease' is unavailable}}
a = 0;
CFStringRef cfstr;
NSString *str = (NSString *)cfstr; // expected-error {{cast of C pointer type 'CFStringRef' (aka 'const struct __CFString *') to Objective-C pointer type 'NSString *' requires a bridged cast}} \
// expected-note {{use __bridge to convert directly (no change in ownership)}} \
// expected-note {{use CFBridgingRelease call to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}} \
str = (NSString *)kUTTypePlainText;
str = b ? kUTTypeRTF : kUTTypePlainText;
str = (NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
str = (NSString *)a; // no change.
SEL s = @selector(retain); // expected-error {{ARC forbids use of 'retain' in a @selector}}
s = @selector(release); // expected-error {{ARC forbids use of 'release' in a @selector}}
s = @selector(autorelease); // expected-error {{ARC forbids use of 'autorelease' in a @selector}}
s = @selector(dealloc); // expected-error {{ARC forbids use of 'dealloc' in a @selector}}
static id __autoreleasing X1; // expected-error {{global variables cannot have __autoreleasing ownership}}
}
struct S {
A* a; // expected-error {{ARC forbids Objective-C objects in struct}}
};
@interface B
-(id)alloc;
- (id)initWithInt: (int) i;
@end
void rdar8861761() {
B *o1 = [[B alloc] initWithInt:0];
B *o2 = [B alloc];
[o2 initWithInt:0];
}
@interface Test13
- (id) init0;
- (void) noninit;
@end
@implementation Test13
- (id) init0 {
self = 0;
}
- (void) noninit {
self = 0; // expected-error {{cannot assign to 'self' outside of a method in the init family}}
for (__strong id x in collection) { // expected-error {{use of undeclared identifier 'collection'}}
x = 0;
}
}
@end
void * cvt(id arg)
{
void* voidp_val;
(void)(int*)arg; // expected-error {{disallowed}}
(void)(id)arg;
(void)(__autoreleasing id*)arg; // expected-error {{disallowed}}
(void)(id*)arg; // expected-error {{disallowed}}
(void)(__autoreleasing id**)voidp_val;
(void)(void*)voidp_val;
(void)(void**)arg; // expected-error {{disallowed}}
cvt((void*)arg); // expected-error 2 {{requires a bridged cast}} \
// expected-note 2 {{use __bridge to}} expected-note {{use CFBridgingRelease call}} expected-note {{use CFBridgingRetain call}}
cvt(0);
(void)(__strong id**)(0);
return arg; // expected-error {{requires a bridged cast}} expected-note {{use __bridge}} expected-note {{use CFBridgingRetain call}}
}
void test12(id collection) {
for (id x in collection) {
x = 0;
}
for (__strong id x in collection) {
x = 0;
}
}
void test6(unsigned cond) {
switch (cond) {
case 0:
;
id x; // expected-note {{jump bypasses initialization of retaining variable}}
case 1: // expected-error {{switch case is in protected scope}}
x = 0;
break;
}
}
@class Test8_incomplete;
@interface Test8_complete @end;
@interface Test8_super @end;
@interface Test8 : Test8_super
- (id) init00;
- (id) init01; // expected-note {{declaration in interface}}
- (id) init02;
- (id) init03; // covariance
- (id) init04; // covariance
- (id) init05;
- (void) init10; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
- (void) init11;
- (void) init12;
- (void) init13; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
- (void) init14; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
- (void) init15;
// These should be invalid to actually call.
- (Test8_incomplete*) init20;
- (Test8_incomplete*) init21; // expected-note {{declaration in interface}}
- (Test8_incomplete*) init22;
- (Test8_incomplete*) init23;
- (Test8_incomplete*) init24;
- (Test8_incomplete*) init25;
- (Test8_super*) init30; // id exception to covariance
- (Test8_super*) init31; // expected-note {{declaration in interface}}
- (Test8_super*) init32;
- (Test8_super*) init33;
- (Test8_super*) init34; // covariance
- (Test8_super*) init35;
- (Test8*) init40; // id exception to covariance
- (Test8*) init41; // expected-note {{declaration in interface}}
- (Test8*) init42;
- (Test8*) init43; // this should be a warning, but that's a general language thing, not an ARC thing
- (Test8*) init44;
- (Test8*) init45;
- (Test8_complete*) init50; // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_complete*) init51; // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_complete*) init52; // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_complete*) init53; // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_complete*) init54; // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_complete*) init55; // expected-error {{init methods must return a type related to the receiver type}}
@end
@implementation Test8
- (id) init00 { return 0; }
- (id) init10 { return 0; } // expected-error {{method implementation does not match its declaration}}
- (id) init20 { return 0; }
- (id) init30 { return 0; }
- (id) init40 { return 0; }
- (id) init50 { return 0; }
- (void) init01 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
- (void) init11 {}
- (void) init21 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
- (void) init31 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
- (void) init41 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
- (void) init51 {}
- (Test8_incomplete*) init02 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_incomplete*) init12 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_incomplete*) init22 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_incomplete*) init32 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_incomplete*) init42 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_incomplete*) init52 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_super*) init03 { return 0; }
- (Test8_super*) init13 { return 0; } // expected-error {{method implementation does not match its declaration}}
- (Test8_super*) init23 { return 0; }
- (Test8_super*) init33 { return 0; }
- (Test8_super*) init43 { return 0; }
- (Test8_super*) init53 { return 0; }
- (Test8*) init04 { return 0; }
- (Test8*) init14 { return 0; } // expected-error {{method implementation does not match its declaration}}
- (Test8*) init24 { return 0; }
- (Test8*) init34 { return 0; }
- (Test8*) init44 { return 0; }
- (Test8*) init54 { return 0; }
- (Test8_complete*) init05 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_complete*) init15 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_complete*) init25 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_complete*) init35 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_complete*) init45 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
- (Test8_complete*) init55 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
@end
@class Test9_incomplete;
@interface Test9
- (Test9_incomplete*) init1; // expected-error {{init methods must return a type related to the receiver type}}
- (Test9_incomplete*) init2;
@end
id test9(Test9 *v) {
return [v init1];
}
// rdar://9491791
void rdar9491791(int p) {
switch (p) {
case 3:;
NSObject *o = [[NSObject alloc] init];
[o release];
break;
default:
break;
}
}
#define RELEASE_MACRO(x) do { [x release]; } while(1)
// rdar://9504750
void rdar9504750(id p) {
RELEASE_MACRO(p); // expected-error {{ARC forbids explicit message send of 'release'}}
}
// rdar://8939557
@interface TestReadonlyProperty : NSObject
@property(assign,readonly) NSObject *value;
@end
@implementation TestReadonlyProperty
@synthesize value;
- (void)viewDidLoad {
value = [NSObject new]; // expected-error {{assigning retained object}}
}
@end
// rdar://9601437
@interface I9601437 {
__unsafe_unretained id x;
}
-(void)Meth;
@end
@implementation I9601437
-(void)Meth {
self->x = [NSObject new]; // expected-error {{assigning retained object}}
}
@end
@interface Test10 : NSObject {
CFStringRef cfstr;
}
@property (retain) id prop;
-(void)foo;
@end
void test(Test10 *x) {
x.prop = ^{ [x foo]; }; // expected-warning {{likely to lead to a retain cycle}} \
// expected-note {{retained by the captured object}}
}
@implementation Test10
-(void)foo {
^{
NSString *str = (NSString *)cfstr; // expected-error {{cast of C pointer type 'CFStringRef' (aka 'const struct __CFString *') to Objective-C pointer type 'NSString *' requires a bridged cast}} \
// expected-note {{use __bridge to convert directly (no change in ownership)}} \
// expected-note {{use CFBridgingRelease call to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}}
};
}
@end