Path: blob/main/contrib/llvm-project/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
35236 views
//===-- TransEmptyStatementsAndDealloc.cpp - Transformations to ARC mode --===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// removeEmptyStatementsAndDealloc:9//10// Removes empty statements that are leftovers from previous transformations.11// e.g for12//13// [x retain];14//15// removeRetainReleaseDealloc will leave an empty ";" that removeEmptyStatements16// will remove.17//18//===----------------------------------------------------------------------===//1920#include "Transforms.h"21#include "Internals.h"22#include "clang/AST/ASTContext.h"23#include "clang/AST/StmtVisitor.h"24#include "clang/Basic/SourceManager.h"2526using namespace clang;27using namespace arcmt;28using namespace trans;2930static bool isEmptyARCMTMacroStatement(NullStmt *S,31std::vector<SourceLocation> &MacroLocs,32ASTContext &Ctx) {33if (!S->hasLeadingEmptyMacro())34return false;3536SourceLocation SemiLoc = S->getSemiLoc();37if (SemiLoc.isInvalid() || SemiLoc.isMacroID())38return false;3940if (MacroLocs.empty())41return false;4243SourceManager &SM = Ctx.getSourceManager();44std::vector<SourceLocation>::iterator I = llvm::upper_bound(45MacroLocs, SemiLoc, BeforeThanCompare<SourceLocation>(SM));46--I;47SourceLocation48AfterMacroLoc = I->getLocWithOffset(getARCMTMacroName().size());49assert(AfterMacroLoc.isFileID());5051if (AfterMacroLoc == SemiLoc)52return true;5354SourceLocation::IntTy RelOffs = 0;55if (!SM.isInSameSLocAddrSpace(AfterMacroLoc, SemiLoc, &RelOffs))56return false;57if (RelOffs < 0)58return false;5960// We make the reasonable assumption that a semicolon after 100 characters61// means that it is not the next token after our macro. If this assumption62// fails it is not critical, we will just fail to clear out, e.g., an empty63// 'if'.64if (RelOffs - getARCMTMacroName().size() > 100)65return false;6667SourceLocation AfterMacroSemiLoc = findSemiAfterLocation(AfterMacroLoc, Ctx);68return AfterMacroSemiLoc == SemiLoc;69}7071namespace {7273/// Returns true if the statement became empty due to previous74/// transformations.75class EmptyChecker : public StmtVisitor<EmptyChecker, bool> {76ASTContext &Ctx;77std::vector<SourceLocation> &MacroLocs;7879public:80EmptyChecker(ASTContext &ctx, std::vector<SourceLocation> ¯oLocs)81: Ctx(ctx), MacroLocs(macroLocs) { }8283bool VisitNullStmt(NullStmt *S) {84return isEmptyARCMTMacroStatement(S, MacroLocs, Ctx);85}86bool VisitCompoundStmt(CompoundStmt *S) {87if (S->body_empty())88return false; // was already empty, not because of transformations.89for (auto *I : S->body())90if (!Visit(I))91return false;92return true;93}94bool VisitIfStmt(IfStmt *S) {95if (S->getConditionVariable())96return false;97Expr *condE = S->getCond();98if (!condE)99return false;100if (hasSideEffects(condE, Ctx))101return false;102if (!S->getThen() || !Visit(S->getThen()))103return false;104return !S->getElse() || Visit(S->getElse());105}106bool VisitWhileStmt(WhileStmt *S) {107if (S->getConditionVariable())108return false;109Expr *condE = S->getCond();110if (!condE)111return false;112if (hasSideEffects(condE, Ctx))113return false;114if (!S->getBody())115return false;116return Visit(S->getBody());117}118bool VisitDoStmt(DoStmt *S) {119Expr *condE = S->getCond();120if (!condE)121return false;122if (hasSideEffects(condE, Ctx))123return false;124if (!S->getBody())125return false;126return Visit(S->getBody());127}128bool VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {129Expr *Exp = S->getCollection();130if (!Exp)131return false;132if (hasSideEffects(Exp, Ctx))133return false;134if (!S->getBody())135return false;136return Visit(S->getBody());137}138bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {139if (!S->getSubStmt())140return false;141return Visit(S->getSubStmt());142}143};144145class EmptyStatementsRemover :146public RecursiveASTVisitor<EmptyStatementsRemover> {147MigrationPass &Pass;148149public:150EmptyStatementsRemover(MigrationPass &pass) : Pass(pass) { }151152bool TraverseStmtExpr(StmtExpr *E) {153CompoundStmt *S = E->getSubStmt();154for (CompoundStmt::body_iterator155I = S->body_begin(), E = S->body_end(); I != E; ++I) {156if (I != E - 1)157check(*I);158TraverseStmt(*I);159}160return true;161}162163bool VisitCompoundStmt(CompoundStmt *S) {164for (auto *I : S->body())165check(I);166return true;167}168169ASTContext &getContext() { return Pass.Ctx; }170171private:172void check(Stmt *S) {173if (!S) return;174if (EmptyChecker(Pass.Ctx, Pass.ARCMTMacroLocs).Visit(S)) {175Transaction Trans(Pass.TA);176Pass.TA.removeStmt(S);177}178}179};180181} // anonymous namespace182183static bool isBodyEmpty(CompoundStmt *body, ASTContext &Ctx,184std::vector<SourceLocation> &MacroLocs) {185for (auto *I : body->body())186if (!EmptyChecker(Ctx, MacroLocs).Visit(I))187return false;188189return true;190}191192static void cleanupDeallocOrFinalize(MigrationPass &pass) {193ASTContext &Ctx = pass.Ctx;194TransformActions &TA = pass.TA;195DeclContext *DC = Ctx.getTranslationUnitDecl();196Selector FinalizeSel =197Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));198199typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>200impl_iterator;201for (impl_iterator I = impl_iterator(DC->decls_begin()),202E = impl_iterator(DC->decls_end()); I != E; ++I) {203ObjCMethodDecl *DeallocM = nullptr;204ObjCMethodDecl *FinalizeM = nullptr;205for (auto *MD : I->instance_methods()) {206if (!MD->hasBody())207continue;208209if (MD->getMethodFamily() == OMF_dealloc) {210DeallocM = MD;211} else if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {212FinalizeM = MD;213}214}215216if (DeallocM) {217if (isBodyEmpty(DeallocM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {218Transaction Trans(TA);219TA.remove(DeallocM->getSourceRange());220}221222if (FinalizeM) {223Transaction Trans(TA);224TA.remove(FinalizeM->getSourceRange());225}226227} else if (FinalizeM) {228if (isBodyEmpty(FinalizeM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {229Transaction Trans(TA);230TA.remove(FinalizeM->getSourceRange());231} else {232Transaction Trans(TA);233TA.replaceText(FinalizeM->getSelectorStartLoc(), "finalize", "dealloc");234}235}236}237}238239void trans::removeEmptyStatementsAndDeallocFinalize(MigrationPass &pass) {240EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());241242cleanupDeallocOrFinalize(pass);243244for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) {245Transaction Trans(pass.TA);246pass.TA.remove(pass.ARCMTMacroLocs[i]);247}248}249250251