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