37 using namespace clang;
38 using namespace arcmt;
39 using namespace trans;
49 : Dcl(D), Releases(releases) { }
57 if (
DeclRefExpr *DE = dyn_cast<DeclRefExpr>(instance)) {
58 if (DE->getDecl() == Dcl)
59 Releases.push_back(E);
69 class AutoreleasePoolRewriter
73 : Body(nullptr), Pass(pass) {
79 void transformBody(
Stmt *body,
Decl *ParentD) {
84 ~AutoreleasePoolRewriter() {
87 for (std::map<VarDecl *, PoolVarInfo>::iterator
88 I = PoolVars.begin(), E = PoolVars.end(); I != E; ++I) {
90 PoolVarInfo &info = I->second;
96 scpI = info.Scopes.begin(),
97 scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
98 PoolScope &scope = *scpI;
101 clearRefsIn(scope.Releases.begin(), scope.Releases.end(), info.Refs);
106 if (info.Refs.empty())
107 VarsToHandle.push_back(var);
110 for (
unsigned i = 0, e = VarsToHandle.size(); i != e; ++i) {
111 PoolVarInfo &info = PoolVars[VarsToHandle[i]];
115 clearUnavailableDiags(info.Dcl);
116 Pass.TA.removeStmt(info.Dcl);
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) {
127 Pass.TA.replaceStmt(*scope.Begin,
"@autoreleasepool {");
128 Pass.TA.removeStmt(*scope.End);
134 "Didn't we check before setting IsFollowedBySimpleReturnStmt " 136 Pass.TA.insertAfterToken(afterSemi,
"\n}");
137 Pass.TA.increaseIndentation(
139 (*retI)->getEndLoc()),
140 scope.CompoundParent->getBeginLoc());
142 Pass.TA.replaceStmt(*scope.Begin,
"@autoreleasepool {");
143 Pass.TA.replaceStmt(*scope.End,
"}");
144 Pass.TA.increaseIndentation(scope.getIndentedRange(),
145 scope.CompoundParent->getBeginLoc());
151 scpI = info.Scopes.begin(),
152 scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
153 PoolScope &scope = *scpI;
155 relI = scope.Releases.begin(),
156 relE = scope.Releases.end(); relI != relE; ++relI) {
157 clearUnavailableDiags(*relI);
158 Pass.TA.removeStmt(*relI);
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];
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;
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())) {
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;
207 if (isPoolDrain(Scopes.back().PoolVar, child)) {
208 PoolScope &scope = Scopes.back();
210 handlePoolScope(scope, S);
218 void clearUnavailableDiags(
Stmt *S) {
220 Pass.TA.clearDiagnostic(diag::err_unavailable,
221 diag::err_unavailable_message,
230 bool IsFollowedBySimpleReturnStmt;
233 PoolScope() : PoolVar(nullptr), CompoundParent(nullptr), Begin(), End(),
234 IsFollowedBySimpleReturnStmt(
false) { }
244 return SourceRange((*rangeS)->getBeginLoc(), (*rangeE)->getEndLoc());
254 NameReferenceChecker(
ASTContext &ctx, PoolScope &scope,
257 : Ctx(ctx), referenceLoc(referenceLoc),
258 declarationLoc(declarationLoc) {
259 ScopeRange =
SourceRange((*scope.Begin)->getBeginLoc(),
260 (*scope.End)->getBeginLoc());
277 if (isInScope(declLoc)) {
278 referenceLoc = refLoc;
279 declarationLoc = declLoc;
296 void handlePoolScope(PoolScope &scope,
CompoundStmt *compoundS) {
300 bool nameUsedOutsideScope =
false;
307 if (
ReturnStmt *retS = dyn_cast<ReturnStmt>(*SI))
308 if ((retS->getRetValue() ==
nullptr ||
309 isa<DeclRefExpr>(retS->getRetValue()->IgnoreParenCasts())) &&
311 scope.IsFollowedBySimpleReturnStmt =
true;
315 for (; SI != SE; ++SI) {
316 nameUsedOutsideScope = !NameReferenceChecker(Pass.Ctx, scope,
318 declarationLoc).TraverseStmt(*SI);
319 if (nameUsedOutsideScope)
326 if (nameUsedOutsideScope) {
327 Pass.TA.reportError(
"a name is referenced outside the " 328 "NSAutoreleasePool scope that it was declared in", referenceLoc);
329 Pass.TA.reportNote(
"name declared here", declarationLoc);
330 Pass.TA.reportNote(
"intended @autoreleasepool scope begins here",
331 (*scope.Begin)->getBeginLoc());
332 Pass.TA.reportNote(
"intended @autoreleasepool scope ends here",
333 (*scope.End)->getBeginLoc());
340 ReleaseCollector releaseColl(scope.PoolVar, scope.Releases);
343 for (; I != scope.End; ++I)
344 releaseColl.TraverseStmt(*I);
347 PoolVars[scope.PoolVar].Scopes.push_back(scope);
350 bool isPoolCreation(
Expr *E) {
351 if (!E)
return false;
354 if (!ME)
return false;
363 if (recME->getMethodFamily() ==
OMF_alloc &&
365 isNSAutoreleasePool(recME->getReceiverInterface()))
374 if (!S)
return false;
377 if (!ME)
return false;
380 if (
DeclRefExpr *dref = dyn_cast<DeclRefExpr>(rec))
381 if (dref->getDecl() == poolVar)
393 bool isNSAutoreleasePool(
QualType Ty) {
398 return isNSAutoreleasePool(interT->getDecl());
402 static Expr *getEssential(
Expr *E) {
403 return cast<Expr>(getEssential((
Stmt*)E));
405 static Stmt *getEssential(
Stmt *S) {
406 if (
FullExpr *FE = dyn_cast<FullExpr>(S))
407 S = FE->getSubExpr();
408 if (
Expr *E = dyn_cast<Expr>(S))
424 PoolVarInfo() : Dcl(nullptr) { }
427 std::map<VarDecl *, PoolVarInfo> PoolVars;
Defines the clang::ASTContext interface.
The receiver is an object instance.
Smart pointer class that efficiently represents Objective-C method names.
A (possibly-)qualified type.
Wrapper for source info for tag types.
Selector getSelector() const
Stmt - This represents one statement.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Defines the SourceManager interface.
ObjCInterfaceDecl * getReceiverInterface() const
Retrieve the Objective-C interface to which this message is being directed, if known.
Decl - This represents one declaration (or definition), e.g.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
Wrapper for source info for typedefs.
Represents a variable declaration or definition.
const T * getAs() const
Member-template getAs<specific type>'.
void clearRefsIn(Stmt *S, ExprSet &refs)
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
One of these records is kept for each identifier that is lexed.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
FullExpr - Represents a "full-expression" node.
SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx, bool IsDecl=false)
'Loc' is the end of a statement range.
Selector getNullarySelector(IdentifierInfo *ID)
A builtin binary operation expression such as "x + y" or "x <= y".
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Represents an ObjC class declaration.
CompoundStmt - This represents a group of statements like { stmt stmt }.
SourceLocation getLocation() const
TagDecl * getDecl() const
SourceLocation getBeginLoc() const
Get the begin source location.
This represents one expression.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
An expression that sends a message to the given Objective-C object or class.
SourceLocation getEnd() const
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
SelectorTable & Selectors
Encodes a location in the source.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
Interfaces are the core concept in Objective-C for object oriented design.
ObjCMethodFamily getMethodFamily() const
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
void collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs)
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
void rewriteAutoreleasePool(MigrationPass &pass)
body_iterator body_begin()
TypedefNameDecl * getTypedefNameDecl() const
SourceManager & getSourceManager()
TranslationUnitDecl * getTranslationUnitDecl() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
A reference to a declared variable, function, enum, etc.
A trivial tuple used to represent a source range.
bool isInstanceMessage() const
Determine whether this is an instance message to either a computed object or to super.
SourceLocation getBegin() const
This class handles loading and caching of source files into memory.
SourceLocation getLocation() const