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 000000000000..d0bc332ff160 --- /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]); +  } +}  | 
