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