1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
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 | BlockVarChecker(VarDecl *var) : Var(var) { } |
49 | |
50 | bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) { |
51 | if (DeclRefExpr * |
52 | ref = dyn_cast<DeclRefExpr>(castE->getSubExpr())) { |
53 | if (ref->getDecl() == Var) { |
54 | if (castE->getCastKind() == CK_LValueToRValue) |
55 | return true; |
56 | if (castE->getCastKind() == CK_NoOp && castE->isLValue() && |
57 | Var->getASTContext().getLangOpts().CPlusPlus) |
58 | return true; |
59 | } |
60 | } |
61 | |
62 | return base::TraverseImplicitCastExpr(castE); |
63 | } |
64 | |
65 | bool VisitDeclRefExpr(DeclRefExpr *E) { |
66 | if (E->getDecl() == Var) |
67 | return false; |
68 | |
69 | return true; |
70 | } |
71 | }; |
72 | |
73 | public: |
74 | RootBlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange) |
75 | : VarsToChange(VarsToChange) { } |
76 | |
77 | bool VisitBlockDecl(BlockDecl *block) { |
78 | SmallVector<VarDecl *, 4> BlockVars; |
79 | |
80 | for (const auto &I : block->captures()) { |
81 | VarDecl *var = I.getVariable(); |
82 | if (I.isByRef() && |
83 | var->getType()->isObjCObjectPointerType() && |
84 | isImplicitStrong(var->getType())) { |
85 | BlockVars.push_back(var); |
86 | } |
87 | } |
88 | |
89 | for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) { |
90 | VarDecl *var = BlockVars[i]; |
91 | |
92 | BlockVarChecker checker(var); |
93 | bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody()); |
94 | if (onlyValueOfVarIsNeeded) |
95 | VarsToChange.insert(var); |
96 | else |
97 | VarsToChange.erase(var); |
98 | } |
99 | |
100 | return true; |
101 | } |
102 | |
103 | private: |
104 | bool isImplicitStrong(QualType ty) { |
105 | if (isa<AttributedType>(ty.getTypePtr())) |
106 | return false; |
107 | return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong; |
108 | } |
109 | }; |
110 | |
111 | class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> { |
112 | llvm::DenseSet<VarDecl *> &VarsToChange; |
113 | |
114 | public: |
115 | BlockObjCVarRewriter(llvm::DenseSet<VarDecl *> &VarsToChange) |
116 | : VarsToChange(VarsToChange) { } |
117 | |
118 | bool TraverseBlockDecl(BlockDecl *block) { |
119 | RootBlockObjCVarRewriter(VarsToChange).TraverseDecl(block); |
120 | return true; |
121 | } |
122 | }; |
123 | |
124 | } |
125 | |
126 | void BlockObjCVariableTraverser::traverseBody(BodyContext &BodyCtx) { |
127 | MigrationPass &Pass = BodyCtx.getMigrationContext().Pass; |
128 | llvm::DenseSet<VarDecl *> VarsToChange; |
129 | |
130 | BlockObjCVarRewriter trans(VarsToChange); |
131 | trans.TraverseStmt(BodyCtx.getTopStmt()); |
132 | |
133 | for (llvm::DenseSet<VarDecl *>::iterator |
134 | I = VarsToChange.begin(), E = VarsToChange.end(); I != E; ++I) { |
135 | VarDecl *var = *I; |
136 | BlocksAttr *attr = var->getAttr<BlocksAttr>(); |
137 | if(!attr) |
138 | continue; |
139 | bool useWeak = canApplyWeak(Pass.Ctx, var->getType()); |
140 | SourceManager &SM = Pass.Ctx.getSourceManager(); |
141 | Transaction Trans(Pass.TA); |
142 | Pass.TA.replaceText(SM.getExpansionLoc(attr->getLocation()), |
143 | "__block", |
144 | useWeak ? "__weak" : "__unsafe_unretained"); |
145 | } |
146 | } |
147 | |