Fix issue 6856: add checks in isOppositeCond when using == and < or > (#1298)
* Fix issue 6856: add checks in isOppositeCond when using == and < or > * Move tests to testcondition * Fix some more tests * Fix test messages * Remove the float check
This commit is contained in:
parent
13cf982b77
commit
b839ad60dd
|
@ -395,7 +395,10 @@ bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token
|
|||
(comp1 == ">" && comp2 == "<=") ||
|
||||
(comp1 == ">=" && comp2 == "<") ||
|
||||
(!isNot && ((comp1 == "<" && comp2 == ">") ||
|
||||
(comp1 == ">" && comp2 == "<"))));
|
||||
(comp1 == ">" && comp2 == "<") ||
|
||||
(comp1 == "==" && (comp2 == "!=" || comp2 == ">" || comp2 == "<")) ||
|
||||
((comp1 == "!=" || comp1 == ">" || comp1 == "<") && comp2 == "==")
|
||||
)));
|
||||
}
|
||||
|
||||
bool isOppositeExpression(bool cpp, const Token * const tok1, const Token * const tok2, const Library& library, bool pure)
|
||||
|
|
|
@ -861,6 +861,28 @@ static std::string conditionString(bool not1, const Token *expr1, const std::str
|
|||
(expr1->isName() ? expr1->str() : std::string("EXPR"));
|
||||
}
|
||||
|
||||
static std::string conditionString(const Token * tok)
|
||||
{
|
||||
if(!tok)
|
||||
return "";
|
||||
if(tok->isComparisonOp()) {
|
||||
bool inconclusive = false;
|
||||
bool not_;
|
||||
std::string op, value;
|
||||
const Token *expr;
|
||||
if(parseComparison(tok, ¬_, &op, &value, &expr, &inconclusive) && expr->isName()) {
|
||||
return conditionString(not_, expr, op, value);
|
||||
}
|
||||
}
|
||||
if(Token::Match(tok, "%cop%|&&|%oror%")) {
|
||||
if(tok->astOperand2())
|
||||
return conditionString(tok->astOperand1()) + " " + tok->str() + " " + conditionString(tok->astOperand2());
|
||||
return tok->str() + "(" + conditionString(tok->astOperand1()) + ")";
|
||||
|
||||
}
|
||||
return tok->expressionString();
|
||||
}
|
||||
|
||||
void CheckCondition::checkIncorrectLogicOperator()
|
||||
{
|
||||
const bool printStyle = mSettings->isEnabled(Settings::STYLE);
|
||||
|
@ -876,14 +898,6 @@ void CheckCondition::checkIncorrectLogicOperator()
|
|||
if (!Token::Match(tok, "%oror%|&&") || !tok->astOperand1() || !tok->astOperand2())
|
||||
continue;
|
||||
|
||||
// Opposite comparisons around || or && => always true or always false
|
||||
if ((tok->astOperand1()->isName() || tok->astOperand2()->isName()) &&
|
||||
isOppositeCond(true, mTokenizer->isCPP(), tok->astOperand1(), tok->astOperand2(), mSettings->library, true)) {
|
||||
|
||||
const bool alwaysTrue(tok->str() == "||");
|
||||
incorrectLogicOperatorError(tok, tok->expressionString(), alwaysTrue, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 'A && (!A || B)' is equivalent to 'A && B'
|
||||
// 'A || (!A && B)' is equivalent to 'A || B'
|
||||
|
@ -934,36 +948,48 @@ void CheckCondition::checkIncorrectLogicOperator()
|
|||
const Token *comp2 = tok->astOperand2();
|
||||
|
||||
bool inconclusive = false;
|
||||
bool parseable = true;
|
||||
|
||||
// Parse LHS
|
||||
bool not1;
|
||||
std::string op1, value1;
|
||||
const Token *expr1;
|
||||
if (!parseComparison(comp1, ¬1, &op1, &value1, &expr1, &inconclusive))
|
||||
continue;
|
||||
const Token *expr1 = nullptr;
|
||||
parseable &= (parseComparison(comp1, ¬1, &op1, &value1, &expr1, &inconclusive));
|
||||
|
||||
// Parse RHS
|
||||
bool not2;
|
||||
std::string op2, value2;
|
||||
const Token *expr2;
|
||||
if (!parseComparison(comp2, ¬2, &op2, &value2, &expr2, &inconclusive))
|
||||
continue;
|
||||
const Token *expr2 = nullptr;
|
||||
parseable &= (parseComparison(comp2, ¬2, &op2, &value2, &expr2, &inconclusive));
|
||||
|
||||
if (inconclusive && !printInconclusive)
|
||||
continue;
|
||||
|
||||
const bool isfloat = astIsFloat(expr1, true) || MathLib::isFloat(value1) || astIsFloat(expr2, true) || MathLib::isFloat(value2);
|
||||
|
||||
// Opposite comparisons around || or && => always true or always false
|
||||
if (!isfloat && isOppositeCond(tok->str() == "||", mTokenizer->isCPP(), tok->astOperand1(), tok->astOperand2(), mSettings->library, true)) {
|
||||
|
||||
const bool alwaysTrue(tok->str() == "||");
|
||||
incorrectLogicOperatorError(tok, conditionString(tok), alwaysTrue, inconclusive);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!parseable)
|
||||
continue;
|
||||
|
||||
if (isSameExpression(mTokenizer->isCPP(), true, comp1, comp2, mSettings->library, true))
|
||||
continue; // same expressions => only report that there are same expressions
|
||||
if (!isSameExpression(mTokenizer->isCPP(), true, expr1, expr2, mSettings->library, true))
|
||||
continue;
|
||||
|
||||
const bool isfloat = astIsFloat(expr1, true) || MathLib::isFloat(value1) || astIsFloat(expr2, true) || MathLib::isFloat(value2);
|
||||
|
||||
// don't check floating point equality comparisons. that is bad
|
||||
// and deserves different warnings.
|
||||
if (isfloat && (op1 == "==" || op1 == "!=" || op2 == "==" || op2 == "!="))
|
||||
continue;
|
||||
|
||||
|
||||
const double d1 = (isfloat) ? MathLib::toDoubleNumber(value1) : 0;
|
||||
const double d2 = (isfloat) ? MathLib::toDoubleNumber(value2) : 0;
|
||||
const MathLib::bigint i1 = (isfloat) ? 0 : MathLib::toLongNumber(value1);
|
||||
|
|
|
@ -70,6 +70,7 @@ private:
|
|||
TEST_CASE(incorrectLogicOperator8); // !
|
||||
TEST_CASE(incorrectLogicOperator9);
|
||||
TEST_CASE(incorrectLogicOperator10); // enum
|
||||
TEST_CASE(incorrectLogicOperator11);
|
||||
TEST_CASE(secondAlwaysTrueFalseWhenFirstTrueError);
|
||||
TEST_CASE(incorrectLogicOp_condSwapping);
|
||||
TEST_CASE(testBug5895);
|
||||
|
@ -1162,12 +1163,12 @@ private:
|
|||
check("void f(int i) {\n"
|
||||
" if (i || !i) {}\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:2]: (warning) Logical disjunction always evaluates to true: i||!i.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:2]: (warning) Logical disjunction always evaluates to true: i || !(i).\n", errout.str());
|
||||
|
||||
check("void f(int a, int b) {\n"
|
||||
" if (a>b || a<=b) {}\n"
|
||||
"}");
|
||||
TODO_ASSERT_EQUALS("[test.cpp:2]: (warning) Logical disjunction always evaluates to true: a>b||a<=b.\n", "", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:2]: (warning) Logical disjunction always evaluates to true: a > b || a <= b.\n", errout.str());
|
||||
|
||||
check("void f(int a, int b) {\n"
|
||||
" if (a>b || a<b) {}\n"
|
||||
|
@ -1218,6 +1219,20 @@ private:
|
|||
ASSERT_EQUALS("[test.cpp:3]: (warning) Logical conjunction always evaluates to false: t == 0 && t == 1.\n", errout.str());
|
||||
}
|
||||
|
||||
void incorrectLogicOperator11() {
|
||||
check("void foo(int i, const int n) { if ( i < n && i == n ) {} }");
|
||||
ASSERT_EQUALS("[test.cpp:1]: (warning) Logical conjunction always evaluates to false: i < n && i == n.\n", errout.str());
|
||||
|
||||
check("void foo(int i, const int n) { if ( i > n && i == n ) {} }");
|
||||
ASSERT_EQUALS("[test.cpp:1]: (warning) Logical conjunction always evaluates to false: i > n && i == n.\n", errout.str());
|
||||
|
||||
check("void foo(int i, const int n) { if ( i == n && i > n ) {} }");
|
||||
ASSERT_EQUALS("[test.cpp:1]: (warning) Logical conjunction always evaluates to false: i == n && i > n.\n", errout.str());
|
||||
|
||||
check("void foo(int i, const int n) { if ( i == n && i < n ) {} }");
|
||||
ASSERT_EQUALS("[test.cpp:1]: (warning) Logical conjunction always evaluates to false: i == n && i < n.\n", errout.str());
|
||||
}
|
||||
|
||||
void secondAlwaysTrueFalseWhenFirstTrueError() {
|
||||
check("void f(int x) {\n"
|
||||
" if (x > 5 && x != 1)\n"
|
||||
|
|
Loading…
Reference in New Issue