diff --git a/lib/executionpath.cpp b/lib/executionpath.cpp index c05aed1e5..a72902ca1 100644 --- a/lib/executionpath.cpp +++ b/lib/executionpath.cpp @@ -89,7 +89,7 @@ static void checkExecutionPaths_(const Token *tok, std::list &c for (; tok; tok = tok->next()) { - if (tok->str() == "}") + if (tok->str() == "}" || tok->str() == "break") return; if (Token::simpleMatch(tok, "while (")) @@ -122,6 +122,82 @@ static void checkExecutionPaths_(const Token *tok, std::list &c return; } + if (tok->str() == "switch") + { + const Token *tok2 = tok->next()->link(); + if (Token::simpleMatch(tok2, ") { case")) + { + // what variable ids should the if be counted for? + std::set countif; + + std::list newchecks; + + for (tok2 = tok2->tokAt(2); tok2; tok2 = tok2->next()) + { + if (tok2->str() == "{") + tok2 = tok2->link(); + else if (tok2->str() == "}") + break; + else if (tok2->str() == "case") + { + if (Token::Match(tok2, "case %num% : ; case")) + continue; + + std::set countif2; + std::list c; + if (!checks.empty()) + { + std::list::const_iterator it; + for (it = checks.begin(); it != checks.end(); ++it) + { + c.push_back((*it)->copy()); + if ((*it)->varId != 0) + countif2.insert((*it)->varId); + } + } + checkExecutionPaths_(tok2, c); + while (!c.empty()) + { + if (c.back()->varId == 0) + { + c.pop_back(); + continue; + } + + bool duplicate = false; + std::list::const_iterator it; + for (it = checks.begin(); it != checks.end(); ++it) + { + if (*(*it) == *c.back()) + { + duplicate = true; + countif2.erase((*it)->varId); + break; + } + } + if (!duplicate) + newchecks.push_back(c.back()); + c.pop_back(); + } + + // Add countif2 ids to countif.. countif. + countif.insert(countif2.begin(), countif2.end()); + } + + // Add newchecks to checks.. + std::copy(newchecks.begin(), newchecks.end(), std::back_inserter(checks)); + + // Increase numberOfIf + std::list::iterator it; + for (it = checks.begin(); it != checks.end(); ++it) + { + if (countif.find((*it)->varId) != countif.end()) + (*it)->numberOfIf++; + } + } + } + } + // for/while/switch/do .. bail out if (Token::Match(tok, "for|while|switch|do")) { diff --git a/test/testother.cpp b/test/testother.cpp index e342d3ae0..4b360e029 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -75,7 +75,8 @@ private: TEST_CASE(uninitvar_arrays); // arrays TEST_CASE(uninitvar_class); // class/struct TEST_CASE(uninitvar_enum); // enum variables - TEST_CASE(uninitvar_if); // handling if/while/switch + TEST_CASE(uninitvar_if); // handling if/while + TEST_CASE(uninitvar_switch); // handling switch TEST_CASE(uninitvar_references); // references TEST_CASE(uninitvar_strncpy); // strncpy doesn't always 0-terminate TEST_CASE(uninitvar_func); // analyse functions @@ -1659,44 +1660,6 @@ private: "}\n"); ASSERT_EQUALS("", errout.str()); - // switch.. - checkUninitVar("char * f()\n" - "{\n" - " static char ret[200];\n" - " memset(ret, 0, sizeof(ret));\n" - " switch (x)\n" - " {\n" - " case 1: return ret;\n" - " case 2: return ret;\n" - " }\n" - " return 0;\n" - "}\n"); - ASSERT_EQUALS("", errout.str()); - - checkUninitVar("int foo(const int iVar, unsigned int slot, unsigned int pin)\n" - "{\n" - " int i;\n" - "\n" - " if (iVar == 0)\n" - " {\n" - " switch (slot)\n" - " {\n" - " case 4: return 5;\n" - " default: return -1;\n" - " }\n" - " }\n" - " else\n" - " {\n" - " switch (pin)\n" - " {\n" - " case 0: i = 2; break;\n" - " default: i = -1; break;\n" - " }\n" - " }\n" - " return i;\n" - "}\n"); - ASSERT_EQUALS("", errout.str()); - // while.. checkUninitVar("int f()\n" "{\n" @@ -1741,6 +1704,58 @@ private: ASSERT_EQUALS("", errout.str()); } + // switch.. + void uninitvar_switch() + { + checkUninitVar("void f(int x)\n" + "{\n" + " short c;\n" + " switch(x) {\n" + " case 1:\n" + " c++;\n" + " break;\n" + " };\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: c\n", errout.str()); + + checkUninitVar("char * f()\n" + "{\n" + " static char ret[200];\n" + " memset(ret, 0, sizeof(ret));\n" + " switch (x)\n" + " {\n" + " case 1: return ret;\n" + " case 2: return ret;\n" + " }\n" + " return 0;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + checkUninitVar("int foo(const int iVar, unsigned int slot, unsigned int pin)\n" + "{\n" + " int i;\n" + "\n" + " if (iVar == 0)\n" + " {\n" + " switch (slot)\n" + " {\n" + " case 4: return 5;\n" + " default: return -1;\n" + " }\n" + " }\n" + " else\n" + " {\n" + " switch (pin)\n" + " {\n" + " case 0: i = 2; break;\n" + " default: i = -1; break;\n" + " }\n" + " }\n" + " return i;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + // arrays.. void uninitvar_arrays() {