forked from OSchip/llvm-project
[arcmt] Don't error if an autoreleased variable is returned after the -autorelease.
rdar://12952025 llvm-svn: 171482
This commit is contained in:
parent
dde168b8b5
commit
b7b89b5ebc
|
@ -162,13 +162,26 @@ public:
|
|||
private:
|
||||
/// \brief Checks for idioms where an unused -autorelease is common.
|
||||
///
|
||||
/// Currently only returns true for this idiom which is common in property
|
||||
/// Returns true for this idiom which is common in property
|
||||
/// setters:
|
||||
///
|
||||
/// [backingValue autorelease];
|
||||
/// backingValue = [newValue retain]; // in general a +1 assign
|
||||
///
|
||||
/// For these as well:
|
||||
///
|
||||
/// [[var retain] autorelease];
|
||||
/// return var;
|
||||
///
|
||||
bool isCommonUnusedAutorelease(ObjCMessageExpr *E) {
|
||||
if (isPlusOneAssignAfterAutorelease(E))
|
||||
return true;
|
||||
if (isReturnedAfterAutorelease(E))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isReturnedAfterAutorelease(ObjCMessageExpr *E) {
|
||||
Expr *Rec = E->getInstanceReceiver();
|
||||
if (!Rec)
|
||||
return false;
|
||||
|
@ -177,36 +190,30 @@ private:
|
|||
if (!RefD)
|
||||
return false;
|
||||
|
||||
Stmt *OuterS = E, *InnerS;
|
||||
do {
|
||||
InnerS = OuterS;
|
||||
OuterS = StmtMap->getParent(InnerS);
|
||||
}
|
||||
while (OuterS && (isa<ParenExpr>(OuterS) ||
|
||||
isa<CastExpr>(OuterS) ||
|
||||
isa<ExprWithCleanups>(OuterS)));
|
||||
|
||||
if (!OuterS)
|
||||
return false;
|
||||
|
||||
// Find next statement after the -autorelease.
|
||||
|
||||
Stmt::child_iterator currChildS = OuterS->child_begin();
|
||||
Stmt::child_iterator childE = OuterS->child_end();
|
||||
for (; currChildS != childE; ++currChildS) {
|
||||
if (*currChildS == InnerS)
|
||||
break;
|
||||
}
|
||||
if (currChildS == childE)
|
||||
return false;
|
||||
++currChildS;
|
||||
if (currChildS == childE)
|
||||
return false;
|
||||
|
||||
Stmt *nextStmt = *currChildS;
|
||||
Stmt *nextStmt = getNextStmt(E);
|
||||
if (!nextStmt)
|
||||
return false;
|
||||
|
||||
// Check for "return <variable>;".
|
||||
|
||||
if (ReturnStmt *RetS = dyn_cast<ReturnStmt>(nextStmt))
|
||||
return RefD == getReferencedDecl(RetS->getRetValue());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isPlusOneAssignAfterAutorelease(ObjCMessageExpr *E) {
|
||||
Expr *Rec = E->getInstanceReceiver();
|
||||
if (!Rec)
|
||||
return false;
|
||||
|
||||
Decl *RefD = getReferencedDecl(Rec);
|
||||
if (!RefD)
|
||||
return false;
|
||||
|
||||
Stmt *nextStmt = getNextStmt(E);
|
||||
if (!nextStmt)
|
||||
return false;
|
||||
nextStmt = nextStmt->IgnoreImplicit();
|
||||
|
||||
// Check for "RefD = [+1 retained object];".
|
||||
|
||||
|
@ -219,11 +226,56 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
Stmt *getNextStmt(Expr *E) {
|
||||
if (!E)
|
||||
return 0;
|
||||
|
||||
Stmt *OuterS = E, *InnerS;
|
||||
do {
|
||||
InnerS = OuterS;
|
||||
OuterS = StmtMap->getParent(InnerS);
|
||||
}
|
||||
while (OuterS && (isa<ParenExpr>(OuterS) ||
|
||||
isa<CastExpr>(OuterS) ||
|
||||
isa<ExprWithCleanups>(OuterS)));
|
||||
|
||||
if (!OuterS)
|
||||
return 0;
|
||||
|
||||
Stmt::child_iterator currChildS = OuterS->child_begin();
|
||||
Stmt::child_iterator childE = OuterS->child_end();
|
||||
for (; currChildS != childE; ++currChildS) {
|
||||
if (*currChildS == InnerS)
|
||||
break;
|
||||
}
|
||||
if (currChildS == childE)
|
||||
return 0;
|
||||
++currChildS;
|
||||
if (currChildS == childE)
|
||||
return 0;
|
||||
|
||||
Stmt *nextStmt = *currChildS;
|
||||
if (!nextStmt)
|
||||
return 0;
|
||||
return nextStmt->IgnoreImplicit();
|
||||
}
|
||||
|
||||
Decl *getReferencedDecl(Expr *E) {
|
||||
if (!E)
|
||||
return 0;
|
||||
|
||||
E = E->IgnoreParenCasts();
|
||||
if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
|
||||
switch (ME->getMethodFamily()) {
|
||||
case OMF_copy:
|
||||
case OMF_autorelease:
|
||||
case OMF_release:
|
||||
case OMF_retain:
|
||||
return getReferencedDecl(ME->getInstanceReceiver());
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
|
||||
return DRE->getDecl();
|
||||
if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
|
||||
|
|
|
@ -64,3 +64,8 @@ void test(A *prevVal, A *newVal) {
|
|||
[prevVal autorelease];
|
||||
prevVal = [newVal retain];
|
||||
}
|
||||
|
||||
id test2(A* val) {
|
||||
[[val retain] autorelease];
|
||||
return val;
|
||||
}
|
||||
|
|
|
@ -60,3 +60,7 @@ int main (int argc, const char * argv[]) {
|
|||
void test(A *prevVal, A *newVal) {
|
||||
prevVal = newVal;
|
||||
}
|
||||
|
||||
id test2(A* val) {
|
||||
return val;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue