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