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