[arcmt] Rewrite uses of Block_copy/Block_release macros.

c = Block_copy(b);
  Block_release(c);
 ---->
  c = [b copy];
  <removed>

rdar://9408211

llvm-svn: 171454
This commit is contained in:
Argyrios Kyrtzidis 2013-01-03 03:17:17 +00:00
parent 95de3f3018
commit 6ba7afb8e1
4 changed files with 126 additions and 9 deletions

View File

@ -30,6 +30,14 @@
// ----> // ---->
// CFStringRef str = (__bridge CFStringRef)self; // 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" #include "Transforms.h"
@ -54,32 +62,32 @@ class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
IdentifierInfo *SelfII; IdentifierInfo *SelfII;
OwningPtr<ParentMap> StmtMap; OwningPtr<ParentMap> StmtMap;
Decl *ParentD; Decl *ParentD;
Stmt *Body;
mutable OwningPtr<ExprSet> Removables;
public: public:
UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0) { UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0), Body(0) {
SelfII = &Pass.Ctx.Idents.get("self"); SelfII = &Pass.Ctx.Idents.get("self");
} }
void transformBody(Stmt *body, Decl *ParentD) { void transformBody(Stmt *body, Decl *ParentD) {
this->ParentD = ParentD; this->ParentD = ParentD;
Body = body;
StmtMap.reset(new ParentMap(body)); StmtMap.reset(new ParentMap(body));
TraverseStmt(body); TraverseStmt(body);
} }
bool VisitCastExpr(CastExpr *E) { bool VisitCastExpr(CastExpr *E) {
if (E->getCastKind() != CK_CPointerToObjCPointerCast if (E->getCastKind() != CK_CPointerToObjCPointerCast &&
&& E->getCastKind() != CK_BitCast) E->getCastKind() != CK_BitCast &&
E->getCastKind() != CK_AnyPointerToBlockPointerCast)
return true; return true;
QualType castType = E->getType(); QualType castType = E->getType();
Expr *castExpr = E->getSubExpr(); Expr *castExpr = E->getSubExpr();
QualType castExprType = castExpr->getType(); QualType castExprType = castExpr->getType();
if (castType->isObjCObjectPointerType() && if (castType->isObjCRetainableType() == castExprType->isObjCRetainableType())
castExprType->isObjCObjectPointerType())
return true;
if (!castType->isObjCObjectPointerType() &&
!castExprType->isObjCObjectPointerType())
return true; return true;
bool exprRetainable = castExprType->isObjCIndirectLifetimeType(); bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
@ -94,7 +102,7 @@ public:
if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc)) if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
return true; return true;
if (castType->isObjCObjectPointerType()) if (castType->isObjCRetainableType())
transformNonObjCToObjCCast(E); transformNonObjCToObjCCast(E);
else else
transformObjCToNonObjCCast(E); transformObjCToNonObjCCast(E);
@ -263,7 +271,78 @@ private:
rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans); 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) { 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())) if (isSelf(E->getSubExpr()))
return rewriteToBridgedCast(E, OBC_Bridge); return rewriteToBridgedCast(E, OBC_Bridge);

View File

@ -10,6 +10,7 @@
#define NS_INLINE static __inline__ __attribute__((always_inline)) #define NS_INLINE static __inline__ __attribute__((always_inline))
#define nil ((void*) 0) #define nil ((void*) 0)
#define NULL ((void*)0)
typedef int BOOL; typedef int BOOL;
typedef unsigned NSUInteger; typedef unsigned NSUInteger;
@ -102,3 +103,8 @@ NS_INLINE id CFBridgingRelease(CFTypeRef CF_CONSUMED X) {
} }
#endif #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__))

View File

@ -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);
}

View File

@ -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];
}