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

View File

@ -60,7 +60,7 @@ public:
/** Check for uninitialized variables */ /** Check for uninitialized variables */
void check(); 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; bool isVariableUsage(const Token *vartok) const;
/** /**

View File

@ -1776,7 +1776,16 @@ private:
" else if (y == 2) { x = 1; }\n" " else if (y == 2) { x = 1; }\n"
" return x;\n" " return x;\n"
"}\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 // initialization in condition
checkUninitVar2("void f() {\n" checkUninitVar2("void f() {\n"