Fixed #7513 (value flow of array dimension with enum doesn't always work)
This commit is contained in:
parent
50352c8d69
commit
66cacde3db
|
@ -1284,25 +1284,18 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
}
|
}
|
||||||
// check for qualified enumerator
|
// check for qualified enumerator
|
||||||
else if (dimension.end) {
|
else if (dimension.end) {
|
||||||
if (dimension.end->enumerator()) {
|
// rhs of [
|
||||||
if (dimension.end->enumerator()->value_known) {
|
const Token *rhs = dimension.start->previous()->astOperand2();
|
||||||
dimension.num = dimension.end->enumerator()->value;
|
|
||||||
|
if (rhs) {
|
||||||
|
// constant folding of expression:
|
||||||
|
ValueFlow::valueFlowConstantFoldAST(rhs);
|
||||||
|
|
||||||
|
// get constant folded value:
|
||||||
|
if (rhs->values.size() == 1U && rhs->values.front().isKnown()) {
|
||||||
|
dimension.num = rhs->values.front().intvalue;
|
||||||
dimension.known = true;
|
dimension.known = true;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// rhs of [
|
|
||||||
const Token *rhs = dimension.start->previous()->astOperand2();
|
|
||||||
|
|
||||||
if (rhs) {
|
|
||||||
// constant folding of expression:
|
|
||||||
ValueFlow::valueFlowConstantFoldAST(rhs);
|
|
||||||
|
|
||||||
// get constant folded value:
|
|
||||||
if (rhs->values.size() == 1U && rhs->values.front().isKnown()) {
|
|
||||||
dimension.num = rhs->values.front().intvalue;
|
|
||||||
dimension.known = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -578,9 +578,7 @@ static void valueFlowSetConstantValue(const Token *tok)
|
||||||
ValueFlow::Value value(MathLib::toLongNumber(tok->str()));
|
ValueFlow::Value value(MathLib::toLongNumber(tok->str()));
|
||||||
value.setKnown();
|
value.setKnown();
|
||||||
setTokenValue(const_cast<Token *>(tok), value);
|
setTokenValue(const_cast<Token *>(tok), value);
|
||||||
}
|
} else if (tok->enumerator() && tok->enumerator()->value_known) {
|
||||||
|
|
||||||
if (tok->enumerator() && tok->enumerator()->value_known) {
|
|
||||||
ValueFlow::Value value(tok->enumerator()->value);
|
ValueFlow::Value value(tok->enumerator()->value);
|
||||||
value.setKnown();
|
value.setKnown();
|
||||||
setTokenValue(const_cast<Token *>(tok), value);
|
setTokenValue(const_cast<Token *>(tok), value);
|
||||||
|
|
|
@ -246,6 +246,7 @@ private:
|
||||||
TEST_CASE(enum2);
|
TEST_CASE(enum2);
|
||||||
TEST_CASE(enum3);
|
TEST_CASE(enum3);
|
||||||
TEST_CASE(enum4);
|
TEST_CASE(enum4);
|
||||||
|
TEST_CASE(enum5);
|
||||||
|
|
||||||
TEST_CASE(isImplicitlyVirtual);
|
TEST_CASE(isImplicitlyVirtual);
|
||||||
TEST_CASE(isPure);
|
TEST_CASE(isPure);
|
||||||
|
@ -288,15 +289,19 @@ private:
|
||||||
TEST_CASE(valuetype);
|
TEST_CASE(valuetype);
|
||||||
}
|
}
|
||||||
|
|
||||||
void array() const {
|
void array() {
|
||||||
std::istringstream code("int a[10+2];");
|
GET_SYMBOL_DB_C("int a[10+2];");
|
||||||
TokenList list(nullptr);
|
ASSERT(db != nullptr);
|
||||||
list.createTokens(code, "test.c");
|
if (!db)
|
||||||
list.front()->tokAt(2)->link(list.front()->tokAt(6));
|
return;
|
||||||
Variable v(list.front()->next(), list.front(), list.back(), 0, Public, nullptr, nullptr, &settings.library);
|
ASSERT(db->getVariableListSize() == 2); // the first one is not used
|
||||||
ASSERT(v.isArray());
|
const Variable * v = db->getVariableFromVarId(1);
|
||||||
ASSERT_EQUALS(1U, v.dimensions().size());
|
ASSERT(v != nullptr);
|
||||||
ASSERT_EQUALS(0U, v.dimension(0));
|
if (!v)
|
||||||
|
return;
|
||||||
|
ASSERT(v->isArray());
|
||||||
|
ASSERT_EQUALS(1U, v->dimensions().size());
|
||||||
|
ASSERT_EQUALS(12U, v->dimension(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void stlarray() const {
|
void stlarray() const {
|
||||||
|
@ -2322,6 +2327,67 @@ private:
|
||||||
TODO_ASSERT_EQUALS(true, false, scope->enumeratorList[2].value_known);
|
TODO_ASSERT_EQUALS(true, false, scope->enumeratorList[2].value_known);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void enum5() {
|
||||||
|
GET_SYMBOL_DB("enum { A = 10, B = 2 };\n"
|
||||||
|
"int a[10 + 2];\n"
|
||||||
|
"int b[A];\n"
|
||||||
|
"int c[A + 2];\n"
|
||||||
|
"int d[10 + B];\n"
|
||||||
|
"int e[A + B];\n");
|
||||||
|
ASSERT(db);
|
||||||
|
if (!db)
|
||||||
|
return;
|
||||||
|
ASSERT_EQUALS(2U, db->scopeList.size());
|
||||||
|
|
||||||
|
// Assert that all enum values are known
|
||||||
|
std::list<Scope>::const_iterator scope = db->scopeList.begin();
|
||||||
|
|
||||||
|
++scope;
|
||||||
|
ASSERT_EQUALS((unsigned int)Scope::eEnum, (unsigned int)scope->type);
|
||||||
|
ASSERT_EQUALS(2U, scope->enumeratorList.size());
|
||||||
|
ASSERT_EQUALS(true, scope->enumeratorList[0].value_known);
|
||||||
|
ASSERT_EQUALS(10, scope->enumeratorList[0].value);
|
||||||
|
ASSERT_EQUALS(true, scope->enumeratorList[1].value_known);
|
||||||
|
ASSERT_EQUALS(2, scope->enumeratorList[1].value);
|
||||||
|
|
||||||
|
ASSERT(db->getVariableListSize() == 6); // the first one is not used
|
||||||
|
const Variable * v = db->getVariableFromVarId(1);
|
||||||
|
ASSERT(v != nullptr);
|
||||||
|
if (!v)
|
||||||
|
return;
|
||||||
|
ASSERT(v->isArray());
|
||||||
|
ASSERT_EQUALS(1U, v->dimensions().size());
|
||||||
|
ASSERT_EQUALS(12U, v->dimension(0));
|
||||||
|
v = db->getVariableFromVarId(2);
|
||||||
|
ASSERT(v != nullptr);
|
||||||
|
if (!v)
|
||||||
|
return;
|
||||||
|
ASSERT(v->isArray());
|
||||||
|
ASSERT_EQUALS(1U, v->dimensions().size());
|
||||||
|
ASSERT_EQUALS(10U, v->dimension(0));
|
||||||
|
v = db->getVariableFromVarId(3);
|
||||||
|
ASSERT(v != nullptr);
|
||||||
|
if (!v)
|
||||||
|
return;
|
||||||
|
ASSERT(v->isArray());
|
||||||
|
ASSERT_EQUALS(1U, v->dimensions().size());
|
||||||
|
ASSERT_EQUALS(12U, v->dimension(0));
|
||||||
|
v = db->getVariableFromVarId(4);
|
||||||
|
ASSERT(v != nullptr);
|
||||||
|
if (!v)
|
||||||
|
return;
|
||||||
|
ASSERT(v->isArray());
|
||||||
|
ASSERT_EQUALS(1U, v->dimensions().size());
|
||||||
|
ASSERT_EQUALS(12U, v->dimension(0));
|
||||||
|
v = db->getVariableFromVarId(5);
|
||||||
|
ASSERT(v != nullptr);
|
||||||
|
if (!v)
|
||||||
|
return;
|
||||||
|
ASSERT(v->isArray());
|
||||||
|
ASSERT_EQUALS(1U, v->dimensions().size());
|
||||||
|
ASSERT_EQUALS(12U, v->dimension(0));
|
||||||
|
}
|
||||||
|
|
||||||
void isImplicitlyVirtual() {
|
void isImplicitlyVirtual() {
|
||||||
{
|
{
|
||||||
GET_SYMBOL_DB("class Base {\n"
|
GET_SYMBOL_DB("class Base {\n"
|
||||||
|
|
Loading…
Reference in New Issue