Skip to content

Commit a95c931

Browse files
authored
Fix issue 8501: false negative: (style) Opposite expression on both sides of (#3012)
1 parent b3b7ecc commit a95c931

3 files changed

Lines changed: 48 additions & 46 deletions

File tree

lib/astutils.cpp

Lines changed: 20 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,18 @@ bool exprDependsOnThis(const Token* expr, nonneg int depth)
648648
return exprDependsOnThis(expr->astOperand1(), depth) || exprDependsOnThis(expr->astOperand2(), depth);
649649
}
650650

651+
static bool hasUnknownVars(const Token* startTok) {
652+
bool result = false;
653+
visitAstNodes(startTok, [&](const Token* tok) {
654+
if (tok->varId() > 0 && !tok->variable()) {
655+
result = true;
656+
return ChildrenToVisit::done;
657+
}
658+
return ChildrenToVisit::op1_and_op2;
659+
});
660+
return result;
661+
}
662+
651663
/// This takes a token that refers to a variable and it will return the token
652664
/// to the expression that the variable is assigned to. If its not valid to
653665
/// make such substitution then it will return the original token.
@@ -671,11 +683,7 @@ static const Token * followVariableExpression(const Token * tok, bool cpp, const
671683
const Token * varTok = getVariableInitExpression(var);
672684
if (!varTok)
673685
return tok;
674-
// Bailout. If variable value depends on value of "this".
675-
if (exprDependsOnThis(varTok))
676-
return tok;
677-
// Skip array access
678-
if (Token::simpleMatch(varTok, "["))
686+
if (hasUnknownVars(varTok))
679687
return tok;
680688
if (var->isVolatile())
681689
return tok;
@@ -692,44 +700,14 @@ static const Token * followVariableExpression(const Token * tok, bool cpp, const
692700
return tok;
693701
if (precedes(varTok, endToken) && isAliased(varTok, endToken, tok->varId()))
694702
return tok;
695-
if (varTok->exprId() != 0 && isVariableChanged(nextAfterAstRightmostLeaf(varTok), endToken, varTok->exprId(), false, nullptr, cpp))
696-
return tok;
697-
// Start at beginning of initialization
698-
const Token * startToken = varTok;
699-
while (Token::Match(startToken, "%op%|.|(|{") && startToken->astOperand1())
700-
startToken = startToken->astOperand1();
701-
// Skip if the variable its referring to is modified
702-
for (const Token * tok2 = startToken; tok2 != endToken; tok2 = tok2->next()) {
703-
if (Token::simpleMatch(tok2, ";"))
704-
break;
705-
if (tok2->astParent() && tok2->isUnaryOp("*"))
703+
const Token* startToken = nextAfterAstRightmostLeaf(varTok);
704+
if (!startToken)
705+
startToken = varTok;
706+
if (varTok->exprId() == 0) {
707+
if (!varTok->isLiteral())
706708
return tok;
707-
if (tok2->tokType() == Token::eIncDecOp ||
708-
tok2->isAssignmentOp() ||
709-
Token::Match(tok2, "%name% .|[|++|--|%assign%")) {
710-
return tok;
711-
}
712-
if (Token::Match(tok2, "%name% ("))
713-
// Bailout when function call is seen
714-
return tok;
715-
if (const Variable * var2 = tok2->variable()) {
716-
if (!var2->scope())
717-
return tok;
718-
const Token * endToken2 = var2->scope() != tok->scope() ? var2->scope()->bodyEnd : endToken;
719-
if (!var2->isLocal() && !var2->isConst() && !var2->isArgument())
720-
return tok;
721-
if (var2->isStatic() && !var2->isConst())
722-
return tok;
723-
if (!var2->isConst() && (!precedes(tok2, endToken2) || isVariableChanged(tok2, endToken2, tok2->varId(), false, nullptr, cpp)))
724-
return tok;
725-
if (precedes(tok2, endToken2) && isAliased(tok2, endToken2, tok2->varId()))
726-
return tok;
727-
// Recognized as a variable but the declaration is unknown
728-
} else if (tok2->varId() > 0) {
729-
return tok;
730-
} else if (tok2->tokType() == Token::eName && !Token::Match(tok2, "sizeof|decltype|typeof") && !tok2->function()) {
731-
return tok;
732-
}
709+
} else if (isExpressionChanged(varTok, startToken, endToken, nullptr, cpp)) {
710+
return tok;
733711
}
734712
return varTok;
735713
}

lib/symboldatabase.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1433,7 +1433,7 @@ void SymbolDatabase::createSymbolDatabaseExprIds()
14331433
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
14341434
if (tok->varId() > 0) {
14351435
tok->exprId(tok->varId());
1436-
} else if (Token::Match(tok, "(|.|%cop%")) {
1436+
} else if (Token::Match(tok, "(|.|[|%cop%")) {
14371437
exprs[tok->str()].push_back(tok);
14381438
tok->exprId(id++);
14391439
}

test/testother.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4953,13 +4953,13 @@ class TestOther : public TestFixture {
49534953
" const int i = sizeof(int);\n"
49544954
" if ( i != sizeof (int)){}\n"
49554955
"}\n");
4956-
TODO_ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (style) The comparison 'i != sizeof(int)' is always false because 'i' and 'sizeof(int)' represent the same value.\n", "", errout.str());
4956+
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (style) The comparison 'i != sizeof(int)' is always false because 'i' and 'sizeof(int)' represent the same value.\n", errout.str());
49574957

49584958
check("void f() {\n"
49594959
" const int i = sizeof(int);\n"
49604960
" if ( sizeof (int) != i){}\n"
49614961
"}\n");
4962-
TODO_ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (style) The comparison 'sizeof(int) != i' is always false because 'sizeof(int)' and 'i' represent the same value.\n", "", errout.str());
4962+
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (style) The comparison 'sizeof(int) != i' is always false because 'sizeof(int)' and 'i' represent the same value.\n", errout.str());
49634963

49644964
check("void f(int a = 1) { if ( a != 1){}}\n");
49654965
ASSERT_EQUALS("", errout.str());
@@ -5100,7 +5100,7 @@ class TestOther : public TestFixture {
51005100
check("struct A { int f() const; };\n"
51015101
"A g();\n"
51025102
"void foo() {\n"
5103-
" for (const A x = A();;) {\n"
5103+
" for (A x = A();;) {\n"
51045104
" const int a = x.f();\n"
51055105
" x = g();\n"
51065106
" if (x.f() == a) break;\n"
@@ -5506,6 +5506,30 @@ class TestOther : public TestFixture {
55065506
" if (!b && g()) {}\n"
55075507
"}\n");
55085508
ASSERT_EQUALS("", errout.str());
5509+
5510+
check("void f(bool *a) {\n"
5511+
" const bool b = a[42];\n"
5512+
" if( b == !(a[42]) ) {}\n"
5513+
"}\n");
5514+
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (style) Opposite expression on both sides of '=='.\n", errout.str());
5515+
5516+
check("void f(bool *a) {\n"
5517+
" const bool b = a[42];\n"
5518+
" if( a[42] == !(b) ) {}\n"
5519+
"}\n");
5520+
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (style) Opposite expression on both sides of '=='.\n", errout.str());
5521+
5522+
check("void f(bool *a) {\n"
5523+
" const bool b = *a;\n"
5524+
" if( b == !(*a) ) {}\n"
5525+
"}\n");
5526+
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (style) Opposite expression on both sides of '=='.\n", errout.str());
5527+
5528+
check("void f(bool *a) {\n"
5529+
" const bool b = *a;\n"
5530+
" if( *a == !(b) ) {}\n"
5531+
"}\n");
5532+
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (style) Opposite expression on both sides of '=='.\n", errout.str());
55095533
}
55105534

55115535
void duplicateVarExpression() {

0 commit comments

Comments
 (0)