From 2bb54fef69ab653943ceff0b428046a55c2df5dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Fri, 19 May 2017 14:34:59 +0200 Subject: [PATCH] ValueFlow: Test ErrorPath handling --- lib/valueflow.cpp | 39 +++++++++++----------------- test/testvalueflow.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 24 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index ac33e579e..829fed58d 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -2746,45 +2746,36 @@ static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger, if (!functionScope) continue; - unsigned int argnr = 0U; - for (const Token *argtok = tok->tokAt(2); argtok; argtok = argtok->nextArgument()) { + const std::vector &callArguments = getArguments(tok); + for (unsigned int argnr = 0U; argnr < callArguments.size(); ++argnr) { + const Token *argtok = callArguments[argnr]; // Get function argument - const Variable * const arg = currentFunction->getArgumentVar(argnr++); - if (!arg) + const Variable * const argvar = currentFunction->getArgumentVar(argnr); + if (!argvar) break; - std::list argvalues; - // passing value(s) to function - if (!argtok->values().empty() && Token::Match(argtok, "%name%|%num%|%str% [,)]")) + std::list argvalues; + if (Token::Match(argtok, "%comp%|%oror%|&&|!") && !argtok->hasKnownIntValue()) { + argvalues.push_back(ValueFlow::Value(0)); + argvalues.push_back(ValueFlow::Value(1)); + } else { argvalues = argtok->values(); - else { - // bool operator => values 1/0 are passed to function.. - const Token *op = argtok; - while (op && op->astParent() && !Token::Match(op->astParent(), "[(,]")) - op = op->astParent(); - if (Token::Match(op, "%comp%|%oror%|&&|!")) { - argvalues.clear(); - argvalues.push_back(ValueFlow::Value(0)); - argvalues.push_back(ValueFlow::Value(1)); - } else if (Token::Match(op, "%cop%") && !op->values().empty()) { - argvalues = op->values(); - } else { - // possible values are unknown.. - continue; - } } + if (argvalues.empty()) + continue; + // Error path.. for (std::list::iterator it = argvalues.begin(); it != argvalues.end(); ++it) - it->errorPath.push_back(ErrorPathItem(argtok, "function call argument")); + it->errorPath.push_back(ErrorPathItem(argtok, "Function argument, integer value " + MathLib::toString(it->intvalue))); // passed values are not "known".. for (std::list::iterator it = argvalues.begin(); it != argvalues.end(); ++it) { it->changeKnownToPossible(); } - valueFlowInjectParameter(tokenlist, errorLogger, settings, arg, functionScope, argvalues); + valueFlowInjectParameter(tokenlist, errorLogger, settings, argvar, functionScope, argvalues); } } } diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 90d97bc17..8ce3323cd 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -53,6 +53,8 @@ private: TEST_CASE(valueFlowCalculations); + TEST_CASE(valueFlowErrorPath); + TEST_CASE(valueFlowBeforeCondition); TEST_CASE(valueFlowBeforeConditionAndAndOrOrGuard); TEST_CASE(valueFlowBeforeConditionAssignIncDec); @@ -108,6 +110,30 @@ private: return false; } + std::string getErrorPathForX(const char code[], unsigned int linenr) { + // Tokenize.. + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + + for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) { + if (tok->str() != "x" || tok->linenr() != linenr) + continue; + + std::ostringstream ostr; + std::list::const_iterator it; + for (it = tok->values().begin(); it != tok->values().end(); ++it) { + for (ValueFlow::Value::ErrorPath::const_iterator ep = it->errorPath.begin(); ep != it->errorPath.end(); ++ep) { + const Token *eptok = ep->first; + const std::string &msg = ep->second; + ostr << eptok->linenr() << ',' << msg << '\n'; + } + } + return ostr.str(); + } + + return ""; + } bool testValueOfX(const char code[], unsigned int linenr, const char value[]) { // Tokenize.. @@ -562,6 +588,38 @@ private: ASSERT_EQUALS(1, values.front().intvalue); } + void valueFlowErrorPath() { + const char *code; + + code = "void f() {\n" + " int x = 53;\n" + " a = x;\n" + "}\n"; + ASSERT_EQUALS("2,Assignment, integer value 53\n", + getErrorPathForX(code, 3U)); + + code = "void f(int y) {\n" + " int x = y;\n" + " a = x;\n" + " y += 12;\n" + " if (y == 32) {}" + "}\n"; + ASSERT_EQUALS("5,Condition 'y==32'\n" + "2,Assignment, integer value 20\n", + getErrorPathForX(code, 3U)); + + code = "void f1(int x) {\n" + " a = x;\n" + "}\n" + "void f2() {\n" + " int x = 3;\n" + " f1(x+1);\n" + "}\n"; + ASSERT_EQUALS("5,Assignment, integer value 3\n" + "6,Function argument, integer value 4\n", + getErrorPathForX(code, 2U)); + } + void valueFlowBeforeCondition() { const char *code;