clang API Documentation

TransRetainReleaseDealloc.cpp
Go to the documentation of this file.
00001 //===--- TransRetainReleaseDealloc.cpp - Transformations to ARC mode ------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // removeRetainReleaseDealloc:
00011 //
00012 // Removes retain/release/autorelease/dealloc messages.
00013 //
00014 //  return [[foo retain] autorelease];
00015 // ---->
00016 //  return foo;
00017 //
00018 //===----------------------------------------------------------------------===//
00019 
00020 #include "Transforms.h"
00021 #include "Internals.h"
00022 #include "clang/AST/ASTContext.h"
00023 #include "clang/AST/ParentMap.h"
00024 #include "clang/Basic/SourceManager.h"
00025 #include "clang/Lex/Lexer.h"
00026 #include "clang/Sema/SemaDiagnostic.h"
00027 #include "llvm/ADT/StringSwitch.h"
00028 
00029 using namespace clang;
00030 using namespace arcmt;
00031 using namespace trans;
00032 
00033 namespace {
00034 
00035 class RetainReleaseDeallocRemover :
00036                        public RecursiveASTVisitor<RetainReleaseDeallocRemover> {
00037   Stmt *Body;
00038   MigrationPass &Pass;
00039 
00040   ExprSet Removables;
00041   std::unique_ptr<ParentMap> StmtMap;
00042 
00043   Selector DelegateSel, FinalizeSel;
00044 
00045 public:
00046   RetainReleaseDeallocRemover(MigrationPass &pass)
00047     : Body(nullptr), Pass(pass) {
00048     DelegateSel =
00049         Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("delegate"));
00050     FinalizeSel =
00051         Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize"));
00052   }
00053 
00054   void transformBody(Stmt *body, Decl *ParentD) {
00055     Body = body;
00056     collectRemovables(body, Removables);
00057     StmtMap.reset(new ParentMap(body));
00058     TraverseStmt(body);
00059   }
00060 
00061   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
00062     switch (E->getMethodFamily()) {
00063     default:
00064       if (E->isInstanceMessage() && E->getSelector() == FinalizeSel)
00065         break;
00066       return true;
00067     case OMF_autorelease:
00068       if (isRemovable(E)) {
00069         if (!isCommonUnusedAutorelease(E)) {
00070           // An unused autorelease is badness. If we remove it the receiver
00071           // will likely die immediately while previously it was kept alive
00072           // by the autorelease pool. This is bad practice in general, leave it
00073           // and emit an error to force the user to restructure their code.
00074           Pass.TA.reportError("it is not safe to remove an unused 'autorelease' "
00075               "message; its receiver may be destroyed immediately",
00076               E->getLocStart(), E->getSourceRange());
00077           return true;
00078         }
00079       }
00080       // Pass through.
00081     case OMF_retain:
00082     case OMF_release:
00083       if (E->getReceiverKind() == ObjCMessageExpr::Instance)
00084         if (Expr *rec = E->getInstanceReceiver()) {
00085           rec = rec->IgnoreParenImpCasts();
00086           if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
00087               (E->getMethodFamily() != OMF_retain || isRemovable(E))) {
00088             std::string err = "it is not safe to remove '";
00089             err += E->getSelector().getAsString() + "' message on "
00090                 "an __unsafe_unretained type";
00091             Pass.TA.reportError(err, rec->getLocStart());
00092             return true;
00093           }
00094 
00095           if (isGlobalVar(rec) &&
00096               (E->getMethodFamily() != OMF_retain || isRemovable(E))) {
00097             std::string err = "it is not safe to remove '";
00098             err += E->getSelector().getAsString() + "' message on "
00099                 "a global variable";
00100             Pass.TA.reportError(err, rec->getLocStart());
00101             return true;
00102           }
00103 
00104           if (E->getMethodFamily() == OMF_release && isDelegateMessage(rec)) {
00105             Pass.TA.reportError("it is not safe to remove 'retain' "
00106                 "message on the result of a 'delegate' message; "
00107                 "the object that was passed to 'setDelegate:' may not be "
00108                 "properly retained", rec->getLocStart());
00109             return true;
00110           }
00111         }
00112     case OMF_dealloc:
00113       break;
00114     }
00115 
00116     switch (E->getReceiverKind()) {
00117     default:
00118       return true;
00119     case ObjCMessageExpr::SuperInstance: {
00120       Transaction Trans(Pass.TA);
00121       clearDiagnostics(E->getSelectorLoc(0));
00122       if (tryRemoving(E))
00123         return true;
00124       Pass.TA.replace(E->getSourceRange(), "self");
00125       return true;
00126     }
00127     case ObjCMessageExpr::Instance:
00128       break;
00129     }
00130 
00131     Expr *rec = E->getInstanceReceiver();
00132     if (!rec) return true;
00133 
00134     Transaction Trans(Pass.TA);
00135     clearDiagnostics(E->getSelectorLoc(0));
00136 
00137     ObjCMessageExpr *Msg = E;
00138     Expr *RecContainer = Msg;
00139     SourceRange RecRange = rec->getSourceRange();
00140     checkForGCDOrXPC(Msg, RecContainer, rec, RecRange);
00141 
00142     if (Msg->getMethodFamily() == OMF_release &&
00143         isRemovable(RecContainer) && isInAtFinally(RecContainer)) {
00144       // Change the -release to "receiver = nil" in a finally to avoid a leak
00145       // when an exception is thrown.
00146       Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
00147       std::string str = " = ";
00148       str += getNilString(Pass.Ctx);
00149       Pass.TA.insertAfterToken(RecRange.getEnd(), str);
00150       return true;
00151     }
00152 
00153     if (!hasSideEffects(rec, Pass.Ctx)) {
00154       if (tryRemoving(RecContainer))
00155         return true;
00156     }
00157     Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
00158 
00159     return true;
00160   }
00161 
00162 private:
00163   /// \brief Checks for idioms where an unused -autorelease is common.
00164   ///
00165   /// Returns true for this idiom which is common in property
00166   /// setters:
00167   ///
00168   ///   [backingValue autorelease];
00169   ///   backingValue = [newValue retain]; // in general a +1 assign
00170   ///
00171   /// For these as well:
00172   ///
00173   ///   [[var retain] autorelease];
00174   ///   return var;
00175   ///
00176   bool isCommonUnusedAutorelease(ObjCMessageExpr *E) {
00177     if (isPlusOneAssignBeforeOrAfterAutorelease(E))
00178       return true;
00179     if (isReturnedAfterAutorelease(E))
00180       return true;
00181     return false;
00182   }
00183 
00184   bool isReturnedAfterAutorelease(ObjCMessageExpr *E) {
00185     Expr *Rec = E->getInstanceReceiver();
00186     if (!Rec)
00187       return false;
00188 
00189     Decl *RefD = getReferencedDecl(Rec);
00190     if (!RefD)
00191       return false;
00192 
00193     Stmt *nextStmt = getNextStmt(E);
00194     if (!nextStmt)
00195       return false;
00196 
00197     // Check for "return <variable>;".
00198 
00199     if (ReturnStmt *RetS = dyn_cast<ReturnStmt>(nextStmt))
00200       return RefD == getReferencedDecl(RetS->getRetValue());
00201 
00202     return false;
00203   }
00204 
00205   bool isPlusOneAssignBeforeOrAfterAutorelease(ObjCMessageExpr *E) {
00206     Expr *Rec = E->getInstanceReceiver();
00207     if (!Rec)
00208       return false;
00209 
00210     Decl *RefD = getReferencedDecl(Rec);
00211     if (!RefD)
00212       return false;
00213 
00214     Stmt *prevStmt, *nextStmt;
00215     std::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E);
00216 
00217     return isPlusOneAssignToVar(prevStmt, RefD) ||
00218            isPlusOneAssignToVar(nextStmt, RefD);
00219   }
00220 
00221   bool isPlusOneAssignToVar(Stmt *S, Decl *RefD) {
00222     if (!S)
00223       return false;
00224 
00225     // Check for "RefD = [+1 retained object];".
00226 
00227     if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
00228       if (RefD != getReferencedDecl(Bop->getLHS()))
00229         return false;
00230       if (isPlusOneAssign(Bop))
00231         return true;
00232       return false;
00233     }
00234 
00235     if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
00236       if (DS->isSingleDecl() && DS->getSingleDecl() == RefD) {
00237         if (VarDecl *VD = dyn_cast<VarDecl>(RefD))
00238           return isPlusOne(VD->getInit());
00239       }
00240       return false;
00241     }
00242 
00243     return false;
00244   }
00245 
00246   Stmt *getNextStmt(Expr *E) {
00247     return getPreviousAndNextStmt(E).second;
00248   }
00249 
00250   std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(Expr *E) {
00251     Stmt *prevStmt = nullptr, *nextStmt = nullptr;
00252     if (!E)
00253       return std::make_pair(prevStmt, nextStmt);
00254 
00255     Stmt *OuterS = E, *InnerS;
00256     do {
00257       InnerS = OuterS;
00258       OuterS = StmtMap->getParent(InnerS);
00259     }
00260     while (OuterS && (isa<ParenExpr>(OuterS) ||
00261                       isa<CastExpr>(OuterS) ||
00262                       isa<ExprWithCleanups>(OuterS)));
00263     
00264     if (!OuterS)
00265       return std::make_pair(prevStmt, nextStmt);
00266 
00267     Stmt::child_iterator currChildS = OuterS->child_begin();
00268     Stmt::child_iterator childE = OuterS->child_end();
00269     Stmt::child_iterator prevChildS = childE;
00270     for (; currChildS != childE; ++currChildS) {
00271       if (*currChildS == InnerS)
00272         break;
00273       prevChildS = currChildS;
00274     }
00275 
00276     if (prevChildS != childE) {
00277       prevStmt = *prevChildS;
00278       if (prevStmt)
00279         prevStmt = prevStmt->IgnoreImplicit();
00280     }
00281 
00282     if (currChildS == childE)
00283       return std::make_pair(prevStmt, nextStmt);
00284     ++currChildS;
00285     if (currChildS == childE)
00286       return std::make_pair(prevStmt, nextStmt);
00287 
00288     nextStmt = *currChildS;
00289     if (nextStmt)
00290       nextStmt = nextStmt->IgnoreImplicit();
00291 
00292     return std::make_pair(prevStmt, nextStmt);
00293   }
00294 
00295   Decl *getReferencedDecl(Expr *E) {
00296     if (!E)
00297       return nullptr;
00298 
00299     E = E->IgnoreParenCasts();
00300     if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
00301       switch (ME->getMethodFamily()) {
00302       case OMF_copy:
00303       case OMF_autorelease:
00304       case OMF_release:
00305       case OMF_retain:
00306         return getReferencedDecl(ME->getInstanceReceiver());
00307       default:
00308         return nullptr;
00309       }
00310     }
00311     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
00312       return DRE->getDecl();
00313     if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
00314       return ME->getMemberDecl();
00315     if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(E))
00316       return IRE->getDecl();
00317 
00318     return nullptr;
00319   }
00320 
00321   /// \brief Check if the retain/release is due to a GCD/XPC macro that are
00322   /// defined as:
00323   ///
00324   /// #define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
00325   /// #define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
00326   /// #define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
00327   /// #define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
00328   ///
00329   /// and return the top container which is the StmtExpr and the macro argument
00330   /// expression.
00331   void checkForGCDOrXPC(ObjCMessageExpr *Msg, Expr *&RecContainer,
00332                         Expr *&Rec, SourceRange &RecRange) {
00333     SourceLocation Loc = Msg->getExprLoc();
00334     if (!Loc.isMacroID())
00335       return;
00336     SourceManager &SM = Pass.Ctx.getSourceManager();
00337     StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM,
00338                                                      Pass.Ctx.getLangOpts());
00339     bool isGCDOrXPC = llvm::StringSwitch<bool>(MacroName)
00340         .Case("dispatch_retain", true)
00341         .Case("dispatch_release", true)
00342         .Case("xpc_retain", true)
00343         .Case("xpc_release", true)
00344         .Default(false);
00345     if (!isGCDOrXPC)
00346       return;
00347 
00348     StmtExpr *StmtE = nullptr;
00349     Stmt *S = Msg;
00350     while (S) {
00351       if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
00352         StmtE = SE;
00353         break;
00354       }
00355       S = StmtMap->getParent(S);
00356     }
00357 
00358     if (!StmtE)
00359       return;
00360 
00361     Stmt::child_range StmtExprChild = StmtE->children();
00362     if (!StmtExprChild)
00363       return;
00364     CompoundStmt *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild);
00365     if (!CompS)
00366       return;
00367 
00368     Stmt::child_range CompStmtChild = CompS->children();
00369     if (!CompStmtChild)
00370       return;
00371     DeclStmt *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild);
00372     if (!DeclS)
00373       return;
00374     if (!DeclS->isSingleDecl())
00375       return;
00376     VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl());
00377     if (!VD)
00378       return;
00379     Expr *Init = VD->getInit();
00380     if (!Init)
00381       return;
00382 
00383     RecContainer = StmtE;
00384     Rec = Init->IgnoreParenImpCasts();
00385     if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Rec))
00386       Rec = EWC->getSubExpr()->IgnoreParenImpCasts();
00387     RecRange = Rec->getSourceRange();
00388     if (SM.isMacroArgExpansion(RecRange.getBegin()))
00389       RecRange.setBegin(SM.getImmediateSpellingLoc(RecRange.getBegin()));
00390     if (SM.isMacroArgExpansion(RecRange.getEnd()))
00391       RecRange.setEnd(SM.getImmediateSpellingLoc(RecRange.getEnd()));
00392   }
00393 
00394   void clearDiagnostics(SourceLocation loc) const {
00395     Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
00396                             diag::err_unavailable,
00397                             diag::err_unavailable_message,
00398                             loc);
00399   }
00400 
00401   bool isDelegateMessage(Expr *E) const {
00402     if (!E) return false;
00403 
00404     E = E->IgnoreParenCasts();
00405 
00406     // Also look through property-getter sugar.
00407     if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E))
00408       E = pseudoOp->getResultExpr()->IgnoreImplicit();
00409 
00410     if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
00411       return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
00412 
00413     return false;
00414   }
00415 
00416   bool isInAtFinally(Expr *E) const {
00417     assert(E);
00418     Stmt *S = E;
00419     while (S) {
00420       if (isa<ObjCAtFinallyStmt>(S))
00421         return true;
00422       S = StmtMap->getParent(S);
00423     }
00424 
00425     return false;
00426   }
00427 
00428   bool isRemovable(Expr *E) const {
00429     return Removables.count(E);
00430   }
00431   
00432   bool tryRemoving(Expr *E) const {
00433     if (isRemovable(E)) {
00434       Pass.TA.removeStmt(E);
00435       return true;
00436     }
00437 
00438     Stmt *parent = StmtMap->getParent(E);
00439 
00440     if (ImplicitCastExpr *castE = dyn_cast_or_null<ImplicitCastExpr>(parent))
00441       return tryRemoving(castE);
00442 
00443     if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
00444       return tryRemoving(parenE);
00445 
00446     if (BinaryOperator *
00447           bopE = dyn_cast_or_null<BinaryOperator>(parent)) {
00448       if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
00449           isRemovable(bopE)) {
00450         Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
00451         return true;
00452       }
00453     }
00454 
00455     return false;
00456   }
00457 
00458 };
00459 
00460 } // anonymous namespace
00461 
00462 void trans::removeRetainReleaseDeallocFinalize(MigrationPass &pass) {
00463   BodyTransform<RetainReleaseDeallocRemover> trans(pass);
00464   trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
00465 }