ValueFlow: Propagate const variables more aggressively (#3606)

* ValueFlow: Propagate const variables more aggressively

* Format

* Fix incorrect addition
This commit is contained in:
Paul Fultz II 2021-12-06 02:16:42 -06:00 committed by GitHub
parent 5fd17ef2c2
commit d2926bfa96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 126 additions and 0 deletions

View File

@ -4764,6 +4764,57 @@ static void valueFlowSymbolicInfer(TokenList* tokenlist, SymbolDatabase* symbold
}
}
static void valueFlowForwardConst(Token* start,
const Token* end,
const Variable* var,
const std::list<ValueFlow::Value>& values,
const Settings* const settings)
{
for (Token* tok = start; tok != end; tok = tok->next()) {
if (tok->varId() == var->declarationId()) {
for (const ValueFlow::Value& value : values)
setTokenValue(tok, value, settings);
} else {
[&] {
// Follow references
std::vector<ReferenceToken> refs = followAllReferences(tok);
ValueFlow::Value::ValueKind refKind =
refs.size() == 1 ? ValueFlow::Value::ValueKind::Known : ValueFlow::Value::ValueKind::Inconclusive;
for (const ReferenceToken& ref : refs) {
if (ref.token->varId() == var->declarationId()) {
for (ValueFlow::Value value : values) {
value.valueKind = refKind;
value.errorPath.insert(value.errorPath.end(), ref.errors.begin(), ref.errors.end());
setTokenValue(tok, value, settings);
}
return;
}
}
// Follow symbolic vaues
for (const ValueFlow::Value& v : tok->values()) {
if (!v.isSymbolicValue())
continue;
if (!v.tokvalue)
continue;
if (v.tokvalue->varId() != var->declarationId())
continue;
for (ValueFlow::Value value : values) {
if (v.intvalue != 0) {
if (!value.isIntValue())
continue;
value.intvalue += v.intvalue;
}
value.valueKind = v.valueKind;
value.bound = v.bound;
value.errorPath.insert(value.errorPath.end(), v.errorPath.begin(), v.errorPath.end());
setTokenValue(tok, value, settings);
}
}
}();
}
}
}
static void valueFlowForwardAssign(Token* const tok,
const Token* expr,
std::vector<const Variable*> vars,
@ -4826,6 +4877,25 @@ static void valueFlowForwardAssign(Token* const tok,
continue;
value.tokvalue = tok;
}
// Const variable
if (expr->variable() && expr->variable()->isConst() && !expr->variable()->isReference()) {
auto it = std::remove_if(values.begin(), values.end(), [](const ValueFlow::Value& value) {
if (!value.isKnown())
return false;
if (value.isIntValue())
return true;
if (value.isFloatValue())
return true;
if (value.isContainerSizeValue())
return true;
if (value.isIteratorValue())
return true;
return false;
});
std::list<ValueFlow::Value> constValues;
constValues.splice(constValues.end(), values, it, values.end());
valueFlowForwardConst(const_cast<Token*>(nextExpression), endOfVarScope, expr->variable(), constValues, settings);
}
valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, expr, values, tokenlist, settings);
}

View File

@ -96,6 +96,7 @@ private:
TEST_CASE(valueFlowForwardLambda);
TEST_CASE(valueFlowForwardTryCatch);
TEST_CASE(valueFlowForwardInconclusiveImpossible);
TEST_CASE(valueFlowForwardConst);
TEST_CASE(valueFlowFwdAnalysis);
@ -3516,6 +3517,61 @@ private:
ASSERT_EQUALS(false, testValueOfXKnown(code, 6U, 1));
}
void valueFlowForwardConst()
{
const char* code;
code = "int f() {\n"
" const int i = 2;\n"
" const int x = i+1;\n"
" goto end;\n"
"end:\n"
" return x;\n"
"}\n";
ASSERT_EQUALS(true, testValueOfXKnown(code, 6U, 3));
code = "int f() {\n"
" int i = 2;\n"
" const int& x = i;\n"
" i++;\n"
" return x;\n"
"}\n";
ASSERT_EQUALS(false, testValueOfXKnown(code, 6U, 2));
code = "int f(int a, int b, int c) {\n"
" const int i = 2;\n"
" const int x = i+1;\n"
" if (a == x) { return 0; }\n"
" if (b == x) { return 0; }\n"
" if (c == x) { return 0; }\n"
" return x;\n"
"}\n";
ASSERT_EQUALS(true, testValueOfXKnown(code, 7U, 3));
code = "int f(int a, int b, int c) {\n"
" const int i = 2;\n"
" const int y = i+1;\n"
" const int& x = y;\n"
" if (a == x) { return 0; }\n"
" if (b == x) { return 0; }\n"
" if (c == x) { return 0; }\n"
" return x;\n"
"}\n";
ASSERT_EQUALS(true, testValueOfXKnown(code, 8U, 3));
code = "int f(int a, int b, int c, int x) {\n"
" const int i = 2;\n"
" const int y = i+1;\n"
" if (a == y) { return 0; }\n"
" if (b == y) { return 0; }\n"
" if (c == y) { return 0; }\n"
" if (x == y)\n"
" return x;\n"
" return 0;\n"
"}\n";
ASSERT_EQUALS(true, testValueOfXKnown(code, 8U, 3));
}
void valueFlowRightShift() {
const char *code;
/* Set some temporary fixed values to simplify testing */