//===--- 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 { ASTContext &Ctx; llvm::DenseSet &MacroLocs; public: EmptyChecker(ASTContext &ctx, llvm::DenseSet ¯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 { MigrationPass &Pass; llvm::DenseSet &MacroLocs; public: EmptyStatementsRemover(MigrationPass &pass, llvm::DenseSet ¯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 &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 &MacroLocs) { ASTContext &Ctx = pass.Ctx; TransformActions &TA = pass.TA; DeclContext *DC = Ctx.getTranslationUnitDecl(); typedef DeclContext::specific_decl_iterator 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 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]); } }