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