diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 33e769012..f3d0d5dee 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1272,14 +1272,10 @@ void SymbolDatabase::createSymbolDatabaseEnums() const_cast(i.name)->enumerator(&i); } - // fill in enumerator values for (std::list::iterator it = scopeList.begin(); it != scopeList.end(); ++it) { if (it->type != Scope::eEnum) continue; - MathLib::bigint value = 0; - bool prev_enum_is_known = true; - for (Enumerator & enumerator : it->enumeratorList) { // look for initialization tokens that can be converted to enumerators and convert them if (enumerator.start) { @@ -1292,28 +1288,6 @@ void SymbolDatabase::createSymbolDatabaseEnums() const_cast(tok3)->enumerator(e); } } - - // look for possible constant folding expressions - // rhs of operator: - Token *rhs = enumerator.start->previous()->astOperand2(); - - // constant folding of expression: - ValueFlow::valueFlowConstantFoldAST(rhs, mSettings); - - // get constant folded value: - if (rhs && rhs->hasKnownIntValue()) { - enumerator.value = rhs->values().front().intvalue; - enumerator.value_known = true; - value = enumerator.value + 1; - prev_enum_is_known = true; - } else - prev_enum_is_known = false; - } - - // not initialized so use default value - else if (prev_enum_is_known) { - enumerator.value = value++; - enumerator.value_known = true; } } } diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 5ba99c6f5..236cbaaf0 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3605,7 +3605,7 @@ void Tokenizer::setVarIdPass1() continue; } - if (!scopeStack.top().isEnum) { + if (!scopeStack.top().isEnum || !(Token::Match(tok->previous(), "{|,") && Token::Match(tok->next(), ",|=|}"))) { const std::map::const_iterator it = variableMap.find(tok->str()); if (it != variableMap.end()) { tok->varId(it->second); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index c715282a1..0c5d69ae8 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1628,6 +1628,34 @@ static void valueFlowOppositeCondition(SymbolDatabase *symboldatabase, const Set } } +static void valueFlowEnumValue(SymbolDatabase * symboldatabase, const Settings * settings) +{ + + for (Scope & scope : symboldatabase->scopeList) { + if (scope.type != Scope::eEnum) + continue; + MathLib::bigint value = 0; + bool prev_enum_is_known = true; + + for (Enumerator & enumerator : scope.enumeratorList) { + if (enumerator.start) { + Token *rhs = enumerator.start->previous()->astOperand2(); + ValueFlow::valueFlowConstantFoldAST(rhs, settings); + if (rhs && rhs->hasKnownIntValue()) { + enumerator.value = rhs->values().front().intvalue; + enumerator.value_known = true; + value = enumerator.value + 1; + prev_enum_is_known = true; + } else + prev_enum_is_known = false; + } else if (prev_enum_is_known) { + enumerator.value = value++; + enumerator.value_known = true; + } + } + } +} + static void valueFlowGlobalConstVar(TokenList* tokenList, const Settings *settings) { // Get variable values... @@ -6791,11 +6819,14 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase, for (Token *tok = tokenlist->front(); tok; tok = tok->next()) tok->clearValueFlow(); + valueFlowEnumValue(symboldatabase, settings); valueFlowNumber(tokenlist); valueFlowString(tokenlist); valueFlowArray(tokenlist); valueFlowUnknownFunctionReturn(tokenlist, settings); valueFlowGlobalConstVar(tokenlist, settings); + valueFlowEnumValue(symboldatabase, settings); + valueFlowNumber(tokenlist); valueFlowGlobalStaticVar(tokenlist, settings); valueFlowPointerAlias(tokenlist); valueFlowLifetime(tokenlist, symboldatabase, errorLogger, settings); diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 85f6774ca..e743df8b3 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -337,6 +337,7 @@ private: TEST_CASE(enum6); TEST_CASE(enum7); TEST_CASE(enum8); + TEST_CASE(enum9); TEST_CASE(sizeOfType); @@ -5034,6 +5035,19 @@ private: ASSERT(!X5->value_known); } + void enum9() { + GET_SYMBOL_DB("const int x = 7; enum E { X0 = x, X1 };\n"); + ASSERT(db != nullptr); + const Enumerator *X0 = db->scopeList.back().findEnumerator("X0"); + ASSERT(X0); + ASSERT(X0->value_known); + ASSERT_EQUALS(X0->value, 7); + const Enumerator *X1 = db->scopeList.back().findEnumerator("X1"); + ASSERT(X1); + ASSERT(X1->value_known); + ASSERT_EQUALS(X1->value, 8); + } + void sizeOfType() { // #7615 - crash in Symboldatabase::sizeOfType() GET_SYMBOL_DB("enum e;\n" diff --git a/test/testvarid.cpp b/test/testvarid.cpp index f95b85138..35786f48d 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -194,6 +194,12 @@ private: TEST_CASE(varidclass20); // #7578: int (*p)[2] TEST_CASE(varid_classnameshaddowsvariablename); // #3990 + TEST_CASE(varidenum1); + TEST_CASE(varidenum2); + TEST_CASE(varidenum3); + TEST_CASE(varidenum4); + TEST_CASE(varidenum5); + TEST_CASE(varidnamespace1); TEST_CASE(varidnamespace2); TEST_CASE(usingNamespace1); @@ -3084,6 +3090,70 @@ private: ASSERT_EQUALS(expected, tokenize(code)); } + void varidenum1() { + const char code[] = "const int eStart = 6;\n" + "enum myEnum {\n" + " A = eStart;\n" + "};\n"; + const char expected[] = "1: const int eStart@1 = 6 ;\n" + "2: enum myEnum {\n" + "3: A = eStart@1 ;\n" + "4: } ;\n"; + ASSERT_EQUALS(expected, tokenize(code)); + } + + void varidenum2() { + const char code[] = "const int eStart = 6;\n" + "enum myEnum {\n" + " A = f(eStart);\n" + "};\n"; + const char expected[] = "1: const int eStart@1 = 6 ;\n" + "2: enum myEnum {\n" + "3: A = f ( eStart@1 ) ;\n" + "4: } ;\n"; + ASSERT_EQUALS(expected, tokenize(code)); + } + + void varidenum3() { + const char code[] = "const int eStart = 6;\n" + "enum myEnum {\n" + " A = f(eStart, x);\n" + "};\n"; + const char expected[] = "1: const int eStart@1 = 6 ;\n" + "2: enum myEnum {\n" + "3: A = f ( eStart@1 , x ) ;\n" + "4: } ;\n"; + ASSERT_EQUALS(expected, tokenize(code)); + } + + void varidenum4() { + const char code[] = "const int eStart = 6;\n" + "enum myEnum {\n" + " A = f(x, eStart);\n" + "};\n"; + const char expected[] = "1: const int eStart@1 = 6 ;\n" + "2: enum myEnum {\n" + "3: A = f ( x , eStart@1 ) ;\n" + "4: } ;\n"; + ASSERT_EQUALS(expected, tokenize(code)); + } + + void varidenum5() { + const char code[] = "const int eStart = 6;\n" + "enum myEnum {\n" + " A = f(x, eStart, y);\n" + "};\n"; + const char expected[] = "1: const int eStart@1 = 6 ;\n" + "2: enum myEnum {\n" + "3: A = f ( x , eStart@1 , y ) ;\n" + "4: } ;\n"; + const char current[] = "1: const int eStart@1 = 6 ;\n" + "2: enum myEnum {\n" + "3: A = f ( x , eStart , y ) ;\n" + "4: } ;\n"; + TODO_ASSERT_EQUALS(expected, current, tokenize(code)); + } + void varid_classnameshaddowsvariablename() { const char code[] = "class Data;\n" "void strange_declarated(const Data& Data);\n"