blob: 97c4e3480c15921e3a36ea01cdb3df774f632b8c [file] [log] [blame]
Benjamin Kramerd81108f2012-11-14 15:08:31 +00001//===--- TransBlockObjCVariable.cpp - Transformations to ARC mode ---------===//
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// rewriteBlockObjCVariable:
11//
Sylvestre Ledru830885c2012-07-23 08:59:39 +000012// Adding __block to an obj-c variable could be either because the variable
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000013// is used for output storage or the user wanted to break a retain cycle.
14// This transformation checks whether a reference of the variable for the block
15// is actually needed (it is assigned to or its address is taken) or not.
16// If the reference is not needed it will assume __block was added to break a
17// cycle so it will remove '__block' and add __weak/__unsafe_unretained.
18// e.g
19//
20// __block Foo *x;
21// bar(^ { [x cake]; });
22// ---->
23// __weak Foo *x;
24// bar(^ { [x cake]; });
25//
26//===----------------------------------------------------------------------===//
27
28#include "Transforms.h"
29#include "Internals.h"
Benjamin Kramer4ab984e2012-07-04 20:19:54 +000030#include "clang/AST/ASTContext.h"
Benjamin Kramerea70eb32012-12-01 15:09:41 +000031#include "clang/AST/Attr.h"
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000032#include "clang/Basic/SourceManager.h"
33
34using namespace clang;
35using namespace arcmt;
36using namespace trans;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000037
38namespace {
39
40class RootBlockObjCVarRewriter :
41 public RecursiveASTVisitor<RootBlockObjCVarRewriter> {
Argyrios Kyrtzidisafdc66f2012-03-05 08:46:24 +000042 llvm::DenseSet<VarDecl *> &VarsToChange;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000043
44 class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> {
45 VarDecl *Var;
46
47 typedef RecursiveASTVisitor<BlockVarChecker> base;
48 public:
49 BlockVarChecker(VarDecl *var) : Var(var) { }
50
51 bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) {
John McCall113bee02012-03-10 09:33:50 +000052 if (DeclRefExpr *
53 ref = dyn_cast<DeclRefExpr>(castE->getSubExpr())) {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000054 if (ref->getDecl() == Var) {
55 if (castE->getCastKind() == CK_LValueToRValue)
56 return true; // Using the value of the variable.
57 if (castE->getCastKind() == CK_NoOp && castE->isLValue() &&
David Blaikiebbafb8a2012-03-11 07:00:24 +000058 Var->getASTContext().getLangOpts().CPlusPlus)
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000059 return true; // Binding to const C++ reference.
60 }
61 }
62
63 return base::TraverseImplicitCastExpr(castE);
64 }
65
John McCall113bee02012-03-10 09:33:50 +000066 bool VisitDeclRefExpr(DeclRefExpr *E) {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000067 if (E->getDecl() == Var)
68 return false; // The reference of the variable, and not just its value,
69 // is needed.
70 return true;
71 }
72 };
73
74public:
Benjamin Kramerd1d76b22012-06-06 17:32:50 +000075 RootBlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)
76 : VarsToChange(VarsToChange) { }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000077
78 bool VisitBlockDecl(BlockDecl *block) {
Chris Lattner0e62c1c2011-07-23 10:55:15 +000079 SmallVector<VarDecl *, 4> BlockVars;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000080
81 for (BlockDecl::capture_iterator
82 I = block->capture_begin(), E = block->capture_end(); I != E; ++I) {
83 VarDecl *var = I->getVariable();
84 if (I->isByRef() &&
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000085 var->getType()->isObjCObjectPointerType() &&
86 isImplicitStrong(var->getType())) {
87 BlockVars.push_back(var);
88 }
89 }
90
91 for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) {
92 VarDecl *var = BlockVars[i];
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000093
94 BlockVarChecker checker(var);
95 bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody());
Argyrios Kyrtzidisafdc66f2012-03-05 08:46:24 +000096 if (onlyValueOfVarIsNeeded)
97 VarsToChange.insert(var);
98 else
99 VarsToChange.erase(var);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000100 }
101
102 return true;
103 }
104
105private:
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000106 bool isImplicitStrong(QualType ty) {
107 if (isa<AttributedType>(ty.getTypePtr()))
108 return false;
109 return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong;
110 }
111};
112
113class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> {
Argyrios Kyrtzidisafdc66f2012-03-05 08:46:24 +0000114 llvm::DenseSet<VarDecl *> &VarsToChange;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000115
116public:
Benjamin Kramer972a96a2012-06-06 20:15:08 +0000117 BlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)
118 : VarsToChange(VarsToChange) { }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000119
120 bool TraverseBlockDecl(BlockDecl *block) {
Benjamin Kramerd1d76b22012-06-06 17:32:50 +0000121 RootBlockObjCVarRewriter(VarsToChange).TraverseDecl(block);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000122 return true;
123 }
124};
125
126} // anonymous namespace
127
Argyrios Kyrtzidisafdc66f2012-03-05 08:46:24 +0000128void BlockObjCVariableTraverser::traverseBody(BodyContext &BodyCtx) {
129 MigrationPass &Pass = BodyCtx.getMigrationContext().Pass;
130 llvm::DenseSet<VarDecl *> VarsToChange;
131
Benjamin Kramer972a96a2012-06-06 20:15:08 +0000132 BlockObjCVarRewriter trans(VarsToChange);
Argyrios Kyrtzidisafdc66f2012-03-05 08:46:24 +0000133 trans.TraverseStmt(BodyCtx.getTopStmt());
134
135 for (llvm::DenseSet<VarDecl *>::iterator
136 I = VarsToChange.begin(), E = VarsToChange.end(); I != E; ++I) {
137 VarDecl *var = *I;
138 BlocksAttr *attr = var->getAttr<BlocksAttr>();
139 if(!attr)
140 continue;
141 bool useWeak = canApplyWeak(Pass.Ctx, var->getType());
142 SourceManager &SM = Pass.Ctx.getSourceManager();
143 Transaction Trans(Pass.TA);
144 Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()),
145 "__block",
146 useWeak ? "__weak" : "__unsafe_unretained");
147 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000148}