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<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
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