clang API Documentation
00001 //===--- TransEmptyStatements.cpp - Tranformations to ARC mode ------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // removeEmptyStatementsAndDealloc: 00011 // 00012 // Removes empty statements that are leftovers from previous transformations. 00013 // e.g for 00014 // 00015 // [x retain]; 00016 // 00017 // removeRetainReleaseDealloc will leave an empty ";" that removeEmptyStatements 00018 // will remove. 00019 // 00020 //===----------------------------------------------------------------------===// 00021 00022 #include "Transforms.h" 00023 #include "Internals.h" 00024 #include "clang/AST/StmtVisitor.h" 00025 #include "clang/Basic/SourceManager.h" 00026 00027 using namespace clang; 00028 using namespace arcmt; 00029 using namespace trans; 00030 00031 static bool isEmptyARCMTMacroStatement(NullStmt *S, 00032 std::vector<SourceLocation> &MacroLocs, 00033 ASTContext &Ctx) { 00034 if (!S->hasLeadingEmptyMacro()) 00035 return false; 00036 00037 SourceLocation SemiLoc = S->getSemiLoc(); 00038 if (SemiLoc.isInvalid() || SemiLoc.isMacroID()) 00039 return false; 00040 00041 if (MacroLocs.empty()) 00042 return false; 00043 00044 SourceManager &SM = Ctx.getSourceManager(); 00045 std::vector<SourceLocation>::iterator 00046 I = std::upper_bound(MacroLocs.begin(), MacroLocs.end(), SemiLoc, 00047 SourceManager::LocBeforeThanCompare(SM)); 00048 --I; 00049 SourceLocation 00050 AfterMacroLoc = I->getLocWithOffset(getARCMTMacroName().size()); 00051 assert(AfterMacroLoc.isFileID()); 00052 00053 if (AfterMacroLoc == SemiLoc) 00054 return true; 00055 00056 int RelOffs = 0; 00057 if (!SM.isInSameSLocAddrSpace(AfterMacroLoc, SemiLoc, &RelOffs)) 00058 return false; 00059 if (RelOffs < 0) 00060 return false; 00061 00062 // We make the reasonable assumption that a semicolon after 100 characters 00063 // means that it is not the next token after our macro. If this assumption 00064 // fails it is not critical, we will just fail to clear out, e.g., an empty 00065 // 'if'. 00066 if (RelOffs - getARCMTMacroName().size() > 100) 00067 return false; 00068 00069 SourceLocation AfterMacroSemiLoc = findSemiAfterLocation(AfterMacroLoc, Ctx); 00070 return AfterMacroSemiLoc == SemiLoc; 00071 } 00072 00073 namespace { 00074 00075 /// \brief Returns true if the statement became empty due to previous 00076 /// transformations. 00077 class EmptyChecker : public StmtVisitor<EmptyChecker, bool> { 00078 ASTContext &Ctx; 00079 std::vector<SourceLocation> &MacroLocs; 00080 00081 public: 00082 EmptyChecker(ASTContext &ctx, std::vector<SourceLocation> ¯oLocs) 00083 : Ctx(ctx), MacroLocs(macroLocs) { } 00084 00085 bool VisitNullStmt(NullStmt *S) { 00086 return isEmptyARCMTMacroStatement(S, MacroLocs, Ctx); 00087 } 00088 bool VisitCompoundStmt(CompoundStmt *S) { 00089 if (S->body_empty()) 00090 return false; // was already empty, not because of transformations. 00091 for (CompoundStmt::body_iterator 00092 I = S->body_begin(), E = S->body_end(); I != E; ++I) 00093 if (!Visit(*I)) 00094 return false; 00095 return true; 00096 } 00097 bool VisitIfStmt(IfStmt *S) { 00098 if (S->getConditionVariable()) 00099 return false; 00100 Expr *condE = S->getCond(); 00101 if (!condE) 00102 return false; 00103 if (hasSideEffects(condE, Ctx)) 00104 return false; 00105 if (!S->getThen() || !Visit(S->getThen())) 00106 return false; 00107 if (S->getElse() && !Visit(S->getElse())) 00108 return false; 00109 return true; 00110 } 00111 bool VisitWhileStmt(WhileStmt *S) { 00112 if (S->getConditionVariable()) 00113 return false; 00114 Expr *condE = S->getCond(); 00115 if (!condE) 00116 return false; 00117 if (hasSideEffects(condE, Ctx)) 00118 return false; 00119 if (!S->getBody()) 00120 return false; 00121 return Visit(S->getBody()); 00122 } 00123 bool VisitDoStmt(DoStmt *S) { 00124 Expr *condE = S->getCond(); 00125 if (!condE) 00126 return false; 00127 if (hasSideEffects(condE, Ctx)) 00128 return false; 00129 if (!S->getBody()) 00130 return false; 00131 return Visit(S->getBody()); 00132 } 00133 bool VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { 00134 Expr *Exp = S->getCollection(); 00135 if (!Exp) 00136 return false; 00137 if (hasSideEffects(Exp, Ctx)) 00138 return false; 00139 if (!S->getBody()) 00140 return false; 00141 return Visit(S->getBody()); 00142 } 00143 bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) { 00144 if (!S->getSubStmt()) 00145 return false; 00146 return Visit(S->getSubStmt()); 00147 } 00148 }; 00149 00150 class EmptyStatementsRemover : 00151 public RecursiveASTVisitor<EmptyStatementsRemover> { 00152 MigrationPass &Pass; 00153 00154 public: 00155 EmptyStatementsRemover(MigrationPass &pass) : Pass(pass) { } 00156 00157 bool TraverseStmtExpr(StmtExpr *E) { 00158 CompoundStmt *S = E->getSubStmt(); 00159 for (CompoundStmt::body_iterator 00160 I = S->body_begin(), E = S->body_end(); I != E; ++I) { 00161 if (I != E - 1) 00162 check(*I); 00163 TraverseStmt(*I); 00164 } 00165 return true; 00166 } 00167 00168 bool VisitCompoundStmt(CompoundStmt *S) { 00169 for (CompoundStmt::body_iterator 00170 I = S->body_begin(), E = S->body_end(); I != E; ++I) 00171 check(*I); 00172 return true; 00173 } 00174 00175 ASTContext &getContext() { return Pass.Ctx; } 00176 00177 private: 00178 void check(Stmt *S) { 00179 if (!S) return; 00180 if (EmptyChecker(Pass.Ctx, Pass.ARCMTMacroLocs).Visit(S)) { 00181 Transaction Trans(Pass.TA); 00182 Pass.TA.removeStmt(S); 00183 } 00184 } 00185 }; 00186 00187 } // anonymous namespace 00188 00189 static bool isBodyEmpty(CompoundStmt *body, ASTContext &Ctx, 00190 std::vector<SourceLocation> &MacroLocs) { 00191 for (CompoundStmt::body_iterator 00192 I = body->body_begin(), E = body->body_end(); I != E; ++I) 00193 if (!EmptyChecker(Ctx, MacroLocs).Visit(*I)) 00194 return false; 00195 00196 return true; 00197 } 00198 00199 static void cleanupDeallocOrFinalize(MigrationPass &pass) { 00200 ASTContext &Ctx = pass.Ctx; 00201 TransformActions &TA = pass.TA; 00202 DeclContext *DC = Ctx.getTranslationUnitDecl(); 00203 Selector FinalizeSel = 00204 Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize")); 00205 00206 typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl> 00207 impl_iterator; 00208 for (impl_iterator I = impl_iterator(DC->decls_begin()), 00209 E = impl_iterator(DC->decls_end()); I != E; ++I) { 00210 ObjCMethodDecl *DeallocM = 0; 00211 ObjCMethodDecl *FinalizeM = 0; 00212 for (ObjCImplementationDecl::instmeth_iterator 00213 MI = I->instmeth_begin(), 00214 ME = I->instmeth_end(); MI != ME; ++MI) { 00215 ObjCMethodDecl *MD = *MI; 00216 if (!MD->hasBody()) 00217 continue; 00218 00219 if (MD->getMethodFamily() == OMF_dealloc) { 00220 DeallocM = MD; 00221 } else if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) { 00222 FinalizeM = MD; 00223 } 00224 } 00225 00226 if (DeallocM) { 00227 if (isBodyEmpty(DeallocM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) { 00228 Transaction Trans(TA); 00229 TA.remove(DeallocM->getSourceRange()); 00230 } 00231 00232 if (FinalizeM) { 00233 Transaction Trans(TA); 00234 TA.remove(FinalizeM->getSourceRange()); 00235 } 00236 00237 } else if (FinalizeM) { 00238 if (isBodyEmpty(FinalizeM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) { 00239 Transaction Trans(TA); 00240 TA.remove(FinalizeM->getSourceRange()); 00241 } else { 00242 Transaction Trans(TA); 00243 TA.replaceText(FinalizeM->getSelectorStartLoc(), "finalize", "dealloc"); 00244 } 00245 } 00246 } 00247 } 00248 00249 void trans::removeEmptyStatementsAndDeallocFinalize(MigrationPass &pass) { 00250 EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 00251 00252 cleanupDeallocOrFinalize(pass); 00253 00254 for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) { 00255 Transaction Trans(pass.TA); 00256 pass.TA.remove(pass.ARCMTMacroLocs[i]); 00257 } 00258 }