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