clang API Documentation

TransBlockObjCVariable.cpp
Go to the documentation of this file.
00001 //===--- TransBlockObjCVariable.cpp - Tranformations to ARC mode ----------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // rewriteBlockObjCVariable:
00011 //
00012 // Adding __block to an obj-c variable could be either because the the variable
00013 // is used for output storage or the user wanted to break a retain cycle.
00014 // This transformation checks whether a reference of the variable for the block
00015 // is actually needed (it is assigned to or its address is taken) or not.
00016 // If the reference is not needed it will assume __block was added to break a
00017 // cycle so it will remove '__block' and add __weak/__unsafe_unretained.
00018 // e.g
00019 //
00020 //   __block Foo *x;
00021 //   bar(^ { [x cake]; });
00022 // ---->
00023 //   __weak Foo *x;
00024 //   bar(^ { [x cake]; });
00025 //
00026 //===----------------------------------------------------------------------===//
00027 
00028 #include "Transforms.h"
00029 #include "Internals.h"
00030 #include "clang/Basic/SourceManager.h"
00031 
00032 using namespace clang;
00033 using namespace arcmt;
00034 using namespace trans;
00035 
00036 namespace {
00037 
00038 class RootBlockObjCVarRewriter :
00039                           public RecursiveASTVisitor<RootBlockObjCVarRewriter> {
00040   MigrationPass &Pass;
00041   llvm::DenseSet<VarDecl *> &VarsToChange;
00042 
00043   class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> {
00044     VarDecl *Var;
00045   
00046     typedef RecursiveASTVisitor<BlockVarChecker> base;
00047   public:
00048     BlockVarChecker(VarDecl *var) : Var(var) { }
00049   
00050     bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) {
00051       if (DeclRefExpr *
00052             ref = dyn_cast<DeclRefExpr>(castE->getSubExpr())) {
00053         if (ref->getDecl() == Var) {
00054           if (castE->getCastKind() == CK_LValueToRValue)
00055             return true; // Using the value of the variable.
00056           if (castE->getCastKind() == CK_NoOp && castE->isLValue() &&
00057               Var->getASTContext().getLangOpts().CPlusPlus)
00058             return true; // Binding to const C++ reference.
00059         }
00060       }
00061 
00062       return base::TraverseImplicitCastExpr(castE);
00063     }
00064 
00065     bool VisitDeclRefExpr(DeclRefExpr *E) {
00066       if (E->getDecl() == Var)
00067         return false; // The reference of the variable, and not just its value,
00068                       //  is needed.
00069       return true;
00070     }
00071   };
00072 
00073 public:
00074   RootBlockObjCVarRewriter(MigrationPass &pass,
00075                            llvm::DenseSet<VarDecl *> &VarsToChange)
00076     : Pass(pass), VarsToChange(VarsToChange) { }
00077 
00078   bool VisitBlockDecl(BlockDecl *block) {
00079     SmallVector<VarDecl *, 4> BlockVars;
00080     
00081     for (BlockDecl::capture_iterator
00082            I = block->capture_begin(), E = block->capture_end(); I != E; ++I) {
00083       VarDecl *var = I->getVariable();
00084       if (I->isByRef() &&
00085           var->getType()->isObjCObjectPointerType() &&
00086           isImplicitStrong(var->getType())) {
00087         BlockVars.push_back(var);
00088       }
00089     }
00090 
00091     for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) {
00092       VarDecl *var = BlockVars[i];
00093 
00094       BlockVarChecker checker(var);
00095       bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody());
00096       if (onlyValueOfVarIsNeeded)
00097         VarsToChange.insert(var);
00098       else
00099         VarsToChange.erase(var);
00100     }
00101 
00102     return true;
00103   }
00104 
00105 private:
00106   bool isImplicitStrong(QualType ty) {
00107     if (isa<AttributedType>(ty.getTypePtr()))
00108       return false;
00109     return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong;
00110   }
00111 };
00112 
00113 class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> {
00114   MigrationPass &Pass;
00115   llvm::DenseSet<VarDecl *> &VarsToChange;
00116 
00117 public:
00118   BlockObjCVarRewriter(MigrationPass &pass,
00119                        llvm::DenseSet<VarDecl *> &VarsToChange)
00120     : Pass(pass), VarsToChange(VarsToChange) { }
00121 
00122   bool TraverseBlockDecl(BlockDecl *block) {
00123     RootBlockObjCVarRewriter(Pass, VarsToChange).TraverseDecl(block);
00124     return true;
00125   }
00126 };
00127 
00128 } // anonymous namespace
00129 
00130 void BlockObjCVariableTraverser::traverseBody(BodyContext &BodyCtx) {
00131   MigrationPass &Pass = BodyCtx.getMigrationContext().Pass;
00132   llvm::DenseSet<VarDecl *> VarsToChange;
00133 
00134   BlockObjCVarRewriter trans(Pass, VarsToChange);
00135   trans.TraverseStmt(BodyCtx.getTopStmt());
00136 
00137   for (llvm::DenseSet<VarDecl *>::iterator
00138          I = VarsToChange.begin(), E = VarsToChange.end(); I != E; ++I) {
00139     VarDecl *var = *I;
00140     BlocksAttr *attr = var->getAttr<BlocksAttr>();
00141     if(!attr)
00142       continue;
00143     bool useWeak = canApplyWeak(Pass.Ctx, var->getType());
00144     SourceManager &SM = Pass.Ctx.getSourceManager();
00145     Transaction Trans(Pass.TA);
00146     Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()),
00147                         "__block",
00148                         useWeak ? "__weak" : "__unsafe_unretained");
00149   }
00150 }