diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index bc7a52ca4..26b21c16a 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1436,6 +1436,52 @@ void SymbolDatabase::setArrayDimensionsUsingValueFlow() Dimension &dimension = const_cast(const_dimension); if (dimension.num != 0 || !dimension.tok) continue; + + if (Token::Match(dimension.tok->previous(), "[<,]")) { + if (dimension.known) + continue; + if (!Token::Match(dimension.tok->previous(), "[<,]")) + continue; + + // In template arguments, there might not be AST + // Determine size by using the "raw tokens" + TokenList tokenList(mSettings); + tokenList.addtoken(";", 0, 0, false); + bool fail = false; + for (const Token *tok = dimension.tok; tok && !Token::Match(tok, "[,>]"); tok = tok->next()) { + if (!tok->isName()) + tokenList.addtoken(tok->str(), 0, 0, false); + + else if (tok->hasKnownIntValue()) + tokenList.addtoken(std::to_string(tok->getKnownIntValue()), 0, 0, false); + + else { + fail = true; + break; + } + } + + if (fail) + continue; + + tokenList.addtoken(";", 0, 0, false); + + for (Token *tok = tokenList.front(); tok;) { + if (TemplateSimplifier::simplifyNumericCalculations(tok, false)) + tok = tokenList.front(); + else + tok = tok->next(); + } + + if (Token::Match(tokenList.front(), "; %num% ;")) { + dimension.known = true; + dimension.num = MathLib::toLongNumber(tokenList.front()->next()->str()); + } + + continue; + } + + // Normal array [..dimension..] dimension.known = false; // check for a single token dimension @@ -2836,17 +2882,13 @@ bool Variable::arrayDimensions(const Settings* settings) for (int i = 0; i < container->size_templateArgNo && tok; i++) { tok = tok->nextTemplateArgument(); } - if (tok) { - while (!tok->astParent() && !Token::Match(tok->next(), "[,<>]")) - tok = tok->next(); - while (tok->astParent() && !Token::Match(tok->astParent(), "[,<>]")) - tok = tok->astParent(); + if (Token::Match(tok, "%num% [,>]")) { dimension_.tok = tok; - ValueFlow::valueFlowConstantFoldAST(const_cast(dimension_.tok), settings); - if (tok->hasKnownIntValue()) { - dimension_.num = tok->getKnownIntValue(); - dimension_.known = true; - } + dimension_.known = true; + dimension_.num = MathLib::toLongNumber(tok->str()); + } else if (tok) { + dimension_.tok = tok; + dimension_.known = false; } mDimensions.push_back(dimension_); return true; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index a6a349c7b..7a84b9a0a 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -5309,8 +5309,8 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold continue; ValueFlow::Value value(0); if (var->valueType()->container->size_templateArgNo >= 0) { - if (var->dimensions().size() == 1 && var->dimensions().front().tok && var->dimensions().front().tok->hasKnownIntValue()) - value.intvalue = var->dimensions().front().tok->getKnownIntValue(); + if (var->dimensions().size() == 1 && var->dimensions().front().known) + value.intvalue = var->dimensions().front().num; else continue; } diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 36cb69b41..18c7fff86 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -110,7 +110,8 @@ private: settings2.platform(Settings::Unspecified); TEST_CASE(array); - TEST_CASE(stlarray); + TEST_CASE(stlarray1); + TEST_CASE(stlarray2); TEST_CASE(test_isVariableDeclarationCanHandleNull); TEST_CASE(test_isVariableDeclarationIdentifiesSimpleDeclaration); @@ -436,12 +437,12 @@ private: ASSERT_EQUALS(12U, v->dimension(0)); } - void stlarray() { - GET_SYMBOL_DB("std::array arr;"); + void stlarray1() { + GET_SYMBOL_DB("std::array arr;"); ASSERT(db != nullptr); if (!db) return; - ASSERT(db->variableList().size() == 2); // the first one is not used + ASSERT_EQUALS(2, db->variableList().size()); // the first one is not used const Variable * v = db->getVariableFromVarId(1); ASSERT(v != nullptr); if (!v) @@ -451,6 +452,21 @@ private: ASSERT_EQUALS(20U, v->dimension(0)); } + void stlarray2() { + GET_SYMBOL_DB("constexpr int sz = 16; std::array arr;"); + ASSERT(db != nullptr); + if (!db) + return; + ASSERT_EQUALS(3, db->variableList().size()); // the first one is not used + const Variable * v = db->getVariableFromVarId(2); + ASSERT(v != nullptr); + if (!v) + return; + ASSERT(v->isArray()); + ASSERT_EQUALS(1U, v->dimensions().size()); + ASSERT_EQUALS(20U, v->dimension(0)); + } + void test_isVariableDeclarationCanHandleNull() { reset(); const bool result = nullScope.isVariableDeclaration(nullptr, vartok, typetok);