xref: /aosp_15_r20/external/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1  //===--- TransBlockObjCVariable.cpp - Transformations to ARC mode ---------===//
2  //
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  //
12  // Adding __block to an obj-c variable could be either because the variable
13  // 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"
30  #include "clang/AST/ASTContext.h"
31  #include "clang/AST/Attr.h"
32  #include "clang/Basic/SourceManager.h"
33  
34  using namespace clang;
35  using namespace arcmt;
36  using namespace trans;
37  
38  namespace {
39  
40  class RootBlockObjCVarRewriter :
41                            public RecursiveASTVisitor<RootBlockObjCVarRewriter> {
42    llvm::DenseSet<VarDecl *> &VarsToChange;
43  
44    class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> {
45      VarDecl *Var;
46  
47      typedef RecursiveASTVisitor<BlockVarChecker> base;
48    public:
BlockVarChecker(VarDecl * var)49      BlockVarChecker(VarDecl *var) : Var(var) { }
50  
TraverseImplicitCastExpr(ImplicitCastExpr * castE)51      bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) {
52        if (DeclRefExpr *
53              ref = dyn_cast<DeclRefExpr>(castE->getSubExpr())) {
54          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() &&
58                Var->getASTContext().getLangOpts().CPlusPlus)
59              return true; // Binding to const C++ reference.
60          }
61        }
62  
63        return base::TraverseImplicitCastExpr(castE);
64      }
65  
VisitDeclRefExpr(DeclRefExpr * E)66      bool VisitDeclRefExpr(DeclRefExpr *E) {
67        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  
74  public:
RootBlockObjCVarRewriter(llvm::DenseSet<VarDecl * > & VarsToChange)75    RootBlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)
76      : VarsToChange(VarsToChange) { }
77  
VisitBlockDecl(BlockDecl * block)78    bool VisitBlockDecl(BlockDecl *block) {
79      SmallVector<VarDecl *, 4> BlockVars;
80  
81      for (const auto &I : block->captures()) {
82        VarDecl *var = I.getVariable();
83        if (I.isByRef() &&
84            var->getType()->isObjCObjectPointerType() &&
85            isImplicitStrong(var->getType())) {
86          BlockVars.push_back(var);
87        }
88      }
89  
90      for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) {
91        VarDecl *var = BlockVars[i];
92  
93        BlockVarChecker checker(var);
94        bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody());
95        if (onlyValueOfVarIsNeeded)
96          VarsToChange.insert(var);
97        else
98          VarsToChange.erase(var);
99      }
100  
101      return true;
102    }
103  
104  private:
isImplicitStrong(QualType ty)105    bool isImplicitStrong(QualType ty) {
106      if (isa<AttributedType>(ty.getTypePtr()))
107        return false;
108      return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong;
109    }
110  };
111  
112  class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> {
113    llvm::DenseSet<VarDecl *> &VarsToChange;
114  
115  public:
BlockObjCVarRewriter(llvm::DenseSet<VarDecl * > & VarsToChange)116    BlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)
117      : VarsToChange(VarsToChange) { }
118  
TraverseBlockDecl(BlockDecl * block)119    bool TraverseBlockDecl(BlockDecl *block) {
120      RootBlockObjCVarRewriter(VarsToChange).TraverseDecl(block);
121      return true;
122    }
123  };
124  
125  } // anonymous namespace
126  
traverseBody(BodyContext & BodyCtx)127  void BlockObjCVariableTraverser::traverseBody(BodyContext &BodyCtx) {
128    MigrationPass &Pass = BodyCtx.getMigrationContext().Pass;
129    llvm::DenseSet<VarDecl *> VarsToChange;
130  
131    BlockObjCVarRewriter trans(VarsToChange);
132    trans.TraverseStmt(BodyCtx.getTopStmt());
133  
134    for (llvm::DenseSet<VarDecl *>::iterator
135           I = VarsToChange.begin(), E = VarsToChange.end(); I != E; ++I) {
136      VarDecl *var = *I;
137      BlocksAttr *attr = var->getAttr<BlocksAttr>();
138      if(!attr)
139        continue;
140      bool useWeak = canApplyWeak(Pass.Ctx, var->getType());
141      SourceManager &SM = Pass.Ctx.getSourceManager();
142      Transaction Trans(Pass.TA);
143      Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()),
144                          "__block",
145                          useWeak ? "__weak" : "__unsafe_unretained");
146    }
147  }
148