1249423Sdim//===-- Transforms.h - Transformations to ARC mode --------------*- C++ -*-===//
2224135Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6224135Sdim//
7224135Sdim//===----------------------------------------------------------------------===//
8224135Sdim
9224135Sdim#ifndef LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H
10224135Sdim#define LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H
11224135Sdim
12249423Sdim#include "clang/AST/ParentMap.h"
13224135Sdim#include "clang/AST/RecursiveASTVisitor.h"
14224135Sdim#include "llvm/ADT/DenseSet.h"
15239462Sdim#include "llvm/Support/SaveAndRestore.h"
16224135Sdim
17224135Sdimnamespace clang {
18224135Sdim  class Decl;
19224135Sdim  class Stmt;
20224135Sdim  class BlockDecl;
21224135Sdim  class ObjCMethodDecl;
22224135Sdim  class FunctionDecl;
23224135Sdim
24224135Sdimnamespace arcmt {
25224135Sdim  class MigrationPass;
26224135Sdim
27224135Sdimnamespace trans {
28224135Sdim
29234353Sdim  class MigrationContext;
30234353Sdim
31224135Sdim//===----------------------------------------------------------------------===//
32224135Sdim// Transformations.
33224135Sdim//===----------------------------------------------------------------------===//
34224135Sdim
35224135Sdimvoid rewriteAutoreleasePool(MigrationPass &pass);
36224135Sdimvoid rewriteUnbridgedCasts(MigrationPass &pass);
37224135Sdimvoid makeAssignARCSafe(MigrationPass &pass);
38234353Sdimvoid removeRetainReleaseDeallocFinalize(MigrationPass &pass);
39234353Sdimvoid removeZeroOutPropsInDeallocFinalize(MigrationPass &pass);
40224135Sdimvoid rewriteUnusedInitDelegate(MigrationPass &pass);
41226633Sdimvoid checkAPIUses(MigrationPass &pass);
42224135Sdim
43234353Sdimvoid removeEmptyStatementsAndDeallocFinalize(MigrationPass &pass);
44224135Sdim
45234353Sdimclass BodyContext {
46234353Sdim  MigrationContext &MigrateCtx;
47234353Sdim  ParentMap PMap;
48234353Sdim  Stmt *TopStmt;
49234353Sdim
50234353Sdimpublic:
51234353Sdim  BodyContext(MigrationContext &MigrateCtx, Stmt *S)
52234353Sdim    : MigrateCtx(MigrateCtx), PMap(S), TopStmt(S) {}
53234353Sdim
54234353Sdim  MigrationContext &getMigrationContext() { return MigrateCtx; }
55234353Sdim  ParentMap &getParentMap() { return PMap; }
56234353Sdim  Stmt *getTopStmt() { return TopStmt; }
57234353Sdim};
58234353Sdim
59234353Sdimclass ObjCImplementationContext {
60234353Sdim  MigrationContext &MigrateCtx;
61234353Sdim  ObjCImplementationDecl *ImpD;
62234353Sdim
63234353Sdimpublic:
64234353Sdim  ObjCImplementationContext(MigrationContext &MigrateCtx,
65234353Sdim                            ObjCImplementationDecl *D)
66234353Sdim    : MigrateCtx(MigrateCtx), ImpD(D) {}
67234353Sdim
68234353Sdim  MigrationContext &getMigrationContext() { return MigrateCtx; }
69234353Sdim  ObjCImplementationDecl *getImplementationDecl() { return ImpD; }
70234353Sdim};
71234353Sdim
72234353Sdimclass ASTTraverser {
73234353Sdimpublic:
74234353Sdim  virtual ~ASTTraverser();
75234353Sdim  virtual void traverseTU(MigrationContext &MigrateCtx) { }
76234353Sdim  virtual void traverseBody(BodyContext &BodyCtx) { }
77234353Sdim  virtual void traverseObjCImplementation(ObjCImplementationContext &ImplCtx) {}
78234353Sdim};
79234353Sdim
80234353Sdimclass MigrationContext {
81234353Sdim  std::vector<ASTTraverser *> Traversers;
82234353Sdim
83234353Sdimpublic:
84234353Sdim  MigrationPass &Pass;
85234353Sdim
86234353Sdim  struct GCAttrOccurrence {
87234353Sdim    enum AttrKind { Weak, Strong } Kind;
88234353Sdim    SourceLocation Loc;
89234353Sdim    QualType ModifiedType;
90234353Sdim    Decl *Dcl;
91341825Sdim    /// true if the attribute is owned, e.g. it is in a body and not just
92234353Sdim    /// in an interface.
93234353Sdim    bool FullyMigratable;
94234353Sdim  };
95234353Sdim  std::vector<GCAttrOccurrence> GCAttrs;
96234353Sdim  llvm::DenseSet<unsigned> AttrSet;
97234353Sdim  llvm::DenseSet<unsigned> RemovedAttrSet;
98234353Sdim
99341825Sdim  /// Set of raw '@' locations for 'assign' properties group that contain
100234353Sdim  /// GC __weak.
101234353Sdim  llvm::DenseSet<unsigned> AtPropsWeak;
102234353Sdim
103234353Sdim  explicit MigrationContext(MigrationPass &pass) : Pass(pass) {}
104234353Sdim  ~MigrationContext();
105341825Sdim
106234353Sdim  typedef std::vector<ASTTraverser *>::iterator traverser_iterator;
107234353Sdim  traverser_iterator traversers_begin() { return Traversers.begin(); }
108234353Sdim  traverser_iterator traversers_end() { return Traversers.end(); }
109234353Sdim
110234353Sdim  void addTraverser(ASTTraverser *traverser) {
111234353Sdim    Traversers.push_back(traverser);
112234353Sdim  }
113234353Sdim
114234353Sdim  bool isGCOwnedNonObjC(QualType T);
115234353Sdim  bool removePropertyAttribute(StringRef fromAttr, SourceLocation atLoc) {
116234353Sdim    return rewritePropertyAttribute(fromAttr, StringRef(), atLoc);
117234353Sdim  }
118234353Sdim  bool rewritePropertyAttribute(StringRef fromAttr, StringRef toAttr,
119234353Sdim                                SourceLocation atLoc);
120234353Sdim  bool addPropertyAttribute(StringRef attr, SourceLocation atLoc);
121234353Sdim
122234353Sdim  void traverse(TranslationUnitDecl *TU);
123234353Sdim
124234353Sdim  void dumpGCAttrs();
125234353Sdim};
126234353Sdim
127234353Sdimclass PropertyRewriteTraverser : public ASTTraverser {
128234353Sdimpublic:
129276479Sdim  void traverseObjCImplementation(ObjCImplementationContext &ImplCtx) override;
130234353Sdim};
131234353Sdim
132234353Sdimclass BlockObjCVariableTraverser : public ASTTraverser {
133234353Sdimpublic:
134276479Sdim  void traverseBody(BodyContext &BodyCtx) override;
135234353Sdim};
136234353Sdim
137249423Sdimclass ProtectedScopeTraverser : public ASTTraverser {
138249423Sdimpublic:
139276479Sdim  void traverseBody(BodyContext &BodyCtx) override;
140249423Sdim};
141249423Sdim
142234353Sdim// GC transformations
143234353Sdim
144234353Sdimclass GCAttrsTraverser : public ASTTraverser {
145234353Sdimpublic:
146276479Sdim  void traverseTU(MigrationContext &MigrateCtx) override;
147234353Sdim};
148234353Sdim
149234353Sdimclass GCCollectableCallsTraverser : public ASTTraverser {
150234353Sdimpublic:
151276479Sdim  void traverseBody(BodyContext &BodyCtx) override;
152234353Sdim};
153234353Sdim
154224135Sdim//===----------------------------------------------------------------------===//
155224135Sdim// Helpers.
156224135Sdim//===----------------------------------------------------------------------===//
157224135Sdim
158341825Sdim/// Determine whether we can add weak to the given type.
159234353Sdimbool canApplyWeak(ASTContext &Ctx, QualType type,
160234353Sdim                  bool AllowOnUnknownClass = false);
161224135Sdim
162239462Sdimbool isPlusOneAssign(const BinaryOperator *E);
163249423Sdimbool isPlusOne(const Expr *E);
164239462Sdim
165341825Sdim/// 'Loc' is the end of a statement range. This returns the location
166224135Sdim/// immediately after the semicolon following the statement.
167224135Sdim/// If no semicolon is found or the location is inside a macro, the returned
168224135Sdim/// source location will be invalid.
169261991SdimSourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx,
170261991Sdim                                     bool IsDecl = false);
171224135Sdim
172341825Sdim/// 'Loc' is the end of a statement range. This returns the location
173226633Sdim/// of the semicolon following the statement.
174226633Sdim/// If no semicolon is found or the location is inside a macro, the returned
175226633Sdim/// source location will be invalid.
176261991SdimSourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx,
177261991Sdim                                     bool IsDecl = false);
178226633Sdim
179224135Sdimbool hasSideEffects(Expr *E, ASTContext &Ctx);
180224135Sdimbool isGlobalVar(Expr *E);
181341825Sdim/// Returns "nil" or "0" if 'nil' macro is not actually defined.
182288943SdimStringRef getNilString(MigrationPass &Pass);
183224135Sdim
184224135Sdimtemplate <typename BODY_TRANS>
185224135Sdimclass BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > {
186224135Sdim  MigrationPass &Pass;
187239462Sdim  Decl *ParentD;
188224135Sdim
189239462Sdim  typedef RecursiveASTVisitor<BodyTransform<BODY_TRANS> > base;
190224135Sdimpublic:
191276479Sdim  BodyTransform(MigrationPass &pass) : Pass(pass), ParentD(nullptr) { }
192224135Sdim
193224135Sdim  bool TraverseStmt(Stmt *rootS) {
194226633Sdim    if (rootS)
195239462Sdim      BODY_TRANS(Pass).transformBody(rootS, ParentD);
196224135Sdim    return true;
197224135Sdim  }
198239462Sdim
199239462Sdim  bool TraverseObjCMethodDecl(ObjCMethodDecl *D) {
200239462Sdim    SaveAndRestore<Decl *> SetParent(ParentD, D);
201239462Sdim    return base::TraverseObjCMethodDecl(D);
202239462Sdim  }
203224135Sdim};
204224135Sdim
205224135Sdimtypedef llvm::DenseSet<Expr *> ExprSet;
206224135Sdim
207224135Sdimvoid clearRefsIn(Stmt *S, ExprSet &refs);
208224135Sdimtemplate <typename iterator>
209224135Sdimvoid clearRefsIn(iterator begin, iterator end, ExprSet &refs) {
210224135Sdim  for (; begin != end; ++begin)
211224135Sdim    clearRefsIn(*begin, refs);
212224135Sdim}
213224135Sdim
214224135Sdimvoid collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs);
215224135Sdim
216224135Sdimvoid collectRemovables(Stmt *S, ExprSet &exprs);
217224135Sdim
218224135Sdim} // end namespace trans
219224135Sdim
220224135Sdim} // end namespace arcmt
221224135Sdim
222224135Sdim} // end namespace clang
223224135Sdim
224224135Sdim#endif
225