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