1accaf19bc1129c0273ec50dba52318e60bc29103Benjamin Kramer//===--- TransBlockObjCVariable.cpp - Transformations to ARC mode ---------===//
27196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//
37196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//                     The LLVM Compiler Infrastructure
47196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//
57196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// This file is distributed under the University of Illinois Open Source
67196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// License. See LICENSE.TXT for details.
77196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//
87196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//===----------------------------------------------------------------------===//
97196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//
107196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// rewriteBlockObjCVariable:
117196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//
12bed28ac1d1463adca3ecf24fca5c30646fa9dbb2Sylvestre Ledru// Adding __block to an obj-c variable could be either because the variable
137196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// is used for output storage or the user wanted to break a retain cycle.
147196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// This transformation checks whether a reference of the variable for the block
157196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// is actually needed (it is assigned to or its address is taken) or not.
167196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// If the reference is not needed it will assume __block was added to break a
177196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// cycle so it will remove '__block' and add __weak/__unsafe_unretained.
187196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// e.g
197196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//
207196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//   __block Foo *x;
217196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//   bar(^ { [x cake]; });
227196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// ---->
237196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//   __weak Foo *x;
247196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//   bar(^ { [x cake]; });
257196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//
267196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//===----------------------------------------------------------------------===//
277196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
287196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#include "Transforms.h"
297196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#include "Internals.h"
30471c8b49982d1132f30b0b0da27fef94fd6e4f67Benjamin Kramer#include "clang/AST/ASTContext.h"
312fa67efeaf66a9332c30a026dc1c21bef6c33a6cBenjamin Kramer#include "clang/AST/Attr.h"
327196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#include "clang/Basic/SourceManager.h"
337196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
347196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisusing namespace clang;
357196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisusing namespace arcmt;
367196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisusing namespace trans;
377196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
387196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisnamespace {
397196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
407196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisclass RootBlockObjCVarRewriter :
417196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis                          public RecursiveASTVisitor<RootBlockObjCVarRewriter> {
422a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis  llvm::DenseSet<VarDecl *> &VarsToChange;
437196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
447196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> {
457196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    VarDecl *Var;
467196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
477196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    typedef RecursiveASTVisitor<BlockVarChecker> base;
487196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  public:
497196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    BlockVarChecker(VarDecl *var) : Var(var) { }
507196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
517196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) {
52f4b88a45902af1802a1cb42ba48b1c474474f228John McCall      if (DeclRefExpr *
53f4b88a45902af1802a1cb42ba48b1c474474f228John McCall            ref = dyn_cast<DeclRefExpr>(castE->getSubExpr())) {
547196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis        if (ref->getDecl() == Var) {
557196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          if (castE->getCastKind() == CK_LValueToRValue)
567196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis            return true; // Using the value of the variable.
577196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          if (castE->getCastKind() == CK_NoOp && castE->isLValue() &&
584e4d08403ca5cfd4d558fa2936215d3a4e5a528dDavid Blaikie              Var->getASTContext().getLangOpts().CPlusPlus)
597196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis            return true; // Binding to const C++ reference.
607196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis        }
617196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      }
627196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
637196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      return base::TraverseImplicitCastExpr(castE);
647196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    }
657196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
66f4b88a45902af1802a1cb42ba48b1c474474f228John McCall    bool VisitDeclRefExpr(DeclRefExpr *E) {
677196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      if (E->getDecl() == Var)
687196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis        return false; // The reference of the variable, and not just its value,
697196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis                      //  is needed.
707196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      return true;
717196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    }
727196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  };
737196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
747196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidispublic:
75facde171ae4b8926622a1bffa833732a06f1875bBenjamin Kramer  RootBlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)
76facde171ae4b8926622a1bffa833732a06f1875bBenjamin Kramer    : VarsToChange(VarsToChange) { }
777196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
787196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  bool VisitBlockDecl(BlockDecl *block) {
795f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner    SmallVector<VarDecl *, 4> BlockVars;
807196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
81651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    for (const auto &I : block->captures()) {
82651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      VarDecl *var = I.getVariable();
83651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      if (I.isByRef() &&
847196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          var->getType()->isObjCObjectPointerType() &&
857196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          isImplicitStrong(var->getType())) {
867196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis        BlockVars.push_back(var);
877196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      }
887196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    }
897196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
907196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) {
917196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      VarDecl *var = BlockVars[i];
927196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
937196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      BlockVarChecker checker(var);
947196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody());
952a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis      if (onlyValueOfVarIsNeeded)
962a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis        VarsToChange.insert(var);
972a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis      else
982a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis        VarsToChange.erase(var);
997196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    }
1007196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1017196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    return true;
1027196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  }
1037196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1047196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisprivate:
1057196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  bool isImplicitStrong(QualType ty) {
1067196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    if (isa<AttributedType>(ty.getTypePtr()))
1077196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      return false;
1087196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong;
1097196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  }
1107196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis};
1117196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1127196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisclass BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> {
1132a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis  llvm::DenseSet<VarDecl *> &VarsToChange;
1147196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1157196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidispublic:
1161ada2a65833266c139010bedfad87e58e5a7d74dBenjamin Kramer  BlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)
1171ada2a65833266c139010bedfad87e58e5a7d74dBenjamin Kramer    : VarsToChange(VarsToChange) { }
1187196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1197196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  bool TraverseBlockDecl(BlockDecl *block) {
120facde171ae4b8926622a1bffa833732a06f1875bBenjamin Kramer    RootBlockObjCVarRewriter(VarsToChange).TraverseDecl(block);
1217196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    return true;
1227196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  }
1237196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis};
1247196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1257196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis} // anonymous namespace
1267196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1272a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidisvoid BlockObjCVariableTraverser::traverseBody(BodyContext &BodyCtx) {
1282a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis  MigrationPass &Pass = BodyCtx.getMigrationContext().Pass;
1292a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis  llvm::DenseSet<VarDecl *> VarsToChange;
1302a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis
1311ada2a65833266c139010bedfad87e58e5a7d74dBenjamin Kramer  BlockObjCVarRewriter trans(VarsToChange);
1322a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis  trans.TraverseStmt(BodyCtx.getTopStmt());
1332a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis
1342a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis  for (llvm::DenseSet<VarDecl *>::iterator
1352a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis         I = VarsToChange.begin(), E = VarsToChange.end(); I != E; ++I) {
1362a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis    VarDecl *var = *I;
1372a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis    BlocksAttr *attr = var->getAttr<BlocksAttr>();
1382a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis    if(!attr)
1392a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis      continue;
1402a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis    bool useWeak = canApplyWeak(Pass.Ctx, var->getType());
1412a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis    SourceManager &SM = Pass.Ctx.getSourceManager();
1422a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis    Transaction Trans(Pass.TA);
1432a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis    Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()),
1442a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis                        "__block",
1452a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis                        useWeak ? "__weak" : "__unsafe_unretained");
1462a2781805a6b55573d369e34c5dcfba307ce83e9Argyrios Kyrtzidis  }
1477196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis}
148