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
|
// 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)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue