1249423Sdim//===--- TransBlockObjCVariable.cpp - Transformations to ARC mode ---------===// 2224135Sdim// 3224135Sdim// The LLVM Compiler Infrastructure 4224135Sdim// 5224135Sdim// This file is distributed under the University of Illinois Open Source 6224135Sdim// License. See LICENSE.TXT for details. 7224135Sdim// 8224135Sdim//===----------------------------------------------------------------------===// 9224135Sdim// 10224135Sdim// rewriteBlockObjCVariable: 11224135Sdim// 12239462Sdim// Adding __block to an obj-c variable could be either because the variable 13224135Sdim// is used for output storage or the user wanted to break a retain cycle. 14224135Sdim// This transformation checks whether a reference of the variable for the block 15224135Sdim// is actually needed (it is assigned to or its address is taken) or not. 16224135Sdim// If the reference is not needed it will assume __block was added to break a 17224135Sdim// cycle so it will remove '__block' and add __weak/__unsafe_unretained. 18224135Sdim// e.g 19224135Sdim// 20224135Sdim// __block Foo *x; 21224135Sdim// bar(^ { [x cake]; }); 22224135Sdim// ----> 23224135Sdim// __weak Foo *x; 24224135Sdim// bar(^ { [x cake]; }); 25224135Sdim// 26224135Sdim//===----------------------------------------------------------------------===// 27224135Sdim 28224135Sdim#include "Transforms.h" 29224135Sdim#include "Internals.h" 30239462Sdim#include "clang/AST/ASTContext.h" 31249423Sdim#include "clang/AST/Attr.h" 32224135Sdim#include "clang/Basic/SourceManager.h" 33224135Sdim 34224135Sdimusing namespace clang; 35224135Sdimusing namespace arcmt; 36224135Sdimusing namespace trans; 37224135Sdim 38224135Sdimnamespace { 39224135Sdim 40224135Sdimclass RootBlockObjCVarRewriter : 41224135Sdim public RecursiveASTVisitor<RootBlockObjCVarRewriter> { 42234353Sdim llvm::DenseSet<VarDecl *> &VarsToChange; 43224135Sdim 44224135Sdim class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> { 45224135Sdim VarDecl *Var; 46224135Sdim 47224135Sdim typedef RecursiveASTVisitor<BlockVarChecker> base; 48224135Sdim public: 49224135Sdim BlockVarChecker(VarDecl *var) : Var(var) { } 50224135Sdim 51224135Sdim bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) { 52234353Sdim if (DeclRefExpr * 53234353Sdim ref = dyn_cast<DeclRefExpr>(castE->getSubExpr())) { 54224135Sdim if (ref->getDecl() == Var) { 55224135Sdim if (castE->getCastKind() == CK_LValueToRValue) 56224135Sdim return true; // Using the value of the variable. 57224135Sdim if (castE->getCastKind() == CK_NoOp && castE->isLValue() && 58234353Sdim Var->getASTContext().getLangOpts().CPlusPlus) 59224135Sdim return true; // Binding to const C++ reference. 60224135Sdim } 61224135Sdim } 62224135Sdim 63224135Sdim return base::TraverseImplicitCastExpr(castE); 64224135Sdim } 65224135Sdim 66234353Sdim bool VisitDeclRefExpr(DeclRefExpr *E) { 67224135Sdim if (E->getDecl() == Var) 68224135Sdim return false; // The reference of the variable, and not just its value, 69224135Sdim // is needed. 70224135Sdim return true; 71224135Sdim } 72224135Sdim }; 73224135Sdim 74224135Sdimpublic: 75239462Sdim RootBlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange) 76239462Sdim : VarsToChange(VarsToChange) { } 77224135Sdim 78224135Sdim bool VisitBlockDecl(BlockDecl *block) { 79226633Sdim SmallVector<VarDecl *, 4> BlockVars; 80224135Sdim 81224135Sdim for (BlockDecl::capture_iterator 82224135Sdim I = block->capture_begin(), E = block->capture_end(); I != E; ++I) { 83224135Sdim VarDecl *var = I->getVariable(); 84224135Sdim if (I->isByRef() && 85224135Sdim var->getType()->isObjCObjectPointerType() && 86224135Sdim isImplicitStrong(var->getType())) { 87224135Sdim BlockVars.push_back(var); 88224135Sdim } 89224135Sdim } 90224135Sdim 91224135Sdim for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) { 92224135Sdim VarDecl *var = BlockVars[i]; 93224135Sdim 94224135Sdim BlockVarChecker checker(var); 95224135Sdim bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody()); 96234353Sdim if (onlyValueOfVarIsNeeded) 97234353Sdim VarsToChange.insert(var); 98234353Sdim else 99234353Sdim VarsToChange.erase(var); 100224135Sdim } 101224135Sdim 102224135Sdim return true; 103224135Sdim } 104224135Sdim 105224135Sdimprivate: 106224135Sdim bool isImplicitStrong(QualType ty) { 107224135Sdim if (isa<AttributedType>(ty.getTypePtr())) 108224135Sdim return false; 109224135Sdim return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong; 110224135Sdim } 111224135Sdim}; 112224135Sdim 113224135Sdimclass BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> { 114234353Sdim llvm::DenseSet<VarDecl *> &VarsToChange; 115224135Sdim 116224135Sdimpublic: 117239462Sdim BlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange) 118239462Sdim : VarsToChange(VarsToChange) { } 119224135Sdim 120224135Sdim bool TraverseBlockDecl(BlockDecl *block) { 121239462Sdim RootBlockObjCVarRewriter(VarsToChange).TraverseDecl(block); 122224135Sdim return true; 123224135Sdim } 124224135Sdim}; 125224135Sdim 126224135Sdim} // anonymous namespace 127224135Sdim 128234353Sdimvoid BlockObjCVariableTraverser::traverseBody(BodyContext &BodyCtx) { 129234353Sdim MigrationPass &Pass = BodyCtx.getMigrationContext().Pass; 130234353Sdim llvm::DenseSet<VarDecl *> VarsToChange; 131234353Sdim 132239462Sdim BlockObjCVarRewriter trans(VarsToChange); 133234353Sdim trans.TraverseStmt(BodyCtx.getTopStmt()); 134234353Sdim 135234353Sdim for (llvm::DenseSet<VarDecl *>::iterator 136234353Sdim I = VarsToChange.begin(), E = VarsToChange.end(); I != E; ++I) { 137234353Sdim VarDecl *var = *I; 138234353Sdim BlocksAttr *attr = var->getAttr<BlocksAttr>(); 139234353Sdim if(!attr) 140234353Sdim continue; 141234353Sdim bool useWeak = canApplyWeak(Pass.Ctx, var->getType()); 142234353Sdim SourceManager &SM = Pass.Ctx.getSourceManager(); 143234353Sdim Transaction Trans(Pass.TA); 144234353Sdim Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()), 145234353Sdim "__block", 146234353Sdim useWeak ? "__weak" : "__unsafe_unretained"); 147234353Sdim } 148224135Sdim} 149