refactor noMemset so it recursively checks parent classes for non-memset-compatible things

This commit is contained in:
Greg Hewgill 2011-03-09 21:29:30 +13:00
parent 7a7257f200
commit 70b4076111
3 changed files with 98 additions and 61 deletions

View File

@ -693,48 +693,36 @@ void CheckClass::unusedPrivateFunctionError(const Token *tok, const std::string
// ClassCheck: Check that memset is not used on classes // ClassCheck: Check that memset is not used on classes
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CheckClass::noMemset() void CheckClass::checkMemsetType(const Token *tok, const std::string &type)
{ {
createSymbolDatabase();
// Locate all 'memset' tokens..
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
{
if (!Token::Match(tok, "memset|memcpy|memmove"))
continue;
std::string type;
if (Token::Match(tok, "memset ( %var% , %num% , sizeof ( %type% ) )"))
type = tok->strAt(8);
else if (Token::Match(tok, "memset ( & %var% , %num% , sizeof ( %type% ) )"))
type = tok->strAt(9);
else if (Token::Match(tok, "memset ( %var% , %num% , sizeof ( struct %type% ) )"))
type = tok->strAt(9);
else if (Token::Match(tok, "memset ( & %var% , %num% , sizeof ( struct %type% ) )"))
type = tok->strAt(10);
else if (Token::Match(tok, "%type% ( %var% , %var% , sizeof ( %type% ) )"))
type = tok->strAt(8);
else if (Token::Match(tok, "memset ( & %var% , %num% , sizeof ( %var% ) )"))
{
unsigned int varid = tok->tokAt(3)->varId();
const Variable *var = symbolDatabase->getVariableFromVarId(varid);
if (var && var->typeStartToken() == var->typeEndToken())
type = var->typeStartToken()->str();
}
// No type defined => The tokens didn't match
if (type.empty())
continue;
// Warn if type is a class or struct that contains any std::* variables // Warn if type is a class or struct that contains any std::* variables
const std::string pattern2(std::string("struct|class ") + type + " {"); const std::string pattern2(std::string("struct|class ") + type + " :|{");
const Token *tstruct = Token::findmatch(_tokenizer->tokens(), pattern2.c_str()); const Token *tstruct = Token::findmatch(_tokenizer->tokens(), pattern2.c_str());
if (!tstruct) if (!tstruct)
continue; return;
const std::string &typeName = tstruct->str(); const std::string &typeName = tstruct->str();
if (tstruct->tokAt(2)->str() == ":")
{
tstruct = tstruct->tokAt(3);
for (; tstruct; tstruct = tstruct->next())
{
while (Token::Match(tstruct, "public|private|protected|virtual"))
{
tstruct = tstruct->next();
}
// recursively check all parent classes
checkMemsetType(tok, tstruct->str());
tstruct = tstruct->next();
if (tstruct->str() != ",")
break;
}
}
for (; tstruct; tstruct = tstruct->next()) for (; tstruct; tstruct = tstruct->next())
{ {
if (tstruct->str() == "}") if (tstruct->str() == "}")
@ -788,6 +776,42 @@ void CheckClass::noMemset()
} }
} }
} }
void CheckClass::noMemset()
{
createSymbolDatabase();
// Locate all 'memset' tokens..
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
{
if (!Token::Match(tok, "memset|memcpy|memmove"))
continue;
std::string type;
if (Token::Match(tok, "memset ( %var% , %num% , sizeof ( %type% ) )"))
type = tok->strAt(8);
else if (Token::Match(tok, "memset ( & %var% , %num% , sizeof ( %type% ) )"))
type = tok->strAt(9);
else if (Token::Match(tok, "memset ( %var% , %num% , sizeof ( struct %type% ) )"))
type = tok->strAt(9);
else if (Token::Match(tok, "memset ( & %var% , %num% , sizeof ( struct %type% ) )"))
type = tok->strAt(10);
else if (Token::Match(tok, "%type% ( %var% , %var% , sizeof ( %type% ) )"))
type = tok->strAt(8);
else if (Token::Match(tok, "memset ( & %var% , %num% , sizeof ( %var% ) )"))
{
unsigned int varid = tok->tokAt(3)->varId();
const Variable *var = symbolDatabase->getVariableFromVarId(varid);
if (var && var->typeStartToken() == var->typeEndToken())
type = var->typeStartToken()->str();
}
// No type defined => The tokens didn't match
if (type.empty())
continue;
checkMemsetType(tok, type);
}
} }
void CheckClass::memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type) void CheckClass::memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type)

View File

@ -84,6 +84,7 @@ public:
* Important: The checking doesn't work on simplified tokens list. * Important: The checking doesn't work on simplified tokens list.
*/ */
void noMemset(); void noMemset();
void checkMemsetType(const Token *tok, const std::string &type);
/** @brief 'operator=' should return something and it should not be const. */ /** @brief 'operator=' should return something and it should not be const. */
void operatorEq(); void operatorEq();

View File

@ -2949,6 +2949,18 @@ private:
" memset(&fred, 0, sizeof(fred));\n" " memset(&fred, 0, sizeof(fred));\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:8]: (error) Using 'memset' on class that contains a 'std::string'\n", errout.str()); ASSERT_EQUALS("[test.cpp:8]: (error) Using 'memset' on class that contains a 'std::string'\n", errout.str());
checkNoMemset("class Fred\n"
"{\n"
" std::string s;\n"
"};\n"
"class Pebbles: public Fred {};\n"
"void f()\n"
"{\n"
" Pebbles pebbles;\n"
" memset(&pebbles, 0, sizeof(pebbles));\n"
"}\n");
ASSERT_EQUALS("[test.cpp:9]: (error) Using 'memset' on class that contains a 'std::string'\n", errout.str());
} }
void memsetOnStruct() void memsetOnStruct()