From c1aed9681de99a6df9b2710103c5f683c6748656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 7 Nov 2023 19:19:19 +0100 Subject: [PATCH] Fix #12151 (Tokenizer::arraySize: enum constant used as index in array initialization) (#5633) --- lib/symboldatabase.h | 4 ++++ lib/tokenize.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ lib/tokenize.h | 1 + test/testtokenize.cpp | 6 ++++++ 4 files changed, 52 insertions(+) diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index f9f4039ff..163a86bef 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -553,6 +553,10 @@ public: return mDimensions.at(index_).known; } + void setDimensions(const std::vector &dimensions_) { + mDimensions = dimensions_; + } + /** * Checks if the variable is an STL type ('std::') * E.g.: diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index c3c33f9eb..d6571b68d 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3393,6 +3393,8 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration) } else { ValueFlow::setValues(list, *mSymbolDatabase, mErrorLogger, mSettings, mTimerResults); } + + arraySizeAfterValueFlow(); } // Warn about unhandled character literals @@ -3807,6 +3809,45 @@ void Tokenizer::arraySize() } } +void Tokenizer::arraySizeAfterValueFlow() +{ + // After ValueFlow, adjust array sizes. + for (const Variable* var: mSymbolDatabase->variableList()) { + if (!var || !var->isArray()) + continue; + if (!Token::Match(var->nameToken(), "%name% [ ] = { [")) + continue; + MathLib::bigint maxIndex = -1; + const Token* const startToken = var->nameToken()->tokAt(4); + const Token* const endToken = startToken->link(); + for (const Token* tok = startToken; tok != endToken; tok = tok->next()) { + if (!Token::Match(tok, "[{,] [") || !Token::simpleMatch(tok->linkAt(1), "] =")) + continue; + const Token* expr = tok->next()->astOperand1(); + if (expr && expr->hasKnownIntValue()) + maxIndex = std::max(maxIndex, expr->getKnownIntValue()); + } + if (maxIndex >= 0) { + // insert array size + Token* tok = const_cast(var->nameToken()->next()); + tok->insertToken(std::to_string(maxIndex + 1)); + // ast + tok->astOperand2(tok->next()); + // Token::scope + tok->next()->scope(tok->scope()); + // Value flow + ValueFlow::Value value(maxIndex + 1); + value.setKnown(); + tok->next()->addValue(value); + // Set array dimensions + Dimension d; + d.num = maxIndex + 1; + std::vector dimensions{d}; + const_cast(var)->setDimensions(dimensions); + } + } +} + static Token *skipTernaryOp(Token *tok) { int colonLevel = 1; diff --git a/lib/tokenize.h b/lib/tokenize.h index 17ae2f5d3..4ca59e5a7 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -164,6 +164,7 @@ public: /** Insert array size where it isn't given */ void arraySize(); + void arraySizeAfterValueFlow(); // cppcheck-suppress functionConst /** Simplify labels and 'case|default' syntaxes. */ diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 0f1f54c93..78ae0a00c 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -272,6 +272,7 @@ private: TEST_CASE(cpp14template); // Ticket #6708 TEST_CASE(arraySize); + TEST_CASE(arraySizeAfterValueFlow); TEST_CASE(labels); TEST_CASE(simplifyInitVar); @@ -4156,6 +4157,11 @@ private: ASSERT_EQUALS("; const char c [ 4 ] = \"abc\" ;", tokenizeAndStringify(";const char c[] = { \"abc\" };")); } + void arraySizeAfterValueFlow() { + const char code[] = "enum {X=10}; int a[] = {[X]=1};"; + ASSERT_EQUALS("enum Anonymous0 { X = 10 } ; int a [ 11 ] = { [ X ] = 1 } ;", tokenizeAndStringify(code)); + } + void labels() { ASSERT_EQUALS("void f ( ) { ab : ; a = 0 ; }", tokenizeAndStringify("void f() { ab: a=0; }")); //ticket #3176