clang API Documentation
00001 //===--- TransEmptyStatements.cpp - Transformations 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/ASTContext.h" 00025 #include "clang/AST/StmtVisitor.h" 00026 #include "clang/Basic/SourceManager.h" 00027 00028 using namespace clang; 00029 using namespace arcmt; 00030 using namespace trans; 00031 00032 static bool isEmptyARCMTMacroStatement(NullStmt *S, 00033 std::vector<SourceLocation> &MacroLocs, 00034 ASTContext &Ctx) { 00035 if (!S->hasLeadingEmptyMacro()) 00036 return false; 00037 00038 SourceLocation SemiLoc = S->getSemiLoc(); 00039 if (SemiLoc.isInvalid() || SemiLoc.isMacroID()) 00040 return false; 00041 00042 if (MacroLocs.empty()) 00043 return false; 00044 00045 SourceManager &SM = Ctx.getSourceManager(); 00046 std::vector<SourceLocation>::iterator 00047 I = std::upper_bound(MacroLocs.begin(), MacroLocs.end(), SemiLoc, 00048 BeforeThanCompare<SourceLocation>(SM)); 00049 --I; 00050 SourceLocation 00051 AfterMacroLoc = I->getLocWithOffset(getARCMTMacroName().size()); 00052 assert(AfterMacroLoc.isFileID()); 00053 00054 if (AfterMacroLoc == SemiLoc) 00055 return true; 00056 00057 int RelOffs = 0; 00058 if (!SM.isInSameSLocAddrSpace(AfterMacroLoc, SemiLoc, &RelOffs)) 00059 return false; 00060 if (RelOffs < 0) 00061 return false; 00062 00063 // We make the reasonable assumption that a semicolon after 100 characters 00064 // means that it is not the next token after our macro. If this assumption 00065 // fails it is not critical, we will just fail to clear out, e.g., an empty 00066 // 'if'. 00067 if (RelOffs - getARCMTMacroName().size() > 100) 00068 return false; 00069 00070 SourceLocation AfterMacroSemiLoc = findSemiAfterLocation(AfterMacroLoc, Ctx); 00071 return AfterMacroSemiLoc == SemiLoc; 00072 } 00073 00074 namespace { 00075 00076 /// \brief Returns true if the statement became empty due to previous 00077 /// transformations. 00078 class EmptyChecker : public StmtVisitor<EmptyChecker, bool> { 00079 ASTContext &Ctx; 00080 std::vector<SourceLocation> &MacroLocs; 00081 00082 public: 00083 EmptyChecker(ASTContext &ctx, std::vector<SourceLocation> ¯oLocs) 00084 : Ctx(ctx), MacroLocs(macroLocs) { } 00085 00086 bool VisitNullStmt(NullStmt *S) { 00087 return isEmptyARCMTMacroStatement(S, MacroLocs, Ctx); 00088 } 00089 bool VisitCompoundStmt(CompoundStmt *S) { 00090 if (S->body_empty()) 00091 return false; // was already empty, not because of transformations. 00092 for (auto *I : S->body()) 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 (auto *I : S->body()) 00170 check(I); 00171 return true; 00172 } 00173 00174 ASTContext &getContext() { return Pass.Ctx; } 00175 00176 private: 00177 void check(Stmt *S) { 00178 if (!S) return; 00179 if (EmptyChecker(Pass.Ctx, Pass.ARCMTMacroLocs).Visit(S)) { 00180 Transaction Trans(Pass.TA); 00181 Pass.TA.removeStmt(S); 00182 } 00183 } 00184 }; 00185 00186 } // anonymous namespace 00187 00188 static bool isBodyEmpty(CompoundStmt *body, ASTContext &Ctx, 00189 std::vector<SourceLocation> &MacroLocs) { 00190 for (auto *I : body->body()) 00191 if (!EmptyChecker(Ctx, MacroLocs).Visit(I)) 00192 return false; 00193 00194 return true; 00195 } 00196 00197 static void cleanupDeallocOrFinalize(MigrationPass &pass) { 00198 ASTContext &Ctx = pass.Ctx; 00199 TransformActions &TA = pass.TA; 00200 DeclContext *DC = Ctx.getTranslationUnitDecl(); 00201 Selector FinalizeSel = 00202 Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize")); 00203 00204 typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl> 00205 impl_iterator; 00206 for (impl_iterator I = impl_iterator(DC->decls_begin()), 00207 E = impl_iterator(DC->decls_end()); I != E; ++I) { 00208 ObjCMethodDecl *DeallocM = nullptr; 00209 ObjCMethodDecl *FinalizeM = nullptr; 00210 for (auto *MD : I->instance_methods()) { 00211 if (!MD->hasBody()) 00212 continue; 00213 00214 if (MD->getMethodFamily() == OMF_dealloc) { 00215 DeallocM = MD; 00216 } else if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) { 00217 FinalizeM = MD; 00218 } 00219 } 00220 00221 if (DeallocM) { 00222 if (isBodyEmpty(DeallocM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) { 00223 Transaction Trans(TA); 00224 TA.remove(DeallocM->getSourceRange()); 00225 } 00226 00227 if (FinalizeM) { 00228 Transaction Trans(TA); 00229 TA.remove(FinalizeM->getSourceRange()); 00230 } 00231 00232 } else if (FinalizeM) { 00233 if (isBodyEmpty(FinalizeM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) { 00234 Transaction Trans(TA); 00235 TA.remove(FinalizeM->getSourceRange()); 00236 } else { 00237 Transaction Trans(TA); 00238 TA.replaceText(FinalizeM->getSelectorStartLoc(), "finalize", "dealloc"); 00239 } 00240 } 00241 } 00242 } 00243 00244 void trans::removeEmptyStatementsAndDeallocFinalize(MigrationPass &pass) { 00245 EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 00246 00247 cleanupDeallocOrFinalize(pass); 00248 00249 for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) { 00250 Transaction Trans(pass.TA); 00251 pass.TA.remove(pass.ARCMTMacroLocs[i]); 00252 } 00253 }