From: Argyrios Kyrtzidis Date: Thu, 3 Jan 2013 03:17:17 +0000 (+0000) Subject: [arcmt] Rewrite uses of Block_copy/Block_release macros. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5d2faa41bc63a2a29535ae3dbbc99daabf14ea2f;p=clang [arcmt] Rewrite uses of Block_copy/Block_release macros. c = Block_copy(b); Block_release(c); ----> c = [b copy]; rdar://9408211 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@171454 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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]; +// +// //===----------------------------------------------------------------------===// #include "Transforms.h" @@ -54,32 +62,32 @@ class UnbridgedCastRewriter : public RecursiveASTVisitor{ IdentifierInfo *SelfII; OwningPtr StmtMap; Decl *ParentD; + Stmt *Body; + mutable OwningPtr 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(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]; +}