Home | History | Annotate | Line # | Download | only in ARCMigrate
      1 //===--- TransRetainReleaseDealloc.cpp - Transformations to ARC mode ------===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // removeRetainReleaseDealloc:
     10 //
     11 // Removes retain/release/autorelease/dealloc messages.
     12 //
     13 //  return [[foo retain] autorelease];
     14 // ---->
     15 //  return foo;
     16 //
     17 //===----------------------------------------------------------------------===//
     18 
     19 #include "Transforms.h"
     20 #include "Internals.h"
     21 #include "clang/AST/ASTContext.h"
     22 #include "clang/AST/ParentMap.h"
     23 #include "clang/Basic/SourceManager.h"
     24 #include "clang/Lex/Lexer.h"
     25 #include "clang/Sema/SemaDiagnostic.h"
     26 #include "llvm/ADT/StringSwitch.h"
     27 
     28 using namespace clang;
     29 using namespace arcmt;
     30 using namespace trans;
     31 
     32 namespace {
     33 
     34 class RetainReleaseDeallocRemover :
     35                        public RecursiveASTVisitor<RetainReleaseDeallocRemover> {
     36   Stmt *Body;
     37   MigrationPass &Pass;
     38 
     39   ExprSet Removables;
     40   std::unique_ptr<ParentMap> StmtMap;
     41 
     42   Selector DelegateSel, FinalizeSel;
     43 
     44 public:
     45   RetainReleaseDeallocRemover(MigrationPass &pass)
     46     : Body(nullptr), Pass(pass) {
     47     DelegateSel =
     48         Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("delegate"));
     49     FinalizeSel =
     50         Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize"));
     51   }
     52 
     53   void transformBody(Stmt *body, Decl *ParentD) {
     54     Body = body;
     55     collectRemovables(body, Removables);
     56     StmtMap.reset(new ParentMap(body));
     57     TraverseStmt(body);
     58   }
     59 
     60   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
     61     switch (E->getMethodFamily()) {
     62     default:
     63       if (E->isInstanceMessage() && E->getSelector() == FinalizeSel)
     64         break;
     65       return true;
     66     case OMF_autorelease:
     67       if (isRemovable(E)) {
     68         if (!isCommonUnusedAutorelease(E)) {
     69           // An unused autorelease is badness. If we remove it the receiver
     70           // will likely die immediately while previously it was kept alive
     71           // by the autorelease pool. This is bad practice in general, leave it
     72           // and emit an error to force the user to restructure their code.
     73           Pass.TA.reportError(
     74               "it is not safe to remove an unused 'autorelease' "
     75               "message; its receiver may be destroyed immediately",
     76               E->getBeginLoc(), E->getSourceRange());
     77           return true;
     78         }
     79       }
     80       // Pass through.
     81       LLVM_FALLTHROUGH;
     82     case OMF_retain:
     83     case OMF_release:
     84       if (E->getReceiverKind() == ObjCMessageExpr::Instance)
     85         if (Expr *rec = E->getInstanceReceiver()) {
     86           rec = rec->IgnoreParenImpCasts();
     87           if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
     88               (E->getMethodFamily() != OMF_retain || isRemovable(E))) {
     89             std::string err = "it is not safe to remove '";
     90             err += E->getSelector().getAsString() + "' message on "
     91                 "an __unsafe_unretained type";
     92             Pass.TA.reportError(err, rec->getBeginLoc());
     93             return true;
     94           }
     95 
     96           if (isGlobalVar(rec) &&
     97               (E->getMethodFamily() != OMF_retain || isRemovable(E))) {
     98             std::string err = "it is not safe to remove '";
     99             err += E->getSelector().getAsString() + "' message on "
    100                 "a global variable";
    101             Pass.TA.reportError(err, rec->getBeginLoc());
    102             return true;
    103           }
    104 
    105           if (E->getMethodFamily() == OMF_release && isDelegateMessage(rec)) {
    106             Pass.TA.reportError(
    107                 "it is not safe to remove 'retain' "
    108                 "message on the result of a 'delegate' message; "
    109                 "the object that was passed to 'setDelegate:' may not be "
    110                 "properly retained",
    111                 rec->getBeginLoc());
    112             return true;
    113           }
    114         }
    115       break;
    116     case OMF_dealloc:
    117       break;
    118     }
    119 
    120     switch (E->getReceiverKind()) {
    121     default:
    122       return true;
    123     case ObjCMessageExpr::SuperInstance: {
    124       Transaction Trans(Pass.TA);
    125       clearDiagnostics(E->getSelectorLoc(0));
    126       if (tryRemoving(E))
    127         return true;
    128       Pass.TA.replace(E->getSourceRange(), "self");
    129       return true;
    130     }
    131     case ObjCMessageExpr::Instance:
    132       break;
    133     }
    134 
    135     Expr *rec = E->getInstanceReceiver();
    136     if (!rec) return true;
    137 
    138     Transaction Trans(Pass.TA);
    139     clearDiagnostics(E->getSelectorLoc(0));
    140 
    141     ObjCMessageExpr *Msg = E;
    142     Expr *RecContainer = Msg;
    143     SourceRange RecRange = rec->getSourceRange();
    144     checkForGCDOrXPC(Msg, RecContainer, rec, RecRange);
    145 
    146     if (Msg->getMethodFamily() == OMF_release &&
    147         isRemovable(RecContainer) && isInAtFinally(RecContainer)) {
    148       // Change the -release to "receiver = nil" in a finally to avoid a leak
    149       // when an exception is thrown.
    150       Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
    151       std::string str = " = ";
    152       str += getNilString(Pass);
    153       Pass.TA.insertAfterToken(RecRange.getEnd(), str);
    154       return true;
    155     }
    156 
    157     if (hasSideEffects(rec, Pass.Ctx) || !tryRemoving(RecContainer))
    158       Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
    159 
    160     return true;
    161   }
    162 
    163 private:
    164   /// Checks for idioms where an unused -autorelease is common.
    165   ///
    166   /// Returns true for this idiom which is common in property
    167   /// setters:
    168   ///
    169   ///   [backingValue autorelease];
    170   ///   backingValue = [newValue retain]; // in general a +1 assign
    171   ///
    172   /// For these as well:
    173   ///
    174   ///   [[var retain] autorelease];
    175   ///   return var;
    176   ///
    177   bool isCommonUnusedAutorelease(ObjCMessageExpr *E) {
    178     return isPlusOneAssignBeforeOrAfterAutorelease(E) ||
    179            isReturnedAfterAutorelease(E);
    180   }
    181 
    182   bool isReturnedAfterAutorelease(ObjCMessageExpr *E) {
    183     Expr *Rec = E->getInstanceReceiver();
    184     if (!Rec)
    185       return false;
    186 
    187     Decl *RefD = getReferencedDecl(Rec);
    188     if (!RefD)
    189       return false;
    190 
    191     Stmt *nextStmt = getNextStmt(E);
    192     if (!nextStmt)
    193       return false;
    194 
    195     // Check for "return <variable>;".
    196 
    197     if (ReturnStmt *RetS = dyn_cast<ReturnStmt>(nextStmt))
    198       return RefD == getReferencedDecl(RetS->getRetValue());
    199 
    200     return false;
    201   }
    202 
    203   bool isPlusOneAssignBeforeOrAfterAutorelease(ObjCMessageExpr *E) {
    204     Expr *Rec = E->getInstanceReceiver();
    205     if (!Rec)
    206       return false;
    207 
    208     Decl *RefD = getReferencedDecl(Rec);
    209     if (!RefD)
    210       return false;
    211 
    212     Stmt *prevStmt, *nextStmt;
    213     std::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E);
    214 
    215     return isPlusOneAssignToVar(prevStmt, RefD) ||
    216            isPlusOneAssignToVar(nextStmt, RefD);
    217   }
    218 
    219   bool isPlusOneAssignToVar(Stmt *S, Decl *RefD) {
    220     if (!S)
    221       return false;
    222 
    223     // Check for "RefD = [+1 retained object];".
    224 
    225     if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
    226       return (RefD == getReferencedDecl(Bop->getLHS())) && isPlusOneAssign(Bop);
    227     }
    228 
    229     if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
    230       if (DS->isSingleDecl() && DS->getSingleDecl() == RefD) {
    231         if (VarDecl *VD = dyn_cast<VarDecl>(RefD))
    232           return isPlusOne(VD->getInit());
    233       }
    234       return false;
    235     }
    236 
    237     return false;
    238   }
    239 
    240   Stmt *getNextStmt(Expr *E) {
    241     return getPreviousAndNextStmt(E).second;
    242   }
    243 
    244   std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(Expr *E) {
    245     Stmt *prevStmt = nullptr, *nextStmt = nullptr;
    246     if (!E)
    247       return std::make_pair(prevStmt, nextStmt);
    248 
    249     Stmt *OuterS = E, *InnerS;
    250     do {
    251       InnerS = OuterS;
    252       OuterS = StmtMap->getParent(InnerS);
    253     }
    254     while (OuterS && (isa<ParenExpr>(OuterS) ||
    255                       isa<CastExpr>(OuterS) ||
    256                       isa<FullExpr>(OuterS)));
    257 
    258     if (!OuterS)
    259       return std::make_pair(prevStmt, nextStmt);
    260 
    261     Stmt::child_iterator currChildS = OuterS->child_begin();
    262     Stmt::child_iterator childE = OuterS->child_end();
    263     Stmt::child_iterator prevChildS = childE;
    264     for (; currChildS != childE; ++currChildS) {
    265       if (*currChildS == InnerS)
    266         break;
    267       prevChildS = currChildS;
    268     }
    269 
    270     if (prevChildS != childE) {
    271       prevStmt = *prevChildS;
    272       if (auto *E = dyn_cast_or_null<Expr>(prevStmt))
    273         prevStmt = E->IgnoreImplicit();
    274     }
    275 
    276     if (currChildS == childE)
    277       return std::make_pair(prevStmt, nextStmt);
    278     ++currChildS;
    279     if (currChildS == childE)
    280       return std::make_pair(prevStmt, nextStmt);
    281 
    282     nextStmt = *currChildS;
    283     if (auto *E = dyn_cast_or_null<Expr>(nextStmt))
    284       nextStmt = E->IgnoreImplicit();
    285 
    286     return std::make_pair(prevStmt, nextStmt);
    287   }
    288 
    289   Decl *getReferencedDecl(Expr *E) {
    290     if (!E)
    291       return nullptr;
    292 
    293     E = E->IgnoreParenCasts();
    294     if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
    295       switch (ME->getMethodFamily()) {
    296       case OMF_copy:
    297       case OMF_autorelease:
    298       case OMF_release:
    299       case OMF_retain:
    300         return getReferencedDecl(ME->getInstanceReceiver());
    301       default:
    302         return nullptr;
    303       }
    304     }
    305     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
    306       return DRE->getDecl();
    307     if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
    308       return ME->getMemberDecl();
    309     if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(E))
    310       return IRE->getDecl();
    311 
    312     return nullptr;
    313   }
    314 
    315   /// Check if the retain/release is due to a GCD/XPC macro that are
    316   /// defined as:
    317   ///
    318   /// #define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
    319   /// #define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
    320   /// #define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
    321   /// #define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
    322   ///
    323   /// and return the top container which is the StmtExpr and the macro argument
    324   /// expression.
    325   void checkForGCDOrXPC(ObjCMessageExpr *Msg, Expr *&RecContainer,
    326                         Expr *&Rec, SourceRange &RecRange) {
    327     SourceLocation Loc = Msg->getExprLoc();
    328     if (!Loc.isMacroID())
    329       return;
    330     SourceManager &SM = Pass.Ctx.getSourceManager();
    331     StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM,
    332                                                      Pass.Ctx.getLangOpts());
    333     bool isGCDOrXPC = llvm::StringSwitch<bool>(MacroName)
    334         .Case("dispatch_retain", true)
    335         .Case("dispatch_release", true)
    336         .Case("xpc_retain", true)
    337         .Case("xpc_release", true)
    338         .Default(false);
    339     if (!isGCDOrXPC)
    340       return;
    341 
    342     StmtExpr *StmtE = nullptr;
    343     Stmt *S = Msg;
    344     while (S) {
    345       if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
    346         StmtE = SE;
    347         break;
    348       }
    349       S = StmtMap->getParent(S);
    350     }
    351 
    352     if (!StmtE)
    353       return;
    354 
    355     Stmt::child_range StmtExprChild = StmtE->children();
    356     if (StmtExprChild.begin() == StmtExprChild.end())
    357       return;
    358     auto *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild.begin());
    359     if (!CompS)
    360       return;
    361 
    362     Stmt::child_range CompStmtChild = CompS->children();
    363     if (CompStmtChild.begin() == CompStmtChild.end())
    364       return;
    365     auto *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild.begin());
    366     if (!DeclS)
    367       return;
    368     if (!DeclS->isSingleDecl())
    369       return;
    370     VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl());
    371     if (!VD)
    372       return;
    373     Expr *Init = VD->getInit();
    374     if (!Init)
    375       return;
    376 
    377     RecContainer = StmtE;
    378     Rec = Init->IgnoreParenImpCasts();
    379     if (FullExpr *FE = dyn_cast<FullExpr>(Rec))
    380       Rec = FE->getSubExpr()->IgnoreParenImpCasts();
    381     RecRange = Rec->getSourceRange();
    382     if (SM.isMacroArgExpansion(RecRange.getBegin()))
    383       RecRange.setBegin(SM.getImmediateSpellingLoc(RecRange.getBegin()));
    384     if (SM.isMacroArgExpansion(RecRange.getEnd()))
    385       RecRange.setEnd(SM.getImmediateSpellingLoc(RecRange.getEnd()));
    386   }
    387 
    388   void clearDiagnostics(SourceLocation loc) const {
    389     Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
    390                             diag::err_unavailable,
    391                             diag::err_unavailable_message,
    392                             loc);
    393   }
    394 
    395   bool isDelegateMessage(Expr *E) const {
    396     if (!E) return false;
    397 
    398     E = E->IgnoreParenCasts();
    399 
    400     // Also look through property-getter sugar.
    401     if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E))
    402       E = pseudoOp->getResultExpr()->IgnoreImplicit();
    403 
    404     if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
    405       return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
    406 
    407     return false;
    408   }
    409 
    410   bool isInAtFinally(Expr *E) const {
    411     assert(E);
    412     Stmt *S = E;
    413     while (S) {
    414       if (isa<ObjCAtFinallyStmt>(S))
    415         return true;
    416       S = StmtMap->getParent(S);
    417     }
    418 
    419     return false;
    420   }
    421 
    422   bool isRemovable(Expr *E) const {
    423     return Removables.count(E);
    424   }
    425 
    426   bool tryRemoving(Expr *E) const {
    427     if (isRemovable(E)) {
    428       Pass.TA.removeStmt(E);
    429       return true;
    430     }
    431 
    432     Stmt *parent = StmtMap->getParent(E);
    433 
    434     if (ImplicitCastExpr *castE = dyn_cast_or_null<ImplicitCastExpr>(parent))
    435       return tryRemoving(castE);
    436 
    437     if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
    438       return tryRemoving(parenE);
    439 
    440     if (BinaryOperator *
    441           bopE = dyn_cast_or_null<BinaryOperator>(parent)) {
    442       if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
    443           isRemovable(bopE)) {
    444         Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
    445         return true;
    446       }
    447     }
    448 
    449     return false;
    450   }
    451 
    452 };
    453 
    454 } // anonymous namespace
    455 
    456 void trans::removeRetainReleaseDeallocFinalize(MigrationPass &pass) {
    457   BodyTransform<RetainReleaseDeallocRemover> trans(pass);
    458   trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
    459 }
    460