xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp (revision 7330f729ccf0bd976a06f95fad452fe774fc7fd1)
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