36 using namespace clang;
37 using namespace arcmt;
38 using namespace trans;
48 : Dcl(D), Releases(releases) { }
56 if (
DeclRefExpr *DE = dyn_cast<DeclRefExpr>(instance)) {
57 if (DE->getDecl() == Dcl)
58 Releases.push_back(E);
68 class AutoreleasePoolRewriter
72 : Body(nullptr), Pass(pass) {
78 void transformBody(
Stmt *body,
Decl *ParentD) {
83 ~AutoreleasePoolRewriter() {
86 for (std::map<VarDecl *, PoolVarInfo>::iterator
87 I = PoolVars.begin(), E = PoolVars.end(); I != E; ++I) {
89 PoolVarInfo &info = I->second;
95 scpI = info.Scopes.begin(),
96 scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
97 PoolScope &scope = *scpI;
100 clearRefsIn(scope.Releases.begin(), scope.Releases.end(), info.Refs);
105 if (info.Refs.empty())
106 VarsToHandle.push_back(var);
109 for (
unsigned i = 0, e = VarsToHandle.size();
i != e; ++
i) {
110 PoolVarInfo &info = PoolVars[VarsToHandle[
i]];
114 clearUnavailableDiags(info.Dcl);
115 Pass.TA.removeStmt(info.Dcl);
119 scpI = info.Scopes.begin(),
120 scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
121 PoolScope &scope = *scpI;
122 clearUnavailableDiags(*scope.Begin);
123 clearUnavailableDiags(*scope.End);
124 if (scope.IsFollowedBySimpleReturnStmt) {
126 Pass.TA.replaceStmt(*scope.Begin,
"@autoreleasepool {");
127 Pass.TA.removeStmt(*scope.End);
133 "Didn't we check before setting IsFollowedBySimpleReturnStmt " 135 Pass.TA.insertAfterToken(afterSemi,
"\n}");
136 Pass.TA.increaseIndentation(
138 (*retI)->getEndLoc()),
139 scope.CompoundParent->getBeginLoc());
141 Pass.TA.replaceStmt(*scope.Begin,
"@autoreleasepool {");
142 Pass.TA.replaceStmt(*scope.End,
"}");
143 Pass.TA.increaseIndentation(scope.getIndentedRange(),
144 scope.CompoundParent->getBeginLoc());
150 scpI = info.Scopes.begin(),
151 scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
152 PoolScope &scope = *scpI;
154 relI = scope.Releases.begin(),
155 relE = scope.Releases.end(); relI != relE; ++relI) {
156 clearUnavailableDiags(*relI);
157 Pass.TA.removeStmt(*relI);
168 Stmt *child = getEssential(*I);
169 if (
DeclStmt *DclS = dyn_cast<DeclStmt>(child)) {
170 if (DclS->isSingleDecl()) {
171 if (
VarDecl *VD = dyn_cast<VarDecl>(DclS->getSingleDecl())) {
172 if (isNSAutoreleasePool(VD->getType())) {
173 PoolVarInfo &info = PoolVars[VD];
178 if (isPoolCreation(VD->getInit())) {
179 Scopes.push_back(PoolScope());
180 Scopes.back().PoolVar = VD;
181 Scopes.back().CompoundParent = S;
182 Scopes.back().Begin = I;
187 }
else if (
BinaryOperator *bop = dyn_cast<BinaryOperator>(child)) {
188 if (
DeclRefExpr *dref = dyn_cast<DeclRefExpr>(bop->getLHS())) {
189 if (
VarDecl *VD = dyn_cast<VarDecl>(dref->getDecl())) {
192 if (isNSAutoreleasePool(VD->getType()) &&
193 isPoolCreation(bop->getRHS())) {
194 Scopes.push_back(PoolScope());
195 Scopes.back().PoolVar = VD;
196 Scopes.back().CompoundParent = S;
197 Scopes.back().Begin = I;
206 if (isPoolDrain(Scopes.back().PoolVar, child)) {
207 PoolScope &scope = Scopes.back();
209 handlePoolScope(scope, S);
217 void clearUnavailableDiags(
Stmt *S) {
219 Pass.TA.clearDiagnostic(diag::err_unavailable,
220 diag::err_unavailable_message,
229 bool IsFollowedBySimpleReturnStmt;
232 PoolScope() : PoolVar(nullptr), CompoundParent(nullptr), Begin(), End(),
233 IsFollowedBySimpleReturnStmt(
false) { }
243 return SourceRange((*rangeS)->getBeginLoc(), (*rangeE)->getEndLoc());
253 NameReferenceChecker(
ASTContext &ctx, PoolScope &scope,
256 : Ctx(ctx), referenceLoc(referenceLoc),
257 declarationLoc(declarationLoc) {
258 ScopeRange =
SourceRange((*scope.Begin)->getBeginLoc(),
259 (*scope.End)->getBeginLoc());
276 if (isInScope(declLoc)) {
277 referenceLoc = refLoc;
278 declarationLoc = declLoc;
295 void handlePoolScope(PoolScope &scope,
CompoundStmt *compoundS) {
299 bool nameUsedOutsideScope =
false;
306 if (
ReturnStmt *retS = dyn_cast<ReturnStmt>(*SI))
307 if ((retS->getRetValue() ==
nullptr ||
308 isa<DeclRefExpr>(retS->getRetValue()->IgnoreParenCasts())) &&
310 scope.IsFollowedBySimpleReturnStmt =
true;
314 for (; SI != SE; ++SI) {
315 nameUsedOutsideScope = !NameReferenceChecker(Pass.Ctx, scope,
317 declarationLoc).TraverseStmt(*SI);
318 if (nameUsedOutsideScope)
325 if (nameUsedOutsideScope) {
326 Pass.TA.reportError(
"a name is referenced outside the " 327 "NSAutoreleasePool scope that it was declared in", referenceLoc);
328 Pass.TA.reportNote(
"name declared here", declarationLoc);
329 Pass.TA.reportNote(
"intended @autoreleasepool scope begins here",
330 (*scope.Begin)->getBeginLoc());
331 Pass.TA.reportNote(
"intended @autoreleasepool scope ends here",
332 (*scope.End)->getBeginLoc());
339 ReleaseCollector releaseColl(scope.PoolVar, scope.Releases);
342 for (; I != scope.End; ++I)
343 releaseColl.TraverseStmt(*I);
346 PoolVars[scope.PoolVar].Scopes.push_back(scope);
349 bool isPoolCreation(
Expr *E) {
350 if (!E)
return false;
353 if (!ME)
return false;
362 if (recME->getMethodFamily() ==
OMF_alloc &&
364 isNSAutoreleasePool(recME->getReceiverInterface()))
373 if (!S)
return false;
376 if (!ME)
return false;
379 if (
DeclRefExpr *dref = dyn_cast<DeclRefExpr>(rec))
380 if (dref->getDecl() == poolVar)
392 bool isNSAutoreleasePool(
QualType Ty) {
397 return isNSAutoreleasePool(interT->getDecl());
401 static Expr *getEssential(
Expr *E) {
402 return cast<Expr>(getEssential((
Stmt*)E));
404 static Stmt *getEssential(
Stmt *S) {
405 if (
FullExpr *FE = dyn_cast<FullExpr>(S))
406 S = FE->getSubExpr();
407 if (
Expr *E = dyn_cast<Expr>(S))
423 PoolVarInfo() : Dcl(nullptr) { }
426 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
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
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