xref: /freebsd-src/contrib/llvm-project/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
10b57cec5SDimitry Andric //===-- TransEmptyStatementsAndDealloc.cpp - Transformations to ARC mode --===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // removeEmptyStatementsAndDealloc:
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric // Removes empty statements that are leftovers from previous transformations.
120b57cec5SDimitry Andric // e.g for
130b57cec5SDimitry Andric //
140b57cec5SDimitry Andric //  [x retain];
150b57cec5SDimitry Andric //
160b57cec5SDimitry Andric // removeRetainReleaseDealloc will leave an empty ";" that removeEmptyStatements
170b57cec5SDimitry Andric // will remove.
180b57cec5SDimitry Andric //
190b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric #include "Transforms.h"
220b57cec5SDimitry Andric #include "Internals.h"
230b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
240b57cec5SDimitry Andric #include "clang/AST/StmtVisitor.h"
250b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric using namespace clang;
280b57cec5SDimitry Andric using namespace arcmt;
290b57cec5SDimitry Andric using namespace trans;
300b57cec5SDimitry Andric 
isEmptyARCMTMacroStatement(NullStmt * S,std::vector<SourceLocation> & MacroLocs,ASTContext & Ctx)310b57cec5SDimitry Andric static bool isEmptyARCMTMacroStatement(NullStmt *S,
320b57cec5SDimitry Andric                                        std::vector<SourceLocation> &MacroLocs,
330b57cec5SDimitry Andric                                        ASTContext &Ctx) {
340b57cec5SDimitry Andric   if (!S->hasLeadingEmptyMacro())
350b57cec5SDimitry Andric     return false;
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric   SourceLocation SemiLoc = S->getSemiLoc();
380b57cec5SDimitry Andric   if (SemiLoc.isInvalid() || SemiLoc.isMacroID())
390b57cec5SDimitry Andric     return false;
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric   if (MacroLocs.empty())
420b57cec5SDimitry Andric     return false;
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric   SourceManager &SM = Ctx.getSourceManager();
450b57cec5SDimitry Andric   std::vector<SourceLocation>::iterator I = llvm::upper_bound(
460b57cec5SDimitry Andric       MacroLocs, SemiLoc, BeforeThanCompare<SourceLocation>(SM));
470b57cec5SDimitry Andric   --I;
480b57cec5SDimitry Andric   SourceLocation
490b57cec5SDimitry Andric       AfterMacroLoc = I->getLocWithOffset(getARCMTMacroName().size());
500b57cec5SDimitry Andric   assert(AfterMacroLoc.isFileID());
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   if (AfterMacroLoc == SemiLoc)
530b57cec5SDimitry Andric     return true;
540b57cec5SDimitry Andric 
55*fe6060f1SDimitry Andric   SourceLocation::IntTy RelOffs = 0;
560b57cec5SDimitry Andric   if (!SM.isInSameSLocAddrSpace(AfterMacroLoc, SemiLoc, &RelOffs))
570b57cec5SDimitry Andric     return false;
580b57cec5SDimitry Andric   if (RelOffs < 0)
590b57cec5SDimitry Andric     return false;
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   // We make the reasonable assumption that a semicolon after 100 characters
620b57cec5SDimitry Andric   // means that it is not the next token after our macro. If this assumption
630b57cec5SDimitry Andric   // fails it is not critical, we will just fail to clear out, e.g., an empty
640b57cec5SDimitry Andric   // 'if'.
650b57cec5SDimitry Andric   if (RelOffs - getARCMTMacroName().size() > 100)
660b57cec5SDimitry Andric     return false;
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   SourceLocation AfterMacroSemiLoc = findSemiAfterLocation(AfterMacroLoc, Ctx);
690b57cec5SDimitry Andric   return AfterMacroSemiLoc == SemiLoc;
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric namespace {
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric /// Returns true if the statement became empty due to previous
750b57cec5SDimitry Andric /// transformations.
760b57cec5SDimitry Andric class EmptyChecker : public StmtVisitor<EmptyChecker, bool> {
770b57cec5SDimitry Andric   ASTContext &Ctx;
780b57cec5SDimitry Andric   std::vector<SourceLocation> &MacroLocs;
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric public:
EmptyChecker(ASTContext & ctx,std::vector<SourceLocation> & macroLocs)810b57cec5SDimitry Andric   EmptyChecker(ASTContext &ctx, std::vector<SourceLocation> &macroLocs)
820b57cec5SDimitry Andric     : Ctx(ctx), MacroLocs(macroLocs) { }
830b57cec5SDimitry Andric 
VisitNullStmt(NullStmt * S)840b57cec5SDimitry Andric   bool VisitNullStmt(NullStmt *S) {
850b57cec5SDimitry Andric     return isEmptyARCMTMacroStatement(S, MacroLocs, Ctx);
860b57cec5SDimitry Andric   }
VisitCompoundStmt(CompoundStmt * S)870b57cec5SDimitry Andric   bool VisitCompoundStmt(CompoundStmt *S) {
880b57cec5SDimitry Andric     if (S->body_empty())
890b57cec5SDimitry Andric       return false; // was already empty, not because of transformations.
900b57cec5SDimitry Andric     for (auto *I : S->body())
910b57cec5SDimitry Andric       if (!Visit(I))
920b57cec5SDimitry Andric         return false;
930b57cec5SDimitry Andric     return true;
940b57cec5SDimitry Andric   }
VisitIfStmt(IfStmt * S)950b57cec5SDimitry Andric   bool VisitIfStmt(IfStmt *S) {
960b57cec5SDimitry Andric     if (S->getConditionVariable())
970b57cec5SDimitry Andric       return false;
980b57cec5SDimitry Andric     Expr *condE = S->getCond();
990b57cec5SDimitry Andric     if (!condE)
1000b57cec5SDimitry Andric       return false;
1010b57cec5SDimitry Andric     if (hasSideEffects(condE, Ctx))
1020b57cec5SDimitry Andric       return false;
1030b57cec5SDimitry Andric     if (!S->getThen() || !Visit(S->getThen()))
1040b57cec5SDimitry Andric       return false;
1050b57cec5SDimitry Andric     return !S->getElse() || Visit(S->getElse());
1060b57cec5SDimitry Andric   }
VisitWhileStmt(WhileStmt * S)1070b57cec5SDimitry Andric   bool VisitWhileStmt(WhileStmt *S) {
1080b57cec5SDimitry Andric     if (S->getConditionVariable())
1090b57cec5SDimitry Andric       return false;
1100b57cec5SDimitry Andric     Expr *condE = S->getCond();
1110b57cec5SDimitry Andric     if (!condE)
1120b57cec5SDimitry Andric       return false;
1130b57cec5SDimitry Andric     if (hasSideEffects(condE, Ctx))
1140b57cec5SDimitry Andric       return false;
1150b57cec5SDimitry Andric     if (!S->getBody())
1160b57cec5SDimitry Andric       return false;
1170b57cec5SDimitry Andric     return Visit(S->getBody());
1180b57cec5SDimitry Andric   }
VisitDoStmt(DoStmt * S)1190b57cec5SDimitry Andric   bool VisitDoStmt(DoStmt *S) {
1200b57cec5SDimitry Andric     Expr *condE = S->getCond();
1210b57cec5SDimitry Andric     if (!condE)
1220b57cec5SDimitry Andric       return false;
1230b57cec5SDimitry Andric     if (hasSideEffects(condE, Ctx))
1240b57cec5SDimitry Andric       return false;
1250b57cec5SDimitry Andric     if (!S->getBody())
1260b57cec5SDimitry Andric       return false;
1270b57cec5SDimitry Andric     return Visit(S->getBody());
1280b57cec5SDimitry Andric   }
VisitObjCForCollectionStmt(ObjCForCollectionStmt * S)1290b57cec5SDimitry Andric   bool VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
1300b57cec5SDimitry Andric     Expr *Exp = S->getCollection();
1310b57cec5SDimitry Andric     if (!Exp)
1320b57cec5SDimitry Andric       return false;
1330b57cec5SDimitry Andric     if (hasSideEffects(Exp, Ctx))
1340b57cec5SDimitry Andric       return false;
1350b57cec5SDimitry Andric     if (!S->getBody())
1360b57cec5SDimitry Andric       return false;
1370b57cec5SDimitry Andric     return Visit(S->getBody());
1380b57cec5SDimitry Andric   }
VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt * S)1390b57cec5SDimitry Andric   bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
1400b57cec5SDimitry Andric     if (!S->getSubStmt())
1410b57cec5SDimitry Andric       return false;
1420b57cec5SDimitry Andric     return Visit(S->getSubStmt());
1430b57cec5SDimitry Andric   }
1440b57cec5SDimitry Andric };
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric class EmptyStatementsRemover :
1470b57cec5SDimitry Andric                             public RecursiveASTVisitor<EmptyStatementsRemover> {
1480b57cec5SDimitry Andric   MigrationPass &Pass;
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric public:
EmptyStatementsRemover(MigrationPass & pass)1510b57cec5SDimitry Andric   EmptyStatementsRemover(MigrationPass &pass) : Pass(pass) { }
1520b57cec5SDimitry Andric 
TraverseStmtExpr(StmtExpr * E)1530b57cec5SDimitry Andric   bool TraverseStmtExpr(StmtExpr *E) {
1540b57cec5SDimitry Andric     CompoundStmt *S = E->getSubStmt();
1550b57cec5SDimitry Andric     for (CompoundStmt::body_iterator
1560b57cec5SDimitry Andric            I = S->body_begin(), E = S->body_end(); I != E; ++I) {
1570b57cec5SDimitry Andric       if (I != E - 1)
1580b57cec5SDimitry Andric         check(*I);
1590b57cec5SDimitry Andric       TraverseStmt(*I);
1600b57cec5SDimitry Andric     }
1610b57cec5SDimitry Andric     return true;
1620b57cec5SDimitry Andric   }
1630b57cec5SDimitry Andric 
VisitCompoundStmt(CompoundStmt * S)1640b57cec5SDimitry Andric   bool VisitCompoundStmt(CompoundStmt *S) {
1650b57cec5SDimitry Andric     for (auto *I : S->body())
1660b57cec5SDimitry Andric       check(I);
1670b57cec5SDimitry Andric     return true;
1680b57cec5SDimitry Andric   }
1690b57cec5SDimitry Andric 
getContext()1700b57cec5SDimitry Andric   ASTContext &getContext() { return Pass.Ctx; }
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric private:
check(Stmt * S)1730b57cec5SDimitry Andric   void check(Stmt *S) {
1740b57cec5SDimitry Andric     if (!S) return;
1750b57cec5SDimitry Andric     if (EmptyChecker(Pass.Ctx, Pass.ARCMTMacroLocs).Visit(S)) {
1760b57cec5SDimitry Andric       Transaction Trans(Pass.TA);
1770b57cec5SDimitry Andric       Pass.TA.removeStmt(S);
1780b57cec5SDimitry Andric     }
1790b57cec5SDimitry Andric   }
1800b57cec5SDimitry Andric };
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric } // anonymous namespace
1830b57cec5SDimitry Andric 
isBodyEmpty(CompoundStmt * body,ASTContext & Ctx,std::vector<SourceLocation> & MacroLocs)1840b57cec5SDimitry Andric static bool isBodyEmpty(CompoundStmt *body, ASTContext &Ctx,
1850b57cec5SDimitry Andric                         std::vector<SourceLocation> &MacroLocs) {
1860b57cec5SDimitry Andric   for (auto *I : body->body())
1870b57cec5SDimitry Andric     if (!EmptyChecker(Ctx, MacroLocs).Visit(I))
1880b57cec5SDimitry Andric       return false;
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric   return true;
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric 
cleanupDeallocOrFinalize(MigrationPass & pass)1930b57cec5SDimitry Andric static void cleanupDeallocOrFinalize(MigrationPass &pass) {
1940b57cec5SDimitry Andric   ASTContext &Ctx = pass.Ctx;
1950b57cec5SDimitry Andric   TransformActions &TA = pass.TA;
1960b57cec5SDimitry Andric   DeclContext *DC = Ctx.getTranslationUnitDecl();
1970b57cec5SDimitry Andric   Selector FinalizeSel =
1980b57cec5SDimitry Andric       Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
2010b57cec5SDimitry Andric     impl_iterator;
2020b57cec5SDimitry Andric   for (impl_iterator I = impl_iterator(DC->decls_begin()),
2030b57cec5SDimitry Andric                      E = impl_iterator(DC->decls_end()); I != E; ++I) {
2040b57cec5SDimitry Andric     ObjCMethodDecl *DeallocM = nullptr;
2050b57cec5SDimitry Andric     ObjCMethodDecl *FinalizeM = nullptr;
2060b57cec5SDimitry Andric     for (auto *MD : I->instance_methods()) {
2070b57cec5SDimitry Andric       if (!MD->hasBody())
2080b57cec5SDimitry Andric         continue;
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric       if (MD->getMethodFamily() == OMF_dealloc) {
2110b57cec5SDimitry Andric         DeallocM = MD;
2120b57cec5SDimitry Andric       } else if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
2130b57cec5SDimitry Andric         FinalizeM = MD;
2140b57cec5SDimitry Andric       }
2150b57cec5SDimitry Andric     }
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric     if (DeallocM) {
2180b57cec5SDimitry Andric       if (isBodyEmpty(DeallocM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {
2190b57cec5SDimitry Andric         Transaction Trans(TA);
2200b57cec5SDimitry Andric         TA.remove(DeallocM->getSourceRange());
2210b57cec5SDimitry Andric       }
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric       if (FinalizeM) {
2240b57cec5SDimitry Andric         Transaction Trans(TA);
2250b57cec5SDimitry Andric         TA.remove(FinalizeM->getSourceRange());
2260b57cec5SDimitry Andric       }
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric     } else if (FinalizeM) {
2290b57cec5SDimitry Andric       if (isBodyEmpty(FinalizeM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {
2300b57cec5SDimitry Andric         Transaction Trans(TA);
2310b57cec5SDimitry Andric         TA.remove(FinalizeM->getSourceRange());
2320b57cec5SDimitry Andric       } else {
2330b57cec5SDimitry Andric         Transaction Trans(TA);
2340b57cec5SDimitry Andric         TA.replaceText(FinalizeM->getSelectorStartLoc(), "finalize", "dealloc");
2350b57cec5SDimitry Andric       }
2360b57cec5SDimitry Andric     }
2370b57cec5SDimitry Andric   }
2380b57cec5SDimitry Andric }
2390b57cec5SDimitry Andric 
removeEmptyStatementsAndDeallocFinalize(MigrationPass & pass)2400b57cec5SDimitry Andric void trans::removeEmptyStatementsAndDeallocFinalize(MigrationPass &pass) {
2410b57cec5SDimitry Andric   EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric   cleanupDeallocOrFinalize(pass);
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric   for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) {
2460b57cec5SDimitry Andric     Transaction Trans(pass.TA);
2470b57cec5SDimitry Andric     pass.TA.remove(pass.ARCMTMacroLocs[i]);
2480b57cec5SDimitry Andric   }
2490b57cec5SDimitry Andric }
250