diff options
Diffstat (limited to 'clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp')
-rw-r--r-- | clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp new file mode 100644 index 0000000..0fb7141 --- /dev/null +++ b/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp @@ -0,0 +1,258 @@ +//===--- TransEmptyStatements.cpp - Tranformations to ARC mode ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// removeEmptyStatementsAndDealloc: +// +// Removes empty statements that are leftovers from previous transformations. +// e.g for +// +// [x retain]; +// +// removeRetainReleaseDealloc will leave an empty ";" that removeEmptyStatements +// will remove. +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/SourceManager.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; + +static bool isEmptyARCMTMacroStatement(NullStmt *S, + std::vector<SourceLocation> &MacroLocs, + ASTContext &Ctx) { + if (!S->hasLeadingEmptyMacro()) + return false; + + SourceLocation SemiLoc = S->getSemiLoc(); + if (SemiLoc.isInvalid() || SemiLoc.isMacroID()) + return false; + + if (MacroLocs.empty()) + return false; + + SourceManager &SM = Ctx.getSourceManager(); + std::vector<SourceLocation>::iterator + I = std::upper_bound(MacroLocs.begin(), MacroLocs.end(), SemiLoc, + SourceManager::LocBeforeThanCompare(SM)); + --I; + SourceLocation + AfterMacroLoc = I->getLocWithOffset(getARCMTMacroName().size()); + assert(AfterMacroLoc.isFileID()); + + if (AfterMacroLoc == SemiLoc) + return true; + + int RelOffs = 0; + if (!SM.isInSameSLocAddrSpace(AfterMacroLoc, SemiLoc, &RelOffs)) + return false; + if (RelOffs < 0) + return false; + + // We make the reasonable assumption that a semicolon after 100 characters + // means that it is not the next token after our macro. If this assumption + // fails it is not critical, we will just fail to clear out, e.g., an empty + // 'if'. + if (RelOffs - getARCMTMacroName().size() > 100) + return false; + + SourceLocation AfterMacroSemiLoc = findSemiAfterLocation(AfterMacroLoc, Ctx); + return AfterMacroSemiLoc == SemiLoc; +} + +namespace { + +/// \brief Returns true if the statement became empty due to previous +/// transformations. +class EmptyChecker : public StmtVisitor<EmptyChecker, bool> { + ASTContext &Ctx; + std::vector<SourceLocation> &MacroLocs; + +public: + EmptyChecker(ASTContext &ctx, std::vector<SourceLocation> ¯oLocs) + : Ctx(ctx), MacroLocs(macroLocs) { } + + bool VisitNullStmt(NullStmt *S) { + return isEmptyARCMTMacroStatement(S, MacroLocs, Ctx); + } + bool VisitCompoundStmt(CompoundStmt *S) { + if (S->body_empty()) + return false; // was already empty, not because of transformations. + for (CompoundStmt::body_iterator + I = S->body_begin(), E = S->body_end(); I != E; ++I) + if (!Visit(*I)) + return false; + return true; + } + bool VisitIfStmt(IfStmt *S) { + if (S->getConditionVariable()) + return false; + Expr *condE = S->getCond(); + if (!condE) + return false; + if (hasSideEffects(condE, Ctx)) + return false; + if (!S->getThen() || !Visit(S->getThen())) + return false; + if (S->getElse() && !Visit(S->getElse())) + return false; + return true; + } + bool VisitWhileStmt(WhileStmt *S) { + if (S->getConditionVariable()) + return false; + Expr *condE = S->getCond(); + if (!condE) + return false; + if (hasSideEffects(condE, Ctx)) + return false; + if (!S->getBody()) + return false; + return Visit(S->getBody()); + } + bool VisitDoStmt(DoStmt *S) { + Expr *condE = S->getCond(); + if (!condE) + return false; + if (hasSideEffects(condE, Ctx)) + return false; + if (!S->getBody()) + return false; + return Visit(S->getBody()); + } + bool VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { + Expr *Exp = S->getCollection(); + if (!Exp) + return false; + if (hasSideEffects(Exp, Ctx)) + return false; + if (!S->getBody()) + return false; + return Visit(S->getBody()); + } + bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) { + if (!S->getSubStmt()) + return false; + return Visit(S->getSubStmt()); + } +}; + +class EmptyStatementsRemover : + public RecursiveASTVisitor<EmptyStatementsRemover> { + MigrationPass &Pass; + +public: + EmptyStatementsRemover(MigrationPass &pass) : Pass(pass) { } + + bool TraverseStmtExpr(StmtExpr *E) { + CompoundStmt *S = E->getSubStmt(); + for (CompoundStmt::body_iterator + I = S->body_begin(), E = S->body_end(); I != E; ++I) { + if (I != E - 1) + check(*I); + TraverseStmt(*I); + } + return true; + } + + bool VisitCompoundStmt(CompoundStmt *S) { + for (CompoundStmt::body_iterator + I = S->body_begin(), E = S->body_end(); I != E; ++I) + check(*I); + return true; + } + + ASTContext &getContext() { return Pass.Ctx; } + +private: + void check(Stmt *S) { + if (!S) return; + if (EmptyChecker(Pass.Ctx, Pass.ARCMTMacroLocs).Visit(S)) { + Transaction Trans(Pass.TA); + Pass.TA.removeStmt(S); + } + } +}; + +} // anonymous namespace + +static bool isBodyEmpty(CompoundStmt *body, ASTContext &Ctx, + std::vector<SourceLocation> &MacroLocs) { + for (CompoundStmt::body_iterator + I = body->body_begin(), E = body->body_end(); I != E; ++I) + if (!EmptyChecker(Ctx, MacroLocs).Visit(*I)) + return false; + + return true; +} + +static void cleanupDeallocOrFinalize(MigrationPass &pass) { + ASTContext &Ctx = pass.Ctx; + TransformActions &TA = pass.TA; + DeclContext *DC = Ctx.getTranslationUnitDecl(); + Selector FinalizeSel = + Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize")); + + typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl> + impl_iterator; + for (impl_iterator I = impl_iterator(DC->decls_begin()), + E = impl_iterator(DC->decls_end()); I != E; ++I) { + ObjCMethodDecl *DeallocM = 0; + ObjCMethodDecl *FinalizeM = 0; + for (ObjCImplementationDecl::instmeth_iterator + MI = (*I)->instmeth_begin(), + ME = (*I)->instmeth_end(); MI != ME; ++MI) { + ObjCMethodDecl *MD = *MI; + if (!MD->hasBody()) + continue; + + if (MD->getMethodFamily() == OMF_dealloc) { + DeallocM = MD; + } else if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) { + FinalizeM = MD; + } + } + + if (DeallocM) { + if (isBodyEmpty(DeallocM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) { + Transaction Trans(TA); + TA.remove(DeallocM->getSourceRange()); + } + + if (FinalizeM) { + Transaction Trans(TA); + TA.remove(FinalizeM->getSourceRange()); + } + + } else if (FinalizeM) { + if (isBodyEmpty(FinalizeM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) { + Transaction Trans(TA); + TA.remove(FinalizeM->getSourceRange()); + } else { + Transaction Trans(TA); + TA.replaceText(FinalizeM->getSelectorStartLoc(), "finalize", "dealloc"); + } + } + } +} + +void trans::removeEmptyStatementsAndDeallocFinalize(MigrationPass &pass) { + EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); + + cleanupDeallocOrFinalize(pass); + + for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) { + Transaction Trans(pass.TA); + pass.TA.remove(pass.ARCMTMacroLocs[i]); + } +} |