1*67e74705SXin Li //===--- TransBlockObjCVariable.cpp - Transformations to ARC mode ---------===// 2*67e74705SXin Li // 3*67e74705SXin Li // The LLVM Compiler Infrastructure 4*67e74705SXin Li // 5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source 6*67e74705SXin Li // License. See LICENSE.TXT for details. 7*67e74705SXin Li // 8*67e74705SXin Li //===----------------------------------------------------------------------===// 9*67e74705SXin Li // 10*67e74705SXin Li // rewriteBlockObjCVariable: 11*67e74705SXin Li // 12*67e74705SXin Li // Adding __block to an obj-c variable could be either because the variable 13*67e74705SXin Li // is used for output storage or the user wanted to break a retain cycle. 14*67e74705SXin Li // This transformation checks whether a reference of the variable for the block 15*67e74705SXin Li // is actually needed (it is assigned to or its address is taken) or not. 16*67e74705SXin Li // If the reference is not needed it will assume __block was added to break a 17*67e74705SXin Li // cycle so it will remove '__block' and add __weak/__unsafe_unretained. 18*67e74705SXin Li // e.g 19*67e74705SXin Li // 20*67e74705SXin Li // __block Foo *x; 21*67e74705SXin Li // bar(^ { [x cake]; }); 22*67e74705SXin Li // ----> 23*67e74705SXin Li // __weak Foo *x; 24*67e74705SXin Li // bar(^ { [x cake]; }); 25*67e74705SXin Li // 26*67e74705SXin Li //===----------------------------------------------------------------------===// 27*67e74705SXin Li 28*67e74705SXin Li #include "Transforms.h" 29*67e74705SXin Li #include "Internals.h" 30*67e74705SXin Li #include "clang/AST/ASTContext.h" 31*67e74705SXin Li #include "clang/AST/Attr.h" 32*67e74705SXin Li #include "clang/Basic/SourceManager.h" 33*67e74705SXin Li 34*67e74705SXin Li using namespace clang; 35*67e74705SXin Li using namespace arcmt; 36*67e74705SXin Li using namespace trans; 37*67e74705SXin Li 38*67e74705SXin Li namespace { 39*67e74705SXin Li 40*67e74705SXin Li class RootBlockObjCVarRewriter : 41*67e74705SXin Li public RecursiveASTVisitor<RootBlockObjCVarRewriter> { 42*67e74705SXin Li llvm::DenseSet<VarDecl *> &VarsToChange; 43*67e74705SXin Li 44*67e74705SXin Li class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> { 45*67e74705SXin Li VarDecl *Var; 46*67e74705SXin Li 47*67e74705SXin Li typedef RecursiveASTVisitor<BlockVarChecker> base; 48*67e74705SXin Li public: BlockVarChecker(VarDecl * var)49*67e74705SXin Li BlockVarChecker(VarDecl *var) : Var(var) { } 50*67e74705SXin Li TraverseImplicitCastExpr(ImplicitCastExpr * castE)51*67e74705SXin Li bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) { 52*67e74705SXin Li if (DeclRefExpr * 53*67e74705SXin Li ref = dyn_cast<DeclRefExpr>(castE->getSubExpr())) { 54*67e74705SXin Li if (ref->getDecl() == Var) { 55*67e74705SXin Li if (castE->getCastKind() == CK_LValueToRValue) 56*67e74705SXin Li return true; // Using the value of the variable. 57*67e74705SXin Li if (castE->getCastKind() == CK_NoOp && castE->isLValue() && 58*67e74705SXin Li Var->getASTContext().getLangOpts().CPlusPlus) 59*67e74705SXin Li return true; // Binding to const C++ reference. 60*67e74705SXin Li } 61*67e74705SXin Li } 62*67e74705SXin Li 63*67e74705SXin Li return base::TraverseImplicitCastExpr(castE); 64*67e74705SXin Li } 65*67e74705SXin Li VisitDeclRefExpr(DeclRefExpr * E)66*67e74705SXin Li bool VisitDeclRefExpr(DeclRefExpr *E) { 67*67e74705SXin Li if (E->getDecl() == Var) 68*67e74705SXin Li return false; // The reference of the variable, and not just its value, 69*67e74705SXin Li // is needed. 70*67e74705SXin Li return true; 71*67e74705SXin Li } 72*67e74705SXin Li }; 73*67e74705SXin Li 74*67e74705SXin Li public: RootBlockObjCVarRewriter(llvm::DenseSet<VarDecl * > & VarsToChange)75*67e74705SXin Li RootBlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange) 76*67e74705SXin Li : VarsToChange(VarsToChange) { } 77*67e74705SXin Li VisitBlockDecl(BlockDecl * block)78*67e74705SXin Li bool VisitBlockDecl(BlockDecl *block) { 79*67e74705SXin Li SmallVector<VarDecl *, 4> BlockVars; 80*67e74705SXin Li 81*67e74705SXin Li for (const auto &I : block->captures()) { 82*67e74705SXin Li VarDecl *var = I.getVariable(); 83*67e74705SXin Li if (I.isByRef() && 84*67e74705SXin Li var->getType()->isObjCObjectPointerType() && 85*67e74705SXin Li isImplicitStrong(var->getType())) { 86*67e74705SXin Li BlockVars.push_back(var); 87*67e74705SXin Li } 88*67e74705SXin Li } 89*67e74705SXin Li 90*67e74705SXin Li for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) { 91*67e74705SXin Li VarDecl *var = BlockVars[i]; 92*67e74705SXin Li 93*67e74705SXin Li BlockVarChecker checker(var); 94*67e74705SXin Li bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody()); 95*67e74705SXin Li if (onlyValueOfVarIsNeeded) 96*67e74705SXin Li VarsToChange.insert(var); 97*67e74705SXin Li else 98*67e74705SXin Li VarsToChange.erase(var); 99*67e74705SXin Li } 100*67e74705SXin Li 101*67e74705SXin Li return true; 102*67e74705SXin Li } 103*67e74705SXin Li 104*67e74705SXin Li private: isImplicitStrong(QualType ty)105*67e74705SXin Li bool isImplicitStrong(QualType ty) { 106*67e74705SXin Li if (isa<AttributedType>(ty.getTypePtr())) 107*67e74705SXin Li return false; 108*67e74705SXin Li return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong; 109*67e74705SXin Li } 110*67e74705SXin Li }; 111*67e74705SXin Li 112*67e74705SXin Li class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> { 113*67e74705SXin Li llvm::DenseSet<VarDecl *> &VarsToChange; 114*67e74705SXin Li 115*67e74705SXin Li public: BlockObjCVarRewriter(llvm::DenseSet<VarDecl * > & VarsToChange)116*67e74705SXin Li BlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange) 117*67e74705SXin Li : VarsToChange(VarsToChange) { } 118*67e74705SXin Li TraverseBlockDecl(BlockDecl * block)119*67e74705SXin Li bool TraverseBlockDecl(BlockDecl *block) { 120*67e74705SXin Li RootBlockObjCVarRewriter(VarsToChange).TraverseDecl(block); 121*67e74705SXin Li return true; 122*67e74705SXin Li } 123*67e74705SXin Li }; 124*67e74705SXin Li 125*67e74705SXin Li } // anonymous namespace 126*67e74705SXin Li traverseBody(BodyContext & BodyCtx)127*67e74705SXin Livoid BlockObjCVariableTraverser::traverseBody(BodyContext &BodyCtx) { 128*67e74705SXin Li MigrationPass &Pass = BodyCtx.getMigrationContext().Pass; 129*67e74705SXin Li llvm::DenseSet<VarDecl *> VarsToChange; 130*67e74705SXin Li 131*67e74705SXin Li BlockObjCVarRewriter trans(VarsToChange); 132*67e74705SXin Li trans.TraverseStmt(BodyCtx.getTopStmt()); 133*67e74705SXin Li 134*67e74705SXin Li for (llvm::DenseSet<VarDecl *>::iterator 135*67e74705SXin Li I = VarsToChange.begin(), E = VarsToChange.end(); I != E; ++I) { 136*67e74705SXin Li VarDecl *var = *I; 137*67e74705SXin Li BlocksAttr *attr = var->getAttr<BlocksAttr>(); 138*67e74705SXin Li if(!attr) 139*67e74705SXin Li continue; 140*67e74705SXin Li bool useWeak = canApplyWeak(Pass.Ctx, var->getType()); 141*67e74705SXin Li SourceManager &SM = Pass.Ctx.getSourceManager(); 142*67e74705SXin Li Transaction Trans(Pass.TA); 143*67e74705SXin Li Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()), 144*67e74705SXin Li "__block", 145*67e74705SXin Li useWeak ? "__weak" : "__unsafe_unretained"); 146*67e74705SXin Li } 147*67e74705SXin Li } 148