xref: /freebsd/contrib/llvm-project/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
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