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