Fixed #7523 (Scope::findEnumerator(): does not find enum constant from other enum type)

This commit is contained in:
Robert Reif 2016-05-29 14:45:45 +02:00 committed by Daniel Marjamäki
parent d0a1a3123c
commit f4dd43a71a
2 changed files with 118 additions and 52 deletions

View File

@ -1206,6 +1206,61 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
}
}
// fill in enumerators in enum
for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) {
if (it->type != Scope::eEnum)
continue;
// add enumerators to enumerator tokens
for (std::size_t i = 0, end = it->enumeratorList.size(); i < end; ++i)
const_cast<Token *>(it->enumeratorList[i].name)->enumerator(&it->enumeratorList[i]);
}
// fill in enumerator values
for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) {
if (it->type != Scope::eEnum)
continue;
MathLib::bigint value = 0;
for (std::size_t i = 0, end = it->enumeratorList.size(); i < end; ++i) {
Enumerator & enumerator = it->enumeratorList[i];
// look for initialization tokens that can be converted to enumerators and convert them
if (enumerator.start) {
for (const Token * tok3 = enumerator.start; tok3 && tok3 != enumerator.end->next(); tok3 = tok3->next()) {
if (tok3->tokType() == Token::eName) {
const Enumerator * e = findEnumerator(tok3);
if (e)
const_cast<Token *>(tok3)->enumerator(e);
}
}
// look for possible constant folding expressions
if (enumerator.start) {
// rhs of operator:
const Token *rhs = enumerator.start->previous()->astOperand2();
// constant folding of expression:
ValueFlow::valueFlowConstantFoldAST(rhs);
// get constant folded value:
if (rhs && rhs->values.size() == 1U && rhs->values.front().isKnown()) {
enumerator.value = rhs->values.front().intvalue;
enumerator.value_known = true;
value = enumerator.value + 1;
}
}
}
// not initialized so use default value
else {
enumerator.value = value++;
enumerator.value_known = true;
}
}
}
// find enumerators
for (const Token* tok = _tokenizer->list.front(); tok != _tokenizer->list.back(); tok = tok->next()) {
if (tok->tokType() != Token::eName)
@ -3256,52 +3311,6 @@ const Token * Scope::addEnum(const Token * tok, bool isCpp)
} else
tok2 = nullptr;
if (tok2) {
// add enumerators to enumerator tokens
for (std::size_t i = 0, end = enumeratorList.size(); i < end; ++i)
const_cast<Token *>(enumeratorList[i].name)->enumerator(&enumeratorList[i]);
MathLib::bigint value = 0;
// fill in enumerator values
for (std::size_t i = 0, end = enumeratorList.size(); i < end; ++i) {
Enumerator & enumerator = enumeratorList[i];
// look for initialization tokens that can be converted to enumerators and convert them
if (enumerator.start) {
for (const Token * tok3 = enumerator.start; tok3 && tok3 != enumerator.end->next(); tok3 = tok3->next()) {
if (tok3->tokType() == Token::eName) {
const Enumerator * e = findEnumerator(tok3->str());
if (e)
const_cast<Token *>(tok3)->enumerator(e);
}
}
// look for possible constant folding expressions
if (enumerator.start) {
// rhs of operator:
const Token *rhs = enumerator.start->previous()->astOperand2();
// constant folding of expression:
ValueFlow::valueFlowConstantFoldAST(rhs);
// get constant folded value:
if (rhs && rhs->values.size() == 1U && rhs->values.front().isKnown()) {
enumerator.value = rhs->values.front().intvalue;
enumerator.value_known = true;
value = enumerator.value + 1;
}
}
}
// not initialized so use default value
else {
enumerator.value = value++;
enumerator.value_known = true;
}
}
}
return tok2;
}

View File

@ -2300,8 +2300,8 @@ private:
}
void enum4() { // #7493
GET_SYMBOL_DB("enum Offsets { O1, O2, O3 };\n"
"enum MyEnums { E1=O1+1, E2=O2+1, E3=O3+1 };");
GET_SYMBOL_DB("enum Offsets { O1, O2, O3=5, O4 };\n"
"enum MyEnums { E1=O1+1, E2, E3=O3+1 };");
ASSERT(db != nullptr);
if (!db)
return;
@ -2313,18 +2313,75 @@ private:
// Offsets
++scope;
ASSERT_EQUALS((unsigned int)Scope::eEnum, (unsigned int)scope->type);
ASSERT_EQUALS(3U, scope->enumeratorList.size());
ASSERT_EQUALS(4U, scope->enumeratorList.size());
ASSERT(scope->enumeratorList[0].name->enumerator() == &scope->enumeratorList[0]);
ASSERT_EQUALS((unsigned int)Token::eEnumerator, (unsigned int)scope->enumeratorList[0].name->tokType());
ASSERT(scope->enumeratorList[0].scope == &*scope);
ASSERT_EQUALS("O1", scope->enumeratorList[0].name->str());
ASSERT(scope->enumeratorList[0].start == nullptr);
ASSERT(scope->enumeratorList[0].end == nullptr);
ASSERT_EQUALS(true, scope->enumeratorList[0].value_known);
ASSERT_EQUALS(0, scope->enumeratorList[0].value);
ASSERT(scope->enumeratorList[1].name->enumerator() == &scope->enumeratorList[1]);
ASSERT_EQUALS((unsigned int)Token::eEnumerator, (unsigned int)scope->enumeratorList[1].name->tokType());
ASSERT(scope->enumeratorList[1].scope == &*scope);
ASSERT_EQUALS("O2", scope->enumeratorList[1].name->str());
ASSERT(scope->enumeratorList[1].start == nullptr);
ASSERT(scope->enumeratorList[1].end == nullptr);
ASSERT_EQUALS(true, scope->enumeratorList[1].value_known);
ASSERT_EQUALS(1, scope->enumeratorList[1].value);
ASSERT(scope->enumeratorList[2].name->enumerator() == &scope->enumeratorList[2]);
ASSERT_EQUALS((unsigned int)Token::eEnumerator, (unsigned int)scope->enumeratorList[2].name->tokType());
ASSERT(scope->enumeratorList[2].scope == &*scope);
ASSERT_EQUALS("O3", scope->enumeratorList[2].name->str());
ASSERT(scope->enumeratorList[2].start != nullptr);
ASSERT(scope->enumeratorList[2].end != nullptr);
ASSERT_EQUALS(true, scope->enumeratorList[2].value_known);
ASSERT_EQUALS(5, scope->enumeratorList[2].value);
ASSERT(scope->enumeratorList[3].name->enumerator() == &scope->enumeratorList[3]);
ASSERT_EQUALS((unsigned int)Token::eEnumerator, (unsigned int)scope->enumeratorList[3].name->tokType());
ASSERT(scope->enumeratorList[3].scope == &*scope);
ASSERT_EQUALS("O4", scope->enumeratorList[3].name->str());
ASSERT(scope->enumeratorList[3].start == nullptr);
ASSERT(scope->enumeratorList[3].end == nullptr);
ASSERT_EQUALS(true, scope->enumeratorList[3].value_known);
ASSERT_EQUALS(6, scope->enumeratorList[3].value);
// MyEnums
++scope;
ASSERT_EQUALS((unsigned int)Scope::eEnum, (unsigned int)scope->type);
ASSERT_EQUALS(3U, scope->enumeratorList.size());
TODO_ASSERT_EQUALS(true, false, scope->enumeratorList[0].value_known);
TODO_ASSERT_EQUALS(true, false, scope->enumeratorList[1].value_known);
TODO_ASSERT_EQUALS(true, false, scope->enumeratorList[2].value_known);
ASSERT(scope->enumeratorList[0].name->enumerator() == &scope->enumeratorList[0]);
ASSERT_EQUALS((unsigned int)Token::eEnumerator, (unsigned int)scope->enumeratorList[0].name->tokType());
ASSERT(scope->enumeratorList[0].scope == &*scope);
ASSERT_EQUALS("E1", scope->enumeratorList[0].name->str());
ASSERT(scope->enumeratorList[0].start != nullptr);
ASSERT(scope->enumeratorList[0].end != nullptr);
ASSERT_EQUALS(true, scope->enumeratorList[0].value_known);
ASSERT_EQUALS(1, scope->enumeratorList[0].value);
ASSERT(scope->enumeratorList[1].name->enumerator() == &scope->enumeratorList[1]);
ASSERT_EQUALS((unsigned int)Token::eEnumerator, (unsigned int)scope->enumeratorList[1].name->tokType());
ASSERT(scope->enumeratorList[1].scope == &*scope);
ASSERT_EQUALS("E2", scope->enumeratorList[1].name->str());
ASSERT(scope->enumeratorList[1].start == nullptr);
ASSERT(scope->enumeratorList[1].end == nullptr);
ASSERT_EQUALS(true, scope->enumeratorList[1].value_known);
ASSERT_EQUALS(2, scope->enumeratorList[1].value);
ASSERT(scope->enumeratorList[2].name->enumerator() == &scope->enumeratorList[2]);
ASSERT_EQUALS((unsigned int)Token::eEnumerator, (unsigned int)scope->enumeratorList[2].name->tokType());
ASSERT(scope->enumeratorList[2].scope == &*scope);
ASSERT_EQUALS("E3", scope->enumeratorList[2].name->str());
ASSERT(scope->enumeratorList[2].start != nullptr);
ASSERT(scope->enumeratorList[2].end != nullptr);
ASSERT_EQUALS(true, scope->enumeratorList[2].value_known);
ASSERT_EQUALS(6, scope->enumeratorList[2].value);
}
void enum5() {