clang API Documentation

TransRetainReleaseDealloc.cpp
Go to the documentation of this file.
00001 //===--- TransRetainReleaseDealloc.cpp - Tranformations 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/Sema/SemaDiagnostic.h"
00023 #include "clang/AST/ParentMap.h"
00024 #include "clang/Lex/Lexer.h"
00025 #include "clang/Basic/SourceManager.h"
00026 
00027 using namespace clang;
00028 using namespace arcmt;
00029 using namespace trans;
00030 
00031 namespace {
00032 
00033 class RetainReleaseDeallocRemover :
00034                        public RecursiveASTVisitor<RetainReleaseDeallocRemover> {
00035   Stmt *Body;
00036   MigrationPass &Pass;
00037 
00038   ExprSet Removables;
00039   OwningPtr<ParentMap> StmtMap;
00040 
00041   Selector DelegateSel, FinalizeSel;
00042 
00043 public:
00044   RetainReleaseDeallocRemover(MigrationPass &pass)
00045     : Body(0), Pass(pass) {
00046     DelegateSel =
00047         Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("delegate"));
00048     FinalizeSel =
00049         Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize"));
00050   }
00051 
00052   void transformBody(Stmt *body) {
00053     Body = body;
00054     collectRemovables(body, Removables);
00055     StmtMap.reset(new ParentMap(body));
00056     TraverseStmt(body);
00057   }
00058 
00059   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
00060     switch (E->getMethodFamily()) {
00061     default:
00062       if (E->isInstanceMessage() && E->getSelector() == FinalizeSel)
00063         break;
00064       return true;
00065     case OMF_autorelease:
00066       if (isRemovable(E)) {
00067         // An unused autorelease is badness. If we remove it the receiver
00068         // will likely die immediately while previously it was kept alive
00069         // by the autorelease pool. This is bad practice in general, leave it
00070         // and emit an error to force the user to restructure his code.
00071         Pass.TA.reportError("it is not safe to remove an unused 'autorelease' "
00072             "message; its receiver may be destroyed immediately",
00073             E->getLocStart(), E->getSourceRange());
00074         return true;
00075       }
00076       // Pass through.
00077     case OMF_retain:
00078     case OMF_release:
00079       if (E->getReceiverKind() == ObjCMessageExpr::Instance)
00080         if (Expr *rec = E->getInstanceReceiver()) {
00081           rec = rec->IgnoreParenImpCasts();
00082           if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
00083               (E->getMethodFamily() != OMF_retain || isRemovable(E))) {
00084             std::string err = "it is not safe to remove '";
00085             err += E->getSelector().getAsString() + "' message on "
00086                 "an __unsafe_unretained type";
00087             Pass.TA.reportError(err, rec->getLocStart());
00088             return true;
00089           }
00090 
00091           if (isGlobalVar(rec) &&
00092               (E->getMethodFamily() != OMF_retain || isRemovable(E))) {
00093             std::string err = "it is not safe to remove '";
00094             err += E->getSelector().getAsString() + "' message on "
00095                 "a global variable";
00096             Pass.TA.reportError(err, rec->getLocStart());
00097             return true;
00098           }
00099 
00100           if (E->getMethodFamily() == OMF_release && isDelegateMessage(rec)) {
00101             Pass.TA.reportError("it is not safe to remove 'retain' "
00102                 "message on the result of a 'delegate' message; "
00103                 "the object that was passed to 'setDelegate:' may not be "
00104                 "properly retained", rec->getLocStart());
00105             return true;
00106           }
00107         }
00108     case OMF_dealloc:
00109       break;
00110     }
00111 
00112     switch (E->getReceiverKind()) {
00113     default:
00114       return true;
00115     case ObjCMessageExpr::SuperInstance: {
00116       Transaction Trans(Pass.TA);
00117       clearDiagnostics(E->getSuperLoc());
00118       if (tryRemoving(E))
00119         return true;
00120       Pass.TA.replace(E->getSourceRange(), "self");
00121       return true;
00122     }
00123     case ObjCMessageExpr::Instance:
00124       break;
00125     }
00126 
00127     Expr *rec = E->getInstanceReceiver();
00128     if (!rec) return true;
00129 
00130     Transaction Trans(Pass.TA);
00131     clearDiagnostics(rec->getExprLoc());
00132 
00133     ObjCMessageExpr *Msg = E;
00134     Expr *RecContainer = Msg;
00135     SourceRange RecRange = rec->getSourceRange();
00136     checkForGCDOrXPC(Msg, RecContainer, rec, RecRange);
00137 
00138     if (Msg->getMethodFamily() == OMF_release &&
00139         isRemovable(RecContainer) && isInAtFinally(RecContainer)) {
00140       // Change the -release to "receiver = nil" in a finally to avoid a leak
00141       // when an exception is thrown.
00142       Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
00143       std::string str = " = ";
00144       str += getNilString(Pass.Ctx);
00145       Pass.TA.insertAfterToken(RecRange.getEnd(), str);
00146       return true;
00147     }
00148 
00149     if (!hasSideEffects(rec, Pass.Ctx)) {
00150       if (tryRemoving(RecContainer))
00151         return true;
00152     }
00153     Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
00154 
00155     return true;
00156   }
00157 
00158 private:
00159   /// \brief Check if the retain/release is due to a GCD/XPC macro that are
00160   /// defined as:
00161   ///
00162   /// #define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
00163   /// #define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
00164   /// #define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
00165   /// #define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
00166   ///
00167   /// and return the top container which is the StmtExpr and the macro argument
00168   /// expression.
00169   void checkForGCDOrXPC(ObjCMessageExpr *Msg, Expr *&RecContainer,
00170                         Expr *&Rec, SourceRange &RecRange) {
00171     SourceLocation Loc = Msg->getExprLoc();
00172     if (!Loc.isMacroID())
00173       return;
00174     SourceManager &SM = Pass.Ctx.getSourceManager();
00175     StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM,
00176                                                      Pass.Ctx.getLangOpts());
00177     bool isGCDOrXPC = llvm::StringSwitch<bool>(MacroName)
00178         .Case("dispatch_retain", true)
00179         .Case("dispatch_release", true)
00180         .Case("xpc_retain", true)
00181         .Case("xpc_release", true)
00182         .Default(false);
00183     if (!isGCDOrXPC)
00184       return;
00185 
00186     StmtExpr *StmtE = 0;
00187     Stmt *S = Msg;
00188     while (S) {
00189       if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
00190         StmtE = SE;
00191         break;
00192       }
00193       S = StmtMap->getParent(S);
00194     }
00195 
00196     if (!StmtE)
00197       return;
00198 
00199     Stmt::child_range StmtExprChild = StmtE->children();
00200     if (!StmtExprChild)
00201       return;
00202     CompoundStmt *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild);
00203     if (!CompS)
00204       return;
00205 
00206     Stmt::child_range CompStmtChild = CompS->children();
00207     if (!CompStmtChild)
00208       return;
00209     DeclStmt *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild);
00210     if (!DeclS)
00211       return;
00212     if (!DeclS->isSingleDecl())
00213       return;
00214     VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl());
00215     if (!VD)
00216       return;
00217     Expr *Init = VD->getInit();
00218     if (!Init)
00219       return;
00220 
00221     RecContainer = StmtE;
00222     Rec = Init->IgnoreParenImpCasts();
00223     if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Rec))
00224       Rec = EWC->getSubExpr()->IgnoreParenImpCasts();
00225     RecRange = Rec->getSourceRange();
00226     if (SM.isMacroArgExpansion(RecRange.getBegin()))
00227       RecRange.setBegin(SM.getImmediateSpellingLoc(RecRange.getBegin()));
00228     if (SM.isMacroArgExpansion(RecRange.getEnd()))
00229       RecRange.setEnd(SM.getImmediateSpellingLoc(RecRange.getEnd()));
00230   }
00231 
00232   void clearDiagnostics(SourceLocation loc) const {
00233     Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
00234                             diag::err_unavailable,
00235                             diag::err_unavailable_message,
00236                             loc);
00237   }
00238 
00239   bool isDelegateMessage(Expr *E) const {
00240     if (!E) return false;
00241 
00242     E = E->IgnoreParenCasts();
00243 
00244     // Also look through property-getter sugar.
00245     if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E))
00246       E = pseudoOp->getResultExpr()->IgnoreImplicit();
00247 
00248     if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
00249       return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
00250 
00251     return false;
00252   }
00253 
00254   bool isInAtFinally(Expr *E) const {
00255     assert(E);
00256     Stmt *S = E;
00257     while (S) {
00258       if (isa<ObjCAtFinallyStmt>(S))
00259         return true;
00260       S = StmtMap->getParent(S);
00261     }
00262 
00263     return false;
00264   }
00265 
00266   bool isRemovable(Expr *E) const {
00267     return Removables.count(E);
00268   }
00269   
00270   bool tryRemoving(Expr *E) const {
00271     if (isRemovable(E)) {
00272       Pass.TA.removeStmt(E);
00273       return true;
00274     }
00275 
00276     Stmt *parent = StmtMap->getParent(E);
00277 
00278     if (ImplicitCastExpr *castE = dyn_cast_or_null<ImplicitCastExpr>(parent))
00279       return tryRemoving(castE);
00280 
00281     if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
00282       return tryRemoving(parenE);
00283 
00284     if (BinaryOperator *
00285           bopE = dyn_cast_or_null<BinaryOperator>(parent)) {
00286       if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
00287           isRemovable(bopE)) {
00288         Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
00289         return true;
00290       }
00291     }
00292 
00293     return false;
00294   }
00295 
00296 };
00297 
00298 } // anonymous namespace
00299 
00300 void trans::removeRetainReleaseDeallocFinalize(MigrationPass &pass) {
00301   BodyTransform<RetainReleaseDeallocRemover> trans(pass);
00302   trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
00303 }