diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index ecd5f5abb..8ef80a58e 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1113,17 +1113,9 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const unsigned int // Inner scope.. if (Token::Match(tok, "if (")) { - // 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 (!suppressErrors && isVariableUsage(tok2, ispointer)) - uninitvarError(tok2, tok2->str()); - return true; - } - if (Token::Match(tok2, "sizeof|decltype|offsetof (")) - tok2 = tok2->next()->link(); - } + // initialization / usage in condition.. + if (checkIfForWhileHead(tok->next(), varid, ispointer, suppressErrors)) + return true; // goto the { tok = tok->next()->link()->next(); @@ -1180,8 +1172,25 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const unsigned int if (Token::Match(tok, "sizeof|offsetof|decltype (")) tok = tok->next()->link(); + // for.. + if (Token::simpleMatch(tok, "for (")) { + // goto the { + const Token *tok2 = tok->next()->link()->next(); + + bool possibleinit = true; + bool init = checkScopeForVariable(tok2->next(), varid, ispointer, &possibleinit); + + // variable is initialized in the loop.. + if (possibleinit || init) + return true; + + // is variable used / initialized in for-head + if (checkIfForWhileHead(tok->next(), varid, ispointer, suppressErrors)) + return true; + } + // TODO: handle loops, try, etc - if (tok->str() == "for" || Token::simpleMatch(tok, ") {") || Token::Match(tok, "%var% {")) { + if (Token::simpleMatch(tok, ") {") || Token::Match(tok, "%var% {")) { return true; } @@ -1210,6 +1219,23 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const unsigned int return ret; } +bool CheckUninitVar::checkIfForWhileHead(const Token *startparanthesis, unsigned int varid, bool ispointer, bool suppressErrors) +{ + const Token * const endpar = startparanthesis->link(); + for (const Token *tok = startparanthesis->next(); tok && tok != endpar; tok = tok->next()) { + if (tok->varId() == varid) { + if (!suppressErrors && isVariableUsage(tok, ispointer)) + uninitvarError(tok, tok->str()); + return true; + } + if (Token::Match(tok, "sizeof|decltype|offsetof (")) + tok = tok->next()->link(); + if (tok->str() == "&&") + suppressErrors = true; + } + return false; +} + bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer) const { if (vartok->previous()->str() == "return") diff --git a/lib/checkuninitvar.h b/lib/checkuninitvar.h index 9cf9acf35..d6896ed4c 100644 --- a/lib/checkuninitvar.h +++ b/lib/checkuninitvar.h @@ -61,8 +61,10 @@ public: /** Check for uninitialized variables */ void check(); bool checkScopeForVariable(const Token *tok, const unsigned int varid, bool ispointer, bool * const possibleInit); + bool checkIfForWhileHead(const Token *startparanthesis, unsigned int varid, bool ispointer, bool suppressErrors); bool isVariableUsage(const Token *vartok, bool ispointer) const; + /** * @brief Uninitialized variables: analyse functions to see how they work with uninitialized variables * @param tokens [in] the token list diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 23a45e9c3..5ce31e8c4 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -1863,7 +1863,7 @@ private: " for (int i = 0; i < 10; i += x) {\n" " }\n" "}\n"); - TODO_ASSERT_EQUALS("error", "", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: x\n", errout.str()); // try checkUninitVar2("void f() {\n" @@ -1917,6 +1917,19 @@ private: "}\n"); ASSERT_EQUALS("", errout.str()); + checkUninitVar2("static void f(int x, int y) {\n" + " int a;\n" + " if (x == 0) { a = y; }\n" + " if (x == 0 && (a == 1)) { }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + checkUninitVar2("static void f(int x, int y) {\n" + " int a;\n" + " if (x == 0 && (a == 1)) { }\n" + "}\n"); + TODO_ASSERT_EQUALS("error", "", errout.str()); + // asm checkUninitVar2("void f() {\n" " int x;\n"