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
17namespace clang {
18 class Decl;
19 class Stmt;
20 class BlockDecl;
21 class ObjCMethodDecl;
22 class FunctionDecl;
23
24namespace arcmt {
25 class MigrationPass;
26
27namespace trans {
28
29 class MigrationContext;
30
31//===----------------------------------------------------------------------===//
32// Transformations.
33//===----------------------------------------------------------------------===//
34
35void rewriteAutoreleasePool(MigrationPass &pass);
36void rewriteUnbridgedCasts(MigrationPass &pass);
37void makeAssignARCSafe(MigrationPass &pass);
38void removeRetainReleaseDeallocFinalize(MigrationPass &pass);
39void removeZeroOutPropsInDeallocFinalize(MigrationPass &pass);
40void rewriteUnusedInitDelegate(MigrationPass &pass);
41void checkAPIUses(MigrationPass &pass);
42
43void removeEmptyStatementsAndDeallocFinalize(MigrationPass &pass);
44
45class BodyContext {
46 MigrationContext &MigrateCtx;
47 ParentMap PMap;
48 Stmt *TopStmt;
49
50public:
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
59class ObjCImplementationContext {
60 MigrationContext &MigrateCtx;
61 ObjCImplementationDecl *ImpD;
62
63public:
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
72class ASTTraverser {
73public:
74 virtual ~ASTTraverser();
75 virtual void traverseTU(MigrationContext &MigrateCtx) { }
76 virtual void traverseBody(BodyContext &BodyCtx) { }
77 virtual void traverseObjCImplementation(ObjCImplementationContext &ImplCtx) {}
78};
79
80class MigrationContext {
81 std::vector<ASTTraverser *> Traversers;
82
83public:
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
127class PropertyRewriteTraverser : public ASTTraverser {
128public:
129 void traverseObjCImplementation(ObjCImplementationContext &ImplCtx) override;
130};
131
132class BlockObjCVariableTraverser : public ASTTraverser {
133public:
134 void traverseBody(BodyContext &BodyCtx) override;
135};
136
137class ProtectedScopeTraverser : public ASTTraverser {
138public:
139 void traverseBody(BodyContext &BodyCtx) override;
140};
141
142// GC transformations
143
144class GCAttrsTraverser : public ASTTraverser {
145public:
146 void traverseTU(MigrationContext &MigrateCtx) override;
147};
148
149class GCCollectableCallsTraverser : public ASTTraverser {
150public:
151 void traverseBody(BodyContext &BodyCtx) override;
152};
153
154//===----------------------------------------------------------------------===//
155// Helpers.
156//===----------------------------------------------------------------------===//
157
158/// Determine whether we can add weak to the given type.
159bool canApplyWeak(ASTContext &Ctx, QualType type,
160 bool AllowOnUnknownClass = false);
161
162bool isPlusOneAssign(const BinaryOperator *E);
163bool 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.
169SourceLocation 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.
176SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx,
177 bool IsDecl = false);
178
179bool hasSideEffects(Expr *E, ASTContext &Ctx);
180bool isGlobalVar(Expr *E);
181/// Returns "nil" or "0" if 'nil' macro is not actually defined.
182StringRef getNilString(MigrationPass &Pass);
183
184template <typename BODY_TRANS>
185class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > {
186 MigrationPass &Pass;
187 Decl *ParentD;
188
189 typedef RecursiveASTVisitor<BodyTransform<BODY_TRANS> > base;
190public:
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
205typedef llvm::DenseSet<Expr *> ExprSet;
206
207void clearRefsIn(Stmt *S, ExprSet &refs);
208template <typename iterator>
209void clearRefsIn(iterator begin, iterator end, ExprSet &refs) {
210 for (; begin != end; ++begin)
211 clearRefsIn(*begin, refs);
212}
213
214void collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs);
215
216void collectRemovables(Stmt *S, ExprSet &exprs);
217
218} // end namespace trans
219
220} // end namespace arcmt
221
222} // end namespace clang
223
224#endif
225