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