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