@@ -1518,27 +1518,41 @@ void CheckClass::operatorEqToSelf()
15181518 if (Token::Match (func.retDef , " %type% &" ) && func.retDef ->str () == scope->className ) {
15191519 // find the parameter name
15201520 const Token *rhs = func.argumentList .begin ()->nameToken ();
1521-
1522- if (!hasAssignSelf (&func, rhs)) {
1521+ const Token* out_ifStatementScopeStart = nullptr ;
1522+ if (!hasAssignSelf (&func, rhs, &out_ifStatementScopeStart )) {
15231523 if (hasAllocation (&func, scope))
15241524 operatorEqToSelfError (func.token );
15251525 }
1526+ else if (out_ifStatementScopeStart != nullptr ) {
1527+ if (hasAllocationInIfScope (&func, scope, out_ifStatementScopeStart))
1528+ operatorEqToSelfError (func.token );
1529+ }
15261530 }
15271531 }
15281532 }
15291533 }
15301534}
15311535
1536+ bool CheckClass::hasAllocationInIfScope (const Function *func, const Scope* scope, const Token *ifStatementScopeStart) const
1537+ {
1538+ const Token *end;
1539+ if (ifStatementScopeStart->str () == " {" )
1540+ end = ifStatementScopeStart->link ();
1541+ else
1542+ end = func->functionScope ->bodyEnd ;
1543+ return hasAllocation (func, scope, ifStatementScopeStart, end);
1544+ }
1545+
15321546bool CheckClass::hasAllocation (const Function *func, const Scope* scope) const
15331547{
1534- // This function is called when no simple check was found for assignment
1535- // to self. We are currently looking for:
1536- // - deallocate member ; ... member =
1537- // - alloc member
1538- // That is not ideal because it can cause false negatives but its currently
1539- // necessary to prevent false positives.
1540- const Token *last = func->functionScope ->bodyEnd ;
1541- for (const Token *tok = func-> functionScope -> bodyStart ; tok && (tok != last ); tok = tok->next ()) {
1548+ return hasAllocation (func, scope, func-> functionScope -> bodyStart , func-> functionScope -> bodyEnd );
1549+ }
1550+
1551+ bool CheckClass::hasAllocation ( const Function *func, const Scope* scope, const Token *start, const Token *end) const
1552+ {
1553+ if (!end)
1554+ end = func->functionScope ->bodyEnd ;
1555+ for (const Token *tok = start ; tok && (tok != end ); tok = tok->next ()) {
15421556 if (Token::Match (tok, " %var% = malloc|realloc|calloc|new" ) && isMemberVar (scope, tok))
15431557 return true ;
15441558
@@ -1554,7 +1568,7 @@ bool CheckClass::hasAllocation(const Function *func, const Scope* scope) const
15541568 continue ;
15551569 // Check for assignment to the deleted pointer (only if its a member of the class)
15561570 if (isMemberVar (scope, var)) {
1557- for (const Token *tok1 = var->next (); tok1 && (tok1 != last ); tok1 = tok1->next ()) {
1571+ for (const Token *tok1 = var->next (); tok1 && (tok1 != end ); tok1 = tok1->next ()) {
15581572 if (Token::Match (tok1, " %varid% =" , var->varId ()))
15591573 return true ;
15601574 }
@@ -1564,7 +1578,70 @@ bool CheckClass::hasAllocation(const Function *func, const Scope* scope) const
15641578 return false ;
15651579}
15661580
1567- bool CheckClass::hasAssignSelf (const Function *func, const Token *rhs)
1581+ static bool isTrueKeyword (const Token* tok)
1582+ {
1583+ return tok->hasKnownIntValue () && tok->getKnownIntValue () == 1 ;
1584+ }
1585+
1586+ static bool isFalseKeyword (const Token* tok)
1587+ {
1588+ return tok->hasKnownIntValue () && tok->getKnownIntValue () == 0 ;
1589+ }
1590+
1591+ /*
1592+ * Checks if self-assignment test is inverse
1593+ * For example 'if (this == &rhs)'
1594+ */
1595+ CheckClass::Bool CheckClass::isInverted (const Token *tok, const Token *rhs)
1596+ {
1597+ bool res = true ;
1598+ for (const Token *itr = tok; itr && itr->str ()!=" (" ; itr=itr->astParent ()) {
1599+ if (Token::simpleMatch (itr, " !=" ) && (isTrueKeyword (itr->astOperand1 ()) || isTrueKeyword (itr->astOperand2 ()))) {
1600+ res = !res;
1601+ }
1602+ else if (Token::simpleMatch (itr, " !=" ) && ( (Token::simpleMatch (itr->astOperand1 (), " this" ) && Token::simpleMatch (itr->astOperand2 (), " &" ) && Token::simpleMatch (itr->astOperand2 ()->next (), rhs->str ().c_str (), rhs->str ().size ()))
1603+ || (Token::simpleMatch (itr->astOperand2 (), " this" ) && Token::simpleMatch (itr->astOperand1 (), " &" ) && Token::simpleMatch (itr->astOperand1 ()->next (), rhs->str ().c_str (), rhs->str ().size ())))) {
1604+ res = !res;
1605+ }
1606+ else if (Token::simpleMatch (itr, " !=" ) && (isFalseKeyword (itr->astOperand1 ()) || isFalseKeyword (itr->astOperand2 ()))) {
1607+ // Do nothing
1608+ }
1609+ else if (Token::simpleMatch (itr, " !" )) {
1610+ res = !res;
1611+ }
1612+ else if (Token::simpleMatch (itr, " ==" ) && (isFalseKeyword (itr->astOperand1 ()) || isFalseKeyword (itr->astOperand2 ()))) {
1613+ res = !res;
1614+ }
1615+ else if (Token::simpleMatch (itr, " ==" ) && (isTrueKeyword (itr->astOperand1 ()) || isTrueKeyword (itr->astOperand2 ()))) {
1616+ // Do nothing
1617+ }
1618+ else if (Token::simpleMatch (itr, " ==" ) && ( (Token::simpleMatch (itr->astOperand1 (), " this" ) && Token::simpleMatch (itr->astOperand2 (), " &" ) && Token::simpleMatch (itr->astOperand2 ()->next (), rhs->str ().c_str (), rhs->str ().size ()))
1619+ || (Token::simpleMatch (itr->astOperand2 (), " this" ) && Token::simpleMatch (itr->astOperand1 (), " &" ) && Token::simpleMatch (itr->astOperand1 ()->next (), rhs->str ().c_str (), rhs->str ().size ())))) {
1620+ // Do nothing
1621+ }
1622+ else {
1623+ return Bool::BAILOUT;
1624+ }
1625+ }
1626+ if (res)
1627+ return Bool::TRUE ;
1628+ return Bool::FALSE ;
1629+ }
1630+
1631+ const Token * CheckClass::getIfStmtBodyStart (const Token *tok, const Token *rhs)
1632+ {
1633+ const Token *top = tok->astTop ();
1634+ if (Token::simpleMatch (top->link (), " ) {" )) {
1635+ switch (isInverted (tok->astParent (), rhs)) {
1636+ case Bool::BAILOUT: return nullptr ;
1637+ case Bool::TRUE : return top->link ()->next ();
1638+ case Bool::FALSE : return top->link ()->next ()->link ();
1639+ }
1640+ }
1641+ return nullptr ;
1642+ }
1643+
1644+ bool CheckClass::hasAssignSelf (const Function *func, const Token *rhs, const Token **out_ifStatementScopeStart)
15681645{
15691646 if (!rhs)
15701647 return false ;
@@ -1586,6 +1663,9 @@ bool CheckClass::hasAssignSelf(const Function *func, const Token *rhs)
15861663 return ChildrenToVisit::op1_and_op2;
15871664 if (tok2 && tok2->isUnaryOp (" &" ) && tok2->astOperand1 ()->str () == rhs->str ())
15881665 ret = true ;
1666+ if (ret) {
1667+ *out_ifStatementScopeStart = getIfStmtBodyStart (tok2, rhs);
1668+ }
15891669 return ret ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2;
15901670 });
15911671 if (ret)
0 commit comments