1 //===--- TransRetainReleaseDealloc.cpp - Transformations to ARC mode ------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // removeRetainReleaseDealloc: 10 // 11 // Removes retain/release/autorelease/dealloc messages. 12 // 13 // return [[foo retain] autorelease]; 14 // ----> 15 // return foo; 16 // 17 //===----------------------------------------------------------------------===// 18 19 #include "Transforms.h" 20 #include "Internals.h" 21 #include "clang/AST/ASTContext.h" 22 #include "clang/AST/ParentMap.h" 23 #include "clang/Basic/SourceManager.h" 24 #include "clang/Lex/Lexer.h" 25 #include "clang/Sema/SemaDiagnostic.h" 26 #include "llvm/ADT/StringSwitch.h" 27 28 using namespace clang; 29 using namespace arcmt; 30 using namespace trans; 31 32 namespace { 33 34 class RetainReleaseDeallocRemover : 35 public RecursiveASTVisitor<RetainReleaseDeallocRemover> { 36 Stmt *Body; 37 MigrationPass &Pass; 38 39 ExprSet Removables; 40 std::unique_ptr<ParentMap> StmtMap; 41 42 Selector DelegateSel, FinalizeSel; 43 44 public: 45 RetainReleaseDeallocRemover(MigrationPass &pass) 46 : Body(nullptr), Pass(pass) { 47 DelegateSel = 48 Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("delegate")); 49 FinalizeSel = 50 Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize")); 51 } 52 53 void transformBody(Stmt *body, Decl *ParentD) { 54 Body = body; 55 collectRemovables(body, Removables); 56 StmtMap.reset(new ParentMap(body)); 57 TraverseStmt(body); 58 } 59 60 bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 61 switch (E->getMethodFamily()) { 62 default: 63 if (E->isInstanceMessage() && E->getSelector() == FinalizeSel) 64 break; 65 return true; 66 case OMF_autorelease: 67 if (isRemovable(E)) { 68 if (!isCommonUnusedAutorelease(E)) { 69 // An unused autorelease is badness. If we remove it the receiver 70 // will likely die immediately while previously it was kept alive 71 // by the autorelease pool. This is bad practice in general, leave it 72 // and emit an error to force the user to restructure their code. 73 Pass.TA.reportError( 74 "it is not safe to remove an unused 'autorelease' " 75 "message; its receiver may be destroyed immediately", 76 E->getBeginLoc(), E->getSourceRange()); 77 return true; 78 } 79 } 80 // Pass through. 81 [[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->getBeginLoc()); 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->getBeginLoc()); 102 return true; 103 } 104 105 if (E->getMethodFamily() == OMF_release && isDelegateMessage(rec)) { 106 Pass.TA.reportError( 107 "it is not safe to remove 'retain' " 108 "message on the result of a 'delegate' message; " 109 "the object that was passed to 'setDelegate:' may not be " 110 "properly retained", 111 rec->getBeginLoc()); 112 return true; 113 } 114 } 115 break; 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<FullExpr>(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 (auto *E = dyn_cast_or_null<Expr>(prevStmt)) 273 prevStmt = E->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 (auto *E = dyn_cast_or_null<Expr>(nextStmt)) 284 nextStmt = E->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 (FullExpr *FE = dyn_cast<FullExpr>(Rec)) 380 Rec = FE->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