[cfe-commits] r135327 - in /cfe/trunk: lib/ARCMigrate/TransRetainReleaseDealloc.cpp test/ARCMT/checking.m
Argyrios Kyrtzidis
akyrtzi at gmail.com
Fri Jul 15 16:48:57 PDT 2011
Author: akirtzidis
Date: Fri Jul 15 18:48:56 2011
New Revision: 135327
URL: http://llvm.org/viewvc/llvm-project?rev=135327&view=rev
Log:
[arcmt] It's not safe to remove the -release on "[[someivar delegate] release];" since it's very likely
that, after migration, the object that was passed to 'setDelegate:' will not be properly retained, e.g:
-whatever {
id x = [[MyDoHicky alloc] init];
[someivar setDelegate: x]; // x won't get retained in ARC.
}
-dealloc {
[[someivar delegate] release]; // give migration error here.
}
rdar://8858009
Modified:
cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
cfe/trunk/test/ARCMT/checking.m
Modified: cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp?rev=135327&r1=135326&r2=135327&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp (original)
+++ cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp Fri Jul 15 18:48:56 2011
@@ -19,9 +19,7 @@
#include "Transforms.h"
#include "Internals.h"
-#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/AST/ParentMap.h"
using namespace clang;
@@ -39,9 +37,14 @@
ExprSet Removables;
llvm::OwningPtr<ParentMap> StmtMap;
+ Selector DelegateSel;
+
public:
RetainReleaseDeallocRemover(MigrationPass &pass)
- : Body(0), Pass(pass) { }
+ : Body(0), Pass(pass) {
+ DelegateSel =
+ Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("delegate"));
+ }
void transformBody(Stmt *body) {
Body = body;
@@ -60,10 +63,9 @@
// 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());
+ Pass.TA.reportError("it is not safe to remove an unused 'autorelease' "
+ "message; its receiver may be destroyed immediately",
+ E->getLocStart(), E->getSourceRange());
return true;
}
// Pass through.
@@ -89,6 +91,14 @@
Pass.TA.reportError(err, rec->getLocStart());
return true;
}
+
+ if (E->getMethodFamily() == OMF_release && isDelegateMessage(rec)) {
+ Pass.TA.reportError("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", rec->getLocStart());
+ return true;
+ }
}
case OMF_dealloc:
break;
@@ -120,8 +130,7 @@
// Change the -release to "receiver = nil" in a finally to avoid a leak
// when an exception is thrown.
Pass.TA.replace(E->getSourceRange(), rec->getSourceRange());
- if (Pass.SemaRef.getPreprocessor()
- .getIdentifierInfo("nil")->hasMacroDefinition())
+ if (Pass.Ctx.Idents.get("nil").hasMacroDefinition())
Pass.TA.insertAfterToken(rec->getLocEnd(), " = nil");
else
Pass.TA.insertAfterToken(rec->getLocEnd(), " = 0");
@@ -145,6 +154,19 @@
loc);
}
+ bool isDelegateMessage(Expr *E) const {
+ if (!E) return false;
+
+ E = E->IgnoreParenCasts();
+ if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
+ return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
+
+ if (ObjCPropertyRefExpr *propE = dyn_cast<ObjCPropertyRefExpr>(E))
+ return propE->getGetterSelector() == DelegateSel;
+
+ return false;
+ }
+
bool isInAtFinally(Expr *E) const {
assert(E);
Stmt *S = E;
Modified: cfe/trunk/test/ARCMT/checking.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/checking.m?rev=135327&r1=135326&r2=135327&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/checking.m (original)
+++ cfe/trunk/test/ARCMT/checking.m Fri Jul 15 18:48:56 2011
@@ -20,6 +20,7 @@
- (oneway void)release;
- (void)dealloc;
-(void)test;
+-(id)delegate;
@end
@implementation A
@@ -34,11 +35,17 @@
- (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}}
id foo = [unsafeS->unsafeObj retain]; // no warning.
@@ -50,7 +57,7 @@
[a retain];
[a retainCount]; // expected-error {{ARC forbids explicit message send of 'retainCount'}}
[a release];
- [a autorelease]; // expected-error {{it is not safe to remove an unused 'autorelease'; its receiver may be destroyed immediately}} \
+ [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}}
CFStringRef cfstr;
More information about the cfe-commits
mailing list