Refactored sizeof simplification and fixed one TODO assert.
This commit is contained in:
parent
d9ae2c171e
commit
8472e58413
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
181
src/tokenize.cpp
181
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;
|
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()
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue