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