1*7330f729Sjoerg //===--- TransAutoreleasePool.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 // rewriteAutoreleasePool:
10*7330f729Sjoerg //
11*7330f729Sjoerg // Calls to NSAutoreleasePools will be rewritten as an @autorelease scope.
12*7330f729Sjoerg //
13*7330f729Sjoerg // NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
14*7330f729Sjoerg // ...
15*7330f729Sjoerg // [pool release];
16*7330f729Sjoerg // ---->
17*7330f729Sjoerg // @autorelease {
18*7330f729Sjoerg // ...
19*7330f729Sjoerg // }
20*7330f729Sjoerg //
21*7330f729Sjoerg // An NSAutoreleasePool will not be touched if:
22*7330f729Sjoerg // - There is not a corresponding -release/-drain in the same scope
23*7330f729Sjoerg // - Not all references of the NSAutoreleasePool variable can be removed
24*7330f729Sjoerg // - There is a variable that is declared inside the intended @autorelease scope
25*7330f729Sjoerg // which is also used outside it.
26*7330f729Sjoerg //
27*7330f729Sjoerg //===----------------------------------------------------------------------===//
28*7330f729Sjoerg
29*7330f729Sjoerg #include "Transforms.h"
30*7330f729Sjoerg #include "Internals.h"
31*7330f729Sjoerg #include "clang/AST/ASTContext.h"
32*7330f729Sjoerg #include "clang/Basic/SourceManager.h"
33*7330f729Sjoerg #include "clang/Sema/SemaDiagnostic.h"
34*7330f729Sjoerg #include <map>
35*7330f729Sjoerg
36*7330f729Sjoerg using namespace clang;
37*7330f729Sjoerg using namespace arcmt;
38*7330f729Sjoerg using namespace trans;
39*7330f729Sjoerg
40*7330f729Sjoerg namespace {
41*7330f729Sjoerg
42*7330f729Sjoerg class ReleaseCollector : public RecursiveASTVisitor<ReleaseCollector> {
43*7330f729Sjoerg Decl *Dcl;
44*7330f729Sjoerg SmallVectorImpl<ObjCMessageExpr *> &Releases;
45*7330f729Sjoerg
46*7330f729Sjoerg public:
ReleaseCollector(Decl * D,SmallVectorImpl<ObjCMessageExpr * > & releases)47*7330f729Sjoerg ReleaseCollector(Decl *D, SmallVectorImpl<ObjCMessageExpr *> &releases)
48*7330f729Sjoerg : Dcl(D), Releases(releases) { }
49*7330f729Sjoerg
VisitObjCMessageExpr(ObjCMessageExpr * E)50*7330f729Sjoerg bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
51*7330f729Sjoerg if (!E->isInstanceMessage())
52*7330f729Sjoerg return true;
53*7330f729Sjoerg if (E->getMethodFamily() != OMF_release)
54*7330f729Sjoerg return true;
55*7330f729Sjoerg Expr *instance = E->getInstanceReceiver()->IgnoreParenCasts();
56*7330f729Sjoerg if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(instance)) {
57*7330f729Sjoerg if (DE->getDecl() == Dcl)
58*7330f729Sjoerg Releases.push_back(E);
59*7330f729Sjoerg }
60*7330f729Sjoerg return true;
61*7330f729Sjoerg }
62*7330f729Sjoerg };
63*7330f729Sjoerg
64*7330f729Sjoerg }
65*7330f729Sjoerg
66*7330f729Sjoerg namespace {
67*7330f729Sjoerg
68*7330f729Sjoerg class AutoreleasePoolRewriter
69*7330f729Sjoerg : public RecursiveASTVisitor<AutoreleasePoolRewriter> {
70*7330f729Sjoerg public:
AutoreleasePoolRewriter(MigrationPass & pass)71*7330f729Sjoerg AutoreleasePoolRewriter(MigrationPass &pass)
72*7330f729Sjoerg : Body(nullptr), Pass(pass) {
73*7330f729Sjoerg PoolII = &pass.Ctx.Idents.get("NSAutoreleasePool");
74*7330f729Sjoerg DrainSel = pass.Ctx.Selectors.getNullarySelector(
75*7330f729Sjoerg &pass.Ctx.Idents.get("drain"));
76*7330f729Sjoerg }
77*7330f729Sjoerg
transformBody(Stmt * body,Decl * ParentD)78*7330f729Sjoerg void transformBody(Stmt *body, Decl *ParentD) {
79*7330f729Sjoerg Body = body;
80*7330f729Sjoerg TraverseStmt(body);
81*7330f729Sjoerg }
82*7330f729Sjoerg
~AutoreleasePoolRewriter()83*7330f729Sjoerg ~AutoreleasePoolRewriter() {
84*7330f729Sjoerg SmallVector<VarDecl *, 8> VarsToHandle;
85*7330f729Sjoerg
86*7330f729Sjoerg for (std::map<VarDecl *, PoolVarInfo>::iterator
87*7330f729Sjoerg I = PoolVars.begin(), E = PoolVars.end(); I != E; ++I) {
88*7330f729Sjoerg VarDecl *var = I->first;
89*7330f729Sjoerg PoolVarInfo &info = I->second;
90*7330f729Sjoerg
91*7330f729Sjoerg // Check that we can handle/rewrite all references of the pool.
92*7330f729Sjoerg
93*7330f729Sjoerg clearRefsIn(info.Dcl, info.Refs);
94*7330f729Sjoerg for (SmallVectorImpl<PoolScope>::iterator
95*7330f729Sjoerg scpI = info.Scopes.begin(),
96*7330f729Sjoerg scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
97*7330f729Sjoerg PoolScope &scope = *scpI;
98*7330f729Sjoerg clearRefsIn(*scope.Begin, info.Refs);
99*7330f729Sjoerg clearRefsIn(*scope.End, info.Refs);
100*7330f729Sjoerg clearRefsIn(scope.Releases.begin(), scope.Releases.end(), info.Refs);
101*7330f729Sjoerg }
102*7330f729Sjoerg
103*7330f729Sjoerg // Even if one reference is not handled we will not do anything about that
104*7330f729Sjoerg // pool variable.
105*7330f729Sjoerg if (info.Refs.empty())
106*7330f729Sjoerg VarsToHandle.push_back(var);
107*7330f729Sjoerg }
108*7330f729Sjoerg
109*7330f729Sjoerg for (unsigned i = 0, e = VarsToHandle.size(); i != e; ++i) {
110*7330f729Sjoerg PoolVarInfo &info = PoolVars[VarsToHandle[i]];
111*7330f729Sjoerg
112*7330f729Sjoerg Transaction Trans(Pass.TA);
113*7330f729Sjoerg
114*7330f729Sjoerg clearUnavailableDiags(info.Dcl);
115*7330f729Sjoerg Pass.TA.removeStmt(info.Dcl);
116*7330f729Sjoerg
117*7330f729Sjoerg // Add "@autoreleasepool { }"
118*7330f729Sjoerg for (SmallVectorImpl<PoolScope>::iterator
119*7330f729Sjoerg scpI = info.Scopes.begin(),
120*7330f729Sjoerg scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
121*7330f729Sjoerg PoolScope &scope = *scpI;
122*7330f729Sjoerg clearUnavailableDiags(*scope.Begin);
123*7330f729Sjoerg clearUnavailableDiags(*scope.End);
124*7330f729Sjoerg if (scope.IsFollowedBySimpleReturnStmt) {
125*7330f729Sjoerg // Include the return in the scope.
126*7330f729Sjoerg Pass.TA.replaceStmt(*scope.Begin, "@autoreleasepool {");
127*7330f729Sjoerg Pass.TA.removeStmt(*scope.End);
128*7330f729Sjoerg Stmt::child_iterator retI = scope.End;
129*7330f729Sjoerg ++retI;
130*7330f729Sjoerg SourceLocation afterSemi =
131*7330f729Sjoerg findLocationAfterSemi((*retI)->getEndLoc(), Pass.Ctx);
132*7330f729Sjoerg assert(afterSemi.isValid() &&
133*7330f729Sjoerg "Didn't we check before setting IsFollowedBySimpleReturnStmt "
134*7330f729Sjoerg "to true?");
135*7330f729Sjoerg Pass.TA.insertAfterToken(afterSemi, "\n}");
136*7330f729Sjoerg Pass.TA.increaseIndentation(
137*7330f729Sjoerg SourceRange(scope.getIndentedRange().getBegin(),
138*7330f729Sjoerg (*retI)->getEndLoc()),
139*7330f729Sjoerg scope.CompoundParent->getBeginLoc());
140*7330f729Sjoerg } else {
141*7330f729Sjoerg Pass.TA.replaceStmt(*scope.Begin, "@autoreleasepool {");
142*7330f729Sjoerg Pass.TA.replaceStmt(*scope.End, "}");
143*7330f729Sjoerg Pass.TA.increaseIndentation(scope.getIndentedRange(),
144*7330f729Sjoerg scope.CompoundParent->getBeginLoc());
145*7330f729Sjoerg }
146*7330f729Sjoerg }
147*7330f729Sjoerg
148*7330f729Sjoerg // Remove rest of pool var references.
149*7330f729Sjoerg for (SmallVectorImpl<PoolScope>::iterator
150*7330f729Sjoerg scpI = info.Scopes.begin(),
151*7330f729Sjoerg scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
152*7330f729Sjoerg PoolScope &scope = *scpI;
153*7330f729Sjoerg for (SmallVectorImpl<ObjCMessageExpr *>::iterator
154*7330f729Sjoerg relI = scope.Releases.begin(),
155*7330f729Sjoerg relE = scope.Releases.end(); relI != relE; ++relI) {
156*7330f729Sjoerg clearUnavailableDiags(*relI);
157*7330f729Sjoerg Pass.TA.removeStmt(*relI);
158*7330f729Sjoerg }
159*7330f729Sjoerg }
160*7330f729Sjoerg }
161*7330f729Sjoerg }
162*7330f729Sjoerg
VisitCompoundStmt(CompoundStmt * S)163*7330f729Sjoerg bool VisitCompoundStmt(CompoundStmt *S) {
164*7330f729Sjoerg SmallVector<PoolScope, 4> Scopes;
165*7330f729Sjoerg
166*7330f729Sjoerg for (Stmt::child_iterator
167*7330f729Sjoerg I = S->body_begin(), E = S->body_end(); I != E; ++I) {
168*7330f729Sjoerg Stmt *child = getEssential(*I);
169*7330f729Sjoerg if (DeclStmt *DclS = dyn_cast<DeclStmt>(child)) {
170*7330f729Sjoerg if (DclS->isSingleDecl()) {
171*7330f729Sjoerg if (VarDecl *VD = dyn_cast<VarDecl>(DclS->getSingleDecl())) {
172*7330f729Sjoerg if (isNSAutoreleasePool(VD->getType())) {
173*7330f729Sjoerg PoolVarInfo &info = PoolVars[VD];
174*7330f729Sjoerg info.Dcl = DclS;
175*7330f729Sjoerg collectRefs(VD, S, info.Refs);
176*7330f729Sjoerg // Does this statement follow the pattern:
177*7330f729Sjoerg // NSAutoreleasePool * pool = [NSAutoreleasePool new];
178*7330f729Sjoerg if (isPoolCreation(VD->getInit())) {
179*7330f729Sjoerg Scopes.push_back(PoolScope());
180*7330f729Sjoerg Scopes.back().PoolVar = VD;
181*7330f729Sjoerg Scopes.back().CompoundParent = S;
182*7330f729Sjoerg Scopes.back().Begin = I;
183*7330f729Sjoerg }
184*7330f729Sjoerg }
185*7330f729Sjoerg }
186*7330f729Sjoerg }
187*7330f729Sjoerg } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(child)) {
188*7330f729Sjoerg if (DeclRefExpr *dref = dyn_cast<DeclRefExpr>(bop->getLHS())) {
189*7330f729Sjoerg if (VarDecl *VD = dyn_cast<VarDecl>(dref->getDecl())) {
190*7330f729Sjoerg // Does this statement follow the pattern:
191*7330f729Sjoerg // pool = [NSAutoreleasePool new];
192*7330f729Sjoerg if (isNSAutoreleasePool(VD->getType()) &&
193*7330f729Sjoerg isPoolCreation(bop->getRHS())) {
194*7330f729Sjoerg Scopes.push_back(PoolScope());
195*7330f729Sjoerg Scopes.back().PoolVar = VD;
196*7330f729Sjoerg Scopes.back().CompoundParent = S;
197*7330f729Sjoerg Scopes.back().Begin = I;
198*7330f729Sjoerg }
199*7330f729Sjoerg }
200*7330f729Sjoerg }
201*7330f729Sjoerg }
202*7330f729Sjoerg
203*7330f729Sjoerg if (Scopes.empty())
204*7330f729Sjoerg continue;
205*7330f729Sjoerg
206*7330f729Sjoerg if (isPoolDrain(Scopes.back().PoolVar, child)) {
207*7330f729Sjoerg PoolScope &scope = Scopes.back();
208*7330f729Sjoerg scope.End = I;
209*7330f729Sjoerg handlePoolScope(scope, S);
210*7330f729Sjoerg Scopes.pop_back();
211*7330f729Sjoerg }
212*7330f729Sjoerg }
213*7330f729Sjoerg return true;
214*7330f729Sjoerg }
215*7330f729Sjoerg
216*7330f729Sjoerg private:
clearUnavailableDiags(Stmt * S)217*7330f729Sjoerg void clearUnavailableDiags(Stmt *S) {
218*7330f729Sjoerg if (S)
219*7330f729Sjoerg Pass.TA.clearDiagnostic(diag::err_unavailable,
220*7330f729Sjoerg diag::err_unavailable_message,
221*7330f729Sjoerg S->getSourceRange());
222*7330f729Sjoerg }
223*7330f729Sjoerg
224*7330f729Sjoerg struct PoolScope {
225*7330f729Sjoerg VarDecl *PoolVar;
226*7330f729Sjoerg CompoundStmt *CompoundParent;
227*7330f729Sjoerg Stmt::child_iterator Begin;
228*7330f729Sjoerg Stmt::child_iterator End;
229*7330f729Sjoerg bool IsFollowedBySimpleReturnStmt;
230*7330f729Sjoerg SmallVector<ObjCMessageExpr *, 4> Releases;
231*7330f729Sjoerg
PoolScope__anon70d3f9af0211::AutoreleasePoolRewriter::PoolScope232*7330f729Sjoerg PoolScope() : PoolVar(nullptr), CompoundParent(nullptr), Begin(), End(),
233*7330f729Sjoerg IsFollowedBySimpleReturnStmt(false) { }
234*7330f729Sjoerg
getIndentedRange__anon70d3f9af0211::AutoreleasePoolRewriter::PoolScope235*7330f729Sjoerg SourceRange getIndentedRange() const {
236*7330f729Sjoerg Stmt::child_iterator rangeS = Begin;
237*7330f729Sjoerg ++rangeS;
238*7330f729Sjoerg if (rangeS == End)
239*7330f729Sjoerg return SourceRange();
240*7330f729Sjoerg Stmt::child_iterator rangeE = Begin;
241*7330f729Sjoerg for (Stmt::child_iterator I = rangeS; I != End; ++I)
242*7330f729Sjoerg ++rangeE;
243*7330f729Sjoerg return SourceRange((*rangeS)->getBeginLoc(), (*rangeE)->getEndLoc());
244*7330f729Sjoerg }
245*7330f729Sjoerg };
246*7330f729Sjoerg
247*7330f729Sjoerg class NameReferenceChecker : public RecursiveASTVisitor<NameReferenceChecker>{
248*7330f729Sjoerg ASTContext &Ctx;
249*7330f729Sjoerg SourceRange ScopeRange;
250*7330f729Sjoerg SourceLocation &referenceLoc, &declarationLoc;
251*7330f729Sjoerg
252*7330f729Sjoerg public:
NameReferenceChecker(ASTContext & ctx,PoolScope & scope,SourceLocation & referenceLoc,SourceLocation & declarationLoc)253*7330f729Sjoerg NameReferenceChecker(ASTContext &ctx, PoolScope &scope,
254*7330f729Sjoerg SourceLocation &referenceLoc,
255*7330f729Sjoerg SourceLocation &declarationLoc)
256*7330f729Sjoerg : Ctx(ctx), referenceLoc(referenceLoc),
257*7330f729Sjoerg declarationLoc(declarationLoc) {
258*7330f729Sjoerg ScopeRange = SourceRange((*scope.Begin)->getBeginLoc(),
259*7330f729Sjoerg (*scope.End)->getBeginLoc());
260*7330f729Sjoerg }
261*7330f729Sjoerg
VisitDeclRefExpr(DeclRefExpr * E)262*7330f729Sjoerg bool VisitDeclRefExpr(DeclRefExpr *E) {
263*7330f729Sjoerg return checkRef(E->getLocation(), E->getDecl()->getLocation());
264*7330f729Sjoerg }
265*7330f729Sjoerg
VisitTypedefTypeLoc(TypedefTypeLoc TL)266*7330f729Sjoerg bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
267*7330f729Sjoerg return checkRef(TL.getBeginLoc(), TL.getTypedefNameDecl()->getLocation());
268*7330f729Sjoerg }
269*7330f729Sjoerg
VisitTagTypeLoc(TagTypeLoc TL)270*7330f729Sjoerg bool VisitTagTypeLoc(TagTypeLoc TL) {
271*7330f729Sjoerg return checkRef(TL.getBeginLoc(), TL.getDecl()->getLocation());
272*7330f729Sjoerg }
273*7330f729Sjoerg
274*7330f729Sjoerg private:
checkRef(SourceLocation refLoc,SourceLocation declLoc)275*7330f729Sjoerg bool checkRef(SourceLocation refLoc, SourceLocation declLoc) {
276*7330f729Sjoerg if (isInScope(declLoc)) {
277*7330f729Sjoerg referenceLoc = refLoc;
278*7330f729Sjoerg declarationLoc = declLoc;
279*7330f729Sjoerg return false;
280*7330f729Sjoerg }
281*7330f729Sjoerg return true;
282*7330f729Sjoerg }
283*7330f729Sjoerg
isInScope(SourceLocation loc)284*7330f729Sjoerg bool isInScope(SourceLocation loc) {
285*7330f729Sjoerg if (loc.isInvalid())
286*7330f729Sjoerg return false;
287*7330f729Sjoerg
288*7330f729Sjoerg SourceManager &SM = Ctx.getSourceManager();
289*7330f729Sjoerg if (SM.isBeforeInTranslationUnit(loc, ScopeRange.getBegin()))
290*7330f729Sjoerg return false;
291*7330f729Sjoerg return SM.isBeforeInTranslationUnit(loc, ScopeRange.getEnd());
292*7330f729Sjoerg }
293*7330f729Sjoerg };
294*7330f729Sjoerg
handlePoolScope(PoolScope & scope,CompoundStmt * compoundS)295*7330f729Sjoerg void handlePoolScope(PoolScope &scope, CompoundStmt *compoundS) {
296*7330f729Sjoerg // Check that all names declared inside the scope are not used
297*7330f729Sjoerg // outside the scope.
298*7330f729Sjoerg {
299*7330f729Sjoerg bool nameUsedOutsideScope = false;
300*7330f729Sjoerg SourceLocation referenceLoc, declarationLoc;
301*7330f729Sjoerg Stmt::child_iterator SI = scope.End, SE = compoundS->body_end();
302*7330f729Sjoerg ++SI;
303*7330f729Sjoerg // Check if the autoreleasepool scope is followed by a simple return
304*7330f729Sjoerg // statement, in which case we will include the return in the scope.
305*7330f729Sjoerg if (SI != SE)
306*7330f729Sjoerg if (ReturnStmt *retS = dyn_cast<ReturnStmt>(*SI))
307*7330f729Sjoerg if ((retS->getRetValue() == nullptr ||
308*7330f729Sjoerg isa<DeclRefExpr>(retS->getRetValue()->IgnoreParenCasts())) &&
309*7330f729Sjoerg findLocationAfterSemi(retS->getEndLoc(), Pass.Ctx).isValid()) {
310*7330f729Sjoerg scope.IsFollowedBySimpleReturnStmt = true;
311*7330f729Sjoerg ++SI; // the return will be included in scope, don't check it.
312*7330f729Sjoerg }
313*7330f729Sjoerg
314*7330f729Sjoerg for (; SI != SE; ++SI) {
315*7330f729Sjoerg nameUsedOutsideScope = !NameReferenceChecker(Pass.Ctx, scope,
316*7330f729Sjoerg referenceLoc,
317*7330f729Sjoerg declarationLoc).TraverseStmt(*SI);
318*7330f729Sjoerg if (nameUsedOutsideScope)
319*7330f729Sjoerg break;
320*7330f729Sjoerg }
321*7330f729Sjoerg
322*7330f729Sjoerg // If not all references were cleared it means some variables/typenames/etc
323*7330f729Sjoerg // declared inside the pool scope are used outside of it.
324*7330f729Sjoerg // We won't try to rewrite the pool.
325*7330f729Sjoerg if (nameUsedOutsideScope) {
326*7330f729Sjoerg Pass.TA.reportError("a name is referenced outside the "
327*7330f729Sjoerg "NSAutoreleasePool scope that it was declared in", referenceLoc);
328*7330f729Sjoerg Pass.TA.reportNote("name declared here", declarationLoc);
329*7330f729Sjoerg Pass.TA.reportNote("intended @autoreleasepool scope begins here",
330*7330f729Sjoerg (*scope.Begin)->getBeginLoc());
331*7330f729Sjoerg Pass.TA.reportNote("intended @autoreleasepool scope ends here",
332*7330f729Sjoerg (*scope.End)->getBeginLoc());
333*7330f729Sjoerg return;
334*7330f729Sjoerg }
335*7330f729Sjoerg }
336*7330f729Sjoerg
337*7330f729Sjoerg // Collect all releases of the pool; they will be removed.
338*7330f729Sjoerg {
339*7330f729Sjoerg ReleaseCollector releaseColl(scope.PoolVar, scope.Releases);
340*7330f729Sjoerg Stmt::child_iterator I = scope.Begin;
341*7330f729Sjoerg ++I;
342*7330f729Sjoerg for (; I != scope.End; ++I)
343*7330f729Sjoerg releaseColl.TraverseStmt(*I);
344*7330f729Sjoerg }
345*7330f729Sjoerg
346*7330f729Sjoerg PoolVars[scope.PoolVar].Scopes.push_back(scope);
347*7330f729Sjoerg }
348*7330f729Sjoerg
isPoolCreation(Expr * E)349*7330f729Sjoerg bool isPoolCreation(Expr *E) {
350*7330f729Sjoerg if (!E) return false;
351*7330f729Sjoerg E = getEssential(E);
352*7330f729Sjoerg ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
353*7330f729Sjoerg if (!ME) return false;
354*7330f729Sjoerg if (ME->getMethodFamily() == OMF_new &&
355*7330f729Sjoerg ME->getReceiverKind() == ObjCMessageExpr::Class &&
356*7330f729Sjoerg isNSAutoreleasePool(ME->getReceiverInterface()))
357*7330f729Sjoerg return true;
358*7330f729Sjoerg if (ME->getReceiverKind() == ObjCMessageExpr::Instance &&
359*7330f729Sjoerg ME->getMethodFamily() == OMF_init) {
360*7330f729Sjoerg Expr *rec = getEssential(ME->getInstanceReceiver());
361*7330f729Sjoerg if (ObjCMessageExpr *recME = dyn_cast_or_null<ObjCMessageExpr>(rec)) {
362*7330f729Sjoerg if (recME->getMethodFamily() == OMF_alloc &&
363*7330f729Sjoerg recME->getReceiverKind() == ObjCMessageExpr::Class &&
364*7330f729Sjoerg isNSAutoreleasePool(recME->getReceiverInterface()))
365*7330f729Sjoerg return true;
366*7330f729Sjoerg }
367*7330f729Sjoerg }
368*7330f729Sjoerg
369*7330f729Sjoerg return false;
370*7330f729Sjoerg }
371*7330f729Sjoerg
isPoolDrain(VarDecl * poolVar,Stmt * S)372*7330f729Sjoerg bool isPoolDrain(VarDecl *poolVar, Stmt *S) {
373*7330f729Sjoerg if (!S) return false;
374*7330f729Sjoerg S = getEssential(S);
375*7330f729Sjoerg ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S);
376*7330f729Sjoerg if (!ME) return false;
377*7330f729Sjoerg if (ME->getReceiverKind() == ObjCMessageExpr::Instance) {
378*7330f729Sjoerg Expr *rec = getEssential(ME->getInstanceReceiver());
379*7330f729Sjoerg if (DeclRefExpr *dref = dyn_cast<DeclRefExpr>(rec))
380*7330f729Sjoerg if (dref->getDecl() == poolVar)
381*7330f729Sjoerg return ME->getMethodFamily() == OMF_release ||
382*7330f729Sjoerg ME->getSelector() == DrainSel;
383*7330f729Sjoerg }
384*7330f729Sjoerg
385*7330f729Sjoerg return false;
386*7330f729Sjoerg }
387*7330f729Sjoerg
isNSAutoreleasePool(ObjCInterfaceDecl * IDecl)388*7330f729Sjoerg bool isNSAutoreleasePool(ObjCInterfaceDecl *IDecl) {
389*7330f729Sjoerg return IDecl && IDecl->getIdentifier() == PoolII;
390*7330f729Sjoerg }
391*7330f729Sjoerg
isNSAutoreleasePool(QualType Ty)392*7330f729Sjoerg bool isNSAutoreleasePool(QualType Ty) {
393*7330f729Sjoerg QualType pointee = Ty->getPointeeType();
394*7330f729Sjoerg if (pointee.isNull())
395*7330f729Sjoerg return false;
396*7330f729Sjoerg if (const ObjCInterfaceType *interT = pointee->getAs<ObjCInterfaceType>())
397*7330f729Sjoerg return isNSAutoreleasePool(interT->getDecl());
398*7330f729Sjoerg return false;
399*7330f729Sjoerg }
400*7330f729Sjoerg
getEssential(Expr * E)401*7330f729Sjoerg static Expr *getEssential(Expr *E) {
402*7330f729Sjoerg return cast<Expr>(getEssential((Stmt*)E));
403*7330f729Sjoerg }
getEssential(Stmt * S)404*7330f729Sjoerg static Stmt *getEssential(Stmt *S) {
405*7330f729Sjoerg if (FullExpr *FE = dyn_cast<FullExpr>(S))
406*7330f729Sjoerg S = FE->getSubExpr();
407*7330f729Sjoerg if (Expr *E = dyn_cast<Expr>(S))
408*7330f729Sjoerg S = E->IgnoreParenCasts();
409*7330f729Sjoerg return S;
410*7330f729Sjoerg }
411*7330f729Sjoerg
412*7330f729Sjoerg Stmt *Body;
413*7330f729Sjoerg MigrationPass &Pass;
414*7330f729Sjoerg
415*7330f729Sjoerg IdentifierInfo *PoolII;
416*7330f729Sjoerg Selector DrainSel;
417*7330f729Sjoerg
418*7330f729Sjoerg struct PoolVarInfo {
419*7330f729Sjoerg DeclStmt *Dcl;
420*7330f729Sjoerg ExprSet Refs;
421*7330f729Sjoerg SmallVector<PoolScope, 2> Scopes;
422*7330f729Sjoerg
PoolVarInfo__anon70d3f9af0211::AutoreleasePoolRewriter::PoolVarInfo423*7330f729Sjoerg PoolVarInfo() : Dcl(nullptr) { }
424*7330f729Sjoerg };
425*7330f729Sjoerg
426*7330f729Sjoerg std::map<VarDecl *, PoolVarInfo> PoolVars;
427*7330f729Sjoerg };
428*7330f729Sjoerg
429*7330f729Sjoerg } // anonymous namespace
430*7330f729Sjoerg
rewriteAutoreleasePool(MigrationPass & pass)431*7330f729Sjoerg void trans::rewriteAutoreleasePool(MigrationPass &pass) {
432*7330f729Sjoerg BodyTransform<AutoreleasePoolRewriter> trans(pass);
433*7330f729Sjoerg trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
434*7330f729Sjoerg }
435