Uninitialized variables: Improved checking when there are multiple if/else and a certain path causes an error

This commit is contained in:
Daniel Marjamäki 2011-12-26 12:36:35 +01:00
parent 2d05cae13b
commit f48edb63a3
3 changed files with 26 additions and 14 deletions

View File

@ -1058,11 +1058,16 @@ void CheckUninitVar::check()
}
}
bool CheckUninitVar::checkScopeForVariable(const Token *tok, const unsigned int varid)
bool CheckUninitVar::checkScopeForVariable(const Token *tok, const unsigned int varid, bool * const possibleInit)
{
if (varid == 0)
return false;
const bool suppressErrors(possibleInit && *possibleInit);
if (possibleInit)
*possibleInit = false;
bool ret = false;
unsigned int number_of_if = 0;
@ -1070,8 +1075,8 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const unsigned int
for (; tok; tok = tok->next()) {
// End of scope..
if (tok->str() == "}") {
if (number_of_if)
return true;
if (number_of_if && possibleInit)
*possibleInit = true;
// might be a noreturn function..
if (Token::simpleMatch(tok->tokAt(-2), ") ; }") &&
@ -1085,15 +1090,11 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const unsigned int
// Inner scope..
if (Token::Match(tok, "if (")) {
if (number_of_if) {
return true;
}
// initialization in condition..
const Token * const endToken = tok->next()->link();
for (const Token *tok2 = tok->tokAt(2); tok2 != endToken; tok2 = tok2->next()) {
if (tok2->varId() == varid) {
if (isVariableUsage(tok2))
if (!suppressErrors && isVariableUsage(tok2))
uninitvarError(tok2, tok2->str());
return true;
}
@ -1104,7 +1105,8 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const unsigned int
// goto the {
tok = tok->next()->link()->next();
const bool initif = checkScopeForVariable(tok->next(), varid);
bool possibleInitIf(number_of_if > 0);
const bool initif = checkScopeForVariable(tok->next(), varid, &possibleInitIf);
// goto the }
tok = tok->link();
@ -1114,7 +1116,7 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const unsigned int
return true; // bail out
if (!Token::Match(tok, "} else {")) {
if (initif) {
if (initif || possibleInitIf) {
++number_of_if;
if (number_of_if >= 2)
return true;
@ -1123,7 +1125,8 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const unsigned int
// goto the {
tok = tok->tokAt(2);
const bool initelse = checkScopeForVariable(tok->next(), varid);
bool possibleInitElse(number_of_if > 0);
const bool initelse = checkScopeForVariable(tok->next(), varid, &possibleInitElse);
// goto the }
tok = tok->link();
@ -1172,7 +1175,7 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const unsigned int
// variable is seen..
if (tok->varId() == varid) {
// Use variable
if (isVariableUsage(tok))
if (!suppressErrors && isVariableUsage(tok))
uninitvarError(tok, tok->str());
else

View File

@ -60,7 +60,7 @@ public:
/** Check for uninitialized variables */
void check();
bool checkScopeForVariable(const Token *tok, const unsigned int varid);
bool checkScopeForVariable(const Token *tok, const unsigned int varid, bool * const possibleInit=0);
bool isVariableUsage(const Token *vartok) const;
/**

View File

@ -1776,7 +1776,16 @@ private:
" else if (y == 2) { x = 1; }\n"
" return x;\n"
"}\n");
TODO_ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: x\n", "", errout.str());
ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: x\n", errout.str());
checkUninitVar2("void f() {\n"
" int x;\n"
" if (y == 1) { x = 1; }\n"
" else if (y == 2) { x = 1; }\n"
" if (y == 3) { }\n" // <- ignore condition
" return x;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: x\n", errout.str());
// initialization in condition
checkUninitVar2("void f() {\n"