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<SourceLocation> AttrSet; |
97 | llvm::DenseSet<SourceLocation> RemovedAttrSet; |
98 | |
99 | /// Set of raw '@' locations for 'assign' properties group that contain |
100 | /// GC __weak. |
101 | llvm::DenseSet<SourceLocation> 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(x: traverser); |
112 | } |
113 | |
114 | bool isGCOwnedNonObjC(QualType T); |
115 | bool removePropertyAttribute(StringRef fromAttr, SourceLocation atLoc) { |
116 | return rewritePropertyAttribute(fromAttr, toAttr: 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 |
225 | |