]> granicus.if.org Git - clang/commitdiff
[arcmt] Rewrite uses of Block_copy/Block_release macros.
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 3 Jan 2013 03:17:17 +0000 (03:17 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 3 Jan 2013 03:17:17 +0000 (03:17 +0000)
  c = Block_copy(b);
  Block_release(c);
 ---->
  c = [b copy];
  <removed>

rdar://9408211

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@171454 91177308-0d34-0410-b5e6-96231b3b80d8

lib/ARCMigrate/TransUnbridgedCasts.cpp
test/ARCMT/Common.h
test/ARCMT/block_copy_release.m [new file with mode: 0644]
test/ARCMT/block_copy_release.m.result [new file with mode: 0644]

index 55518d12666b5784c28acb49ec6049788a499f0f..3c77f2e6b3d52dc91f83d72e13467b92c1e8aa37 100644 (file)
 // ---->
 //  CFStringRef str = (__bridge CFStringRef)self;
 //
+// Uses of Block_copy/Block_release macros are rewritten:
+//
+//  c = Block_copy(b);
+//  Block_release(c);
+// ---->
+//  c = [b copy];
+//  <removed>
+//
 //===----------------------------------------------------------------------===//
 
 #include "Transforms.h"
@@ -54,32 +62,32 @@ class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
   IdentifierInfo *SelfII;
   OwningPtr<ParentMap> StmtMap;
   Decl *ParentD;
+  Stmt *Body;
+  mutable OwningPtr<ExprSet> Removables;
 
 public:
-  UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0) {
+  UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0), Body(0) {
     SelfII = &Pass.Ctx.Idents.get("self");
   }
 
   void transformBody(Stmt *body, Decl *ParentD) {
     this->ParentD = ParentD;
+    Body = body;
     StmtMap.reset(new ParentMap(body));
     TraverseStmt(body);
   }
 
   bool VisitCastExpr(CastExpr *E) {
-    if (E->getCastKind() != CK_CPointerToObjCPointerCast
-        && E->getCastKind() != CK_BitCast)
+    if (E->getCastKind() != CK_CPointerToObjCPointerCast &&
+        E->getCastKind() != CK_BitCast &&
+        E->getCastKind() != CK_AnyPointerToBlockPointerCast)
       return true;
 
     QualType castType = E->getType();
     Expr *castExpr = E->getSubExpr();
     QualType castExprType = castExpr->getType();
 
-    if (castType->isObjCObjectPointerType() &&
-        castExprType->isObjCObjectPointerType())
-      return true;
-    if (!castType->isObjCObjectPointerType() &&
-        !castExprType->isObjCObjectPointerType())
+    if (castType->isObjCRetainableType() == castExprType->isObjCRetainableType())
       return true;
     
     bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
@@ -94,7 +102,7 @@ public:
     if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
       return true;
 
-    if (castType->isObjCObjectPointerType())
+    if (castType->isObjCRetainableType())
       transformNonObjCToObjCCast(E);
     else
       transformObjCToNonObjCCast(E);
@@ -263,7 +271,78 @@ private:
     rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
   }
 
+  void getBlockMacroRanges(CastExpr *E, SourceRange &Outer, SourceRange &Inner) {
+    SourceManager &SM = Pass.Ctx.getSourceManager();
+    SourceLocation Loc = E->getExprLoc();
+    assert(Loc.isMacroID());
+    SourceLocation MacroBegin, MacroEnd;
+    llvm::tie(MacroBegin, MacroEnd) = SM.getImmediateExpansionRange(Loc);
+    SourceRange SubRange = E->getSubExpr()->IgnoreParenImpCasts()->getSourceRange();
+    SourceLocation InnerBegin = SM.getImmediateMacroCallerLoc(SubRange.getBegin());
+    SourceLocation InnerEnd = SM.getImmediateMacroCallerLoc(SubRange.getEnd());
+
+    Outer = SourceRange(MacroBegin, MacroEnd);
+    Inner = SourceRange(InnerBegin, InnerEnd);
+  }
+
+  void rewriteBlockCopyMacro(CastExpr *E) {
+    SourceRange OuterRange, InnerRange;
+    getBlockMacroRanges(E, OuterRange, InnerRange);
+
+    Transaction Trans(Pass.TA);
+    Pass.TA.replace(OuterRange, InnerRange);
+    Pass.TA.insert(InnerRange.getBegin(), "[");
+    Pass.TA.insertAfterToken(InnerRange.getEnd(), " copy]");
+    Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
+                            diag::err_arc_cast_requires_bridge,
+                            OuterRange);
+  }
+
+  void removeBlockReleaseMacro(CastExpr *E) {
+    SourceRange OuterRange, InnerRange;
+    getBlockMacroRanges(E, OuterRange, InnerRange);
+
+    Transaction Trans(Pass.TA);
+    Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
+                            diag::err_arc_cast_requires_bridge,
+                            OuterRange);
+    if (!hasSideEffects(E, Pass.Ctx)) {
+      if (tryRemoving(cast<Expr>(StmtMap->getParentIgnoreParenCasts(E))))
+        return;
+    }
+    Pass.TA.replace(OuterRange, InnerRange);
+  }
+
+  bool tryRemoving(Expr *E) const {
+    if (!Removables) {
+      Removables.reset(new ExprSet);
+      collectRemovables(Body, *Removables);
+    }
+
+    if (Removables->count(E)) {
+      Pass.TA.removeStmt(E);
+      return true;
+    }
+
+    return false;
+  }
+
   void transformObjCToNonObjCCast(CastExpr *E) {
+    SourceLocation CastLoc = E->getExprLoc();
+    if (CastLoc.isMacroID()) {
+      StringRef MacroName = Lexer::getImmediateMacroName(CastLoc,
+                                                    Pass.Ctx.getSourceManager(),
+                                                    Pass.Ctx.getLangOpts());
+      if (MacroName == "Block_copy") {
+        rewriteBlockCopyMacro(E);
+        return;
+      }
+      if (MacroName == "Block_release") {
+        removeBlockReleaseMacro(E);
+        return;
+      }
+    }
+
     if (isSelf(E->getSubExpr()))
       return rewriteToBridgedCast(E, OBC_Bridge);
 
index ed48949702472c189717339ce7360831a830a78c..b388ecab741097ab5881ef4a51e85ebe85b0cef7 100644 (file)
@@ -10,6 +10,7 @@
 
 #define NS_INLINE static __inline__ __attribute__((always_inline))
 #define nil ((void*) 0)
+#define NULL ((void*)0)
 
 typedef int BOOL;
 typedef unsigned NSUInteger;
@@ -102,3 +103,8 @@ NS_INLINE id CFBridgingRelease(CFTypeRef CF_CONSUMED X) {
 }
 
 #endif
+
+void *_Block_copy(const void *aBlock);
+void _Block_release(const void *aBlock);
+#define Block_copy(...) ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__)))
+#define Block_release(...) _Block_release((const void *)(__VA_ARGS__))
diff --git a/test/ARCMT/block_copy_release.m b/test/ARCMT/block_copy_release.m
new file mode 100644 (file)
index 0000000..ae3b826
--- /dev/null
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+typedef void (^blk)(int);
+
+void func(blk b) {
+  blk c = Block_copy(b);
+  Block_release(c);
+}
+
+void func2(id b) {
+  id c = Block_copy(b);
+  Block_release(c);
+}
diff --git a/test/ARCMT/block_copy_release.m.result b/test/ARCMT/block_copy_release.m.result
new file mode 100644 (file)
index 0000000..b292b64
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+typedef void (^blk)(int);
+
+void func(blk b) {
+  blk c = [b copy];
+}
+
+void func2(id b) {
+  id c = [b copy];
+}