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/ASTContext.h" 25#include "clang/AST/StmtVisitor.h" 26#include "clang/Basic/SourceManager.h" 27 28using namespace clang; 29using namespace arcmt; 30using namespace trans; 31 32static bool isEmptyARCMTMacroStatement(NullStmt *S, 33 std::vector<SourceLocation> &MacroLocs, 34 ASTContext &Ctx) { 35 if (!S->hasLeadingEmptyMacro()) 36 return false; 37 38 SourceLocation SemiLoc = S->getSemiLoc(); 39 if (SemiLoc.isInvalid() || SemiLoc.isMacroID()) 40 return false; 41 42 if (MacroLocs.empty()) 43 return false; 44 45 SourceManager &SM = Ctx.getSourceManager(); 46 std::vector<SourceLocation>::iterator 47 I = std::upper_bound(MacroLocs.begin(), MacroLocs.end(), SemiLoc, 48 BeforeThanCompare<SourceLocation>(SM)); 49 --I; 50 SourceLocation 51 AfterMacroLoc = I->getLocWithOffset(getARCMTMacroName().size()); 52 assert(AfterMacroLoc.isFileID()); 53 54 if (AfterMacroLoc == SemiLoc) 55 return true; 56 57 int RelOffs = 0; 58 if (!SM.isInSameSLocAddrSpace(AfterMacroLoc, SemiLoc, &RelOffs)) 59 return false; 60 if (RelOffs < 0) 61 return false; 62 63 // We make the reasonable assumption that a semicolon after 100 characters 64 // means that it is not the next token after our macro. If this assumption 65 // fails it is not critical, we will just fail to clear out, e.g., an empty 66 // 'if'. 67 if (RelOffs - getARCMTMacroName().size() > 100) 68 return false; 69 70 SourceLocation AfterMacroSemiLoc = findSemiAfterLocation(AfterMacroLoc, Ctx); 71 return AfterMacroSemiLoc == SemiLoc; 72} 73 74namespace { 75 76/// \brief Returns true if the statement became empty due to previous 77/// transformations. 78class EmptyChecker : public StmtVisitor<EmptyChecker, bool> { 79 ASTContext &Ctx; 80 std::vector<SourceLocation> &MacroLocs; 81 82public: 83 EmptyChecker(ASTContext &ctx, std::vector<SourceLocation> ¯oLocs) 84 : Ctx(ctx), MacroLocs(macroLocs) { } 85 86 bool VisitNullStmt(NullStmt *S) { 87 return isEmptyARCMTMacroStatement(S, MacroLocs, Ctx); 88 } 89 bool VisitCompoundStmt(CompoundStmt *S) { 90 if (S->body_empty()) 91 return false; // was already empty, not because of transformations. 92 for (CompoundStmt::body_iterator 93 I = S->body_begin(), E = S->body_end(); I != E; ++I) 94 if (!Visit(*I)) 95 return false; 96 return true; 97 } 98 bool VisitIfStmt(IfStmt *S) { 99 if (S->getConditionVariable()) 100 return false; 101 Expr *condE = S->getCond(); 102 if (!condE) 103 return false; 104 if (hasSideEffects(condE, Ctx)) 105 return false; 106 if (!S->getThen() || !Visit(S->getThen())) 107 return false; 108 if (S->getElse() && !Visit(S->getElse())) 109 return false; 110 return true; 111 } 112 bool VisitWhileStmt(WhileStmt *S) { 113 if (S->getConditionVariable()) 114 return false; 115 Expr *condE = S->getCond(); 116 if (!condE) 117 return false; 118 if (hasSideEffects(condE, Ctx)) 119 return false; 120 if (!S->getBody()) 121 return false; 122 return Visit(S->getBody()); 123 } 124 bool VisitDoStmt(DoStmt *S) { 125 Expr *condE = S->getCond(); 126 if (!condE) 127 return false; 128 if (hasSideEffects(condE, Ctx)) 129 return false; 130 if (!S->getBody()) 131 return false; 132 return Visit(S->getBody()); 133 } 134 bool VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { 135 Expr *Exp = S->getCollection(); 136 if (!Exp) 137 return false; 138 if (hasSideEffects(Exp, Ctx)) 139 return false; 140 if (!S->getBody()) 141 return false; 142 return Visit(S->getBody()); 143 } 144 bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) { 145 if (!S->getSubStmt()) 146 return false; 147 return Visit(S->getSubStmt()); 148 } 149}; 150 151class EmptyStatementsRemover : 152 public RecursiveASTVisitor<EmptyStatementsRemover> { 153 MigrationPass &Pass; 154 155public: 156 EmptyStatementsRemover(MigrationPass &pass) : Pass(pass) { } 157 158 bool TraverseStmtExpr(StmtExpr *E) { 159 CompoundStmt *S = E->getSubStmt(); 160 for (CompoundStmt::body_iterator 161 I = S->body_begin(), E = S->body_end(); I != E; ++I) { 162 if (I != E - 1) 163 check(*I); 164 TraverseStmt(*I); 165 } 166 return true; 167 } 168 169 bool VisitCompoundStmt(CompoundStmt *S) { 170 for (CompoundStmt::body_iterator 171 I = S->body_begin(), E = S->body_end(); I != E; ++I) 172 check(*I); 173 return true; 174 } 175 176 ASTContext &getContext() { return Pass.Ctx; } 177 178private: 179 void check(Stmt *S) { 180 if (!S) return; 181 if (EmptyChecker(Pass.Ctx, Pass.ARCMTMacroLocs).Visit(S)) { 182 Transaction Trans(Pass.TA); 183 Pass.TA.removeStmt(S); 184 } 185 } 186}; 187 188} // anonymous namespace 189 190static bool isBodyEmpty(CompoundStmt *body, ASTContext &Ctx, 191 std::vector<SourceLocation> &MacroLocs) { 192 for (CompoundStmt::body_iterator 193 I = body->body_begin(), E = body->body_end(); I != E; ++I) 194 if (!EmptyChecker(Ctx, MacroLocs).Visit(*I)) 195 return false; 196 197 return true; 198} 199 200static void cleanupDeallocOrFinalize(MigrationPass &pass) { 201 ASTContext &Ctx = pass.Ctx; 202 TransformActions &TA = pass.TA; 203 DeclContext *DC = Ctx.getTranslationUnitDecl(); 204 Selector FinalizeSel = 205 Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize")); 206 207 typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl> 208 impl_iterator; 209 for (impl_iterator I = impl_iterator(DC->decls_begin()), 210 E = impl_iterator(DC->decls_end()); I != E; ++I) { 211 ObjCMethodDecl *DeallocM = 0; 212 ObjCMethodDecl *FinalizeM = 0; 213 for (ObjCImplementationDecl::instmeth_iterator 214 MI = I->instmeth_begin(), 215 ME = I->instmeth_end(); MI != ME; ++MI) { 216 ObjCMethodDecl *MD = *MI; 217 if (!MD->hasBody()) 218 continue; 219 220 if (MD->getMethodFamily() == OMF_dealloc) { 221 DeallocM = MD; 222 } else if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) { 223 FinalizeM = MD; 224 } 225 } 226 227 if (DeallocM) { 228 if (isBodyEmpty(DeallocM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) { 229 Transaction Trans(TA); 230 TA.remove(DeallocM->getSourceRange()); 231 } 232 233 if (FinalizeM) { 234 Transaction Trans(TA); 235 TA.remove(FinalizeM->getSourceRange()); 236 } 237 238 } else if (FinalizeM) { 239 if (isBodyEmpty(FinalizeM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) { 240 Transaction Trans(TA); 241 TA.remove(FinalizeM->getSourceRange()); 242 } else { 243 Transaction Trans(TA); 244 TA.replaceText(FinalizeM->getSelectorStartLoc(), "finalize", "dealloc"); 245 } 246 } 247 } 248} 249 250void trans::removeEmptyStatementsAndDeallocFinalize(MigrationPass &pass) { 251 EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 252 253 cleanupDeallocOrFinalize(pass); 254 255 for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) { 256 Transaction Trans(pass.TA); 257 pass.TA.remove(pass.ARCMTMacroLocs[i]); 258 } 259} 260