Home | History | Annotate | Line # | Download | only in ARCMigrate
      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