diff options
Diffstat (limited to 'lib/ARCMigrate/TransRetainReleaseDealloc.cpp')
| -rw-r--r-- | lib/ARCMigrate/TransRetainReleaseDealloc.cpp | 459 | 
1 files changed, 0 insertions, 459 deletions
diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp deleted file mode 100644 index b76fc65574dd4..0000000000000 --- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp +++ /dev/null @@ -1,459 +0,0 @@ -//===--- TransRetainReleaseDealloc.cpp - Transformations to ARC mode ------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// removeRetainReleaseDealloc: -// -// Removes retain/release/autorelease/dealloc messages. -// -//  return [[foo retain] autorelease]; -// ----> -//  return foo; -// -//===----------------------------------------------------------------------===// - -#include "Transforms.h" -#include "Internals.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/ParentMap.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/Lexer.h" -#include "clang/Sema/SemaDiagnostic.h" -#include "llvm/ADT/StringSwitch.h" - -using namespace clang; -using namespace arcmt; -using namespace trans; - -namespace { - -class RetainReleaseDeallocRemover : -                       public RecursiveASTVisitor<RetainReleaseDeallocRemover> { -  Stmt *Body; -  MigrationPass &Pass; - -  ExprSet Removables; -  std::unique_ptr<ParentMap> StmtMap; - -  Selector DelegateSel, FinalizeSel; - -public: -  RetainReleaseDeallocRemover(MigrationPass &pass) -    : Body(nullptr), Pass(pass) { -    DelegateSel = -        Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("delegate")); -    FinalizeSel = -        Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize")); -  } - -  void transformBody(Stmt *body, Decl *ParentD) { -    Body = body; -    collectRemovables(body, Removables); -    StmtMap.reset(new ParentMap(body)); -    TraverseStmt(body); -  } - -  bool VisitObjCMessageExpr(ObjCMessageExpr *E) { -    switch (E->getMethodFamily()) { -    default: -      if (E->isInstanceMessage() && E->getSelector() == FinalizeSel) -        break; -      return true; -    case OMF_autorelease: -      if (isRemovable(E)) { -        if (!isCommonUnusedAutorelease(E)) { -          // An unused autorelease is badness. If we remove it the receiver -          // will likely die immediately while previously it was kept alive -          // by the autorelease pool. This is bad practice in general, leave it -          // and emit an error to force the user to restructure their code. -          Pass.TA.reportError( -              "it is not safe to remove an unused 'autorelease' " -              "message; its receiver may be destroyed immediately", -              E->getBeginLoc(), E->getSourceRange()); -          return true; -        } -      } -      // Pass through. -      LLVM_FALLTHROUGH; -    case OMF_retain: -    case OMF_release: -      if (E->getReceiverKind() == ObjCMessageExpr::Instance) -        if (Expr *rec = E->getInstanceReceiver()) { -          rec = rec->IgnoreParenImpCasts(); -          if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone && -              (E->getMethodFamily() != OMF_retain || isRemovable(E))) { -            std::string err = "it is not safe to remove '"; -            err += E->getSelector().getAsString() + "' message on " -                "an __unsafe_unretained type"; -            Pass.TA.reportError(err, rec->getBeginLoc()); -            return true; -          } - -          if (isGlobalVar(rec) && -              (E->getMethodFamily() != OMF_retain || isRemovable(E))) { -            std::string err = "it is not safe to remove '"; -            err += E->getSelector().getAsString() + "' message on " -                "a global variable"; -            Pass.TA.reportError(err, rec->getBeginLoc()); -            return true; -          } - -          if (E->getMethodFamily() == OMF_release && isDelegateMessage(rec)) { -            Pass.TA.reportError( -                "it is not safe to remove 'retain' " -                "message on the result of a 'delegate' message; " -                "the object that was passed to 'setDelegate:' may not be " -                "properly retained", -                rec->getBeginLoc()); -            return true; -          } -        } -      break; -    case OMF_dealloc: -      break; -    } - -    switch (E->getReceiverKind()) { -    default: -      return true; -    case ObjCMessageExpr::SuperInstance: { -      Transaction Trans(Pass.TA); -      clearDiagnostics(E->getSelectorLoc(0)); -      if (tryRemoving(E)) -        return true; -      Pass.TA.replace(E->getSourceRange(), "self"); -      return true; -    } -    case ObjCMessageExpr::Instance: -      break; -    } - -    Expr *rec = E->getInstanceReceiver(); -    if (!rec) return true; - -    Transaction Trans(Pass.TA); -    clearDiagnostics(E->getSelectorLoc(0)); - -    ObjCMessageExpr *Msg = E; -    Expr *RecContainer = Msg; -    SourceRange RecRange = rec->getSourceRange(); -    checkForGCDOrXPC(Msg, RecContainer, rec, RecRange); - -    if (Msg->getMethodFamily() == OMF_release && -        isRemovable(RecContainer) && isInAtFinally(RecContainer)) { -      // Change the -release to "receiver = nil" in a finally to avoid a leak -      // when an exception is thrown. -      Pass.TA.replace(RecContainer->getSourceRange(), RecRange); -      std::string str = " = "; -      str += getNilString(Pass); -      Pass.TA.insertAfterToken(RecRange.getEnd(), str); -      return true; -    } - -    if (hasSideEffects(rec, Pass.Ctx) || !tryRemoving(RecContainer)) -      Pass.TA.replace(RecContainer->getSourceRange(), RecRange); - -    return true; -  } - -private: -  /// Checks for idioms where an unused -autorelease is common. -  /// -  /// Returns true for this idiom which is common in property -  /// setters: -  /// -  ///   [backingValue autorelease]; -  ///   backingValue = [newValue retain]; // in general a +1 assign -  /// -  /// For these as well: -  /// -  ///   [[var retain] autorelease]; -  ///   return var; -  /// -  bool isCommonUnusedAutorelease(ObjCMessageExpr *E) { -    return isPlusOneAssignBeforeOrAfterAutorelease(E) || -           isReturnedAfterAutorelease(E); -  } - -  bool isReturnedAfterAutorelease(ObjCMessageExpr *E) { -    Expr *Rec = E->getInstanceReceiver(); -    if (!Rec) -      return false; - -    Decl *RefD = getReferencedDecl(Rec); -    if (!RefD) -      return false; - -    Stmt *nextStmt = getNextStmt(E); -    if (!nextStmt) -      return false; - -    // Check for "return <variable>;". - -    if (ReturnStmt *RetS = dyn_cast<ReturnStmt>(nextStmt)) -      return RefD == getReferencedDecl(RetS->getRetValue()); - -    return false; -  } - -  bool isPlusOneAssignBeforeOrAfterAutorelease(ObjCMessageExpr *E) { -    Expr *Rec = E->getInstanceReceiver(); -    if (!Rec) -      return false; - -    Decl *RefD = getReferencedDecl(Rec); -    if (!RefD) -      return false; - -    Stmt *prevStmt, *nextStmt; -    std::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E); - -    return isPlusOneAssignToVar(prevStmt, RefD) || -           isPlusOneAssignToVar(nextStmt, RefD); -  } - -  bool isPlusOneAssignToVar(Stmt *S, Decl *RefD) { -    if (!S) -      return false; - -    // Check for "RefD = [+1 retained object];". - -    if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) { -      return (RefD == getReferencedDecl(Bop->getLHS())) && isPlusOneAssign(Bop); -    } - -    if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) { -      if (DS->isSingleDecl() && DS->getSingleDecl() == RefD) { -        if (VarDecl *VD = dyn_cast<VarDecl>(RefD)) -          return isPlusOne(VD->getInit()); -      } -      return false; -    } - -    return false; -  } - -  Stmt *getNextStmt(Expr *E) { -    return getPreviousAndNextStmt(E).second; -  } - -  std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(Expr *E) { -    Stmt *prevStmt = nullptr, *nextStmt = nullptr; -    if (!E) -      return std::make_pair(prevStmt, nextStmt); - -    Stmt *OuterS = E, *InnerS; -    do { -      InnerS = OuterS; -      OuterS = StmtMap->getParent(InnerS); -    } -    while (OuterS && (isa<ParenExpr>(OuterS) || -                      isa<CastExpr>(OuterS) || -                      isa<FullExpr>(OuterS))); - -    if (!OuterS) -      return std::make_pair(prevStmt, nextStmt); - -    Stmt::child_iterator currChildS = OuterS->child_begin(); -    Stmt::child_iterator childE = OuterS->child_end(); -    Stmt::child_iterator prevChildS = childE; -    for (; currChildS != childE; ++currChildS) { -      if (*currChildS == InnerS) -        break; -      prevChildS = currChildS; -    } - -    if (prevChildS != childE) { -      prevStmt = *prevChildS; -      if (auto *E = dyn_cast_or_null<Expr>(prevStmt)) -        prevStmt = E->IgnoreImplicit(); -    } - -    if (currChildS == childE) -      return std::make_pair(prevStmt, nextStmt); -    ++currChildS; -    if (currChildS == childE) -      return std::make_pair(prevStmt, nextStmt); - -    nextStmt = *currChildS; -    if (auto *E = dyn_cast_or_null<Expr>(nextStmt)) -      nextStmt = E->IgnoreImplicit(); - -    return std::make_pair(prevStmt, nextStmt); -  } - -  Decl *getReferencedDecl(Expr *E) { -    if (!E) -      return nullptr; - -    E = E->IgnoreParenCasts(); -    if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) { -      switch (ME->getMethodFamily()) { -      case OMF_copy: -      case OMF_autorelease: -      case OMF_release: -      case OMF_retain: -        return getReferencedDecl(ME->getInstanceReceiver()); -      default: -        return nullptr; -      } -    } -    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) -      return DRE->getDecl(); -    if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) -      return ME->getMemberDecl(); -    if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(E)) -      return IRE->getDecl(); - -    return nullptr; -  } - -  /// Check if the retain/release is due to a GCD/XPC macro that are -  /// defined as: -  /// -  /// #define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; }) -  /// #define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; }) -  /// #define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; }) -  /// #define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; }) -  /// -  /// and return the top container which is the StmtExpr and the macro argument -  /// expression. -  void checkForGCDOrXPC(ObjCMessageExpr *Msg, Expr *&RecContainer, -                        Expr *&Rec, SourceRange &RecRange) { -    SourceLocation Loc = Msg->getExprLoc(); -    if (!Loc.isMacroID()) -      return; -    SourceManager &SM = Pass.Ctx.getSourceManager(); -    StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, -                                                     Pass.Ctx.getLangOpts()); -    bool isGCDOrXPC = llvm::StringSwitch<bool>(MacroName) -        .Case("dispatch_retain", true) -        .Case("dispatch_release", true) -        .Case("xpc_retain", true) -        .Case("xpc_release", true) -        .Default(false); -    if (!isGCDOrXPC) -      return; - -    StmtExpr *StmtE = nullptr; -    Stmt *S = Msg; -    while (S) { -      if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) { -        StmtE = SE; -        break; -      } -      S = StmtMap->getParent(S); -    } - -    if (!StmtE) -      return; - -    Stmt::child_range StmtExprChild = StmtE->children(); -    if (StmtExprChild.begin() == StmtExprChild.end()) -      return; -    auto *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild.begin()); -    if (!CompS) -      return; - -    Stmt::child_range CompStmtChild = CompS->children(); -    if (CompStmtChild.begin() == CompStmtChild.end()) -      return; -    auto *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild.begin()); -    if (!DeclS) -      return; -    if (!DeclS->isSingleDecl()) -      return; -    VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()); -    if (!VD) -      return; -    Expr *Init = VD->getInit(); -    if (!Init) -      return; - -    RecContainer = StmtE; -    Rec = Init->IgnoreParenImpCasts(); -    if (FullExpr *FE = dyn_cast<FullExpr>(Rec)) -      Rec = FE->getSubExpr()->IgnoreParenImpCasts(); -    RecRange = Rec->getSourceRange(); -    if (SM.isMacroArgExpansion(RecRange.getBegin())) -      RecRange.setBegin(SM.getImmediateSpellingLoc(RecRange.getBegin())); -    if (SM.isMacroArgExpansion(RecRange.getEnd())) -      RecRange.setEnd(SM.getImmediateSpellingLoc(RecRange.getEnd())); -  } - -  void clearDiagnostics(SourceLocation loc) const { -    Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message, -                            diag::err_unavailable, -                            diag::err_unavailable_message, -                            loc); -  } - -  bool isDelegateMessage(Expr *E) const { -    if (!E) return false; - -    E = E->IgnoreParenCasts(); - -    // Also look through property-getter sugar. -    if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E)) -      E = pseudoOp->getResultExpr()->IgnoreImplicit(); - -    if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) -      return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel); - -    return false; -  } - -  bool isInAtFinally(Expr *E) const { -    assert(E); -    Stmt *S = E; -    while (S) { -      if (isa<ObjCAtFinallyStmt>(S)) -        return true; -      S = StmtMap->getParent(S); -    } - -    return false; -  } - -  bool isRemovable(Expr *E) const { -    return Removables.count(E); -  } - -  bool tryRemoving(Expr *E) const { -    if (isRemovable(E)) { -      Pass.TA.removeStmt(E); -      return true; -    } - -    Stmt *parent = StmtMap->getParent(E); - -    if (ImplicitCastExpr *castE = dyn_cast_or_null<ImplicitCastExpr>(parent)) -      return tryRemoving(castE); - -    if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent)) -      return tryRemoving(parenE); - -    if (BinaryOperator * -          bopE = dyn_cast_or_null<BinaryOperator>(parent)) { -      if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E && -          isRemovable(bopE)) { -        Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange()); -        return true; -      } -    } - -    return false; -  } - -}; - -} // anonymous namespace - -void trans::removeRetainReleaseDeallocFinalize(MigrationPass &pass) { -  BodyTransform<RetainReleaseDeallocRemover> trans(pass); -  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); -}  | 
