Merge branch 'master' of http://github.com/danmar/cppcheck
This commit is contained in:
commit
9f5f0e13a6
|
@ -689,87 +689,43 @@ 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::checkMemsetType(const Scope *start, const Token *tok, const Token *typeTok)
|
void CheckClass::checkMemsetType(const Scope *start, const Token *tok, const Scope *type)
|
||||||
{
|
{
|
||||||
// Warn if type is a class or struct that contains any std::* variables
|
|
||||||
const Scope *scope = symbolDatabase->findVariableType(start, typeTok);
|
|
||||||
if (!scope)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const Token *tstruct = scope->classDef;
|
|
||||||
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
|
// recursively check all parent classes
|
||||||
checkMemsetType(start, tok, tstruct);
|
for (size_t i = 0; i < type->derivedFrom.size(); i++)
|
||||||
|
{
|
||||||
tstruct = tstruct->next();
|
if (type->derivedFrom[i].scope)
|
||||||
if (tstruct->str() != ",")
|
checkMemsetType(start, tok, type->derivedFrom[i].scope);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; tstruct; tstruct = tstruct->next())
|
// Warn if type is a class that contains any virtual functions
|
||||||
{
|
std::list<Function>::const_iterator func;
|
||||||
if (tstruct->str() == "}")
|
|
||||||
break;
|
|
||||||
|
|
||||||
// struct with function? skip function body..
|
for (func = type->functionList.begin(); func != type->functionList.end(); ++func)
|
||||||
if (Token::simpleMatch(tstruct, ") {"))
|
|
||||||
{
|
{
|
||||||
tstruct = tstruct->next()->link();
|
if (func->isVirtual)
|
||||||
if (!tstruct)
|
memsetError(tok, tok->str(), "virtual method", type->classDef->str());
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// before a statement there must be either:
|
// Warn if type is a class or struct that contains any std::* variables
|
||||||
// * private:|protected:|public:
|
std::list<Variable>::const_iterator var;
|
||||||
// * { } ;
|
|
||||||
if (Token::Match(tstruct, "[;{}]") ||
|
|
||||||
tstruct->str().find(":") != std::string::npos)
|
|
||||||
{
|
|
||||||
if (Token::Match(tstruct->next(), "std :: %type% %var% ;"))
|
|
||||||
memsetError(tok, tok->str(), "'std::" + tstruct->strAt(3) + "'", typeName);
|
|
||||||
|
|
||||||
else if (Token::Match(tstruct->next(), "std :: %type% <"))
|
for (var = type->varlist.begin(); var != type->varlist.end(); ++var)
|
||||||
{
|
{
|
||||||
// backup the type
|
// don't warn if variable static or const
|
||||||
const std::string typestr(tstruct->strAt(3));
|
if (!var->isStatic() && !var->isConst())
|
||||||
|
|
||||||
// check if it's a pointer variable..
|
|
||||||
unsigned int level = 0;
|
|
||||||
while (0 != (tstruct = tstruct->next()))
|
|
||||||
{
|
{
|
||||||
if (tstruct->str() == "<")
|
const Token *tok1 = var->typeStartToken();
|
||||||
++level;
|
|
||||||
else if (tstruct->str() == ">")
|
|
||||||
{
|
|
||||||
if (level <= 1)
|
|
||||||
break;
|
|
||||||
--level;
|
|
||||||
}
|
|
||||||
else if (tstruct->str() == "(")
|
|
||||||
tstruct = tstruct->link();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tstruct)
|
// skip mutable token
|
||||||
break;
|
if (var->isMutable())
|
||||||
|
tok1 = tok1->next();
|
||||||
|
|
||||||
// found error => report
|
// check for std:: type that is not a pointer or reference
|
||||||
if (Token::Match(tstruct, "> %var% ;"))
|
if (Token::simpleMatch(tok1, "std ::") && !Token::Match(var->nameToken()->previous(), "*|&"))
|
||||||
memsetError(tok, tok->str(), "'std::" + typestr + "'", typeName);
|
memsetError(tok, tok->str(), "'std::" + tok1->strAt(2) + "'", type->classDef->str());
|
||||||
}
|
|
||||||
else if (Token::simpleMatch(tstruct->next(), "virtual"))
|
/** @todo warn if type is class/struct that doesn't require initialization */
|
||||||
memsetError(tok, tok->str(), "virtual method", typeName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -823,7 +779,10 @@ void CheckClass::noMemset()
|
||||||
if (!typeTok)
|
if (!typeTok)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
checkMemsetType(&(*scope), tok, typeTok);
|
const Scope *type = symbolDatabase->findVariableType(&(*scope), typeTok);
|
||||||
|
|
||||||
|
if (type)
|
||||||
|
checkMemsetType(&(*scope), tok, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +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 Scope *start, const Token *tok, const Token *typeTok);
|
void checkMemsetType(const Scope *start, const Token *tok, const Scope *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();
|
||||||
|
|
|
@ -104,7 +104,7 @@ bool CheckMemoryLeak::isclass(const Tokenizer *_tokenizer, const Token *tok) con
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, unsigned int varid) const
|
CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, unsigned int varid, std::list<const Token *> *callstack) const
|
||||||
{
|
{
|
||||||
// What we may have...
|
// What we may have...
|
||||||
// * var = (char *)malloc(10);
|
// * var = (char *)malloc(10);
|
||||||
|
@ -190,7 +190,19 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2,
|
||||||
|
|
||||||
// User function
|
// User function
|
||||||
const Token *ftok = tokenizer->getFunctionTokenByName(tok2->str().c_str());
|
const Token *ftok = tokenizer->getFunctionTokenByName(tok2->str().c_str());
|
||||||
return functionReturnType(ftok);
|
if (ftok == NULL)
|
||||||
|
return No;
|
||||||
|
|
||||||
|
// Prevent recursion
|
||||||
|
if (callstack && std::find(callstack->begin(), callstack->end(), ftok) != callstack->end())
|
||||||
|
return No;
|
||||||
|
|
||||||
|
std::list<const Token *> cs;
|
||||||
|
if (!callstack)
|
||||||
|
callstack = &cs;
|
||||||
|
|
||||||
|
callstack->push_back(ftok);
|
||||||
|
return functionReturnType(ftok, callstack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -386,13 +398,11 @@ void CheckMemoryLeak::mismatchAllocDealloc(const std::list<const Token *> &calls
|
||||||
reportErr(callstack, Severity::error, "mismatchAllocDealloc", "Mismatching allocation and deallocation: " + varname);
|
reportErr(callstack, Severity::error, "mismatchAllocDealloc", "Mismatching allocation and deallocation: " + varname);
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok) const
|
CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok, std::list<const Token *> *callstack) const
|
||||||
{
|
{
|
||||||
if (!tok)
|
if (!tok)
|
||||||
return No;
|
return No;
|
||||||
|
|
||||||
const std::string functionName = tok->str();
|
|
||||||
|
|
||||||
// Locate start of function
|
// Locate start of function
|
||||||
while (tok)
|
while (tok)
|
||||||
{
|
{
|
||||||
|
@ -437,11 +447,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok)
|
||||||
}
|
}
|
||||||
else if (tok2->str() == "return")
|
else if (tok2->str() == "return")
|
||||||
{
|
{
|
||||||
// recursion => bail out
|
AllocType allocType = getAllocationType(tok2->next(), 0, callstack);
|
||||||
if (tok2->strAt(1) == functionName)
|
|
||||||
return No;
|
|
||||||
|
|
||||||
AllocType allocType = getAllocationType(tok2->next(), 0);
|
|
||||||
if (allocType != No)
|
if (allocType != No)
|
||||||
return allocType;
|
return allocType;
|
||||||
}
|
}
|
||||||
|
@ -457,11 +463,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok)
|
||||||
{
|
{
|
||||||
if (Token::Match(tok, "%varid% =", varid))
|
if (Token::Match(tok, "%varid% =", varid))
|
||||||
{
|
{
|
||||||
// recursion => bail out
|
allocType = getAllocationType(tok->tokAt(2), varid, callstack);
|
||||||
if (tok->strAt(2) == functionName)
|
|
||||||
return No;
|
|
||||||
|
|
||||||
allocType = getAllocationType(tok->tokAt(2), varid);
|
|
||||||
}
|
}
|
||||||
if (Token::Match(tok, "= %varid% ;", varid))
|
if (Token::Match(tok, "= %varid% ;", varid))
|
||||||
{
|
{
|
||||||
|
|
|
@ -114,7 +114,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Get type of allocation at given position
|
* @brief Get type of allocation at given position
|
||||||
*/
|
*/
|
||||||
AllocType getAllocationType(const Token *tok2, unsigned int varid) const;
|
AllocType getAllocationType(const Token *tok2, unsigned int varid, std::list<const Token *> *callstack = NULL) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get type of reallocation at given position
|
* @brief Get type of reallocation at given position
|
||||||
|
@ -144,7 +144,7 @@ public:
|
||||||
void memleakUponReallocFailureError(const Token *tok, const std::string &varname);
|
void memleakUponReallocFailureError(const Token *tok, const std::string &varname);
|
||||||
|
|
||||||
/** What type of allocated memory does the given function return? */
|
/** What type of allocated memory does the given function return? */
|
||||||
AllocType functionReturnType(const Token *tok) const;
|
AllocType functionReturnType(const Token *tok, std::list<const Token *> *callstack = NULL) const;
|
||||||
|
|
||||||
/** Function allocates pointed-to argument (a la asprintf)? */
|
/** Function allocates pointed-to argument (a la asprintf)? */
|
||||||
const char *functionArgAlloc(const Token *tok, unsigned int targetpar, AllocType &allocType) const;
|
const char *functionArgAlloc(const Token *tok, unsigned int targetpar, AllocType &allocType) const;
|
||||||
|
|
|
@ -5715,6 +5715,17 @@ void Tokenizer::simplifyVarDecl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (Token::Match(tok2, "%type% :: %type% %var% ,|="))
|
||||||
|
{
|
||||||
|
if (tok2->tokAt(3)->str() != "operator")
|
||||||
|
{
|
||||||
|
tok2 = tok2->tokAt(4); // The ',' token
|
||||||
|
typelen = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tok2 = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
else if (Token::Match(tok2, "%type% %var% [ %num% ] ,|=|[") ||
|
else if (Token::Match(tok2, "%type% %var% [ %num% ] ,|=|[") ||
|
||||||
Token::Match(tok2, "%type% %var% [ %var% ] ,|=|["))
|
Token::Match(tok2, "%type% %var% [ %var% ] ,|=|["))
|
||||||
{
|
{
|
||||||
|
|
|
@ -2933,6 +2933,28 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkNoMemset("class Fred\n"
|
||||||
|
"{\n"
|
||||||
|
" static std::string b;\n"
|
||||||
|
"};\n"
|
||||||
|
"void f()\n"
|
||||||
|
"{\n"
|
||||||
|
" Fred fred;\n"
|
||||||
|
" memset(&fred, 0, sizeof(Fred));\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkNoMemset("class Fred\n"
|
||||||
|
"{\n"
|
||||||
|
" std::string * b; \n"
|
||||||
|
"};\n"
|
||||||
|
"void f()\n"
|
||||||
|
"{\n"
|
||||||
|
" Fred fred;\n"
|
||||||
|
" memset(&fred, 0, sizeof(Fred));\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
checkNoMemset("class Fred\n"
|
checkNoMemset("class Fred\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" std::string b; \n"
|
" std::string b; \n"
|
||||||
|
@ -2944,6 +2966,17 @@ private:
|
||||||
"}\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"
|
||||||
|
" mutable std::string b; \n"
|
||||||
|
"};\n"
|
||||||
|
"void f()\n"
|
||||||
|
"{\n"
|
||||||
|
" Fred fred;\n"
|
||||||
|
" 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"
|
checkNoMemset("class Fred\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
|
|
|
@ -3631,6 +3631,18 @@ private:
|
||||||
" char *s = foo();\n"
|
" char *s = foo();\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("int shl()\n"
|
||||||
|
"{\n"
|
||||||
|
" int a = shr();\n"
|
||||||
|
" return a;\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"int shr()\n"
|
||||||
|
"{\n"
|
||||||
|
" return shl();\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4115,8 +4115,7 @@ private:
|
||||||
void vardecl_stl_2()
|
void vardecl_stl_2()
|
||||||
{
|
{
|
||||||
const char code1[] = "{ std::string x = \"abc\"; }";
|
const char code1[] = "{ std::string x = \"abc\"; }";
|
||||||
TODO_ASSERT_EQUALS("{ std :: string x ; x = \"abc\" ; }",
|
ASSERT_EQUALS("{ std :: string x ; x = \"abc\" ; }", tokenizeAndStringify(code1));
|
||||||
"{ std :: string x = \"abc\" ; }", tokenizeAndStringify(code1));
|
|
||||||
|
|
||||||
const char code2[] = "{ std::vector<int> x = y; }";
|
const char code2[] = "{ std::vector<int> x = y; }";
|
||||||
TODO_ASSERT_EQUALS("{ std :: vector < int > x ; x = y ; }",
|
TODO_ASSERT_EQUALS("{ std :: vector < int > x ; x = y ; }",
|
||||||
|
|
Loading…
Reference in New Issue