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 29using namespace clang; 30using namespace arcmt; 31using namespace trans; 32 33namespace { 34 35class 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 45public: 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->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.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 162private: 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 462void trans::removeRetainReleaseDeallocFinalize(MigrationPass &pass) { 463 BodyTransform<RetainReleaseDeallocRemover> trans(pass); 464 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 465} 466