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