Fix FP in solveExpr when using symbolic values (#3391)
This commit is contained in:
parent
e6cf4cad87
commit
0f897acecd
|
@ -2322,7 +2322,7 @@ struct ValueFlowAnalyzer : Analyzer {
|
|||
}
|
||||
};
|
||||
|
||||
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist);
|
||||
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist);
|
||||
|
||||
struct SingleValueFlowAnalyzer : ValueFlowAnalyzer {
|
||||
std::unordered_map<nonneg int, const Variable*> varids;
|
||||
|
@ -2580,52 +2580,43 @@ static const Token* parseBinaryIntOp(const Token* expr, MathLib::bigint& known)
|
|||
return varTok;
|
||||
}
|
||||
|
||||
template<class F>
|
||||
void transformIntValues(std::list<ValueFlow::Value>& values, F f)
|
||||
{
|
||||
std::transform(values.begin(), values.end(), values.begin(), [&](ValueFlow::Value x) {
|
||||
if (x.isIntValue() || x.isIteratorValue())
|
||||
x.intvalue = f(x.intvalue);
|
||||
return x;
|
||||
});
|
||||
}
|
||||
|
||||
static const Token* solveExprValues(const Token* expr, std::list<ValueFlow::Value>& values)
|
||||
static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
|
||||
{
|
||||
if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
|
||||
return expr;
|
||||
if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
|
||||
return expr;
|
||||
MathLib::bigint intval;
|
||||
const Token* binaryTok = parseBinaryIntOp(expr, intval);
|
||||
if (binaryTok && expr->str().size() == 1) {
|
||||
switch (expr->str()[0]) {
|
||||
case '+': {
|
||||
transformIntValues(values, [&](MathLib::bigint x) {
|
||||
return x - intval;
|
||||
});
|
||||
return solveExprValues(binaryTok, values);
|
||||
value.intvalue -= intval;
|
||||
return solveExprValue(binaryTok, value);
|
||||
}
|
||||
case '-': {
|
||||
value.intvalue += intval;
|
||||
return solveExprValue(binaryTok, value);
|
||||
}
|
||||
case '*': {
|
||||
if (intval == 0)
|
||||
break;
|
||||
transformIntValues(values, [&](MathLib::bigint x) {
|
||||
return x / intval;
|
||||
});
|
||||
return solveExprValues(binaryTok, values);
|
||||
value.intvalue /= intval;
|
||||
return solveExprValue(binaryTok, value);
|
||||
}
|
||||
case '^': {
|
||||
transformIntValues(values, [&](MathLib::bigint x) {
|
||||
return x ^ intval;
|
||||
});
|
||||
return solveExprValues(binaryTok, values);
|
||||
value.intvalue ^= intval;
|
||||
return solveExprValue(binaryTok, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist)
|
||||
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist)
|
||||
{
|
||||
std::list<ValueFlow::Value> values = {value};
|
||||
const Token* expr = solveExprValues(exprTok, values);
|
||||
return ExpressionAnalyzer(expr, values.front(), tokenlist);
|
||||
const Token* expr = solveExprValue(exprTok, value);
|
||||
return ExpressionAnalyzer(expr, value, tokenlist);
|
||||
}
|
||||
|
||||
static Analyzer::Result valueFlowForward(Token* startToken,
|
||||
|
@ -2635,8 +2626,11 @@ static Analyzer::Result valueFlowForward(Token* startToken,
|
|||
TokenList* const tokenlist,
|
||||
const Settings* settings)
|
||||
{
|
||||
const Token* expr = solveExprValues(exprTok, values);
|
||||
return valueFlowForwardExpression(startToken, endToken, expr, values, tokenlist, settings);
|
||||
Analyzer::Result result{};
|
||||
for (const ValueFlow::Value& v : values) {
|
||||
result.update(valueFlowGenericForward(startToken, endToken, makeAnalyzer(exprTok, v, tokenlist), settings));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Analyzer::Result valueFlowForward(Token* top,
|
||||
|
|
|
@ -6028,6 +6028,19 @@ private:
|
|||
ASSERT_EQUALS(false, testValueOfXKnown(code, 4U, "i", 0));
|
||||
ASSERT_EQUALS(false, testValueOfXKnown(code, 4U, "i", 1));
|
||||
ASSERT_EQUALS(true, testValueOfXKnown(code, 4U, "j", 0));
|
||||
|
||||
code = "void f(int x) {\n"
|
||||
" int y = x + 1;\n"
|
||||
" return x;\n"
|
||||
"}\n";
|
||||
ASSERT_EQUALS(false, testValueOfXKnown(code, 3U, "y", 0));
|
||||
ASSERT_EQUALS(true, testValueOfXKnown(code, 3U, "y", -1));
|
||||
|
||||
code = "void f(int x) {\n"
|
||||
" int y = x * 2;\n"
|
||||
" return x;\n"
|
||||
"}\n";
|
||||
ASSERT_EQUALS(false, testValueOfXKnown(code, 3U, "y", 0));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue