refactor noMemset so it recursively checks parent classes for non-memset-compatible things
This commit is contained in:
parent
7a7257f200
commit
70b4076111
|
@ -693,48 +693,36 @@ void CheckClass::unusedPrivateFunctionError(const Token *tok, const std::string
|
|||
// 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
|
||||
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());
|
||||
|
||||
if (!tstruct)
|
||||
continue;
|
||||
return;
|
||||
|
||||
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())
|
||||
{
|
||||
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)
|
||||
|
|
|
@ -84,6 +84,7 @@ public:
|
|||
* Important: The checking doesn't work on simplified tokens list.
|
||||
*/
|
||||
void noMemset();
|
||||
void checkMemsetType(const Token *tok, const std::string &type);
|
||||
|
||||
/** @brief 'operator=' should return something and it should not be const. */
|
||||
void operatorEq();
|
||||
|
|
|
@ -2949,6 +2949,18 @@ private:
|
|||
" memset(&fred, 0, sizeof(fred));\n"
|
||||
"}\n");
|
||||
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()
|
||||
|
|
Loading…
Reference in New Issue