Fix 7843 and 7844: ValueFlow for abs (#3373)
* Refactor: Use valueFlowForward to forward values in condition expression * Formattting * Make known when using bools as well * Set abs function as always positive * Add test * Add valueFlowSymbolicAbs * Set impossible values * Fix test case * Fix error messages * Merge
This commit is contained in:
parent
c630be7f8f
commit
7be9b217e6
|
@ -1564,6 +1564,11 @@ static void valueFlowImpossibleValues(TokenList* tokenList, const Settings* sett
|
||||||
value.bound = ValueFlow::Value::Bound::Lower;
|
value.bound = ValueFlow::Value::Bound::Lower;
|
||||||
value.setImpossible();
|
value.setImpossible();
|
||||||
setTokenValue(tok, value, settings);
|
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<Token*>(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)
|
static void valueFlowSymbolicInfer(TokenList* tokenlist, SymbolDatabase* symboldatabase)
|
||||||
{
|
{
|
||||||
for (const Scope* scope : symboldatabase->functionScopes) {
|
for (const Scope* scope : symboldatabase->functionScopes) {
|
||||||
|
@ -4108,6 +4141,10 @@ static void valueFlowSymbolicInfer(TokenList* tokenlist, SymbolDatabase* symbold
|
||||||
value.valueKind = rhs->valueKind;
|
value.valueKind = rhs->valueKind;
|
||||||
value.errorPath = rhs->errorPath;
|
value.errorPath = rhs->errorPath;
|
||||||
}
|
}
|
||||||
|
if (Token::Match(tok, "%comp%") && value.isImpossible() && value.intvalue != 0) {
|
||||||
|
value.intvalue = 0;
|
||||||
|
value.setKnown();
|
||||||
|
}
|
||||||
setTokenValue(tok, value, tokenlist->getSettings());
|
setTokenValue(tok, value, tokenlist->getSettings());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4632,7 +4669,6 @@ struct ConditionHandler {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// *INDENT-ON*
|
// *INDENT-ON*
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7055,6 +7091,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
|
||||||
while (n > 0 && values < getTotalValues(tokenlist)) {
|
while (n > 0 && values < getTotalValues(tokenlist)) {
|
||||||
values = getTotalValues(tokenlist);
|
values = getTotalValues(tokenlist);
|
||||||
valueFlowImpossibleValues(tokenlist, settings);
|
valueFlowImpossibleValues(tokenlist, settings);
|
||||||
|
valueFlowSymbolicAbs(tokenlist, symboldatabase);
|
||||||
valueFlowSymbolicInfer(tokenlist, symboldatabase);
|
valueFlowSymbolicInfer(tokenlist, symboldatabase);
|
||||||
valueFlowArrayBool(tokenlist);
|
valueFlowArrayBool(tokenlist);
|
||||||
valueFlowRightShift(tokenlist, settings);
|
valueFlowRightShift(tokenlist, settings);
|
||||||
|
|
|
@ -3728,6 +3728,28 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
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
|
// #9948
|
||||||
check("bool f(bool a, bool b) {\n"
|
check("bool f(bool a, bool b) {\n"
|
||||||
" return a || ! b || ! a;\n"
|
" return a || ! b || ! a;\n"
|
||||||
|
|
Loading…
Reference in New Issue