clang API Documentation

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