From a6320a35e0816bba473ffafe1fbea38cad960ca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 6 Jan 2014 16:37:52 +0100 Subject: [PATCH] value flow: added experimental subfunction handling --- lib/token.cpp | 2 ++ lib/valueflow.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++ test/testvalueflow.cpp | 19 +++++++++++- 3 files changed, 90 insertions(+), 1 deletion(-) diff --git a/lib/token.cpp b/lib/token.cpp index a069f73dd..77774cc5d 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -206,6 +206,7 @@ void Token::deleteThis() _function = _next->_function; _variable = _next->_variable; _originalName = _next->_originalName; + values = _next->values; if (_link) _link->link(this); @@ -229,6 +230,7 @@ void Token::deleteThis() _function = _previous->_function; _variable = _previous->_variable; _originalName = _previous->_originalName; + values = _previous->values; if (_link) _link->link(this); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index f1f303fcf..3f33825cf 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -24,6 +24,18 @@ #include "token.h" #include "tokenlist.h" +#include + + +static void printvalues(const Token *tok) +{ + if (tok->values.empty()) + std::cout << "empty"; + for (std::list::const_iterator it = tok->values.begin(); it != tok->values.end(); ++it) + std::cout << " " << (it->intvalue); + std::cout << std::endl; +} + static void bailout(TokenList *tokenlist, ErrorLogger *errorLogger, const Token *tok, const std::string &what) { std::list callstack; @@ -110,10 +122,68 @@ static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLog } } +static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) +{ + std::list argvalues; + for (Token *tok = tokenlist->front(); tok; tok = tok->next()) { + if (Token::Match(tok, "[(,] %var% [,)]") && !tok->next()->values.empty()) + argvalues = tok->next()->values; + else if (Token::Match(tok, "[(,] %num% [,)]")) { + ValueFlow::Value val; + val.condition = 0; + val.intvalue = MathLib::toLongNumber(tok->next()->str()); + argvalues.clear(); + argvalues.push_back(val); + } else { + continue; + } + + const Token * const argumentToken = tok->next(); + + // is this a function call? + const Token *ftok = tok; + while (ftok && ftok->str() != "(") + ftok = ftok->astParent(); + if (!ftok || !ftok->astOperand1() || !ftok->astOperand2() || !ftok->astOperand1()->function()) + continue; + + // Get argument nr + unsigned int argnr = 0; + for (const Token *argtok = ftok->next(); argtok && argtok != argumentToken; argtok = argtok->nextArgument()) + ++ argnr; + + // Get function argument, and check if parameter is passed by value + const Function * const function = ftok->astOperand1()->function(); + const Variable * const arg = function ? function->getArgumentVar(argnr) : NULL; + if (!Token::Match(arg ? arg->typeStartToken() : NULL, "const| %type% %var% ,|)")) + continue; + + // Function scope.. + const Scope * const functionScope = function ? function->functionScope : NULL; + if (!functionScope) + continue; + + // Set value in function scope.. + const unsigned int varid2 = arg->nameToken()->varId(); + for (const Token *tok2 = functionScope->classStart->next(); tok2 != functionScope->classEnd; tok2 = tok2->next()) { + if (Token::Match(tok2, "%cop%|return %varid%", varid2)) { + tok2 = tok2->next(); + std::list &values = const_cast(tok2)->values; + values.insert(values.begin(), argvalues.begin(), argvalues.end()); + } else if (tok2->varId() == varid2 || tok2->str() == "{") { + if (settings->debugwarnings) + bailout(tokenlist, errorLogger, tok2, "parameter " + arg->nameToken()->str()); + continue; + } + } + } +} + void ValueFlow::setValues(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) { for (Token *tok = tokenlist->front(); tok; tok = tok->next()) tok->values.clear(); valueFlowBeforeCondition(tokenlist, errorLogger, settings); + valueFlowSubFunction(tokenlist, errorLogger, settings); } diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 5c3d3396a..d33a0cc98 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -35,6 +35,7 @@ private: void run() { TEST_CASE(valueFlowBeforeCondition); + TEST_CASE(valueFlowSubFunction); } bool testValueOfX(const char code[], unsigned int linenr, int value) { @@ -53,7 +54,6 @@ private: if (it->intvalue == value) return true; } - return false; } } @@ -103,6 +103,23 @@ private: "}"); ASSERT_EQUALS("[test.cpp:4]: (debug) ValueFlow bailout: global variable x\n", errout.str()); } + + void valueFlowSubFunction() { + const char *code; + + code = "void f1(int x) { return x; }\n" + "void f2(int x) {\n" + " f1(123);\n" + "}"; + ASSERT_EQUALS(true, testValueOfX(code, 1U, 123)); + + code = "void f1(int x) { return x; }\n" + "void f2(int x) {\n" + " f1(x);\n" + " if (x==0){}\n" + "}"; + ASSERT_EQUALS(true, testValueOfX(code, 1U, 0)); + } }; REGISTER_TEST(TestValueFlow)