clang API Documentation

TransAutoreleasePool.cpp
Go to the documentation of this file.
00001 //===--- TransAutoreleasePool.cpp - Transformations to ARC mode -----------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // rewriteAutoreleasePool:
00011 //
00012 // Calls to NSAutoreleasePools will be rewritten as an @autorelease scope.
00013 //
00014 //  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00015 //  ...
00016 //  [pool release];
00017 // ---->
00018 //  @autorelease {
00019 //  ...
00020 //  }
00021 //
00022 // An NSAutoreleasePool will not be touched if:
00023 // - There is not a corresponding -release/-drain in the same scope
00024 // - Not all references of the NSAutoreleasePool variable can be removed
00025 // - There is a variable that is declared inside the intended @autorelease scope
00026 //   which is also used outside it.
00027 //
00028 //===----------------------------------------------------------------------===//
00029 
00030 #include "Transforms.h"
00031 #include "Internals.h"
00032 #include "clang/AST/ASTContext.h"
00033 #include "clang/Basic/SourceManager.h"
00034 #include "clang/Sema/SemaDiagnostic.h"
00035 #include <map>
00036 
00037 using namespace clang;
00038 using namespace arcmt;
00039 using namespace trans;
00040 
00041 namespace {
00042 
00043 class ReleaseCollector : public RecursiveASTVisitor<ReleaseCollector> {
00044   Decl *Dcl;
00045   SmallVectorImpl<ObjCMessageExpr *> &Releases;
00046 
00047 public:
00048   ReleaseCollector(Decl *D, SmallVectorImpl<ObjCMessageExpr *> &releases)
00049     : Dcl(D), Releases(releases) { }
00050 
00051   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
00052     if (!E->isInstanceMessage())
00053       return true;
00054     if (E->getMethodFamily() != OMF_release)
00055       return true;
00056     Expr *instance = E->getInstanceReceiver()->IgnoreParenCasts();
00057     if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(instance)) {
00058       if (DE->getDecl() == Dcl)
00059         Releases.push_back(E);
00060     }
00061     return true;
00062   }
00063 };
00064 
00065 }
00066 
00067 namespace {
00068 
00069 class AutoreleasePoolRewriter
00070                          : public RecursiveASTVisitor<AutoreleasePoolRewriter> {
00071 public:
00072   AutoreleasePoolRewriter(MigrationPass &pass)
00073     : Body(nullptr), Pass(pass) {
00074     PoolII = &pass.Ctx.Idents.get("NSAutoreleasePool");
00075     DrainSel = pass.Ctx.Selectors.getNullarySelector(
00076                                                  &pass.Ctx.Idents.get("drain"));
00077   }
00078 
00079   void transformBody(Stmt *body, Decl *ParentD) {
00080     Body = body;
00081     TraverseStmt(body);
00082   }
00083   
00084   ~AutoreleasePoolRewriter() {
00085     SmallVector<VarDecl *, 8> VarsToHandle;
00086 
00087     for (std::map<VarDecl *, PoolVarInfo>::iterator
00088            I = PoolVars.begin(), E = PoolVars.end(); I != E; ++I) {
00089       VarDecl *var = I->first;
00090       PoolVarInfo &info = I->second;
00091 
00092       // Check that we can handle/rewrite all references of the pool.
00093 
00094       clearRefsIn(info.Dcl, info.Refs);
00095       for (SmallVectorImpl<PoolScope>::iterator
00096              scpI = info.Scopes.begin(),
00097              scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
00098         PoolScope &scope = *scpI;
00099         clearRefsIn(*scope.Begin, info.Refs);
00100         clearRefsIn(*scope.End, info.Refs);
00101         clearRefsIn(scope.Releases.begin(), scope.Releases.end(), info.Refs);
00102       }
00103 
00104       // Even if one reference is not handled we will not do anything about that
00105       // pool variable.
00106       if (info.Refs.empty())
00107         VarsToHandle.push_back(var);
00108     }
00109 
00110     for (unsigned i = 0, e = VarsToHandle.size(); i != e; ++i) {
00111       PoolVarInfo &info = PoolVars[VarsToHandle[i]];
00112 
00113       Transaction Trans(Pass.TA);
00114 
00115       clearUnavailableDiags(info.Dcl);
00116       Pass.TA.removeStmt(info.Dcl);
00117 
00118       // Add "@autoreleasepool { }"
00119       for (SmallVectorImpl<PoolScope>::iterator
00120              scpI = info.Scopes.begin(),
00121              scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
00122         PoolScope &scope = *scpI;
00123         clearUnavailableDiags(*scope.Begin);
00124         clearUnavailableDiags(*scope.End);
00125         if (scope.IsFollowedBySimpleReturnStmt) {
00126           // Include the return in the scope.
00127           Pass.TA.replaceStmt(*scope.Begin, "@autoreleasepool {");
00128           Pass.TA.removeStmt(*scope.End);
00129           Stmt::child_iterator retI = scope.End;
00130           ++retI;
00131           SourceLocation afterSemi = findLocationAfterSemi((*retI)->getLocEnd(),
00132                                                            Pass.Ctx);
00133           assert(afterSemi.isValid() &&
00134                  "Didn't we check before setting IsFollowedBySimpleReturnStmt "
00135                  "to true?");
00136           Pass.TA.insertAfterToken(afterSemi, "\n}");
00137           Pass.TA.increaseIndentation(
00138                                 SourceRange(scope.getIndentedRange().getBegin(),
00139                                             (*retI)->getLocEnd()),
00140                                       scope.CompoundParent->getLocStart());
00141         } else {
00142           Pass.TA.replaceStmt(*scope.Begin, "@autoreleasepool {");
00143           Pass.TA.replaceStmt(*scope.End, "}");
00144           Pass.TA.increaseIndentation(scope.getIndentedRange(),
00145                                       scope.CompoundParent->getLocStart());
00146         }
00147       }
00148 
00149       // Remove rest of pool var references.
00150       for (SmallVectorImpl<PoolScope>::iterator
00151              scpI = info.Scopes.begin(),
00152              scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
00153         PoolScope &scope = *scpI;
00154         for (SmallVectorImpl<ObjCMessageExpr *>::iterator
00155                relI = scope.Releases.begin(),
00156                relE = scope.Releases.end(); relI != relE; ++relI) {
00157           clearUnavailableDiags(*relI);
00158           Pass.TA.removeStmt(*relI);
00159         }
00160       }
00161     }
00162   }
00163 
00164   bool VisitCompoundStmt(CompoundStmt *S) {
00165     SmallVector<PoolScope, 4> Scopes;
00166 
00167     for (Stmt::child_iterator
00168            I = S->body_begin(), E = S->body_end(); I != E; ++I) {
00169       Stmt *child = getEssential(*I);
00170       if (DeclStmt *DclS = dyn_cast<DeclStmt>(child)) {
00171         if (DclS->isSingleDecl()) {
00172           if (VarDecl *VD = dyn_cast<VarDecl>(DclS->getSingleDecl())) {
00173             if (isNSAutoreleasePool(VD->getType())) {
00174               PoolVarInfo &info = PoolVars[VD];
00175               info.Dcl = DclS;
00176               collectRefs(VD, S, info.Refs);
00177               // Does this statement follow the pattern:  
00178               // NSAutoreleasePool * pool = [NSAutoreleasePool  new];
00179               if (isPoolCreation(VD->getInit())) {
00180                 Scopes.push_back(PoolScope());
00181                 Scopes.back().PoolVar = VD;
00182                 Scopes.back().CompoundParent = S;
00183                 Scopes.back().Begin = I;
00184               }
00185             }
00186           }
00187         }
00188       } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(child)) {
00189         if (DeclRefExpr *dref = dyn_cast<DeclRefExpr>(bop->getLHS())) {
00190           if (VarDecl *VD = dyn_cast<VarDecl>(dref->getDecl())) {
00191             // Does this statement follow the pattern:  
00192             // pool = [NSAutoreleasePool  new];
00193             if (isNSAutoreleasePool(VD->getType()) &&
00194                 isPoolCreation(bop->getRHS())) {
00195               Scopes.push_back(PoolScope());
00196               Scopes.back().PoolVar = VD;
00197               Scopes.back().CompoundParent = S;
00198               Scopes.back().Begin = I;
00199             }
00200           }
00201         }
00202       }
00203 
00204       if (Scopes.empty())
00205         continue;
00206 
00207       if (isPoolDrain(Scopes.back().PoolVar, child)) {
00208         PoolScope &scope = Scopes.back();
00209         scope.End = I;
00210         handlePoolScope(scope, S);
00211         Scopes.pop_back();
00212       }
00213     }
00214     return true;
00215   }
00216 
00217 private:
00218   void clearUnavailableDiags(Stmt *S) {
00219     if (S)
00220       Pass.TA.clearDiagnostic(diag::err_unavailable,
00221                               diag::err_unavailable_message,
00222                               S->getSourceRange());
00223   }
00224 
00225   struct PoolScope {
00226     VarDecl *PoolVar;
00227     CompoundStmt *CompoundParent;
00228     Stmt::child_iterator Begin;
00229     Stmt::child_iterator End;
00230     bool IsFollowedBySimpleReturnStmt;
00231     SmallVector<ObjCMessageExpr *, 4> Releases;
00232 
00233     PoolScope() : PoolVar(nullptr), CompoundParent(nullptr), Begin(), End(),
00234                   IsFollowedBySimpleReturnStmt(false) { }
00235 
00236     SourceRange getIndentedRange() const {
00237       Stmt::child_iterator rangeS = Begin;
00238       ++rangeS;
00239       if (rangeS == End)
00240         return SourceRange();
00241       Stmt::child_iterator rangeE = Begin;
00242       for (Stmt::child_iterator I = rangeS; I != End; ++I)
00243         ++rangeE;
00244       return SourceRange((*rangeS)->getLocStart(), (*rangeE)->getLocEnd());
00245     }
00246   };
00247 
00248   class NameReferenceChecker : public RecursiveASTVisitor<NameReferenceChecker>{
00249     ASTContext &Ctx;
00250     SourceRange ScopeRange;
00251     SourceLocation &referenceLoc, &declarationLoc;
00252 
00253   public:
00254     NameReferenceChecker(ASTContext &ctx, PoolScope &scope,
00255                          SourceLocation &referenceLoc,
00256                          SourceLocation &declarationLoc)
00257       : Ctx(ctx), referenceLoc(referenceLoc),
00258         declarationLoc(declarationLoc) {
00259       ScopeRange = SourceRange((*scope.Begin)->getLocStart(),
00260                                (*scope.End)->getLocStart());
00261     }
00262 
00263     bool VisitDeclRefExpr(DeclRefExpr *E) {
00264       return checkRef(E->getLocation(), E->getDecl()->getLocation());
00265     }
00266 
00267     bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
00268       return checkRef(TL.getBeginLoc(), TL.getTypedefNameDecl()->getLocation());
00269     }
00270 
00271     bool VisitTagTypeLoc(TagTypeLoc TL) {
00272       return checkRef(TL.getBeginLoc(), TL.getDecl()->getLocation());
00273     }
00274 
00275   private:
00276     bool checkRef(SourceLocation refLoc, SourceLocation declLoc) {
00277       if (isInScope(declLoc)) {
00278         referenceLoc = refLoc;
00279         declarationLoc = declLoc;
00280         return false;
00281       }
00282       return true;
00283     }
00284 
00285     bool isInScope(SourceLocation loc) {
00286       if (loc.isInvalid())
00287         return false;
00288 
00289       SourceManager &SM = Ctx.getSourceManager();
00290       if (SM.isBeforeInTranslationUnit(loc, ScopeRange.getBegin()))
00291         return false;
00292       return SM.isBeforeInTranslationUnit(loc, ScopeRange.getEnd());
00293     }
00294   };
00295 
00296   void handlePoolScope(PoolScope &scope, CompoundStmt *compoundS) {
00297     // Check that all names declared inside the scope are not used
00298     // outside the scope.
00299     {
00300       bool nameUsedOutsideScope = false;
00301       SourceLocation referenceLoc, declarationLoc;
00302       Stmt::child_iterator SI = scope.End, SE = compoundS->body_end();
00303       ++SI;
00304       // Check if the autoreleasepool scope is followed by a simple return
00305       // statement, in which case we will include the return in the scope.
00306       if (SI != SE)
00307         if (ReturnStmt *retS = dyn_cast<ReturnStmt>(*SI))
00308           if ((retS->getRetValue() == nullptr ||
00309                isa<DeclRefExpr>(retS->getRetValue()->IgnoreParenCasts())) &&
00310               findLocationAfterSemi(retS->getLocEnd(), Pass.Ctx).isValid()) {
00311             scope.IsFollowedBySimpleReturnStmt = true;
00312             ++SI; // the return will be included in scope, don't check it.
00313           }
00314       
00315       for (; SI != SE; ++SI) {
00316         nameUsedOutsideScope = !NameReferenceChecker(Pass.Ctx, scope,
00317                                                      referenceLoc,
00318                                               declarationLoc).TraverseStmt(*SI);
00319         if (nameUsedOutsideScope)
00320           break;
00321       }
00322 
00323       // If not all references were cleared it means some variables/typenames/etc
00324       // declared inside the pool scope are used outside of it.
00325       // We won't try to rewrite the pool.
00326       if (nameUsedOutsideScope) {
00327         Pass.TA.reportError("a name is referenced outside the "
00328             "NSAutoreleasePool scope that it was declared in", referenceLoc);
00329         Pass.TA.reportNote("name declared here", declarationLoc);
00330         Pass.TA.reportNote("intended @autoreleasepool scope begins here",
00331                            (*scope.Begin)->getLocStart());
00332         Pass.TA.reportNote("intended @autoreleasepool scope ends here",
00333                            (*scope.End)->getLocStart());
00334         return;
00335       }
00336     }
00337 
00338     // Collect all releases of the pool; they will be removed.
00339     {
00340       ReleaseCollector releaseColl(scope.PoolVar, scope.Releases);
00341       Stmt::child_iterator I = scope.Begin;
00342       ++I;
00343       for (; I != scope.End; ++I)
00344         releaseColl.TraverseStmt(*I);
00345     }
00346 
00347     PoolVars[scope.PoolVar].Scopes.push_back(scope);
00348   }
00349 
00350   bool isPoolCreation(Expr *E) {
00351     if (!E) return false;
00352     E = getEssential(E);
00353     ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
00354     if (!ME) return false;
00355     if (ME->getMethodFamily() == OMF_new &&
00356         ME->getReceiverKind() == ObjCMessageExpr::Class &&
00357         isNSAutoreleasePool(ME->getReceiverInterface()))
00358       return true;
00359     if (ME->getReceiverKind() == ObjCMessageExpr::Instance &&
00360         ME->getMethodFamily() == OMF_init) {
00361       Expr *rec = getEssential(ME->getInstanceReceiver());
00362       if (ObjCMessageExpr *recME = dyn_cast_or_null<ObjCMessageExpr>(rec)) {
00363         if (recME->getMethodFamily() == OMF_alloc &&
00364             recME->getReceiverKind() == ObjCMessageExpr::Class &&
00365             isNSAutoreleasePool(recME->getReceiverInterface()))
00366           return true;
00367       }
00368     }
00369 
00370     return false;
00371   }
00372 
00373   bool isPoolDrain(VarDecl *poolVar, Stmt *S) {
00374     if (!S) return false;
00375     S = getEssential(S);
00376     ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S);
00377     if (!ME) return false;
00378     if (ME->getReceiverKind() == ObjCMessageExpr::Instance) {
00379       Expr *rec = getEssential(ME->getInstanceReceiver());
00380       if (DeclRefExpr *dref = dyn_cast<DeclRefExpr>(rec))
00381         if (dref->getDecl() == poolVar)
00382           return ME->getMethodFamily() == OMF_release ||
00383                  ME->getSelector() == DrainSel;
00384     }
00385 
00386     return false;
00387   }
00388 
00389   bool isNSAutoreleasePool(ObjCInterfaceDecl *IDecl) {
00390     return IDecl && IDecl->getIdentifier() == PoolII;
00391   }
00392 
00393   bool isNSAutoreleasePool(QualType Ty) {
00394     QualType pointee = Ty->getPointeeType();
00395     if (pointee.isNull())
00396       return false;
00397     if (const ObjCInterfaceType *interT = pointee->getAs<ObjCInterfaceType>())
00398       return isNSAutoreleasePool(interT->getDecl());
00399     return false;
00400   }
00401 
00402   static Expr *getEssential(Expr *E) {
00403     return cast<Expr>(getEssential((Stmt*)E));
00404   }
00405   static Stmt *getEssential(Stmt *S) {
00406     if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S))
00407       S = EWC->getSubExpr();
00408     if (Expr *E = dyn_cast<Expr>(S))
00409       S = E->IgnoreParenCasts();
00410     return S;
00411   }
00412 
00413   Stmt *Body;
00414   MigrationPass &Pass;
00415 
00416   IdentifierInfo *PoolII;
00417   Selector DrainSel;
00418   
00419   struct PoolVarInfo {
00420     DeclStmt *Dcl;
00421     ExprSet Refs;
00422     SmallVector<PoolScope, 2> Scopes;
00423 
00424     PoolVarInfo() : Dcl(nullptr) { }
00425   };
00426 
00427   std::map<VarDecl *, PoolVarInfo> PoolVars;
00428 };
00429 
00430 } // anonymous namespace
00431 
00432 void trans::rewriteAutoreleasePool(MigrationPass &pass) {
00433   BodyTransform<AutoreleasePoolRewriter> trans(pass);
00434   trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
00435 }