Fixed #1566 (false negative: uninitialized variable)

This commit is contained in:
Daniel Marjamäki 2010-04-04 09:17:53 +02:00
parent 849be383e6
commit 78852b08ab
3 changed files with 73 additions and 11 deletions

View File

@ -2288,7 +2288,7 @@ private:
}
if (tok3->varId() == varid)
{
varid = 0; // variable is used.. maybe it's initialized. clear the variable id.
varid = 0; // variable is used.. maybe it's initialized. clear the variable id.
break;
}
}
@ -2340,7 +2340,7 @@ public:
/** Functions that don't handle uninitialized variables well */
static std::set<std::string> uvarFunctions;
static void analyseFunctions(const Token * const tokens, std::set<std::string> &func)
static void analyseFunctions(const Token * const tokens, std::set<std::string> &func, bool showAll)
{
for (const Token *tok = tokens; tok; tok = tok->next())
{
@ -2365,9 +2365,67 @@ public:
continue;
}
if (Token::Match(tok2, "const %type% %var% ,|)") && tok2->next()->isStandardType())
if (tok2->isStandardType() && Token::Match(tok2, "%type% & %var% ,|)"))
{
tok2 = tok2->tokAt(2);
const unsigned int varid(tok2->tokAt(2)->varId());
// flags for read/write
bool r = false, w = false;
// check how the variable is used in the function
unsigned int indentlevel = 0;
for (const Token *tok3 = tok2; tok3; tok3 = tok3->next())
{
if (tok3->str() == "{")
++indentlevel;
else if (tok3->str() == "}")
{
if (indentlevel <= 1)
break;
--indentlevel;
}
else if (indentlevel == 0 && tok3->str() == ";")
break;
else if (indentlevel >= 1 && tok3->varId() == varid)
{
if (Token::Match(tok3->previous(), "++|--") ||
Token::Match(tok3->next(), "++|--"))
{
r = true;
}
// --all
else if (showAll)
{
if (!Token::simpleMatch(tok3->next(), "="))
r = true;
else
{
w = true;
break;
}
}
else
{
w = true;
break;
}
}
}
if (!r || w)
break;
tok2 = tok2->tokAt(3);
continue;
}
if (Token::Match(tok2, "const %type% &|*| const| %var% ,|)") && tok2->next()->isStandardType())
{
tok2 = tok2->tokAt(3);
while (tok2->isName())
tok2 = tok2->next();
continue;
}
@ -2389,9 +2447,9 @@ std::set<std::string> CheckUninitVar::uvarFunctions;
/// @}
void CheckOther::analyseFunctions(const Token * const tokens, std::set<std::string> &func)
void CheckOther::analyseFunctions(const Token * const tokens, std::set<std::string> &func, bool showAll)
{
CheckUninitVar::analyseFunctions(tokens, func);
CheckUninitVar::analyseFunctions(tokens, func, showAll);
}
@ -2408,7 +2466,7 @@ void CheckOther::executionPaths()
{
// no writing if multiple threads are used (TODO: thread safe analysis?)
if (_settings->_jobs == 1)
CheckUninitVar::analyseFunctions(_tokenizer->tokens(), CheckUninitVar::uvarFunctions);
CheckUninitVar::analyseFunctions(_tokenizer->tokens(), CheckUninitVar::uvarFunctions, _settings->_showAll);
CheckUninitVar c(this);
checkExecutionPaths(_tokenizer->tokens(), &c);

View File

@ -93,8 +93,9 @@ public:
* @brief Uninitialized variables: analyse functions to see how they work with uninitialized variables
* @param tokens [in] the token list
* @param func [out] names of functions that don't handle uninitialized variables well. the function names are added to the set. No clearing is made.
* @param showAll [in] enable --all checking
*/
static void analyseFunctions(const Token * const tokens, std::set<std::string> &func);
static void analyseFunctions(const Token * const tokens, std::set<std::string> &func, bool showAll);
/** @brief Are there C-style pointer casts in a c++ file? */
void warningOldStylePointerCast();

View File

@ -1843,18 +1843,21 @@ private:
tokenizer.tokenize(istr, "test.cpp");
std::set<std::string> f;
CheckOther::analyseFunctions(tokenizer.tokens(), f);
CheckOther::analyseFunctions(tokenizer.tokens(), f, true);
std::string ret;
for (std::set<std::string>::const_iterator it = f.begin(); it != f.end(); ++it)
ret += *it + " ";
ret += (ret.empty() ? "" : " ") + *it;
return ret;
}
void uninitvar_func()
{
// function analysis..
ASSERT_EQUALS("foo ", analyseFunctions("void foo(int x) { }"));
ASSERT_EQUALS("foo", analyseFunctions("void foo(int x) { }"));
ASSERT_EQUALS("foo", analyseFunctions("void foo(const int &x) { }"));
ASSERT_EQUALS("foo", analyseFunctions("void foo(int &x) { ++x; }"));
ASSERT_EQUALS("", analyseFunctions("void foo(int &x) { x = 0; }"));
ASSERT_EQUALS("", analyseFunctions("void foo(s x) { }"));
// function calls..