зеркало из https://github.com/microsoft/clang-1.git
[arcmt] Allow removing an -autorelease of a variable initialized in the previous statement.
rdar://11074996 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@171485 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
ea2224d707
Коммит
20bcd4ead4
|
@ -174,7 +174,7 @@ private:
|
||||||
/// return var;
|
/// return var;
|
||||||
///
|
///
|
||||||
bool isCommonUnusedAutorelease(ObjCMessageExpr *E) {
|
bool isCommonUnusedAutorelease(ObjCMessageExpr *E) {
|
||||||
if (isPlusOneAssignAfterAutorelease(E))
|
if (isPlusOneAssignBeforeOrAfterAutorelease(E))
|
||||||
return true;
|
return true;
|
||||||
if (isReturnedAfterAutorelease(E))
|
if (isReturnedAfterAutorelease(E))
|
||||||
return true;
|
return true;
|
||||||
|
@ -202,7 +202,7 @@ private:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPlusOneAssignAfterAutorelease(ObjCMessageExpr *E) {
|
bool isPlusOneAssignBeforeOrAfterAutorelease(ObjCMessageExpr *E) {
|
||||||
Expr *Rec = E->getInstanceReceiver();
|
Expr *Rec = E->getInstanceReceiver();
|
||||||
if (!Rec)
|
if (!Rec)
|
||||||
return false;
|
return false;
|
||||||
|
@ -211,24 +211,46 @@ private:
|
||||||
if (!RefD)
|
if (!RefD)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Stmt *nextStmt = getNextStmt(E);
|
Stmt *prevStmt, *nextStmt;
|
||||||
if (!nextStmt)
|
llvm::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E);
|
||||||
|
|
||||||
|
return isPlusOneAssignToVar(prevStmt, RefD) ||
|
||||||
|
isPlusOneAssignToVar(nextStmt, RefD);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPlusOneAssignToVar(Stmt *S, Decl *RefD) {
|
||||||
|
if (!S)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check for "RefD = [+1 retained object];".
|
// Check for "RefD = [+1 retained object];".
|
||||||
|
|
||||||
if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(nextStmt)) {
|
if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
|
||||||
if (RefD != getReferencedDecl(Bop->getLHS()))
|
if (RefD != getReferencedDecl(Bop->getLHS()))
|
||||||
return false;
|
return false;
|
||||||
if (isPlusOneAssign(Bop))
|
if (isPlusOneAssign(Bop))
|
||||||
return true;
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
|
||||||
|
if (DS->isSingleDecl() && DS->getSingleDecl() == RefD) {
|
||||||
|
if (VarDecl *VD = dyn_cast<VarDecl>(RefD))
|
||||||
|
return isPlusOne(VD->getInit());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt *getNextStmt(Expr *E) {
|
Stmt *getNextStmt(Expr *E) {
|
||||||
|
return getPreviousAndNextStmt(E).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(Expr *E) {
|
||||||
|
Stmt *prevStmt = 0, *nextStmt = 0;
|
||||||
if (!E)
|
if (!E)
|
||||||
return 0;
|
return std::make_pair(prevStmt, nextStmt);
|
||||||
|
|
||||||
Stmt *OuterS = E, *InnerS;
|
Stmt *OuterS = E, *InnerS;
|
||||||
do {
|
do {
|
||||||
|
@ -240,24 +262,34 @@ private:
|
||||||
isa<ExprWithCleanups>(OuterS)));
|
isa<ExprWithCleanups>(OuterS)));
|
||||||
|
|
||||||
if (!OuterS)
|
if (!OuterS)
|
||||||
return 0;
|
return std::make_pair(prevStmt, nextStmt);
|
||||||
|
|
||||||
Stmt::child_iterator currChildS = OuterS->child_begin();
|
Stmt::child_iterator currChildS = OuterS->child_begin();
|
||||||
Stmt::child_iterator childE = OuterS->child_end();
|
Stmt::child_iterator childE = OuterS->child_end();
|
||||||
|
Stmt::child_iterator prevChildS = childE;
|
||||||
for (; currChildS != childE; ++currChildS) {
|
for (; currChildS != childE; ++currChildS) {
|
||||||
if (*currChildS == InnerS)
|
if (*currChildS == InnerS)
|
||||||
break;
|
break;
|
||||||
|
prevChildS = currChildS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prevChildS != childE) {
|
||||||
|
prevStmt = *prevChildS;
|
||||||
|
if (prevStmt)
|
||||||
|
prevStmt = prevStmt->IgnoreImplicit();
|
||||||
|
}
|
||||||
|
|
||||||
if (currChildS == childE)
|
if (currChildS == childE)
|
||||||
return 0;
|
return std::make_pair(prevStmt, nextStmt);
|
||||||
++currChildS;
|
++currChildS;
|
||||||
if (currChildS == childE)
|
if (currChildS == childE)
|
||||||
return 0;
|
return std::make_pair(prevStmt, nextStmt);
|
||||||
|
|
||||||
Stmt *nextStmt = *currChildS;
|
nextStmt = *currChildS;
|
||||||
if (!nextStmt)
|
if (nextStmt)
|
||||||
return 0;
|
nextStmt = nextStmt->IgnoreImplicit();
|
||||||
return nextStmt->IgnoreImplicit();
|
|
||||||
|
return std::make_pair(prevStmt, nextStmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
Decl *getReferencedDecl(Expr *E) {
|
Decl *getReferencedDecl(Expr *E) {
|
||||||
|
|
|
@ -71,13 +71,22 @@ bool trans::isPlusOneAssign(const BinaryOperator *E) {
|
||||||
if (E->getOpcode() != BO_Assign)
|
if (E->getOpcode() != BO_Assign)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
return isPlusOne(E->getRHS());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool trans::isPlusOne(const Expr *E) {
|
||||||
|
if (!E)
|
||||||
|
return false;
|
||||||
|
if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E))
|
||||||
|
E = EWC->getSubExpr();
|
||||||
|
|
||||||
if (const ObjCMessageExpr *
|
if (const ObjCMessageExpr *
|
||||||
ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts()))
|
ME = dyn_cast<ObjCMessageExpr>(E->IgnoreParenCasts()))
|
||||||
if (ME->getMethodFamily() == OMF_retain)
|
if (ME->getMethodFamily() == OMF_retain)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (const CallExpr *
|
if (const CallExpr *
|
||||||
callE = dyn_cast<CallExpr>(E->getRHS()->IgnoreParenCasts())) {
|
callE = dyn_cast<CallExpr>(E->IgnoreParenCasts())) {
|
||||||
if (const FunctionDecl *FD = callE->getDirectCallee()) {
|
if (const FunctionDecl *FD = callE->getDirectCallee()) {
|
||||||
if (FD->getAttr<CFReturnsRetainedAttr>())
|
if (FD->getAttr<CFReturnsRetainedAttr>())
|
||||||
return true;
|
return true;
|
||||||
|
@ -98,7 +107,7 @@ bool trans::isPlusOneAssign(const BinaryOperator *E) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS());
|
const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E);
|
||||||
while (implCE && implCE->getCastKind() == CK_BitCast)
|
while (implCE && implCE->getCastKind() == CK_BitCast)
|
||||||
implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
|
implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
|
||||||
|
|
||||||
|
|
|
@ -161,6 +161,7 @@ bool canApplyWeak(ASTContext &Ctx, QualType type,
|
||||||
bool AllowOnUnknownClass = false);
|
bool AllowOnUnknownClass = false);
|
||||||
|
|
||||||
bool isPlusOneAssign(const BinaryOperator *E);
|
bool isPlusOneAssign(const BinaryOperator *E);
|
||||||
|
bool isPlusOne(const Expr *E);
|
||||||
|
|
||||||
/// \brief 'Loc' is the end of a statement range. This returns the location
|
/// \brief 'Loc' is the end of a statement range. This returns the location
|
||||||
/// immediately after the semicolon following the statement.
|
/// immediately after the semicolon following the statement.
|
||||||
|
|
|
@ -69,3 +69,8 @@ id test2(A* val) {
|
||||||
[[val retain] autorelease];
|
[[val retain] autorelease];
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
id test3() {
|
||||||
|
id a = [[A alloc] init];
|
||||||
|
[a autorelease];
|
||||||
|
}
|
||||||
|
|
|
@ -64,3 +64,7 @@ void test(A *prevVal, A *newVal) {
|
||||||
id test2(A* val) {
|
id test2(A* val) {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
id test3() {
|
||||||
|
id a = [[A alloc] init];
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче