Refactored sizeof simplification and fixed one TODO assert.

This commit is contained in:
Reijo Tomperi 2009-10-07 10:54:34 +03:00
parent d9ae2c171e
commit 8472e58413
5 changed files with 99 additions and 118 deletions

View File

@ -703,7 +703,9 @@ void CheckBufferOverrun::checkGlobalAndLocalVariable()
continue; 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) if (total_size == 0)
continue; continue;
@ -748,7 +750,7 @@ void CheckBufferOverrun::checkStructVariable()
const char *varname[3] = {0, 0, 0}; const char *varname[3] = {0, 0, 0};
varname[1] = tok2->strAt(ivar); varname[1] = tok2->strAt(ivar);
int arrsize = std::atoi(tok2->strAt(ivar + 2)); 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) if (total_size == 0)
continue; continue;

View File

@ -1939,7 +1939,7 @@ void CheckMemoryLeakInFunction::check()
// Declare a local variable => Check // Declare a local variable => Check
if (indentlevel > 0 && infunc) if (indentlevel > 0 && infunc)
{ {
unsigned int sz = _tokenizer->sizeOfType(tok->strAt(1)); unsigned int sz = _tokenizer->sizeOfType(tok->tokAt(1));
if (sz < 1) if (sz < 1)
sz = 1; sz = 1;

View File

@ -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; return 0;
std::map<std::string, unsigned int>::const_iterator it = _typeSize.find(type); if (type->str()[0] == '"')
return (Token::getStrLength(type) + 1);
std::map<std::string, unsigned int>::const_iterator it = _typeSize.find(type->strAt(0));
if (it == _typeSize.end()) if (it == _typeSize.end())
return 0; return 0;
@ -1412,31 +1415,6 @@ bool Tokenizer::createLinks()
void Tokenizer::simplifySizeof() 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.. // Fill the map _typeSize..
_typeSize.clear(); _typeSize.clear();
_typeSize["char"] = sizeof(char); _typeSize["char"] = sizeof(char);
@ -1455,46 +1433,70 @@ void Tokenizer::simplifySizeof()
} }
} }
// Locate variable declarations and calculate the size
// Replace 'sizeof(var)' with 'sizeof(type)' std::map<unsigned int, std::string> sizeOfVar;
for (Token *tok = _tokens; tok; tok = tok->next()) for (Token *tok = _tokens; tok; tok = tok->next())
{ {
if (! Token::Match(tok, "[;{}] %type% *| %var% ;")) if (tok->varId() != 0 && sizeOfVar.find(tok->varId()) == sizeOfVar.end())
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 (tok2->str() == "{") const unsigned int varId = tok->varId();
++indentlevel; if (Token::Match(tok->tokAt(-3), "[;{}] %type% * %var% ;") ||
else if (tok2->str() == "}") Token::Match(tok->tokAt(-4), "[;{}] const %type% * %var% ;") ||
Token::Match(tok->tokAt(-2), "[;{}] %type% %var% ;") ||
Token::Match(tok->tokAt(-3), "[;{}] const %type% %var% ;"))
{ {
--indentlevel; sizeOfVar[varId] = MathLib::toString<long>(sizeOfType(tok->tokAt(-1)));
if (indentlevel < 0)
break;
} }
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); int size = sizeOfType(tok->tokAt(-1));
tok2->str(tok->strAt(type_tok)); if (size <= 0)
continue;
sizeOfVar[varId] = MathLib::toString<long>(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<long>(size);
} }
} }
} }
// Replace 'sizeof(type)'..
for (Token *tok = _tokens; tok; tok = tok->next()) for (Token *tok = _tokens; tok; tok = tok->next())
{ {
if (tok->str() != "sizeof") if (tok->str() != "sizeof")
continue; 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("(")) if (tok->strAt(1) != std::string("("))
{ {
// Add parenthesis around the sizeof // Add parenthesis around the sizeof
@ -1537,27 +1539,38 @@ void Tokenizer::simplifySizeof()
} }
// sizeof(type *) => sizeof(*) // sizeof(type *) => sizeof(*)
if (Token::Match(tok, "sizeof ( %type% *)")) if (Token::Match(tok->next(), "( %type% *)"))
{ {
tok->next()->deleteNext(); tok->next()->deleteNext();
continue;
} }
if (Token::Match(tok, "sizeof ( * )")) if (Token::Match(tok->next(), "( * )"))
{ {
tok->str(MathLib::toString<long>(sizeOfType(tok->strAt(2)))); tok->str(MathLib::toString<long>(sizeOfType(tok->tokAt(2))));
Token::eraseTokens(tok, tok->tokAt(4)); 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 if (sizeOfVar.find(tok->tokAt(2)->varId()) != sizeOfVar.end())
// similar name with type (#329) {
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% )")) else if (Token::Match(tok, "sizeof ( %type% )"))
{ {
const char *type = tok->strAt(2); int size = sizeOfType(tok->tokAt(2));
int size = sizeOfType(type);
if (size > 0) if (size > 0)
{ {
tok->str(MathLib::toString<long>(size)); tok->str(MathLib::toString<long>(size));
@ -1577,7 +1590,7 @@ void Tokenizer::simplifySizeof()
const Token *decltok = Token::findmatch(_tokens, "%type% %varid% [", varid); const Token *decltok = Token::findmatch(_tokens, "%type% %varid% [", varid);
if (decltok) 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<long>(total_size));
Token::eraseTokens(tok2, tok2->tokAt(4));
}
}
}
} }
void Tokenizer::simplifyTokenList() void Tokenizer::simplifyTokenList()

View File

@ -85,8 +85,12 @@ public:
std::string fileLine(const Token *tok) const; 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<std::string> *getFiles() const; const std::vector<std::string> *getFiles() const;

View File

@ -657,31 +657,31 @@ private:
{ {
// ticket #487 // ticket #487
{ {
const char code[] = "const char *str = \"1\"; sizeof(str);"; const char code[] = "; const char *str = \"1\"; sizeof(str);";
const char *str = "1"; const char *str = "1";
std::ostringstream expected; 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"; const char str[] = "1";
std::ostringstream expected; 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)); 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'}; const char str[] = {'1'};
std::ostringstream expected; 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)); TODO_ASSERT_EQUALS(expected.str(), sizeof_(code));
} }
@ -700,6 +700,12 @@ private:
expected << "; " << sizeof("\"quote\""); expected << "; " << sizeof("\"quote\"");
ASSERT_EQUALS(expected.str(), sizeof_("; 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() void casting()