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