TransEmptyStatementsAndDealloc.cpp revision 226633
1189251Ssam//===--- TransEmptyStatements.cpp - Tranformations to ARC mode ------------===//
2189251Ssam//
3189251Ssam//                     The LLVM Compiler Infrastructure
4189251Ssam//
5252726Srpaulo// This file is distributed under the University of Illinois Open Source
6252726Srpaulo// License. See LICENSE.TXT for details.
7189251Ssam//
8189251Ssam//===----------------------------------------------------------------------===//
9189251Ssam//
10189251Ssam// removeEmptyStatementsAndDealloc:
11189251Ssam//
12189251Ssam// Removes empty statements that are leftovers from previous transformations.
13189251Ssam// e.g for
14189251Ssam//
15189251Ssam//  [x retain];
16189251Ssam//
17189251Ssam// removeRetainReleaseDealloc will leave an empty ";" that removeEmptyStatements
18189251Ssam// will remove.
19189251Ssam//
20189251Ssam//===----------------------------------------------------------------------===//
21189251Ssam
22189251Ssam#include "Transforms.h"
23189251Ssam#include "Internals.h"
24189251Ssam#include "clang/AST/StmtVisitor.h"
25189251Ssam#include "clang/Basic/SourceManager.h"
26189251Ssam
27189251Ssamusing namespace clang;
28189251Ssamusing namespace arcmt;
29189251Ssamusing namespace trans;
30189251Ssam
31189251Ssamstatic bool isEmptyARCMTMacroStatement(NullStmt *S,
32189251Ssam                                       std::vector<SourceLocation> &MacroLocs,
33189251Ssam                                       ASTContext &Ctx) {
34189251Ssam  if (!S->hasLeadingEmptyMacro())
35189251Ssam    return false;
36189251Ssam
37189251Ssam  SourceLocation SemiLoc = S->getSemiLoc();
38189251Ssam  if (SemiLoc.isInvalid() || SemiLoc.isMacroID())
39189251Ssam    return false;
40189251Ssam
41189251Ssam  if (MacroLocs.empty())
42189251Ssam    return false;
43189251Ssam
44189251Ssam  SourceManager &SM = Ctx.getSourceManager();
45189251Ssam  std::vector<SourceLocation>::iterator
46189251Ssam    I = std::upper_bound(MacroLocs.begin(), MacroLocs.end(), SemiLoc,
47189251Ssam                         SourceManager::LocBeforeThanCompare(SM));
48189251Ssam  --I;
49189251Ssam  SourceLocation
50189251Ssam      AfterMacroLoc = I->getLocWithOffset(getARCMTMacroName().size());
51189251Ssam  assert(AfterMacroLoc.isFileID());
52189251Ssam
53189251Ssam  if (AfterMacroLoc == SemiLoc)
54189251Ssam    return true;
55189251Ssam
56189251Ssam  int RelOffs = 0;
57189251Ssam  if (!SM.isInSameSLocAddrSpace(AfterMacroLoc, SemiLoc, &RelOffs))
58189251Ssam    return false;
59189251Ssam  if (RelOffs < 0)
60189251Ssam    return false;
61189251Ssam
62  // We make the reasonable assumption that a semicolon after 100 characters
63  // means that it is not the next token after our macro. If this assumption
64  // fails it is not critical, we will just fail to clear out, e.g., an empty
65  // 'if'.
66  if (RelOffs - getARCMTMacroName().size() > 100)
67    return false;
68
69  SourceLocation AfterMacroSemiLoc = findSemiAfterLocation(AfterMacroLoc, Ctx);
70  return AfterMacroSemiLoc == SemiLoc;
71}
72
73namespace {
74
75/// \brief Returns true if the statement became empty due to previous
76/// transformations.
77class EmptyChecker : public StmtVisitor<EmptyChecker, bool> {
78  ASTContext &Ctx;
79  std::vector<SourceLocation> &MacroLocs;
80
81public:
82  EmptyChecker(ASTContext &ctx, std::vector<SourceLocation> &macroLocs)
83    : Ctx(ctx), MacroLocs(macroLocs) { }
84
85  bool VisitNullStmt(NullStmt *S) {
86    return isEmptyARCMTMacroStatement(S, MacroLocs, Ctx);
87  }
88  bool VisitCompoundStmt(CompoundStmt *S) {
89    if (S->body_empty())
90      return false; // was already empty, not because of transformations.
91    for (CompoundStmt::body_iterator
92           I = S->body_begin(), E = S->body_end(); I != E; ++I)
93      if (!Visit(*I))
94        return false;
95    return true;
96  }
97  bool VisitIfStmt(IfStmt *S) {
98    if (S->getConditionVariable())
99      return false;
100    Expr *condE = S->getCond();
101    if (!condE)
102      return false;
103    if (hasSideEffects(condE, Ctx))
104      return false;
105    if (!S->getThen() || !Visit(S->getThen()))
106      return false;
107    if (S->getElse() && !Visit(S->getElse()))
108      return false;
109    return true;
110  }
111  bool VisitWhileStmt(WhileStmt *S) {
112    if (S->getConditionVariable())
113      return false;
114    Expr *condE = S->getCond();
115    if (!condE)
116      return false;
117    if (hasSideEffects(condE, Ctx))
118      return false;
119    if (!S->getBody())
120      return false;
121    return Visit(S->getBody());
122  }
123  bool VisitDoStmt(DoStmt *S) {
124    Expr *condE = S->getCond();
125    if (!condE)
126      return false;
127    if (hasSideEffects(condE, Ctx))
128      return false;
129    if (!S->getBody())
130      return false;
131    return Visit(S->getBody());
132  }
133  bool VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
134    Expr *Exp = S->getCollection();
135    if (!Exp)
136      return false;
137    if (hasSideEffects(Exp, Ctx))
138      return false;
139    if (!S->getBody())
140      return false;
141    return Visit(S->getBody());
142  }
143  bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
144    if (!S->getSubStmt())
145      return false;
146    return Visit(S->getSubStmt());
147  }
148};
149
150class EmptyStatementsRemover :
151                            public RecursiveASTVisitor<EmptyStatementsRemover> {
152  MigrationPass &Pass;
153
154public:
155  EmptyStatementsRemover(MigrationPass &pass) : Pass(pass) { }
156
157  bool TraverseStmtExpr(StmtExpr *E) {
158    CompoundStmt *S = E->getSubStmt();
159    for (CompoundStmt::body_iterator
160           I = S->body_begin(), E = S->body_end(); I != E; ++I) {
161      if (I != E - 1)
162        check(*I);
163      TraverseStmt(*I);
164    }
165    return true;
166  }
167
168  bool VisitCompoundStmt(CompoundStmt *S) {
169    for (CompoundStmt::body_iterator
170           I = S->body_begin(), E = S->body_end(); I != E; ++I)
171      check(*I);
172    return true;
173  }
174
175  ASTContext &getContext() { return Pass.Ctx; }
176
177private:
178  void check(Stmt *S) {
179    if (!S) return;
180    if (EmptyChecker(Pass.Ctx, Pass.ARCMTMacroLocs).Visit(S)) {
181      Transaction Trans(Pass.TA);
182      Pass.TA.removeStmt(S);
183    }
184  }
185};
186
187} // anonymous namespace
188
189static bool isBodyEmpty(CompoundStmt *body, ASTContext &Ctx,
190                        std::vector<SourceLocation> &MacroLocs) {
191  for (CompoundStmt::body_iterator
192         I = body->body_begin(), E = body->body_end(); I != E; ++I)
193    if (!EmptyChecker(Ctx, MacroLocs).Visit(*I))
194      return false;
195
196  return true;
197}
198
199static void removeDeallocMethod(MigrationPass &pass) {
200  ASTContext &Ctx = pass.Ctx;
201  TransformActions &TA = pass.TA;
202  DeclContext *DC = Ctx.getTranslationUnitDecl();
203
204  typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
205    impl_iterator;
206  for (impl_iterator I = impl_iterator(DC->decls_begin()),
207                     E = impl_iterator(DC->decls_end()); I != E; ++I) {
208    for (ObjCImplementationDecl::instmeth_iterator
209           MI = (*I)->instmeth_begin(),
210           ME = (*I)->instmeth_end(); MI != ME; ++MI) {
211      ObjCMethodDecl *MD = *MI;
212      if (MD->getMethodFamily() == OMF_dealloc) {
213        if (MD->hasBody() &&
214            isBodyEmpty(MD->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {
215          Transaction Trans(TA);
216          TA.remove(MD->getSourceRange());
217        }
218        break;
219      }
220    }
221  }
222}
223
224void trans::removeEmptyStatementsAndDealloc(MigrationPass &pass) {
225  EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
226
227  removeDeallocMethod(pass);
228
229  for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) {
230    Transaction Trans(pass.TA);
231    pass.TA.remove(pass.ARCMTMacroLocs[i]);
232  }
233}
234