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