blob: b896c4898a125b4920c3ee89c45e95d9cffe0383 [file] [log] [blame]
Argyrios Kyrtzidisfd3455a2011-06-21 20:20:42 +00001//===--- TransEmptyStatements.cpp - Tranformations to ARC mode ------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// removeEmptyStatementsAndDealloc:
11//
12// Removes empty statements that are leftovers from previous transformations.
13// e.g for
14//
15// [x retain];
16//
17// removeRetainReleaseDealloc will leave an empty ";" that removeEmptyStatements
18// will remove.
19//
20//===----------------------------------------------------------------------===//
21
22#include "Transforms.h"
23#include "Internals.h"
24#include "clang/AST/StmtVisitor.h"
25
26using namespace clang;
27using namespace arcmt;
28using namespace trans;
Argyrios Kyrtzidisfd3455a2011-06-21 20:20:42 +000029
30namespace {
31
32/// \brief Returns true if the statement became empty due to previous
33/// transformations.
34class EmptyChecker : public StmtVisitor<EmptyChecker, bool> {
35 ASTContext &Ctx;
36 llvm::DenseSet<unsigned> &MacroLocs;
37
38public:
39 EmptyChecker(ASTContext &ctx, llvm::DenseSet<unsigned> &macroLocs)
40 : Ctx(ctx), MacroLocs(macroLocs) { }
41
42 bool VisitNullStmt(NullStmt *S) {
43 return isMacroLoc(S->getLeadingEmptyMacroLoc());
44 }
45 bool VisitCompoundStmt(CompoundStmt *S) {
46 if (S->body_empty())
47 return false; // was already empty, not because of transformations.
48 for (CompoundStmt::body_iterator
49 I = S->body_begin(), E = S->body_end(); I != E; ++I)
50 if (!Visit(*I))
51 return false;
52 return true;
53 }
54 bool VisitIfStmt(IfStmt *S) {
55 if (S->getConditionVariable())
56 return false;
57 Expr *condE = S->getCond();
58 if (!condE)
59 return false;
60 if (hasSideEffects(condE, Ctx))
61 return false;
62 if (!S->getThen() || !Visit(S->getThen()))
63 return false;
64 if (S->getElse() && !Visit(S->getElse()))
65 return false;
66 return true;
67 }
68 bool VisitWhileStmt(WhileStmt *S) {
69 if (S->getConditionVariable())
70 return false;
71 Expr *condE = S->getCond();
72 if (!condE)
73 return false;
74 if (hasSideEffects(condE, Ctx))
75 return false;
76 if (!S->getBody())
77 return false;
78 return Visit(S->getBody());
79 }
80 bool VisitDoStmt(DoStmt *S) {
81 Expr *condE = S->getCond();
82 if (!condE)
83 return false;
84 if (hasSideEffects(condE, Ctx))
85 return false;
86 if (!S->getBody())
87 return false;
88 return Visit(S->getBody());
89 }
90 bool VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
91 Expr *Exp = S->getCollection();
92 if (!Exp)
93 return false;
94 if (hasSideEffects(Exp, Ctx))
95 return false;
96 if (!S->getBody())
97 return false;
98 return Visit(S->getBody());
99 }
100 bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
101 if (!S->getSubStmt())
102 return false;
103 return Visit(S->getSubStmt());
104 }
105
106private:
107 bool isMacroLoc(SourceLocation loc) {
108 if (loc.isInvalid()) return false;
109 return MacroLocs.count(loc.getRawEncoding());
110 }
111};
112
113class EmptyStatementsRemover :
114 public RecursiveASTVisitor<EmptyStatementsRemover> {
115 MigrationPass &Pass;
116 llvm::DenseSet<unsigned> &MacroLocs;
117
118public:
119 EmptyStatementsRemover(MigrationPass &pass,
120 llvm::DenseSet<unsigned> &macroLocs)
121 : Pass(pass), MacroLocs(macroLocs) { }
122
123 bool TraverseStmtExpr(StmtExpr *E) {
124 CompoundStmt *S = E->getSubStmt();
125 for (CompoundStmt::body_iterator
126 I = S->body_begin(), E = S->body_end(); I != E; ++I) {
127 if (I != E - 1)
128 check(*I);
129 TraverseStmt(*I);
130 }
131 return true;
132 }
133
134 bool VisitCompoundStmt(CompoundStmt *S) {
135 for (CompoundStmt::body_iterator
136 I = S->body_begin(), E = S->body_end(); I != E; ++I)
137 check(*I);
138 return true;
139 }
140
141 bool isMacroLoc(SourceLocation loc) {
142 if (loc.isInvalid()) return false;
143 return MacroLocs.count(loc.getRawEncoding());
144 }
145
146 ASTContext &getContext() { return Pass.Ctx; }
147
148private:
149 void check(Stmt *S) {
150 if (!S) return;
151 if (EmptyChecker(Pass.Ctx, MacroLocs).Visit(S)) {
152 Transaction Trans(Pass.TA);
153 Pass.TA.removeStmt(S);
154 }
155 }
156};
157
158} // anonymous namespace
159
160static bool isBodyEmpty(CompoundStmt *body,
161 ASTContext &Ctx, llvm::DenseSet<unsigned> &MacroLocs) {
162 for (CompoundStmt::body_iterator
163 I = body->body_begin(), E = body->body_end(); I != E; ++I)
164 if (!EmptyChecker(Ctx, MacroLocs).Visit(*I))
165 return false;
166
167 return true;
168}
169
170static void removeDeallocMethod(MigrationPass &pass,
171 llvm::DenseSet<unsigned> &MacroLocs) {
172 ASTContext &Ctx = pass.Ctx;
173 TransformActions &TA = pass.TA;
174 DeclContext *DC = Ctx.getTranslationUnitDecl();
175
176 typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
177 impl_iterator;
178 for (impl_iterator I = impl_iterator(DC->decls_begin()),
179 E = impl_iterator(DC->decls_end()); I != E; ++I) {
180 for (ObjCImplementationDecl::instmeth_iterator
181 MI = (*I)->instmeth_begin(),
182 ME = (*I)->instmeth_end(); MI != ME; ++MI) {
183 ObjCMethodDecl *MD = *MI;
184 if (MD->getMethodFamily() == OMF_dealloc) {
185 if (MD->hasBody() &&
186 isBodyEmpty(MD->getCompoundBody(), Ctx, MacroLocs)) {
187 Transaction Trans(TA);
188 TA.remove(MD->getSourceRange());
189 }
190 break;
191 }
192 }
193 }
194}
195
196void trans::removeEmptyStatementsAndDealloc(MigrationPass &pass) {
197 llvm::DenseSet<unsigned> MacroLocs;
198 for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i)
199 MacroLocs.insert(pass.ARCMTMacroLocs[i].getRawEncoding());
200
201 EmptyStatementsRemover(pass, MacroLocs)
202 .TraverseDecl(pass.Ctx.getTranslationUnitDecl());
203
204 removeDeallocMethod(pass, MacroLocs);
205
206 for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) {
207 Transaction Trans(pass.TA);
208 pass.TA.remove(pass.ARCMTMacroLocs[i]);
209 }
210}