clang API Documentation

TransEmptyStatementsAndDealloc.cpp
Go to the documentation of this file.
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> &macroLocs)
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 }