From f48edb63a3256cf55ee8eb3682fae92eefa18e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 26 Dec 2011 12:36:35 +0100 Subject: [PATCH] Uninitialized variables: Improved checking when there are multiple if/else and a certain path causes an error --- lib/checkuninitvar.cpp | 27 +++++++++++++++------------ lib/checkuninitvar.h | 2 +- test/testuninitvar.cpp | 11 ++++++++++- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index d1e18939a..999b9bf69 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -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 diff --git a/lib/checkuninitvar.h b/lib/checkuninitvar.h index ce756a272..108fb63b1 100644 --- a/lib/checkuninitvar.h +++ b/lib/checkuninitvar.h @@ -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; /** diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index d4daee407..37a614cf3 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -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"