From 8472e58413d37a45b85b79c94ab9b7f07789b213 Mon Sep 17 00:00:00 2001 From: Reijo Tomperi Date: Wed, 7 Oct 2009 10:54:34 +0300 Subject: [PATCH] Refactored sizeof simplification and fixed one TODO assert. --- src/checkbufferoverrun.cpp | 6 +- src/checkmemoryleak.cpp | 2 +- src/tokenize.cpp | 181 +++++++++++++++--------------------- src/tokenize.h | 8 +- test/testsimplifytokens.cpp | 20 ++-- 5 files changed, 99 insertions(+), 118 deletions(-) diff --git a/src/checkbufferoverrun.cpp b/src/checkbufferoverrun.cpp index 500d02b62..871976836 100644 --- a/src/checkbufferoverrun.cpp +++ b/src/checkbufferoverrun.cpp @@ -703,7 +703,9 @@ void CheckBufferOverrun::checkGlobalAndLocalVariable() continue; } - int total_size = size * ((*type == '*') ? 4 : _tokenizer->sizeOfType(type)); + Token sizeTok; + sizeTok.str(type); + int total_size = size * ((*type == '*') ? 4 : _tokenizer->sizeOfType(&sizeTok)); if (total_size == 0) continue; @@ -748,7 +750,7 @@ void CheckBufferOverrun::checkStructVariable() const char *varname[3] = {0, 0, 0}; varname[1] = tok2->strAt(ivar); int arrsize = std::atoi(tok2->strAt(ivar + 2)); - int total_size = arrsize * _tokenizer->sizeOfType(tok2->strAt(1)); + int total_size = arrsize * _tokenizer->sizeOfType(tok2->tokAt(1)); if (total_size == 0) continue; diff --git a/src/checkmemoryleak.cpp b/src/checkmemoryleak.cpp index 75ed487fa..66a915116 100644 --- a/src/checkmemoryleak.cpp +++ b/src/checkmemoryleak.cpp @@ -1939,7 +1939,7 @@ void CheckMemoryLeakInFunction::check() // Declare a local variable => Check if (indentlevel > 0 && infunc) { - unsigned int sz = _tokenizer->sizeOfType(tok->strAt(1)); + unsigned int sz = _tokenizer->sizeOfType(tok->tokAt(1)); if (sz < 1) sz = 1; diff --git a/src/tokenize.cpp b/src/tokenize.cpp index 8f9b8a268..964db061a 100644 --- a/src/tokenize.cpp +++ b/src/tokenize.cpp @@ -123,12 +123,15 @@ void Tokenizer::addtoken(const char str[], const unsigned int lineno, const unsi -int Tokenizer::sizeOfType(const char type[]) const +int Tokenizer::sizeOfType(const Token *type) const { - if (!type) + if (!type || !type->strAt(0)) return 0; - std::map::const_iterator it = _typeSize.find(type); + if (type->str()[0] == '"') + return (Token::getStrLength(type) + 1); + + std::map::const_iterator it = _typeSize.find(type->strAt(0)); if (it == _typeSize.end()) return 0; @@ -1412,31 +1415,6 @@ bool Tokenizer::createLinks() void Tokenizer::simplifySizeof() { - // Replace 'sizeof(str)' - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() != "sizeof") - continue; - - if (Token::Match(tok, "sizeof %str%")) - { - tok->deleteThis(); - std::ostringstream ostr; - ostr << (Token::getStrLength(tok) + 1); - tok->str(ostr.str()); - } - - if (Token::Match(tok, "sizeof ( %str% )")) - { - tok->deleteThis(); - tok->deleteThis(); - tok->deleteNext(); - std::ostringstream ostr; - ostr << (Token::getStrLength(tok) + 1); - tok->str(ostr.str()); - } - } - // Fill the map _typeSize.. _typeSize.clear(); _typeSize["char"] = sizeof(char); @@ -1455,46 +1433,70 @@ void Tokenizer::simplifySizeof() } } - - // Replace 'sizeof(var)' with 'sizeof(type)' + // Locate variable declarations and calculate the size + std::map sizeOfVar; for (Token *tok = _tokens; tok; tok = tok->next()) { - if (! Token::Match(tok, "[;{}] %type% *| %var% ;")) - continue; - - const int type_tok = (tok->tokAt(2)->str() == "*" ? 2 : 1); - const int varname_tok = type_tok + 1; - const unsigned int varid = tok->tokAt(varname_tok)->varId(); - - if (varid <= 0) - continue; - - int indentlevel = 0; - for (Token *tok2 = tok; tok2; tok2 = tok2->next()) + if (tok->varId() != 0 && sizeOfVar.find(tok->varId()) == sizeOfVar.end()) { - if (tok2->str() == "{") - ++indentlevel; - else if (tok2->str() == "}") + const unsigned int varId = tok->varId(); + if (Token::Match(tok->tokAt(-3), "[;{}] %type% * %var% ;") || + Token::Match(tok->tokAt(-4), "[;{}] const %type% * %var% ;") || + Token::Match(tok->tokAt(-2), "[;{}] %type% %var% ;") || + Token::Match(tok->tokAt(-3), "[;{}] const %type% %var% ;")) { - --indentlevel; - if (indentlevel < 0) - break; + sizeOfVar[varId] = MathLib::toString(sizeOfType(tok->tokAt(-1))); } - else if (Token::Match(tok2, "sizeof ( %varid% )", varid)) + + else if (Token::Match(tok->tokAt(-1), "%type% %var% [ %num% ] [;=]") || + Token::Match(tok->tokAt(-2), "%type% * %var% [ %num% ] [;=]")) { - tok2 = tok2->tokAt(2); - tok2->str(tok->strAt(type_tok)); + int size = sizeOfType(tok->tokAt(-1)); + if (size <= 0) + continue; + + sizeOfVar[varId] = MathLib::toString(size * MathLib::toLongNumber(tok->strAt(2))); + } + + else if (Token::Match(tok->tokAt(-1), "%type% %var% [ ] = %str% ;")) + { + int size = sizeOfType(tok->tokAt(4)); + if (size <= 0) + continue; + + sizeOfVar[varId] = MathLib::toString(size); } } } - - // Replace 'sizeof(type)'.. for (Token *tok = _tokens; tok; tok = tok->next()) { if (tok->str() != "sizeof") continue; + // sizeof "text" + if (Token::Match(tok->next(), "%str%")) + { + tok->deleteThis(); + std::ostringstream ostr; + ostr << (Token::getStrLength(tok) + 1); + tok->str(ostr.str()); + continue; + } + + // sizeof ("text") + if (Token::Match(tok->next(), "( %str% )")) + { + tok->deleteThis(); + tok->deleteThis(); + tok->deleteNext(); + std::ostringstream ostr; + ostr << (Token::getStrLength(tok) + 1); + tok->str(ostr.str()); + continue; + } + + // sizeof int -> sizeof( int ) if (tok->strAt(1) != std::string("(")) { // Add parenthesis around the sizeof @@ -1537,27 +1539,38 @@ void Tokenizer::simplifySizeof() } // sizeof(type *) => sizeof(*) - if (Token::Match(tok, "sizeof ( %type% *)")) + if (Token::Match(tok->next(), "( %type% *)")) { tok->next()->deleteNext(); + continue; } - if (Token::Match(tok, "sizeof ( * )")) + if (Token::Match(tok->next(), "( * )")) { - tok->str(MathLib::toString(sizeOfType(tok->strAt(2)))); + tok->str(MathLib::toString(sizeOfType(tok->tokAt(2)))); Token::eraseTokens(tok, tok->tokAt(4)); } - else if (Token::Match(tok, "sizeof ( %var% )") && tok->tokAt(2)->varId() > 0) + // sizeof( a ) + else if (Token::Match(tok->next(), "( %var% )") && tok->tokAt(2)->varId() != 0) { - // don't try to replace size of variable if variable has - // similar name with type (#329) + if (sizeOfVar.find(tok->tokAt(2)->varId()) != sizeOfVar.end()) + { + tok->deleteThis(); + tok->deleteThis(); + tok->deleteNext(); + tok->str(sizeOfVar[tok->varId()]); + } + else + { + // don't try to replace size of variable if variable has + // similar name with type (#329) + } } else if (Token::Match(tok, "sizeof ( %type% )")) { - const char *type = tok->strAt(2); - int size = sizeOfType(type); + int size = sizeOfType(tok->tokAt(2)); if (size > 0) { tok->str(MathLib::toString(size)); @@ -1577,7 +1590,7 @@ void Tokenizer::simplifySizeof() const Token *decltok = Token::findmatch(_tokens, "%type% %varid% [", varid); if (decltok) { - sz = sizeOfType(decltok->strAt(0)); + sz = sizeOfType(decltok); } } @@ -1589,50 +1602,6 @@ void Tokenizer::simplifySizeof() } } - // Replace 'sizeof(var)' - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (! Token::Match(tok, "%type% *| %var% [ %num% ] ;")) - continue; - - const int type_tok = ((tok->next()->str() == "*") ? 1 : 0); - - int size = sizeOfType(tok->tokAt(type_tok)->str().c_str()); - if (size <= 0) - continue; - - const int varname_tok = type_tok + 1; - const unsigned int varid = tok->tokAt(varname_tok)->varId(); - if (varid == 0) - continue; - - const int num_tok = varname_tok + 2; - int total_size = size * MathLib::toLongNumber(tok->strAt(num_tok)); - - // Replace 'sizeof(var)' with number - int indentlevel = 0; - const int next_tok = num_tok + 3; - for (Token *tok2 = tok->tokAt(next_tok); tok2; tok2 = tok2->next()) - { - if (tok2->str() == "{") - { - ++indentlevel; - } - - else if (tok2->str() == "}") - { - --indentlevel; - if (indentlevel < 0) - break; - } - - else if (Token::Match(tok2, "sizeof ( %varid% )", varid)) - { - tok2->str(MathLib::toString(total_size)); - Token::eraseTokens(tok2, tok2->tokAt(4)); - } - } - } } void Tokenizer::simplifyTokenList() diff --git a/src/tokenize.h b/src/tokenize.h index 3cfc1bd10..de0b46cd3 100644 --- a/src/tokenize.h +++ b/src/tokenize.h @@ -85,8 +85,12 @@ public: std::string fileLine(const Token *tok) const; - // Return size. - int sizeOfType(const char type[]) const; + /** + * Calculates sizeof value for given type. + * @param type Token which will contain e.g. "int", "*", or string. + * @return sizeof for given type, or 0 if it can't be calculated. + */ + int sizeOfType(const Token *type) const; const std::vector *getFiles() const; diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 1d61ab9e6..d7fa4b6fb 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -657,31 +657,31 @@ private: { // ticket #487 { - const char code[] = "const char *str = \"1\"; sizeof(str);"; + const char code[] = "; const char *str = \"1\"; sizeof(str);"; const char *str = "1"; std::ostringstream expected; - expected << "const char * str ; str = \"1\" ; " << sizeof(str) << " ;"; + expected << "; const char * str ; str = \"1\" ; " << sizeof(str) << " ;"; - TODO_ASSERT_EQUALS(expected.str(), sizeof_(code)); + ASSERT_EQUALS(expected.str(), sizeof_(code)); } { - const char code[] = "const char str[] = \"1\"; sizeof(str);"; + const char code[] = "; const char str[] = \"1\"; sizeof(str);"; const char str[] = "1"; std::ostringstream expected; - expected << "const char * str ; str = \"1\" ; " << sizeof(str) << " ;"; + expected << "; const char * str ; str = \"1\" ; " << sizeof(str) << " ;"; TODO_ASSERT_EQUALS(expected.str(), sizeof_(code)); } { - const char code[] = "const char str[] = {'1'}; sizeof(str);"; + const char code[] = "; const char str[] = {'1'}; sizeof(str);"; const char str[] = {'1'}; std::ostringstream expected; - expected << "const char * str ; str = { '1' } ; " << sizeof(str) << " ;"; + expected << "; const char * str ; str = { '1' } ; " << sizeof(str) << " ;"; TODO_ASSERT_EQUALS(expected.str(), sizeof_(code)); } @@ -700,6 +700,12 @@ private: expected << "; " << sizeof("\"quote\""); ASSERT_EQUALS(expected.str(), sizeof_("; sizeof(\"\\\"quote\\\"\")")); } + + { + std::ostringstream expected; + expected << "void f ( ) { char str [ 100 ] = \"100\" ; " << sizeof(char)*100 << " }"; + ASSERT_EQUALS(expected.str(), tok("void f ( ) { char str [ 100 ] = \"100\" ; sizeof ( str ) }")); + } } void casting()