Skip to content

Commit

Permalink
Fix #12151 (Tokenizer::arraySize: enum constant used as index in arra…
Browse files Browse the repository at this point in the history
…y initialization) (#5633)
  • Loading branch information
danmar committed Nov 7, 2023
1 parent 13e7450 commit c1aed96
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 0 deletions.
4 changes: 4 additions & 0 deletions lib/symboldatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,10 @@ class CPPCHECKLIB Variable {
return mDimensions.at(index_).known;
}

void setDimensions(const std::vector<Dimension> &dimensions_) {
mDimensions = dimensions_;
}

/**
* Checks if the variable is an STL type ('std::')
* E.g.:
Expand Down
41 changes: 41 additions & 0 deletions lib/tokenize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<Token*>(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<Dimension> dimensions{d};
const_cast<Variable*>(var)->setDimensions(dimensions);
}
}
}

static Token *skipTernaryOp(Token *tok)
{
int colonLevel = 1;
Expand Down
1 change: 1 addition & 0 deletions lib/tokenize.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ class CPPCHECKLIB Tokenizer {

/** Insert array size where it isn't given */
void arraySize();
void arraySizeAfterValueFlow(); // cppcheck-suppress functionConst

/** Simplify labels and 'case|default' syntaxes.
*/
Expand Down
6 changes: 6 additions & 0 deletions test/testtokenize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ class TestTokenizer : public TestFixture {
TEST_CASE(cpp14template); // Ticket #6708

TEST_CASE(arraySize);
TEST_CASE(arraySizeAfterValueFlow);

TEST_CASE(labels);
TEST_CASE(simplifyInitVar);
Expand Down Expand Up @@ -4156,6 +4157,11 @@ class TestTokenizer : public TestFixture {
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
Expand Down

0 comments on commit c1aed96

Please sign in to comment.