1 //===--- TransEmptyStatements.cpp - Tranformations to ARC mode ------------===// 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 // removeEmptyStatementsAndDealloc: 11 // 12 // Removes empty statements that are leftovers from previous transformations. 13 // e.g for 14 // 15 // [x retain]; 16 // 17 // removeRetainReleaseDealloc will leave an empty ";" that removeEmptyStatements 18 // will remove. 19 // 20 //===----------------------------------------------------------------------===// 21 22 #include "Transforms.h" 23 #include "Internals.h" 24 #include "clang/AST/StmtVisitor.h" 25 26 using namespace clang; 27 using namespace arcmt; 28 using namespace trans; 29 30 namespace { 31 32 /// \brief Returns true if the statement became empty due to previous 33 /// transformations. 34 class EmptyChecker : public StmtVisitor<EmptyChecker, bool> { 35 ASTContext &Ctx; 36 llvm::DenseSet<unsigned> &MacroLocs; 37 38 public: 39 EmptyChecker(ASTContext &ctx, llvm::DenseSet<unsigned> ¯oLocs) 40 : Ctx(ctx), MacroLocs(macroLocs) { } 41 42 bool VisitNullStmt(NullStmt *S) { 43 return isMacroLoc(S->getLeadingEmptyMacroLoc()); 44 } 45 bool VisitCompoundStmt(CompoundStmt *S) { 46 if (S->body_empty()) 47 return false; // was already empty, not because of transformations. 48 for (CompoundStmt::body_iterator 49 I = S->body_begin(), E = S->body_end(); I != E; ++I) 50 if (!Visit(*I)) 51 return false; 52 return true; 53 } 54 bool VisitIfStmt(IfStmt *S) { 55 if (S->getConditionVariable()) 56 return false; 57 Expr *condE = S->getCond(); 58 if (!condE) 59 return false; 60 if (hasSideEffects(condE, Ctx)) 61 return false; 62 if (!S->getThen() || !Visit(S->getThen())) 63 return false; 64 if (S->getElse() && !Visit(S->getElse())) 65 return false; 66 return true; 67 } 68 bool VisitWhileStmt(WhileStmt *S) { 69 if (S->getConditionVariable()) 70 return false; 71 Expr *condE = S->getCond(); 72 if (!condE) 73 return false; 74 if (hasSideEffects(condE, Ctx)) 75 return false; 76 if (!S->getBody()) 77 return false; 78 return Visit(S->getBody()); 79 } 80 bool VisitDoStmt(DoStmt *S) { 81 Expr *condE = S->getCond(); 82 if (!condE) 83 return false; 84 if (hasSideEffects(condE, Ctx)) 85 return false; 86 if (!S->getBody()) 87 return false; 88 return Visit(S->getBody()); 89 } 90 bool VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { 91 Expr *Exp = S->getCollection(); 92 if (!Exp) 93 return false; 94 if (hasSideEffects(Exp, Ctx)) 95 return false; 96 if (!S->getBody()) 97 return false; 98 return Visit(S->getBody()); 99 } 100 bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) { 101 if (!S->getSubStmt()) 102 return false; 103 return Visit(S->getSubStmt()); 104 } 105 106 private: 107 bool isMacroLoc(SourceLocation loc) { 108 if (loc.isInvalid()) return false; 109 return MacroLocs.count(loc.getRawEncoding()); 110 } 111 }; 112 113 class EmptyStatementsRemover : 114 public RecursiveASTVisitor<EmptyStatementsRemover> { 115 MigrationPass &Pass; 116 llvm::DenseSet<unsigned> &MacroLocs; 117 118 public: 119 EmptyStatementsRemover(MigrationPass &pass, 120 llvm::DenseSet<unsigned> ¯oLocs) 121 : Pass(pass), MacroLocs(macroLocs) { } 122 123 bool TraverseStmtExpr(StmtExpr *E) { 124 CompoundStmt *S = E->getSubStmt(); 125 for (CompoundStmt::body_iterator 126 I = S->body_begin(), E = S->body_end(); I != E; ++I) { 127 if (I != E - 1) 128 check(*I); 129 TraverseStmt(*I); 130 } 131 return true; 132 } 133 134 bool VisitCompoundStmt(CompoundStmt *S) { 135 for (CompoundStmt::body_iterator 136 I = S->body_begin(), E = S->body_end(); I != E; ++I) 137 check(*I); 138 return true; 139 } 140 141 bool isMacroLoc(SourceLocation loc) { 142 if (loc.isInvalid()) return false; 143 return MacroLocs.count(loc.getRawEncoding()); 144 } 145 146 ASTContext &getContext() { return Pass.Ctx; } 147 148 private: 149 void check(Stmt *S) { 150 if (!S) return; 151 if (EmptyChecker(Pass.Ctx, MacroLocs).Visit(S)) { 152 Transaction Trans(Pass.TA); 153 Pass.TA.removeStmt(S); 154 } 155 } 156 }; 157 158 } // anonymous namespace 159 160 static bool isBodyEmpty(CompoundStmt *body, 161 ASTContext &Ctx, llvm::DenseSet<unsigned> &MacroLocs) { 162 for (CompoundStmt::body_iterator 163 I = body->body_begin(), E = body->body_end(); I != E; ++I) 164 if (!EmptyChecker(Ctx, MacroLocs).Visit(*I)) 165 return false; 166 167 return true; 168 } 169 170 static void removeDeallocMethod(MigrationPass &pass, 171 llvm::DenseSet<unsigned> &MacroLocs) { 172 ASTContext &Ctx = pass.Ctx; 173 TransformActions &TA = pass.TA; 174 DeclContext *DC = Ctx.getTranslationUnitDecl(); 175 176 typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl> 177 impl_iterator; 178 for (impl_iterator I = impl_iterator(DC->decls_begin()), 179 E = impl_iterator(DC->decls_end()); I != E; ++I) { 180 for (ObjCImplementationDecl::instmeth_iterator 181 MI = (*I)->instmeth_begin(), 182 ME = (*I)->instmeth_end(); MI != ME; ++MI) { 183 ObjCMethodDecl *MD = *MI; 184 if (MD->getMethodFamily() == OMF_dealloc) { 185 if (MD->hasBody() && 186 isBodyEmpty(MD->getCompoundBody(), Ctx, MacroLocs)) { 187 Transaction Trans(TA); 188 TA.remove(MD->getSourceRange()); 189 } 190 break; 191 } 192 } 193 } 194 } 195 196 void trans::removeEmptyStatementsAndDealloc(MigrationPass &pass) { 197 llvm::DenseSet<unsigned> MacroLocs; 198 for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) 199 MacroLocs.insert(pass.ARCMTMacroLocs[i].getRawEncoding()); 200 201 EmptyStatementsRemover(pass, MacroLocs) 202 .TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 203 204 removeDeallocMethod(pass, MacroLocs); 205 206 for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) { 207 Transaction Trans(pass.TA); 208 pass.TA.remove(pass.ARCMTMacroLocs[i]); 209 } 210 } 211