aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/ARCMigrate/TransUnbridgedCasts.cpp97
-rw-r--r--test/ARCMT/Common.h6
-rw-r--r--test/ARCMT/block_copy_release.m17
-rw-r--r--test/ARCMT/block_copy_release.m.result15
4 files changed, 126 insertions, 9 deletions
diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp
index 55518d1266..3c77f2e6b3 100644
--- a/lib/ARCMigrate/TransUnbridgedCasts.cpp
+++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp
@@ -30,6 +30,14 @@
// ---->
// 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);
diff --git a/test/ARCMT/Common.h b/test/ARCMT/Common.h
index ed48949702..b388ecab74 100644
--- a/test/ARCMT/Common.h
+++ b/test/ARCMT/Common.h
@@ -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
index 0000000000..ae3b82660a
--- /dev/null
+++ b/test/ARCMT/block_copy_release.m
@@ -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
index 0000000000..b292b64f17
--- /dev/null
+++ b/test/ARCMT/block_copy_release.m.result
@@ -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];
+}