clang  6.0.0svn
TransBlockObjCVariable.cpp
Go to the documentation of this file.
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"
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 
48  public:
49  BlockVarChecker(VarDecl *var) : Var(var) { }
50 
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 
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:
75  RootBlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)
76  : VarsToChange(VarsToChange) { }
77 
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:
105  bool isImplicitStrong(QualType ty) {
106  if (isa<AttributedType>(ty.getTypePtr()))
107  return false;
109  }
110 };
111 
112 class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> {
113  llvm::DenseSet<VarDecl *> &VarsToChange;
114 
115 public:
116  BlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange)
117  : VarsToChange(VarsToChange) { }
118 
119  bool TraverseBlockDecl(BlockDecl *block) {
120  RootBlockObjCVarRewriter(VarsToChange).TraverseDecl(block);
121  return true;
122  }
123 };
124 
125 } // anonymous namespace
126 
128  MigrationPass &Pass = BodyCtx.getMigrationContext().Pass;
129  llvm::DenseSet<VarDecl *> VarsToChange;
130 
131  BlockObjCVarRewriter trans(VarsToChange);
132  trans.TraverseStmt(BodyCtx.getTopStmt());
133 
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());
142  Transaction Trans(Pass.TA);
143  Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()),
144  "__block",
145  useWeak ? "__weak" : "__unsafe_unretained");
146  }
147 }
Defines the clang::ASTContext interface.
A (possibly-)qualified type.
Definition: Type.h:653
Defines the SourceManager interface.
VarDecl - An instance of this class is created to represent a variable declaration or definition...
Definition: Decl.h:807
Stmt * getBody() const override
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition: Decl.h:3767
Expr * getSubExpr()
Definition: Expr.h:2761
Qualifiers getLocalQualifiers() const
Retrieve the set of qualifiers local to this particular QualType instance, not including any qualifie...
Definition: Type.h:5739
MigrationContext & getMigrationContext()
Definition: Transforms.h:55
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:5720
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
BlockDecl - This represents a block literal declaration, which is like an unnamed FunctionDecl...
Definition: Decl.h:3689
ObjCLifetime getObjCLifetime() const
Definition: Type.h:341
ValueDecl * getDecl()
Definition: Expr.h:1041
const SourceManager & SM
Definition: Format.cpp:1337
bool canApplyWeak(ASTContext &Ctx, QualType type, bool AllowOnUnknownClass=false)
Determine whether we can add weak to the given type.
Definition: Transforms.cpp:38
Assigning into this object requires the old value to be released and the new value to be retained...
Definition: Type.h:180
CastKind getCastKind() const
Definition: Expr.h:2757
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:365
bool isObjCObjectPointerType() const
Definition: Type.h:6041
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition: Expr.h:2822
bool isLValue() const
isLValue - True if this expression is an "l-value" according to the rules of the current language...
Definition: Expr.h:249
Dataflow Directional Tag Classes.
ArrayRef< Capture > captures() const
Definition: Decl.h:3815
void replaceText(SourceLocation loc, StringRef text, StringRef replacementText)
T * getAttr() const
Definition: DeclBase.h:531
SourceManager & getSourceManager()
Definition: ASTContext.h:643
TransformActions & TA
Definition: Internals.h:151
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:956
QualType getType() const
Definition: Decl.h:639
const LangOptions & getLangOpts() const
Definition: ASTContext.h:688
This class handles loading and caching of source files into memory.