diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 15a89282b..a19f5112e 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1118,6 +1118,7 @@ void CheckOther::nullPointer() } + /** * \brief parse a function call and extract information about variable usage * \param tok first token @@ -1620,7 +1621,7 @@ private: if (tok.varId()) { // Used.. - if (Token::Match(tok.previous(), "[[+-*/] %var% []+-*/]")) + if (Token::Match(tok.previous(), "[[(,+-*/] %var% []),+-*/]")) { use(foundError, checks, &tok); return &tok; @@ -1708,7 +1709,7 @@ private: } } - if (Token::Match(&tok, "%var% (")) + if (Token::Match(&tok, "%var% (") && uvarFunctions.find(tok.str()) == uvarFunctions.end()) { if (Token::simpleMatch(&tok, "sizeof (")) return tok.next()->link(); @@ -1891,8 +1892,61 @@ private: return ExecutionPath::parseCondition(tok, checks); } + +public: + + static std::set uvarFunctions; + + static void analyseFunctions(const Token * const tokens, std::set &func) + { + for (const Token *tok = tokens; tok; tok = tok->next()) + { + if (tok->str() == "{") + { + tok = tok->link(); + continue; + } + if (tok->str() != "::" && Token::Match(tok->next(), "%var% ( %type%")) + { + if (!Token::simpleMatch(tok->tokAt(2)->link(), ") {")) + continue; + const Token *tok2 = tok->tokAt(3); + while (tok2 && tok2->str() != ")") + { + if (tok2->str() == ",") + tok2 = tok2->next(); + + if (Token::Match(tok2, "%type% %var% ,|)") && tok2->isStandardType()) + { + tok2 = tok2->tokAt(2); + continue; + } + + if (Token::Match(tok2, "const %type% %var% ,|)") && tok2->next()->isStandardType()) + { + tok2 = tok2->tokAt(2); + continue; + } + + break; + } + + // found simple function.. + if (tok2->link() == tok->tokAt(2)) + func.insert(tok->next()->str()); + } + } + } }; +std::set CheckUninitVar::uvarFunctions; + + +void CheckOther::analyseFunctions(const Token * const tokens, std::set &func) +{ + CheckUninitVar::analyseFunctions(tokens, func); +} + void CheckOther::executionPaths() @@ -1905,6 +1959,7 @@ void CheckOther::executionPaths() // check if variable is accessed uninitialized.. { + CheckUninitVar::analyseFunctions(_tokenizer->tokens(), CheckUninitVar::uvarFunctions); CheckUninitVar c(this); checkExecutionPaths(_tokenizer->tokens(), &c); } diff --git a/lib/checkother.h b/lib/checkother.h index 3228fc42f..8165c1970 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -81,6 +81,11 @@ public: checkOther.executionPaths(); } + + // TODO move CheckUninitVar? + static void analyseFunctions(const Token * const tokens, std::set &func); + + // Casting void warningOldStylePointerCast(); diff --git a/test/testother.cpp b/test/testother.cpp index 301c42762..df0829cf4 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -70,6 +70,7 @@ private: TEST_CASE(nullpointer7); TEST_CASE(uninitvar1); + TEST_CASE(uninitvar_func); // analyse functions TEST_CASE(oldStylePointerCast); @@ -1668,6 +1669,39 @@ private: "}\n"); ASSERT_EQUALS("", errout.str()); + + // sub functions.. + checkUninitVar("int foo(int x) { return x; }\n" + "void f2()\n" + "{\n" + " int x;\n" + " foo(x);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: x\n", errout.str()); + + } + + + std::string analyseFunctions(const char code[]) + { + // Tokenize.. + Tokenizer tokenizer; + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + + std::set f; + CheckOther::analyseFunctions(tokenizer.tokens(), f); + + std::string ret; + for (std::set::const_iterator it = f.begin(); it != f.end(); ++it) + ret += *it + " "; + return ret; + } + + void uninitvar_func() + { + ASSERT_EQUALS("foo ", analyseFunctions("void foo(int x) { }")); + ASSERT_EQUALS("", analyseFunctions("void foo(s x) { }")); }