diff --git a/lib/checkother.cpp b/lib/checkother.cpp index d3b7cac76..f82fea122 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1277,6 +1277,20 @@ private: return &tok; } + + bool parseCondition(const Token &tok, std::list &checks) const + { + if (Token::Match(&tok, "!| %var% (")) + { + bool foundError = false; + std::list var; + parseFunctionCall(tok.str() == "!" ? *tok.next() : tok, var, 0); + for (std::list::const_iterator it = var.begin(); it != var.end(); ++it) + dereference(foundError, checks, *it); + } + + return ExecutionPath::parseCondition(tok, checks); + } }; @@ -1592,6 +1606,24 @@ private: } return &tok; } + + bool parseCondition(const Token &tok, std::list &checks) const + { + bool foundError = false; + + if (tok.varId() && Token::Match(&tok, "%var% <|<=|==|!=|)|[")) + use(foundError, checks, &tok); + + else if (Token::Match(&tok, "!| %var% (")) + { + std::list var; + parseFunctionCall(tok.str() == "!" ? *tok.next() : tok, var, 1); + for (std::list::const_iterator it = var.begin(); it != var.end(); ++it) + use_array(foundError, checks, *it); + } + + return ExecutionPath::parseCondition(tok, checks); + } }; diff --git a/lib/executionpath.cpp b/lib/executionpath.cpp index 5045ae79b..e2072c560 100644 --- a/lib/executionpath.cpp +++ b/lib/executionpath.cpp @@ -22,6 +22,32 @@ #include +// default : bail out if the condition is has variable handling +bool ExecutionPath::parseCondition(const Token &tok, std::list & /*checks*/) const +{ + unsigned int parlevel = 0; + for (const Token *tok2 = &tok; tok2; tok2 = tok2->next()) + { + if (tok2->str() == "(") + ++parlevel; + else if (tok2->str() == ")") + { + if (parlevel == 0) + break; + --parlevel; + } + else if (Token::Match(tok2, ";{}")) + break; + if (tok2->varId() != 0) + { + return true; + } + } + + return false; +} + + const Token *checkExecutionPaths(const Token *tok, std::list &checks) { const std::auto_ptr check(checks.front()->copy()); @@ -70,24 +96,16 @@ const Token *checkExecutionPaths(const Token *tok, std::list &c // goto "(" tok = tok->next(); + // parse condition + if (check->parseCondition(*tok->next(), checks)) + { + ExecutionPath::bailOut(checks); + return 0; + } + // goto ")" tok = tok ? tok->link() : 0; - // Check if the condition contains the variable - if (tok) - { - for (const Token *tok2 = tok->link(); tok2 && tok2 != tok; tok2 = tok2->next()) - { - // The variable may be initialized.. - // if (someFunction(&var)) .. - if (tok2->varId()) - { - ExecutionPath::bailOut(checks); - return 0; - } - } - } - // goto "{" tok = tok ? tok->next() : 0; diff --git a/lib/executionpath.h b/lib/executionpath.h index 9c46ea7a7..c6088e814 100644 --- a/lib/executionpath.h +++ b/lib/executionpath.h @@ -80,11 +80,19 @@ public: /** * Parse tokens at given location * @param tok token to parse - * @param foundError If an error is found this is set to true and the return token is the error token + * @param foundError If an error is found this is set to true * @param checks The execution paths. All execution paths in the list are executed in the current scope. - * @return if error is found => error token. if you want to skip tokens, return the last skipped token. otherwise return tok. + * @return the token before the "next" token. **/ virtual const Token *parse(const Token &tok, bool &foundError, std::list &checks) const = 0; + + /** + * Parse condition + * @param tok first token in condition. + * @param checks The execution paths. All execution paths in the list are executed in the current scope + * @return true => bail out all checking + **/ + virtual bool parseCondition(const Token &tok, std::list &checks) const; }; diff --git a/test/testother.cpp b/test/testother.cpp index f86abb7d6..afb58e0e2 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -998,6 +998,13 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: ret\n", errout.str()); + checkUninitVar("static void foo()\n" + "{\n" + " int i;\n" + " if (i);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: i\n", errout.str()); + checkUninitVar("static void foo()\n" "{\n" " int x, y;\n"