clang API Documentation

TransBlockObjCVariable.cpp
Go to the documentation of this file.
00001 //===--- TransBlockObjCVariable.cpp - Transformations 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 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/AST/ASTContext.h"
00031 #include "clang/AST/Attr.h"
00032 #include "clang/Basic/SourceManager.h"
00033 
00034 using namespace clang;
00035 using namespace arcmt;
00036 using namespace trans;
00037 
00038 namespace {
00039 
00040 class RootBlockObjCVarRewriter :
00041                           public RecursiveASTVisitor<RootBlockObjCVarRewriter> {
00042   llvm::DenseSet<VarDecl *> &VarsToChange;
00043 
00044   class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> {
00045     VarDecl *Var;
00046   
00047     typedef RecursiveASTVisitor<BlockVarChecker> base;
00048   public:
00049     BlockVarChecker(VarDecl *var) : Var(var) { }
00050   
00051     bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) {
00052       if (DeclRefExpr *
00053             ref = dyn_cast<DeclRefExpr>(castE->getSubExpr())) {
00054         if (ref->getDecl() == Var) {
00055           if (castE->getCastKind() == CK_LValueToRValue)
00056             return true; // Using the value of the variable.
00057           if (castE->getCastKind() == CK_NoOp && castE->isLValue() &&
00058               Var->getASTContext().getLangOpts().CPlusPlus)
00059             return true; // Binding to const C++ reference.
00060         }
00061       }
00062 
00063       return base::TraverseImplicitCastExpr(castE);
00064     }
00065 
00066     bool VisitDeclRefExpr(DeclRefExpr *E) {
00067       if (E->getDecl() == Var)
00068         return false; // The reference of the variable, and not just its value,
00069                       //  is needed.
00070       return true;
00071     }
00072   };
00073 
00074 public:
00075   RootBlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)
00076     : VarsToChange(VarsToChange) { }
00077 
00078   bool VisitBlockDecl(BlockDecl *block) {
00079     SmallVector<VarDecl *, 4> BlockVars;
00080     
00081     for (const auto &I : block->captures()) {
00082       VarDecl *var = I.getVariable();
00083       if (I.isByRef() &&
00084           var->getType()->isObjCObjectPointerType() &&
00085           isImplicitStrong(var->getType())) {
00086         BlockVars.push_back(var);
00087       }
00088     }
00089 
00090     for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) {
00091       VarDecl *var = BlockVars[i];
00092 
00093       BlockVarChecker checker(var);
00094       bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody());
00095       if (onlyValueOfVarIsNeeded)
00096         VarsToChange.insert(var);
00097       else
00098         VarsToChange.erase(var);
00099     }
00100 
00101     return true;
00102   }
00103 
00104 private:
00105   bool isImplicitStrong(QualType ty) {
00106     if (isa<AttributedType>(ty.getTypePtr()))
00107       return false;
00108     return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong;
00109   }
00110 };
00111 
00112 class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> {
00113   llvm::DenseSet<VarDecl *> &VarsToChange;
00114 
00115 public:
00116   BlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)
00117     : VarsToChange(VarsToChange) { }
00118 
00119   bool TraverseBlockDecl(BlockDecl *block) {
00120     RootBlockObjCVarRewriter(VarsToChange).TraverseDecl(block);
00121     return true;
00122   }
00123 };
00124 
00125 } // anonymous namespace
00126 
00127 void BlockObjCVariableTraverser::traverseBody(BodyContext &BodyCtx) {
00128   MigrationPass &Pass = BodyCtx.getMigrationContext().Pass;
00129   llvm::DenseSet<VarDecl *> VarsToChange;
00130 
00131   BlockObjCVarRewriter trans(VarsToChange);
00132   trans.TraverseStmt(BodyCtx.getTopStmt());
00133 
00134   for (llvm::DenseSet<VarDecl *>::iterator
00135          I = VarsToChange.begin(), E = VarsToChange.end(); I != E; ++I) {
00136     VarDecl *var = *I;
00137     BlocksAttr *attr = var->getAttr<BlocksAttr>();
00138     if(!attr)
00139       continue;
00140     bool useWeak = canApplyWeak(Pass.Ctx, var->getType());
00141     SourceManager &SM = Pass.Ctx.getSourceManager();
00142     Transaction Trans(Pass.TA);
00143     Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()),
00144                         "__block",
00145                         useWeak ? "__weak" : "__unsafe_unretained");
00146   }
00147 }