diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 5fe9eebe8..ae7d7ac07 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1564,6 +1564,11 @@ static void valueFlowImpossibleValues(TokenList* tokenList, const Settings* sett value.bound = ValueFlow::Value::Bound::Lower; value.setImpossible(); setTokenValue(tok, value, settings); + } else if (Token::Match(tok, "abs|labs|llabs|fabs|fabsf|fabsl (")) { + ValueFlow::Value value{-1}; + value.bound = ValueFlow::Value::Bound::Upper; + value.setImpossible(); + setTokenValue(tok->next(), value, settings); } } } @@ -4058,6 +4063,34 @@ static void valueFlowSymbolic(TokenList* tokenlist, SymbolDatabase* symboldataba } } +static void valueFlowSymbolicAbs(TokenList* tokenlist, SymbolDatabase* symboldatabase) +{ + for (const Scope* scope : symboldatabase->functionScopes) { + for (Token* tok = const_cast(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) { + if (!Token::Match(tok, "abs|labs|llabs|fabs|fabsf|fabsl (")) + continue; + if (tok->hasKnownIntValue()) + continue; + + const Token* arg = tok->next()->astOperand2(); + if (!arg) + continue; + ValueFlow::Value c = inferCondition(">=", arg, 0); + if (!c.isKnown()) + continue; + + ValueFlow::Value v = makeSymbolic(arg); + v.errorPath = c.errorPath; + v.errorPath.emplace_back(tok, "Passed to " + tok->str()); + if (c.intvalue == 0) + v.setImpossible(); + else + v.setKnown(); + setTokenValue(tok->next(), v, tokenlist->getSettings()); + } + } +} + static void valueFlowSymbolicInfer(TokenList* tokenlist, SymbolDatabase* symboldatabase) { for (const Scope* scope : symboldatabase->functionScopes) { @@ -4108,6 +4141,10 @@ static void valueFlowSymbolicInfer(TokenList* tokenlist, SymbolDatabase* symbold value.valueKind = rhs->valueKind; value.errorPath = rhs->errorPath; } + if (Token::Match(tok, "%comp%") && value.isImpossible() && value.intvalue != 0) { + value.intvalue = 0; + value.setKnown(); + } setTokenValue(tok, value, tokenlist->getSettings()); } } @@ -4632,7 +4669,6 @@ struct ConditionHandler { return; } // *INDENT-ON* - } } @@ -7055,6 +7091,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase, while (n > 0 && values < getTotalValues(tokenlist)) { values = getTotalValues(tokenlist); valueFlowImpossibleValues(tokenlist, settings); + valueFlowSymbolicAbs(tokenlist, symboldatabase); valueFlowSymbolicInfer(tokenlist, symboldatabase); valueFlowArrayBool(tokenlist); valueFlowRightShift(tokenlist, settings); diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 64b4cd9b6..a7bbdf2ee 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -3728,6 +3728,28 @@ private: "}\n"); ASSERT_EQUALS("", errout.str()); + // #7843 + check("void f(int i) {\n" + " if(abs(i) == -1) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2]: (style) Condition 'abs(i)==-1' is always false\n", errout.str()); + + // #7844 + check("void f(int i) {\n" + " if(i > 0 && abs(i) == i) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2]: (style) Condition 'abs(i)==i' is always true\n", errout.str()); + + check("void f(int i) {\n" + " if(i < 0 && abs(i) == i) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2]: (style) Condition 'abs(i)==i' is always false\n", errout.str()); + + check("void f(int i) {\n" + " if(i > -3 && abs(i) == i) {}\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + // #9948 check("bool f(bool a, bool b) {\n" " return a || ! b || ! a;\n"