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