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