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