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