diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index d357298bc..152fd6ee5 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1260,7 +1260,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti const Token *rhs = enumerator.start->previous()->astOperand2(); // constant folding of expression: - ValueFlow::valueFlowConstantFoldAST(rhs); + ValueFlow::valueFlowConstantFoldAST(rhs, _settings); // get constant folded value: if (rhs && rhs->values.size() == 1U && rhs->values.front().isKnown()) { @@ -1361,7 +1361,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti const Token *rhs = dimension.start->previous()->astOperand2(); // constant folding of expression: - ValueFlow::valueFlowConstantFoldAST(rhs); + ValueFlow::valueFlowConstantFoldAST(rhs, _settings); // get constant folded value: if (rhs && rhs->values.size() == 1U && rhs->values.front().isKnown()) { diff --git a/lib/tokenlist.h b/lib/tokenlist.h index 3b6e75985..739f6757f 100644 --- a/lib/tokenlist.h +++ b/lib/tokenlist.h @@ -40,6 +40,10 @@ public: _settings = settings; } + const Settings *getSettings() const { + return _settings; + } + /** @return the source file path. e.g. "file.cpp" */ const std::string& getSourceFilePath() const; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index e4f8fd7a6..3bd6ad1ae 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -572,7 +572,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value) // Handle various constants.. -static void valueFlowSetConstantValue(const Token *tok) +static Token * valueFlowSetConstantValue(const Token *tok, const Settings *settings) { if ((tok->isNumber() && MathLib::isInt(tok->str())) || (tok->tokType() == Token::eChar)) { ValueFlow::Value value(MathLib::toLongNumber(tok->str())); @@ -582,14 +582,48 @@ static void valueFlowSetConstantValue(const Token *tok) ValueFlow::Value value(tok->enumerator()->value); value.setKnown(); setTokenValue(const_cast(tok), value); + } else if (Token::simpleMatch(tok, "sizeof (") && tok->tokAt(2)) { + const Token *tok2 = tok->tokAt(2); + if (tok2->enumerator() && tok2->enumerator()->scope) { + long long size = settings->sizeof_int; + const Token * type = tok2->enumerator()->scope->enumType; + if (type) { + size = type->str() == "char" ? 1 : + type->str() == "short" ? settings->sizeof_short : + type->str() == "int" ? settings->sizeof_int : + (type->str() == "long" && type->isLong()) ? settings->sizeof_long_long : + type->str() == "long" ? settings->sizeof_long : 0; + } + ValueFlow::Value value(size); + value.setKnown(); + setTokenValue(const_cast(tok), value); + setTokenValue(const_cast(tok->next()), value); + } else if (tok2->type() && tok2->type()->isEnumType()) { + long long size = settings->sizeof_int; + const Token * type = tok2->type()->classScope->enumType; + if (type) { + size = type->str() == "char" ? 1 : + type->str() == "short" ? settings->sizeof_short : + type->str() == "int" ? settings->sizeof_int : + (type->str() == "long" && type->isLong()) ? settings->sizeof_long_long : + type->str() == "long" ? settings->sizeof_long : 0; + } + ValueFlow::Value value(size); + value.setKnown(); + setTokenValue(const_cast(tok), value); + setTokenValue(const_cast(tok->next()), value); + } + // skip over enum + tok = tok->linkAt(1); } + return tok->next(); } static void valueFlowNumber(TokenList *tokenlist) { - for (Token *tok = tokenlist->front(); tok; tok = tok->next()) { - valueFlowSetConstantValue(tok); + for (Token *tok = tokenlist->front(); tok;) { + tok = valueFlowSetConstantValue(tok, tokenlist->getSettings()); } if (tokenlist->isCPP()) { @@ -2375,12 +2409,12 @@ static void valueFlowFunctionReturn(TokenList *tokenlist, ErrorLogger *errorLogg } } -const ValueFlow::Value *ValueFlow::valueFlowConstantFoldAST(const Token *expr) +const ValueFlow::Value *ValueFlow::valueFlowConstantFoldAST(const Token *expr, const Settings *settings) { if (expr && expr->values.empty()) { - valueFlowConstantFoldAST(expr->astOperand1()); - valueFlowConstantFoldAST(expr->astOperand2()); - valueFlowSetConstantValue(expr); + valueFlowConstantFoldAST(expr->astOperand1(), settings); + valueFlowConstantFoldAST(expr->astOperand2(), settings); + valueFlowSetConstantValue(expr, settings); } return expr && expr->values.size() == 1U && expr->values.front().isKnown() ? &expr->values.front() : nullptr; } diff --git a/lib/valueflow.h b/lib/valueflow.h index 643a2c227..908c98b32 100644 --- a/lib/valueflow.h +++ b/lib/valueflow.h @@ -95,7 +95,7 @@ namespace ValueFlow { }; /// Constant folding of expression. This can be used before the full ValueFlow has been executed (ValueFlow::setValues). - const ValueFlow::Value * valueFlowConstantFoldAST(const Token *expr); + const ValueFlow::Value * valueFlowConstantFoldAST(const Token *expr, const Settings *settings); /// Perform valueflow analysis. void setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings); diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 39fe99294..af52bcdb8 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -248,6 +248,7 @@ private: TEST_CASE(enum4); TEST_CASE(enum5); TEST_CASE(enum6); + TEST_CASE(enum7); TEST_CASE(isImplicitlyVirtual); TEST_CASE(isPure); @@ -2469,6 +2470,54 @@ private: ASSERT(function->retType && function->retType->name() == "Enum"); } +#define TEST(S) \ + v = db->getVariableFromVarId(id++); \ + ASSERT(v != nullptr); \ + if (!v) \ + return; \ + ASSERT(v->isArray()); \ + ASSERT_EQUALS(1U, v->dimensions().size()); \ + ASSERT_EQUALS(S, v->dimension(0)) + + void enum7() { + GET_SYMBOL_DB("enum E { X };\n" + "enum EC : char { C };\n" + "enum ES : short { S };\n" + "enum EI : int { I };\n" + "enum EL : long { L };\n" + "enum ELL : long long { LL };\n" + "char array1[sizeof(E)];\n" + "char array2[sizeof(X)];\n" + "char array3[sizeof(EC)];\n" + "char array4[sizeof(C)];\n" + "char array5[sizeof(ES)];\n" + "char array6[sizeof(S)];\n" + "char array7[sizeof(EI)];\n" + "char array8[sizeof(I)];\n" + "char array9[sizeof(EL)];\n" + "char array10[sizeof(L)];\n" + "char array11[sizeof(ELL)];\n" + "char array12[sizeof(LL)];\n"); + ASSERT(db); + if (!db) + return; + ASSERT(db->getVariableListSize() == 13); // the first one is not used + const Variable * v; + unsigned int id = 1; + TEST(settings.sizeof_int); + TEST(settings.sizeof_int); + TEST(1); + TEST(1); + TEST(settings.sizeof_short); + TEST(settings.sizeof_short); + TEST(settings.sizeof_int); + TEST(settings.sizeof_int); + TEST(settings.sizeof_long); + TEST(settings.sizeof_long); + TEST(settings.sizeof_long_long); + TEST(settings.sizeof_long_long); + } + void isImplicitlyVirtual() { { GET_SYMBOL_DB("class Base {\n"