Uninitialized variables: Improved checking when there are multiple if/else and a certain path causes an error
This commit is contained in:
parent
2d05cae13b
commit
f48edb63a3
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue