150
|
1 //===-- Transforms.h - Transformations to ARC mode --------------*- C++ -*-===//
|
|
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 #ifndef LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H
|
|
10 #define LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H
|
|
11
|
|
12 #include "clang/AST/ParentMap.h"
|
|
13 #include "clang/AST/RecursiveASTVisitor.h"
|
|
14 #include "llvm/ADT/DenseSet.h"
|
|
15 #include "llvm/Support/SaveAndRestore.h"
|
|
16
|
|
17 namespace clang {
|
|
18 class Decl;
|
|
19 class Stmt;
|
|
20 class BlockDecl;
|
|
21 class ObjCMethodDecl;
|
|
22 class FunctionDecl;
|
|
23
|
|
24 namespace arcmt {
|
|
25 class MigrationPass;
|
|
26
|
|
27 namespace trans {
|
|
28
|
|
29 class MigrationContext;
|
|
30
|
|
31 //===----------------------------------------------------------------------===//
|
|
32 // Transformations.
|
|
33 //===----------------------------------------------------------------------===//
|
|
34
|
|
35 void rewriteAutoreleasePool(MigrationPass &pass);
|
|
36 void rewriteUnbridgedCasts(MigrationPass &pass);
|
|
37 void makeAssignARCSafe(MigrationPass &pass);
|
|
38 void removeRetainReleaseDeallocFinalize(MigrationPass &pass);
|
|
39 void removeZeroOutPropsInDeallocFinalize(MigrationPass &pass);
|
|
40 void rewriteUnusedInitDelegate(MigrationPass &pass);
|
|
41 void checkAPIUses(MigrationPass &pass);
|
|
42
|
|
43 void removeEmptyStatementsAndDeallocFinalize(MigrationPass &pass);
|
|
44
|
|
45 class BodyContext {
|
|
46 MigrationContext &MigrateCtx;
|
|
47 ParentMap PMap;
|
|
48 Stmt *TopStmt;
|
|
49
|
|
50 public:
|
|
51 BodyContext(MigrationContext &MigrateCtx, Stmt *S)
|
|
52 : MigrateCtx(MigrateCtx), PMap(S), TopStmt(S) {}
|
|
53
|
|
54 MigrationContext &getMigrationContext() { return MigrateCtx; }
|
|
55 ParentMap &getParentMap() { return PMap; }
|
|
56 Stmt *getTopStmt() { return TopStmt; }
|
|
57 };
|
|
58
|
|
59 class ObjCImplementationContext {
|
|
60 MigrationContext &MigrateCtx;
|
|
61 ObjCImplementationDecl *ImpD;
|
|
62
|
|
63 public:
|
|
64 ObjCImplementationContext(MigrationContext &MigrateCtx,
|
|
65 ObjCImplementationDecl *D)
|
|
66 : MigrateCtx(MigrateCtx), ImpD(D) {}
|
|
67
|
|
68 MigrationContext &getMigrationContext() { return MigrateCtx; }
|
|
69 ObjCImplementationDecl *getImplementationDecl() { return ImpD; }
|
|
70 };
|
|
71
|
|
72 class ASTTraverser {
|
|
73 public:
|
|
74 virtual ~ASTTraverser();
|
|
75 virtual void traverseTU(MigrationContext &MigrateCtx) { }
|
|
76 virtual void traverseBody(BodyContext &BodyCtx) { }
|
|
77 virtual void traverseObjCImplementation(ObjCImplementationContext &ImplCtx) {}
|
|
78 };
|
|
79
|
|
80 class MigrationContext {
|
|
81 std::vector<ASTTraverser *> Traversers;
|
|
82
|
|
83 public:
|
|
84 MigrationPass &Pass;
|
|
85
|
|
86 struct GCAttrOccurrence {
|
|
87 enum AttrKind { Weak, Strong } Kind;
|
|
88 SourceLocation Loc;
|
|
89 QualType ModifiedType;
|
|
90 Decl *Dcl;
|
|
91 /// true if the attribute is owned, e.g. it is in a body and not just
|
|
92 /// in an interface.
|
|
93 bool FullyMigratable;
|
|
94 };
|
|
95 std::vector<GCAttrOccurrence> GCAttrs;
|
|
96 llvm::DenseSet<unsigned> AttrSet;
|
|
97 llvm::DenseSet<unsigned> RemovedAttrSet;
|
|
98
|
|
99 /// Set of raw '@' locations for 'assign' properties group that contain
|
|
100 /// GC __weak.
|
|
101 llvm::DenseSet<unsigned> AtPropsWeak;
|
|
102
|
|
103 explicit MigrationContext(MigrationPass &pass) : Pass(pass) {}
|
|
104 ~MigrationContext();
|
|
105
|
|
106 typedef std::vector<ASTTraverser *>::iterator traverser_iterator;
|
|
107 traverser_iterator traversers_begin() { return Traversers.begin(); }
|
|
108 traverser_iterator traversers_end() { return Traversers.end(); }
|
|
109
|
|
110 void addTraverser(ASTTraverser *traverser) {
|
|
111 Traversers.push_back(traverser);
|
|
112 }
|
|
113
|
|
114 bool isGCOwnedNonObjC(QualType T);
|
|
115 bool removePropertyAttribute(StringRef fromAttr, SourceLocation atLoc) {
|
|
116 return rewritePropertyAttribute(fromAttr, StringRef(), atLoc);
|
|
117 }
|
|
118 bool rewritePropertyAttribute(StringRef fromAttr, StringRef toAttr,
|
|
119 SourceLocation atLoc);
|
|
120 bool addPropertyAttribute(StringRef attr, SourceLocation atLoc);
|
|
121
|
|
122 void traverse(TranslationUnitDecl *TU);
|
|
123
|
|
124 void dumpGCAttrs();
|
|
125 };
|
|
126
|
|
127 class PropertyRewriteTraverser : public ASTTraverser {
|
|
128 public:
|
|
129 void traverseObjCImplementation(ObjCImplementationContext &ImplCtx) override;
|
|
130 };
|
|
131
|
|
132 class BlockObjCVariableTraverser : public ASTTraverser {
|
|
133 public:
|
|
134 void traverseBody(BodyContext &BodyCtx) override;
|
|
135 };
|
|
136
|
|
137 class ProtectedScopeTraverser : public ASTTraverser {
|
|
138 public:
|
|
139 void traverseBody(BodyContext &BodyCtx) override;
|
|
140 };
|
|
141
|
|
142 // GC transformations
|
|
143
|
|
144 class GCAttrsTraverser : public ASTTraverser {
|
|
145 public:
|
|
146 void traverseTU(MigrationContext &MigrateCtx) override;
|
|
147 };
|
|
148
|
|
149 class GCCollectableCallsTraverser : public ASTTraverser {
|
|
150 public:
|
|
151 void traverseBody(BodyContext &BodyCtx) override;
|
|
152 };
|
|
153
|
|
154 //===----------------------------------------------------------------------===//
|
|
155 // Helpers.
|
|
156 //===----------------------------------------------------------------------===//
|
|
157
|
|
158 /// Determine whether we can add weak to the given type.
|
|
159 bool canApplyWeak(ASTContext &Ctx, QualType type,
|
|
160 bool AllowOnUnknownClass = false);
|
|
161
|
|
162 bool isPlusOneAssign(const BinaryOperator *E);
|
|
163 bool isPlusOne(const Expr *E);
|
|
164
|
|
165 /// 'Loc' is the end of a statement range. This returns the location
|
|
166 /// immediately after the semicolon following the statement.
|
|
167 /// If no semicolon is found or the location is inside a macro, the returned
|
|
168 /// source location will be invalid.
|
|
169 SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx,
|
|
170 bool IsDecl = false);
|
|
171
|
|
172 /// 'Loc' is the end of a statement range. This returns the location
|
|
173 /// of the semicolon following the statement.
|
|
174 /// If no semicolon is found or the location is inside a macro, the returned
|
|
175 /// source location will be invalid.
|
|
176 SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx,
|
|
177 bool IsDecl = false);
|
|
178
|
|
179 bool hasSideEffects(Expr *E, ASTContext &Ctx);
|
|
180 bool isGlobalVar(Expr *E);
|
|
181 /// Returns "nil" or "0" if 'nil' macro is not actually defined.
|
|
182 StringRef getNilString(MigrationPass &Pass);
|
|
183
|
|
184 template <typename BODY_TRANS>
|
|
185 class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > {
|
|
186 MigrationPass &Pass;
|
|
187 Decl *ParentD;
|
|
188
|
|
189 typedef RecursiveASTVisitor<BodyTransform<BODY_TRANS> > base;
|
|
190 public:
|
|
191 BodyTransform(MigrationPass &pass) : Pass(pass), ParentD(nullptr) { }
|
|
192
|
|
193 bool TraverseStmt(Stmt *rootS) {
|
|
194 if (rootS)
|
|
195 BODY_TRANS(Pass).transformBody(rootS, ParentD);
|
|
196 return true;
|
|
197 }
|
|
198
|
|
199 bool TraverseObjCMethodDecl(ObjCMethodDecl *D) {
|
|
200 SaveAndRestore<Decl *> SetParent(ParentD, D);
|
|
201 return base::TraverseObjCMethodDecl(D);
|
|
202 }
|
|
203 };
|
|
204
|
|
205 typedef llvm::DenseSet<Expr *> ExprSet;
|
|
206
|
|
207 void clearRefsIn(Stmt *S, ExprSet &refs);
|
|
208 template <typename iterator>
|
|
209 void clearRefsIn(iterator begin, iterator end, ExprSet &refs) {
|
|
210 for (; begin != end; ++begin)
|
|
211 clearRefsIn(*begin, refs);
|
|
212 }
|
|
213
|
|
214 void collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs);
|
|
215
|
|
216 void collectRemovables(Stmt *S, ExprSet &exprs);
|
|
217
|
|
218 } // end namespace trans
|
|
219
|
|
220 } // end namespace arcmt
|
|
221
|
|
222 } // end namespace clang
|
|
223
|
|
224 #endif
|