clang API Documentation
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 }