[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