[arcmt] Emit an error for unused -autorelease messages.

An unused autorelease is badness. If we remove it the receiver
will likely die immediately while previously it was kept alive
by the autorelease pool. This is bad practice in general, so leave it
and emit an error to force the user to restructure his code.

rdar://9599884

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@135193 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Argyrios Kyrtzidis 2011-07-14 21:26:49 +00:00
Родитель ac420c5053
Коммит e0e40768cc
5 изменённых файлов: 21 добавлений и 8 удалений

Просмотреть файл

@ -52,14 +52,26 @@ public:
switch (E->getMethodFamily()) { switch (E->getMethodFamily()) {
default: default:
return true; return true;
case OMF_autorelease:
if (isRemovable(E)) {
// An unused autorelease is badness. If we remove it the receiver
// will likely die immediately while previously it was kept alive
// by the autorelease pool. This is bad practice in general, leave it
// and emit an error to force the user to restructure his code.
std::string err = "it is not safe to remove an unused '";
err += E->getSelector().getAsString() + "'; its receiver may be "
"destroyed immediately";
Pass.TA.reportError(err, E->getLocStart(), E->getSourceRange());
return true;
}
// Pass through.
case OMF_retain: case OMF_retain:
case OMF_release: case OMF_release:
case OMF_autorelease:
if (E->getReceiverKind() == ObjCMessageExpr::Instance) if (E->getReceiverKind() == ObjCMessageExpr::Instance)
if (Expr *rec = E->getInstanceReceiver()) { if (Expr *rec = E->getInstanceReceiver()) {
rec = rec->IgnoreParenImpCasts(); rec = rec->IgnoreParenImpCasts();
if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone){ if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone){
std::string err = "It is not safe to remove '"; std::string err = "it is not safe to remove '";
err += E->getSelector().getAsString() + "' message on " err += E->getSelector().getAsString() + "' message on "
"an __unsafe_unretained type"; "an __unsafe_unretained type";
Pass.TA.reportError(err, rec->getLocStart()); Pass.TA.reportError(err, rec->getLocStart());

Просмотреть файл

@ -37,13 +37,14 @@ struct UnsafeS {
@end @end
void test1(A *a, BOOL b, struct UnsafeS *unsafeS) { void test1(A *a, BOOL b, struct UnsafeS *unsafeS) {
[unsafeS->unsafeObj retain]; // expected-error {{It is not safe to remove 'retain' message on an __unsafe_unretained type}} \ [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 {{ARC forbids explicit message send}}
[a dealloc]; [a dealloc];
[a retain]; [a retain];
[a retainCount]; // expected-error {{ARC forbids explicit message send of 'retainCount'}} [a retainCount]; // expected-error {{ARC forbids explicit message send of 'retainCount'}}
[a release]; [a release];
[a autorelease]; [a autorelease]; // expected-error {{it is not safe to remove an unused 'autorelease'; its receiver may be destroyed immediately}} \
// expected-error {{ARC forbids explicit message send}}
CFStringRef cfstr; 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}} \ 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}} \

Просмотреть файл

@ -12,7 +12,7 @@ struct foo {
NSString *s; NSString *s;
foo(NSString *s): s([s retain]){ foo(NSString *s): s([s retain]){
NSAutoreleasePool *pool = [NSAutoreleasePool new]; NSAutoreleasePool *pool = [NSAutoreleasePool new];
[[NSString string] autorelease]; [[[NSString string] retain] release];
[pool drain]; [pool drain];
} }
~foo(){ [s release]; } ~foo(){ [s release]; }

Просмотреть файл

@ -13,7 +13,7 @@
@implementation myController @implementation myController
-(id) test:(id) x { -(id) test:(id) x {
[[x retain] autorelease]; [[x retain] release];
return [[x retain] autorelease]; return [[x retain] autorelease];
} }

Просмотреть файл

@ -38,8 +38,8 @@ id IhaveSideEffect();
[[self retain] something]; [[self retain] something];
[[IhaveSideEffect() retain] autorelease]; [[IhaveSideEffect() retain] release];
[[x retain] autorelease]; [[x retain] release];
// do stuff with x; // do stuff with x;
[x release]; [x release];
return [self retain]; return [self retain];