clang API Documentation
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 }