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