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