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