From 1b6e4589dab80dbdae70a2b2ac17d49f82d0f41a Mon Sep 17 00:00:00 2001 From: PKEuS Date: Mon, 11 May 2015 17:30:11 +0200 Subject: [PATCH] Implemented array size calculation for n-dimensional arrays with arbitrary dereferencing (#6657) --- lib/tokenize.cpp | 48 ++++++++++++++++++++++++++++++------- test/testsimplifytokens.cpp | 15 ++++++++++++ 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 2324fcccb..5a24fbd8c 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3116,12 +3116,34 @@ bool Tokenizer::simplifySizeof() } } - else if (Token::Match(tok, "sizeof ( * %name% )") || Token::Match(tok, "sizeof ( %name% [ %num% ] )")) { + else if (Token::simpleMatch(tok, "sizeof ( *") || Token::Match(tok, "sizeof ( %name% [")) { // Some default value.. std::size_t sz = 0; - const unsigned int varid = tok->tokAt((tok->strAt(2) == "*") ? 3 : 2)->varId(); - if ((varid != 0) && (declTokOfVar.find(varid) != declTokOfVar.end())) { + unsigned int derefs = 0; + + const Token* nametok = tok->tokAt(2); + if (nametok->str() == "*") { + do { + nametok = nametok->next(); + derefs++; + } while (nametok && nametok->str() == "*"); + + if (!Token::Match(nametok, "%name% )")) + continue; + } else { + const Token* tok2 = nametok->next(); + do { + tok2 = tok2->link()->next(); + derefs++; + } while (tok2 && tok2->str() == "["); + + if (!tok2 || tok2->str() != ")") + continue; + } + + const unsigned int varid = nametok->varId(); + if (derefs != 0 && varid != 0 && declTokOfVar.find(varid) != declTokOfVar.end()) { // Try to locate variable declaration.. const Token *decltok = declTokOfVar[varid]; if (Token::Match(decltok->previous(), "%type%|* %name% [")) { @@ -3130,20 +3152,28 @@ bool Tokenizer::simplifySizeof() sz = sizeOfType(decltok->tokAt(-2)); } // Multi-dimensional array.. - if (Token::Match(decltok,"%name% [") && Token::simpleMatch(decltok->linkAt(1), "] [")) { - const Token *tok2 = decltok->linkAt(1); + if (Token::Match(decltok, "%name% [") && Token::simpleMatch(decltok->linkAt(1), "] [")) { + const Token *tok2 = decltok; + for (unsigned int i = 0; i < derefs; i++) + tok2 = tok2->linkAt(1); // Skip all dimensions that are derefenced before the sizeof call while (Token::Match(tok2, "] [ %num% ]")) { sz = sz * MathLib::toLongNumber(tok2->strAt(2)); - tok2 = tok2->linkAt(3); + tok2 = tok2->linkAt(1); } if (Token::simpleMatch(tok2, "] [")) sz = 0; } - } else if (tok->strAt(3) == "[" && tok->tokAt(2)->isStandardType()) { - sz = sizeOfType(tok->tokAt(2)); + } else if (nametok->strAt(1) == "[" && nametok->isStandardType()) { + sz = sizeOfType(nametok); if (sz == 0) continue; - sz *= static_cast(MathLib::toLongNumber(tok->strAt(4))); + const Token *tok2 = nametok->next(); + while (Token::Match(tok2, "[ %num% ]")) { + sz *= static_cast(MathLib::toLongNumber(tok2->strAt(1))); + tok2 = tok2->link()->next(); + } + if (!tok2 || tok2->str() != ")") + continue; } if (sz > 0) { diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 1587e6800..b55aa696f 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -894,6 +894,21 @@ private: "sizeof(i[1]);\n" "sizeof(i);"; ASSERT_EQUALS("char i [ 2 ] [ 20 ] ; 20 ; 40 ;", tok(code)); + + code = "char i[2][20][30];\n" + "sizeof(i[1][4][2]);\n" + "sizeof(***i);\n" + "sizeof(i[1][4]);\n" + "sizeof(**i);\n" + "sizeof(i[1]);\n" + "sizeof(*i);\n" + "sizeof(i);"; + ASSERT_EQUALS("char i [ 2 ] [ 20 ] [ 30 ] ; 1 ; 1 ; 30 ; 30 ; 600 ; 600 ; 1200 ;", tok(code)); + + code = "sizeof(char[20]);\n" + "sizeof(char[20][3]);\n" + "sizeof(char[unknown][3]);"; + ASSERT_EQUALS("20 ; 60 ; sizeof ( char [ unknown ] [ 3 ] ) ;", tok(code)); } void sizeof5() {