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   OwningPtr<ParentMap> StmtMap;
     42 
     43   Selector DelegateSel, FinalizeSel;
     44 
     45 public:
     46   RetainReleaseDeallocRemover(MigrationPass &pass)
     47     : Body(0), 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 his 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->getSuperLoc());
    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(rec->getExprLoc());
    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.Ctx);
    149       Pass.TA.insertAfterToken(RecRange.getEnd(), str);
    150       return true;
    151     }
    152 
    153     if (!hasSideEffects(rec, Pass.Ctx)) {
    154       if (tryRemoving(RecContainer))
    155         return true;
    156     }
    157     Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
    158 
    159     return true;
    160   }
    161 
    162 private:
    163   /// \brief Checks for idioms where an unused -autorelease is common.
    164   ///
    165   /// Returns true for this idiom which is common in property
    166   /// setters:
    167   ///
    168   ///   [backingValue autorelease];
    169   ///   backingValue = [newValue retain]; // in general a +1 assign
    170   ///
    171   /// For these as well:
    172   ///
    173   ///   [[var retain] autorelease];
    174   ///   return var;
    175   ///
    176   bool isCommonUnusedAutorelease(ObjCMessageExpr *E) {
    177     if (isPlusOneAssignBeforeOrAfterAutorelease(E))
    178       return true;
    179     if (isReturnedAfterAutorelease(E))
    180       return true;
    181     return false;
    182   }
    183 
    184   bool isReturnedAfterAutorelease(ObjCMessageExpr *E) {
    185     Expr *Rec = E->getInstanceReceiver();
    186     if (!Rec)
    187       return false;
    188 
    189     Decl *RefD = getReferencedDecl(Rec);
    190     if (!RefD)
    191       return false;
    192 
    193     Stmt *nextStmt = getNextStmt(E);
    194     if (!nextStmt)
    195       return false;
    196 
    197     // Check for "return <variable>;".
    198 
    199     if (ReturnStmt *RetS = dyn_cast<ReturnStmt>(nextStmt))
    200       return RefD == getReferencedDecl(RetS->getRetValue());
    201 
    202     return false;
    203   }
    204 
    205   bool isPlusOneAssignBeforeOrAfterAutorelease(ObjCMessageExpr *E) {
    206     Expr *Rec = E->getInstanceReceiver();
    207     if (!Rec)
    208       return false;
    209 
    210     Decl *RefD = getReferencedDecl(Rec);
    211     if (!RefD)
    212       return false;
    213 
    214     Stmt *prevStmt, *nextStmt;
    215     llvm::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E);
    216 
    217     return isPlusOneAssignToVar(prevStmt, RefD) ||
    218            isPlusOneAssignToVar(nextStmt, RefD);
    219   }
    220 
    221   bool isPlusOneAssignToVar(Stmt *S, Decl *RefD) {
    222     if (!S)
    223       return false;
    224 
    225     // Check for "RefD = [+1 retained object];".
    226 
    227     if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
    228       if (RefD != getReferencedDecl(Bop->getLHS()))
    229         return false;
    230       if (isPlusOneAssign(Bop))
    231         return true;
    232       return false;
    233     }
    234 
    235     if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
    236       if (DS->isSingleDecl() && DS->getSingleDecl() == RefD) {
    237         if (VarDecl *VD = dyn_cast<VarDecl>(RefD))
    238           return isPlusOne(VD->getInit());
    239       }
    240       return false;
    241     }
    242 
    243     return false;
    244   }
    245 
    246   Stmt *getNextStmt(Expr *E) {
    247     return getPreviousAndNextStmt(E).second;
    248   }
    249 
    250   std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(Expr *E) {
    251     Stmt *prevStmt = 0, *nextStmt = 0;
    252     if (!E)
    253       return std::make_pair(prevStmt, nextStmt);
    254 
    255     Stmt *OuterS = E, *InnerS;
    256     do {
    257       InnerS = OuterS;
    258       OuterS = StmtMap->getParent(InnerS);
    259     }
    260     while (OuterS && (isa<ParenExpr>(OuterS) ||
    261                       isa<CastExpr>(OuterS) ||
    262                       isa<ExprWithCleanups>(OuterS)));
    263 
    264     if (!OuterS)
    265       return std::make_pair(prevStmt, nextStmt);
    266 
    267     Stmt::child_iterator currChildS = OuterS->child_begin();
    268     Stmt::child_iterator childE = OuterS->child_end();
    269     Stmt::child_iterator prevChildS = childE;
    270     for (; currChildS != childE; ++currChildS) {
    271       if (*currChildS == InnerS)
    272         break;
    273       prevChildS = currChildS;
    274     }
    275 
    276     if (prevChildS != childE) {
    277       prevStmt = *prevChildS;
    278       if (prevStmt)
    279         prevStmt = prevStmt->IgnoreImplicit();
    280     }
    281 
    282     if (currChildS == childE)
    283       return std::make_pair(prevStmt, nextStmt);
    284     ++currChildS;
    285     if (currChildS == childE)
    286       return std::make_pair(prevStmt, nextStmt);
    287 
    288     nextStmt = *currChildS;
    289     if (nextStmt)
    290       nextStmt = nextStmt->IgnoreImplicit();
    291 
    292     return std::make_pair(prevStmt, nextStmt);
    293   }
    294 
    295   Decl *getReferencedDecl(Expr *E) {
    296     if (!E)
    297       return 0;
    298 
    299     E = E->IgnoreParenCasts();
    300     if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
    301       switch (ME->getMethodFamily()) {
    302       case OMF_copy:
    303       case OMF_autorelease:
    304       case OMF_release:
    305       case OMF_retain:
    306         return getReferencedDecl(ME->getInstanceReceiver());
    307       default:
    308         return 0;
    309       }
    310     }
    311     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
    312       return DRE->getDecl();
    313     if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
    314       return ME->getMemberDecl();
    315     if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(E))
    316       return IRE->getDecl();
    317 
    318     return 0;
    319   }
    320 
    321   /// \brief Check if the retain/release is due to a GCD/XPC macro that are
    322   /// defined as:
    323   ///
    324   /// #define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
    325   /// #define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
    326   /// #define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
    327   /// #define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
    328   ///
    329   /// and return the top container which is the StmtExpr and the macro argument
    330   /// expression.
    331   void checkForGCDOrXPC(ObjCMessageExpr *Msg, Expr *&RecContainer,
    332                         Expr *&Rec, SourceRange &RecRange) {
    333     SourceLocation Loc = Msg->getExprLoc();
    334     if (!Loc.isMacroID())
    335       return;
    336     SourceManager &SM = Pass.Ctx.getSourceManager();
    337     StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM,
    338                                                      Pass.Ctx.getLangOpts());
    339     bool isGCDOrXPC = llvm::StringSwitch<bool>(MacroName)
    340         .Case("dispatch_retain", true)
    341         .Case("dispatch_release", true)
    342         .Case("xpc_retain", true)
    343         .Case("xpc_release", true)
    344         .Default(false);
    345     if (!isGCDOrXPC)
    346       return;
    347 
    348     StmtExpr *StmtE = 0;
    349     Stmt *S = Msg;
    350     while (S) {
    351       if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
    352         StmtE = SE;
    353         break;
    354       }
    355       S = StmtMap->getParent(S);
    356     }
    357 
    358     if (!StmtE)
    359       return;
    360 
    361     Stmt::child_range StmtExprChild = StmtE->children();
    362     if (!StmtExprChild)
    363       return;
    364     CompoundStmt *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild);
    365     if (!CompS)
    366       return;
    367 
    368     Stmt::child_range CompStmtChild = CompS->children();
    369     if (!CompStmtChild)
    370       return;
    371     DeclStmt *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild);
    372     if (!DeclS)
    373       return;
    374     if (!DeclS->isSingleDecl())
    375       return;
    376     VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl());
    377     if (!VD)
    378       return;
    379     Expr *Init = VD->getInit();
    380     if (!Init)
    381       return;
    382 
    383     RecContainer = StmtE;
    384     Rec = Init->IgnoreParenImpCasts();
    385     if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Rec))
    386       Rec = EWC->getSubExpr()->IgnoreParenImpCasts();
    387     RecRange = Rec->getSourceRange();
    388     if (SM.isMacroArgExpansion(RecRange.getBegin()))
    389       RecRange.setBegin(SM.getImmediateSpellingLoc(RecRange.getBegin()));
    390     if (SM.isMacroArgExpansion(RecRange.getEnd()))
    391       RecRange.setEnd(SM.getImmediateSpellingLoc(RecRange.getEnd()));
    392   }
    393 
    394   void clearDiagnostics(SourceLocation loc) const {
    395     Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
    396                             diag::err_unavailable,
    397                             diag::err_unavailable_message,
    398                             loc);
    399   }
    400 
    401   bool isDelegateMessage(Expr *E) const {
    402     if (!E) return false;
    403 
    404     E = E->IgnoreParenCasts();
    405 
    406     // Also look through property-getter sugar.
    407     if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E))
    408       E = pseudoOp->getResultExpr()->IgnoreImplicit();
    409 
    410     if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
    411       return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
    412 
    413     return false;
    414   }
    415 
    416   bool isInAtFinally(Expr *E) const {
    417     assert(E);
    418     Stmt *S = E;
    419     while (S) {
    420       if (isa<ObjCAtFinallyStmt>(S))
    421         return true;
    422       S = StmtMap->getParent(S);
    423     }
    424 
    425     return false;
    426   }
    427 
    428   bool isRemovable(Expr *E) const {
    429     return Removables.count(E);
    430   }
    431 
    432   bool tryRemoving(Expr *E) const {
    433     if (isRemovable(E)) {
    434       Pass.TA.removeStmt(E);
    435       return true;
    436     }
    437 
    438     Stmt *parent = StmtMap->getParent(E);
    439 
    440     if (ImplicitCastExpr *castE = dyn_cast_or_null<ImplicitCastExpr>(parent))
    441       return tryRemoving(castE);
    442 
    443     if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
    444       return tryRemoving(parenE);
    445 
    446     if (BinaryOperator *
    447           bopE = dyn_cast_or_null<BinaryOperator>(parent)) {
    448       if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
    449           isRemovable(bopE)) {
    450         Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
    451         return true;
    452       }
    453     }
    454 
    455     return false;
    456   }
    457 
    458 };
    459 
    460 } // anonymous namespace
    461 
    462 void trans::removeRetainReleaseDeallocFinalize(MigrationPass &pass) {
    463   BodyTransform<RetainReleaseDeallocRemover> trans(pass);
    464   trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
    465 }
    466