xref: /minix3/external/bsd/llvm/dist/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc //===--- TransBlockObjCVariable.cpp - Transformations to ARC mode ---------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // rewriteBlockObjCVariable:
11f4a2713aSLionel Sambuc //
12f4a2713aSLionel Sambuc // Adding __block to an obj-c variable could be either because the variable
13f4a2713aSLionel Sambuc // is used for output storage or the user wanted to break a retain cycle.
14f4a2713aSLionel Sambuc // This transformation checks whether a reference of the variable for the block
15f4a2713aSLionel Sambuc // is actually needed (it is assigned to or its address is taken) or not.
16f4a2713aSLionel Sambuc // If the reference is not needed it will assume __block was added to break a
17f4a2713aSLionel Sambuc // cycle so it will remove '__block' and add __weak/__unsafe_unretained.
18f4a2713aSLionel Sambuc // e.g
19f4a2713aSLionel Sambuc //
20f4a2713aSLionel Sambuc //   __block Foo *x;
21f4a2713aSLionel Sambuc //   bar(^ { [x cake]; });
22f4a2713aSLionel Sambuc // ---->
23f4a2713aSLionel Sambuc //   __weak Foo *x;
24f4a2713aSLionel Sambuc //   bar(^ { [x cake]; });
25f4a2713aSLionel Sambuc //
26f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
27f4a2713aSLionel Sambuc 
28f4a2713aSLionel Sambuc #include "Transforms.h"
29f4a2713aSLionel Sambuc #include "Internals.h"
30f4a2713aSLionel Sambuc #include "clang/AST/ASTContext.h"
31f4a2713aSLionel Sambuc #include "clang/AST/Attr.h"
32f4a2713aSLionel Sambuc #include "clang/Basic/SourceManager.h"
33f4a2713aSLionel Sambuc 
34f4a2713aSLionel Sambuc using namespace clang;
35f4a2713aSLionel Sambuc using namespace arcmt;
36f4a2713aSLionel Sambuc using namespace trans;
37f4a2713aSLionel Sambuc 
38f4a2713aSLionel Sambuc namespace {
39f4a2713aSLionel Sambuc 
40f4a2713aSLionel Sambuc class RootBlockObjCVarRewriter :
41f4a2713aSLionel Sambuc                           public RecursiveASTVisitor<RootBlockObjCVarRewriter> {
42f4a2713aSLionel Sambuc   llvm::DenseSet<VarDecl *> &VarsToChange;
43f4a2713aSLionel Sambuc 
44f4a2713aSLionel Sambuc   class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> {
45f4a2713aSLionel Sambuc     VarDecl *Var;
46f4a2713aSLionel Sambuc 
47f4a2713aSLionel Sambuc     typedef RecursiveASTVisitor<BlockVarChecker> base;
48f4a2713aSLionel Sambuc   public:
BlockVarChecker(VarDecl * var)49f4a2713aSLionel Sambuc     BlockVarChecker(VarDecl *var) : Var(var) { }
50f4a2713aSLionel Sambuc 
TraverseImplicitCastExpr(ImplicitCastExpr * castE)51f4a2713aSLionel Sambuc     bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) {
52f4a2713aSLionel Sambuc       if (DeclRefExpr *
53f4a2713aSLionel Sambuc             ref = dyn_cast<DeclRefExpr>(castE->getSubExpr())) {
54f4a2713aSLionel Sambuc         if (ref->getDecl() == Var) {
55f4a2713aSLionel Sambuc           if (castE->getCastKind() == CK_LValueToRValue)
56f4a2713aSLionel Sambuc             return true; // Using the value of the variable.
57f4a2713aSLionel Sambuc           if (castE->getCastKind() == CK_NoOp && castE->isLValue() &&
58f4a2713aSLionel Sambuc               Var->getASTContext().getLangOpts().CPlusPlus)
59f4a2713aSLionel Sambuc             return true; // Binding to const C++ reference.
60f4a2713aSLionel Sambuc         }
61f4a2713aSLionel Sambuc       }
62f4a2713aSLionel Sambuc 
63f4a2713aSLionel Sambuc       return base::TraverseImplicitCastExpr(castE);
64f4a2713aSLionel Sambuc     }
65f4a2713aSLionel Sambuc 
VisitDeclRefExpr(DeclRefExpr * E)66f4a2713aSLionel Sambuc     bool VisitDeclRefExpr(DeclRefExpr *E) {
67f4a2713aSLionel Sambuc       if (E->getDecl() == Var)
68f4a2713aSLionel Sambuc         return false; // The reference of the variable, and not just its value,
69f4a2713aSLionel Sambuc                       //  is needed.
70f4a2713aSLionel Sambuc       return true;
71f4a2713aSLionel Sambuc     }
72f4a2713aSLionel Sambuc   };
73f4a2713aSLionel Sambuc 
74f4a2713aSLionel Sambuc public:
RootBlockObjCVarRewriter(llvm::DenseSet<VarDecl * > & VarsToChange)75f4a2713aSLionel Sambuc   RootBlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)
76f4a2713aSLionel Sambuc     : VarsToChange(VarsToChange) { }
77f4a2713aSLionel Sambuc 
VisitBlockDecl(BlockDecl * block)78f4a2713aSLionel Sambuc   bool VisitBlockDecl(BlockDecl *block) {
79f4a2713aSLionel Sambuc     SmallVector<VarDecl *, 4> BlockVars;
80f4a2713aSLionel Sambuc 
81*0a6a1f1dSLionel Sambuc     for (const auto &I : block->captures()) {
82*0a6a1f1dSLionel Sambuc       VarDecl *var = I.getVariable();
83*0a6a1f1dSLionel Sambuc       if (I.isByRef() &&
84f4a2713aSLionel Sambuc           var->getType()->isObjCObjectPointerType() &&
85f4a2713aSLionel Sambuc           isImplicitStrong(var->getType())) {
86f4a2713aSLionel Sambuc         BlockVars.push_back(var);
87f4a2713aSLionel Sambuc       }
88f4a2713aSLionel Sambuc     }
89f4a2713aSLionel Sambuc 
90f4a2713aSLionel Sambuc     for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) {
91f4a2713aSLionel Sambuc       VarDecl *var = BlockVars[i];
92f4a2713aSLionel Sambuc 
93f4a2713aSLionel Sambuc       BlockVarChecker checker(var);
94f4a2713aSLionel Sambuc       bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody());
95f4a2713aSLionel Sambuc       if (onlyValueOfVarIsNeeded)
96f4a2713aSLionel Sambuc         VarsToChange.insert(var);
97f4a2713aSLionel Sambuc       else
98f4a2713aSLionel Sambuc         VarsToChange.erase(var);
99f4a2713aSLionel Sambuc     }
100f4a2713aSLionel Sambuc 
101f4a2713aSLionel Sambuc     return true;
102f4a2713aSLionel Sambuc   }
103f4a2713aSLionel Sambuc 
104f4a2713aSLionel Sambuc private:
isImplicitStrong(QualType ty)105f4a2713aSLionel Sambuc   bool isImplicitStrong(QualType ty) {
106f4a2713aSLionel Sambuc     if (isa<AttributedType>(ty.getTypePtr()))
107f4a2713aSLionel Sambuc       return false;
108f4a2713aSLionel Sambuc     return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong;
109f4a2713aSLionel Sambuc   }
110f4a2713aSLionel Sambuc };
111f4a2713aSLionel Sambuc 
112f4a2713aSLionel Sambuc class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> {
113f4a2713aSLionel Sambuc   llvm::DenseSet<VarDecl *> &VarsToChange;
114f4a2713aSLionel Sambuc 
115f4a2713aSLionel Sambuc public:
BlockObjCVarRewriter(llvm::DenseSet<VarDecl * > & VarsToChange)116f4a2713aSLionel Sambuc   BlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)
117f4a2713aSLionel Sambuc     : VarsToChange(VarsToChange) { }
118f4a2713aSLionel Sambuc 
TraverseBlockDecl(BlockDecl * block)119f4a2713aSLionel Sambuc   bool TraverseBlockDecl(BlockDecl *block) {
120f4a2713aSLionel Sambuc     RootBlockObjCVarRewriter(VarsToChange).TraverseDecl(block);
121f4a2713aSLionel Sambuc     return true;
122f4a2713aSLionel Sambuc   }
123f4a2713aSLionel Sambuc };
124f4a2713aSLionel Sambuc 
125f4a2713aSLionel Sambuc } // anonymous namespace
126f4a2713aSLionel Sambuc 
traverseBody(BodyContext & BodyCtx)127f4a2713aSLionel Sambuc void BlockObjCVariableTraverser::traverseBody(BodyContext &BodyCtx) {
128f4a2713aSLionel Sambuc   MigrationPass &Pass = BodyCtx.getMigrationContext().Pass;
129f4a2713aSLionel Sambuc   llvm::DenseSet<VarDecl *> VarsToChange;
130f4a2713aSLionel Sambuc 
131f4a2713aSLionel Sambuc   BlockObjCVarRewriter trans(VarsToChange);
132f4a2713aSLionel Sambuc   trans.TraverseStmt(BodyCtx.getTopStmt());
133f4a2713aSLionel Sambuc 
134f4a2713aSLionel Sambuc   for (llvm::DenseSet<VarDecl *>::iterator
135f4a2713aSLionel Sambuc          I = VarsToChange.begin(), E = VarsToChange.end(); I != E; ++I) {
136f4a2713aSLionel Sambuc     VarDecl *var = *I;
137f4a2713aSLionel Sambuc     BlocksAttr *attr = var->getAttr<BlocksAttr>();
138f4a2713aSLionel Sambuc     if(!attr)
139f4a2713aSLionel Sambuc       continue;
140f4a2713aSLionel Sambuc     bool useWeak = canApplyWeak(Pass.Ctx, var->getType());
141f4a2713aSLionel Sambuc     SourceManager &SM = Pass.Ctx.getSourceManager();
142f4a2713aSLionel Sambuc     Transaction Trans(Pass.TA);
143f4a2713aSLionel Sambuc     Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()),
144f4a2713aSLionel Sambuc                         "__block",
145f4a2713aSLionel Sambuc                         useWeak ? "__weak" : "__unsafe_unretained");
146f4a2713aSLionel Sambuc   }
147f4a2713aSLionel Sambuc }
148