diff options
Diffstat (limited to 'lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp')
-rw-r--r-- | lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp new file mode 100644 index 0000000..d0bc332 --- /dev/null +++ b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp @@ -0,0 +1,211 @@ +//===--- 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" + +using namespace clang; +using namespace arcmt; +using namespace trans; +using llvm::StringRef; + +namespace { + +/// \brief Returns true if the statement became empty due to previous +/// transformations. +class EmptyChecker : public StmtVisitor<EmptyChecker, bool> { + ASTContext &Ctx; + llvm::DenseSet<unsigned> &MacroLocs; + +public: + EmptyChecker(ASTContext &ctx, llvm::DenseSet<unsigned> ¯oLocs) + : Ctx(ctx), MacroLocs(macroLocs) { } + + bool VisitNullStmt(NullStmt *S) { + return isMacroLoc(S->getLeadingEmptyMacroLoc()); + } + 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()); + } + +private: + bool isMacroLoc(SourceLocation loc) { + if (loc.isInvalid()) return false; + return MacroLocs.count(loc.getRawEncoding()); + } +}; + +class EmptyStatementsRemover : + public RecursiveASTVisitor<EmptyStatementsRemover> { + MigrationPass &Pass; + llvm::DenseSet<unsigned> &MacroLocs; + +public: + EmptyStatementsRemover(MigrationPass &pass, + llvm::DenseSet<unsigned> ¯oLocs) + : Pass(pass), MacroLocs(macroLocs) { } + + 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; + } + + bool isMacroLoc(SourceLocation loc) { + if (loc.isInvalid()) return false; + return MacroLocs.count(loc.getRawEncoding()); + } + + ASTContext &getContext() { return Pass.Ctx; } + +private: + void check(Stmt *S) { + if (!S) return; + if (EmptyChecker(Pass.Ctx, MacroLocs).Visit(S)) { + Transaction Trans(Pass.TA); + Pass.TA.removeStmt(S); + } + } +}; + +} // anonymous namespace + +static bool isBodyEmpty(CompoundStmt *body, + ASTContext &Ctx, llvm::DenseSet<unsigned> &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 removeDeallocMethod(MigrationPass &pass, + llvm::DenseSet<unsigned> &MacroLocs) { + ASTContext &Ctx = pass.Ctx; + TransformActions &TA = pass.TA; + DeclContext *DC = Ctx.getTranslationUnitDecl(); + + 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) { + for (ObjCImplementationDecl::instmeth_iterator + MI = (*I)->instmeth_begin(), + ME = (*I)->instmeth_end(); MI != ME; ++MI) { + ObjCMethodDecl *MD = *MI; + if (MD->getMethodFamily() == OMF_dealloc) { + if (MD->hasBody() && + isBodyEmpty(MD->getCompoundBody(), Ctx, MacroLocs)) { + Transaction Trans(TA); + TA.remove(MD->getSourceRange()); + } + break; + } + } + } +} + +void trans::removeEmptyStatementsAndDealloc(MigrationPass &pass) { + llvm::DenseSet<unsigned> MacroLocs; + for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) + MacroLocs.insert(pass.ARCMTMacroLocs[i].getRawEncoding()); + + EmptyStatementsRemover(pass, MacroLocs) + .TraverseDecl(pass.Ctx.getTranslationUnitDecl()); + + removeDeallocMethod(pass, MacroLocs); + + for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) { + Transaction Trans(pass.TA); + pass.TA.remove(pass.ARCMTMacroLocs[i]); + } +} |