зеркало из https://github.com/microsoft/clang-1.git
[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:
Родитель
ac420c5053
Коммит
e0e40768cc
|
@ -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];
|
||||||
|
|
Загрузка…
Ссылка в новой задаче