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