1*06f32e7eSjoerg //===-- TransEmptyStatementsAndDealloc.cpp - Transformations to ARC mode --===//
2*06f32e7eSjoerg //
3*06f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
5*06f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06f32e7eSjoerg //
7*06f32e7eSjoerg //===----------------------------------------------------------------------===//
8*06f32e7eSjoerg //
9*06f32e7eSjoerg // removeEmptyStatementsAndDealloc:
10*06f32e7eSjoerg //
11*06f32e7eSjoerg // Removes empty statements that are leftovers from previous transformations.
12*06f32e7eSjoerg // e.g for
13*06f32e7eSjoerg //
14*06f32e7eSjoerg //  [x retain];
15*06f32e7eSjoerg //
16*06f32e7eSjoerg // removeRetainReleaseDealloc will leave an empty ";" that removeEmptyStatements
17*06f32e7eSjoerg // will remove.
18*06f32e7eSjoerg //
19*06f32e7eSjoerg //===----------------------------------------------------------------------===//
20*06f32e7eSjoerg 
21*06f32e7eSjoerg #include "Transforms.h"
22*06f32e7eSjoerg #include "Internals.h"
23*06f32e7eSjoerg #include "clang/AST/ASTContext.h"
24*06f32e7eSjoerg #include "clang/AST/StmtVisitor.h"
25*06f32e7eSjoerg #include "clang/Basic/SourceManager.h"
26*06f32e7eSjoerg 
27*06f32e7eSjoerg using namespace clang;
28*06f32e7eSjoerg using namespace arcmt;
29*06f32e7eSjoerg using namespace trans;
30*06f32e7eSjoerg 
isEmptyARCMTMacroStatement(NullStmt * S,std::vector<SourceLocation> & MacroLocs,ASTContext & Ctx)31*06f32e7eSjoerg static bool isEmptyARCMTMacroStatement(NullStmt *S,
32*06f32e7eSjoerg                                        std::vector<SourceLocation> &MacroLocs,
33*06f32e7eSjoerg                                        ASTContext &Ctx) {
34*06f32e7eSjoerg   if (!S->hasLeadingEmptyMacro())
35*06f32e7eSjoerg     return false;
36*06f32e7eSjoerg 
37*06f32e7eSjoerg   SourceLocation SemiLoc = S->getSemiLoc();
38*06f32e7eSjoerg   if (SemiLoc.isInvalid() || SemiLoc.isMacroID())
39*06f32e7eSjoerg     return false;
40*06f32e7eSjoerg 
41*06f32e7eSjoerg   if (MacroLocs.empty())
42*06f32e7eSjoerg     return false;
43*06f32e7eSjoerg 
44*06f32e7eSjoerg   SourceManager &SM = Ctx.getSourceManager();
45*06f32e7eSjoerg   std::vector<SourceLocation>::iterator I = llvm::upper_bound(
46*06f32e7eSjoerg       MacroLocs, SemiLoc, BeforeThanCompare<SourceLocation>(SM));
47*06f32e7eSjoerg   --I;
48*06f32e7eSjoerg   SourceLocation
49*06f32e7eSjoerg       AfterMacroLoc = I->getLocWithOffset(getARCMTMacroName().size());
50*06f32e7eSjoerg   assert(AfterMacroLoc.isFileID());
51*06f32e7eSjoerg 
52*06f32e7eSjoerg   if (AfterMacroLoc == SemiLoc)
53*06f32e7eSjoerg     return true;
54*06f32e7eSjoerg 
55*06f32e7eSjoerg   int RelOffs = 0;
56*06f32e7eSjoerg   if (!SM.isInSameSLocAddrSpace(AfterMacroLoc, SemiLoc, &RelOffs))
57*06f32e7eSjoerg     return false;
58*06f32e7eSjoerg   if (RelOffs < 0)
59*06f32e7eSjoerg     return false;
60*06f32e7eSjoerg 
61*06f32e7eSjoerg   // We make the reasonable assumption that a semicolon after 100 characters
62*06f32e7eSjoerg   // means that it is not the next token after our macro. If this assumption
63*06f32e7eSjoerg   // fails it is not critical, we will just fail to clear out, e.g., an empty
64*06f32e7eSjoerg   // 'if'.
65*06f32e7eSjoerg   if (RelOffs - getARCMTMacroName().size() > 100)
66*06f32e7eSjoerg     return false;
67*06f32e7eSjoerg 
68*06f32e7eSjoerg   SourceLocation AfterMacroSemiLoc = findSemiAfterLocation(AfterMacroLoc, Ctx);
69*06f32e7eSjoerg   return AfterMacroSemiLoc == SemiLoc;
70*06f32e7eSjoerg }
71*06f32e7eSjoerg 
72*06f32e7eSjoerg namespace {
73*06f32e7eSjoerg 
74*06f32e7eSjoerg /// Returns true if the statement became empty due to previous
75*06f32e7eSjoerg /// transformations.
76*06f32e7eSjoerg class EmptyChecker : public StmtVisitor<EmptyChecker, bool> {
77*06f32e7eSjoerg   ASTContext &Ctx;
78*06f32e7eSjoerg   std::vector<SourceLocation> &MacroLocs;
79*06f32e7eSjoerg 
80*06f32e7eSjoerg public:
EmptyChecker(ASTContext & ctx,std::vector<SourceLocation> & macroLocs)81*06f32e7eSjoerg   EmptyChecker(ASTContext &ctx, std::vector<SourceLocation> &macroLocs)
82*06f32e7eSjoerg     : Ctx(ctx), MacroLocs(macroLocs) { }
83*06f32e7eSjoerg 
VisitNullStmt(NullStmt * S)84*06f32e7eSjoerg   bool VisitNullStmt(NullStmt *S) {
85*06f32e7eSjoerg     return isEmptyARCMTMacroStatement(S, MacroLocs, Ctx);
86*06f32e7eSjoerg   }
VisitCompoundStmt(CompoundStmt * S)87*06f32e7eSjoerg   bool VisitCompoundStmt(CompoundStmt *S) {
88*06f32e7eSjoerg     if (S->body_empty())
89*06f32e7eSjoerg       return false; // was already empty, not because of transformations.
90*06f32e7eSjoerg     for (auto *I : S->body())
91*06f32e7eSjoerg       if (!Visit(I))
92*06f32e7eSjoerg         return false;
93*06f32e7eSjoerg     return true;
94*06f32e7eSjoerg   }
VisitIfStmt(IfStmt * S)95*06f32e7eSjoerg   bool VisitIfStmt(IfStmt *S) {
96*06f32e7eSjoerg     if (S->getConditionVariable())
97*06f32e7eSjoerg       return false;
98*06f32e7eSjoerg     Expr *condE = S->getCond();
99*06f32e7eSjoerg     if (!condE)
100*06f32e7eSjoerg       return false;
101*06f32e7eSjoerg     if (hasSideEffects(condE, Ctx))
102*06f32e7eSjoerg       return false;
103*06f32e7eSjoerg     if (!S->getThen() || !Visit(S->getThen()))
104*06f32e7eSjoerg       return false;
105*06f32e7eSjoerg     return !S->getElse() || Visit(S->getElse());
106*06f32e7eSjoerg   }
VisitWhileStmt(WhileStmt * S)107*06f32e7eSjoerg   bool VisitWhileStmt(WhileStmt *S) {
108*06f32e7eSjoerg     if (S->getConditionVariable())
109*06f32e7eSjoerg       return false;
110*06f32e7eSjoerg     Expr *condE = S->getCond();
111*06f32e7eSjoerg     if (!condE)
112*06f32e7eSjoerg       return false;
113*06f32e7eSjoerg     if (hasSideEffects(condE, Ctx))
114*06f32e7eSjoerg       return false;
115*06f32e7eSjoerg     if (!S->getBody())
116*06f32e7eSjoerg       return false;
117*06f32e7eSjoerg     return Visit(S->getBody());
118*06f32e7eSjoerg   }
VisitDoStmt(DoStmt * S)119*06f32e7eSjoerg   bool VisitDoStmt(DoStmt *S) {
120*06f32e7eSjoerg     Expr *condE = S->getCond();
121*06f32e7eSjoerg     if (!condE)
122*06f32e7eSjoerg       return false;
123*06f32e7eSjoerg     if (hasSideEffects(condE, Ctx))
124*06f32e7eSjoerg       return false;
125*06f32e7eSjoerg     if (!S->getBody())
126*06f32e7eSjoerg       return false;
127*06f32e7eSjoerg     return Visit(S->getBody());
128*06f32e7eSjoerg   }
VisitObjCForCollectionStmt(ObjCForCollectionStmt * S)129*06f32e7eSjoerg   bool VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
130*06f32e7eSjoerg     Expr *Exp = S->getCollection();
131*06f32e7eSjoerg     if (!Exp)
132*06f32e7eSjoerg       return false;
133*06f32e7eSjoerg     if (hasSideEffects(Exp, Ctx))
134*06f32e7eSjoerg       return false;
135*06f32e7eSjoerg     if (!S->getBody())
136*06f32e7eSjoerg       return false;
137*06f32e7eSjoerg     return Visit(S->getBody());
138*06f32e7eSjoerg   }
VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt * S)139*06f32e7eSjoerg   bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
140*06f32e7eSjoerg     if (!S->getSubStmt())
141*06f32e7eSjoerg       return false;
142*06f32e7eSjoerg     return Visit(S->getSubStmt());
143*06f32e7eSjoerg   }
144*06f32e7eSjoerg };
145*06f32e7eSjoerg 
146*06f32e7eSjoerg class EmptyStatementsRemover :
147*06f32e7eSjoerg                             public RecursiveASTVisitor<EmptyStatementsRemover> {
148*06f32e7eSjoerg   MigrationPass &Pass;
149*06f32e7eSjoerg 
150*06f32e7eSjoerg public:
EmptyStatementsRemover(MigrationPass & pass)151*06f32e7eSjoerg   EmptyStatementsRemover(MigrationPass &pass) : Pass(pass) { }
152*06f32e7eSjoerg 
TraverseStmtExpr(StmtExpr * E)153*06f32e7eSjoerg   bool TraverseStmtExpr(StmtExpr *E) {
154*06f32e7eSjoerg     CompoundStmt *S = E->getSubStmt();
155*06f32e7eSjoerg     for (CompoundStmt::body_iterator
156*06f32e7eSjoerg            I = S->body_begin(), E = S->body_end(); I != E; ++I) {
157*06f32e7eSjoerg       if (I != E - 1)
158*06f32e7eSjoerg         check(*I);
159*06f32e7eSjoerg       TraverseStmt(*I);
160*06f32e7eSjoerg     }
161*06f32e7eSjoerg     return true;
162*06f32e7eSjoerg   }
163*06f32e7eSjoerg 
VisitCompoundStmt(CompoundStmt * S)164*06f32e7eSjoerg   bool VisitCompoundStmt(CompoundStmt *S) {
165*06f32e7eSjoerg     for (auto *I : S->body())
166*06f32e7eSjoerg       check(I);
167*06f32e7eSjoerg     return true;
168*06f32e7eSjoerg   }
169*06f32e7eSjoerg 
getContext()170*06f32e7eSjoerg   ASTContext &getContext() { return Pass.Ctx; }
171*06f32e7eSjoerg 
172*06f32e7eSjoerg private:
check(Stmt * S)173*06f32e7eSjoerg   void check(Stmt *S) {
174*06f32e7eSjoerg     if (!S) return;
175*06f32e7eSjoerg     if (EmptyChecker(Pass.Ctx, Pass.ARCMTMacroLocs).Visit(S)) {
176*06f32e7eSjoerg       Transaction Trans(Pass.TA);
177*06f32e7eSjoerg       Pass.TA.removeStmt(S);
178*06f32e7eSjoerg     }
179*06f32e7eSjoerg   }
180*06f32e7eSjoerg };
181*06f32e7eSjoerg 
182*06f32e7eSjoerg } // anonymous namespace
183*06f32e7eSjoerg 
isBodyEmpty(CompoundStmt * body,ASTContext & Ctx,std::vector<SourceLocation> & MacroLocs)184*06f32e7eSjoerg static bool isBodyEmpty(CompoundStmt *body, ASTContext &Ctx,
185*06f32e7eSjoerg                         std::vector<SourceLocation> &MacroLocs) {
186*06f32e7eSjoerg   for (auto *I : body->body())
187*06f32e7eSjoerg     if (!EmptyChecker(Ctx, MacroLocs).Visit(I))
188*06f32e7eSjoerg       return false;
189*06f32e7eSjoerg 
190*06f32e7eSjoerg   return true;
191*06f32e7eSjoerg }
192*06f32e7eSjoerg 
cleanupDeallocOrFinalize(MigrationPass & pass)193*06f32e7eSjoerg static void cleanupDeallocOrFinalize(MigrationPass &pass) {
194*06f32e7eSjoerg   ASTContext &Ctx = pass.Ctx;
195*06f32e7eSjoerg   TransformActions &TA = pass.TA;
196*06f32e7eSjoerg   DeclContext *DC = Ctx.getTranslationUnitDecl();
197*06f32e7eSjoerg   Selector FinalizeSel =
198*06f32e7eSjoerg       Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));
199*06f32e7eSjoerg 
200*06f32e7eSjoerg   typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
201*06f32e7eSjoerg     impl_iterator;
202*06f32e7eSjoerg   for (impl_iterator I = impl_iterator(DC->decls_begin()),
203*06f32e7eSjoerg                      E = impl_iterator(DC->decls_end()); I != E; ++I) {
204*06f32e7eSjoerg     ObjCMethodDecl *DeallocM = nullptr;
205*06f32e7eSjoerg     ObjCMethodDecl *FinalizeM = nullptr;
206*06f32e7eSjoerg     for (auto *MD : I->instance_methods()) {
207*06f32e7eSjoerg       if (!MD->hasBody())
208*06f32e7eSjoerg         continue;
209*06f32e7eSjoerg 
210*06f32e7eSjoerg       if (MD->getMethodFamily() == OMF_dealloc) {
211*06f32e7eSjoerg         DeallocM = MD;
212*06f32e7eSjoerg       } else if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
213*06f32e7eSjoerg         FinalizeM = MD;
214*06f32e7eSjoerg       }
215*06f32e7eSjoerg     }
216*06f32e7eSjoerg 
217*06f32e7eSjoerg     if (DeallocM) {
218*06f32e7eSjoerg       if (isBodyEmpty(DeallocM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {
219*06f32e7eSjoerg         Transaction Trans(TA);
220*06f32e7eSjoerg         TA.remove(DeallocM->getSourceRange());
221*06f32e7eSjoerg       }
222*06f32e7eSjoerg 
223*06f32e7eSjoerg       if (FinalizeM) {
224*06f32e7eSjoerg         Transaction Trans(TA);
225*06f32e7eSjoerg         TA.remove(FinalizeM->getSourceRange());
226*06f32e7eSjoerg       }
227*06f32e7eSjoerg 
228*06f32e7eSjoerg     } else if (FinalizeM) {
229*06f32e7eSjoerg       if (isBodyEmpty(FinalizeM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {
230*06f32e7eSjoerg         Transaction Trans(TA);
231*06f32e7eSjoerg         TA.remove(FinalizeM->getSourceRange());
232*06f32e7eSjoerg       } else {
233*06f32e7eSjoerg         Transaction Trans(TA);
234*06f32e7eSjoerg         TA.replaceText(FinalizeM->getSelectorStartLoc(), "finalize", "dealloc");
235*06f32e7eSjoerg       }
236*06f32e7eSjoerg     }
237*06f32e7eSjoerg   }
238*06f32e7eSjoerg }
239*06f32e7eSjoerg 
removeEmptyStatementsAndDeallocFinalize(MigrationPass & pass)240*06f32e7eSjoerg void trans::removeEmptyStatementsAndDeallocFinalize(MigrationPass &pass) {
241*06f32e7eSjoerg   EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
242*06f32e7eSjoerg 
243*06f32e7eSjoerg   cleanupDeallocOrFinalize(pass);
244*06f32e7eSjoerg 
245*06f32e7eSjoerg   for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) {
246*06f32e7eSjoerg     Transaction Trans(pass.TA);
247*06f32e7eSjoerg     pass.TA.remove(pass.ARCMTMacroLocs[i]);
248*06f32e7eSjoerg   }
249*06f32e7eSjoerg }
250