From 4f43e4f9aa8c48902ce2aad5619a51b3318c1845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 29 Jun 2014 18:04:38 +0200 Subject: [PATCH] Fixed #5959 (ValueFlow: return value from subfunction) --- lib/valueflow.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++ test/testvalueflow.cpp | 21 ++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 21476ed51..030883be4 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1263,12 +1263,77 @@ static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger, } } +static bool constval(const Token * tok) +{ + return tok && tok->values.size() == 1U && tok->values.front().varId == 0U; +} + +static void valueFlowFunctionReturn(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) +{ + for (Token *tok = tokenlist->front(); tok; tok = tok->next()) { + if (tok->str() != "(" || !tok->astOperand1() || !tok->astOperand1()->function()) + continue; + + // Arguments.. + std::vector parvalues; + { + const Token *partok = tok->astOperand2(); + while (partok && partok->str() == "," && constval(partok->astOperand2())) + partok = partok->astOperand1(); + if (!constval(partok)) + continue; + parvalues.push_back(partok->values.front().intvalue); + partok = partok->astParent(); + while (partok && partok->str() == ",") { + parvalues.push_back(partok->astOperand2()->values.front().intvalue); + partok = partok->astParent(); + } + if (partok != tok) + continue; + } + + // Get scope and args of function + const Function * const function = tok->astOperand1()->function(); + const Scope * const functionScope = function ? function->functionScope : nullptr; + if (!functionScope || !Token::simpleMatch(functionScope->classStart, "{ return")) { + if (functionScope && settings->debugwarnings) + bailout(tokenlist, errorLogger, tok, "function return; nontrivial function body"); + continue; + } + + std::map programMemory; + for (unsigned int i = 0; i < parvalues.size(); ++i) { + const Variable * const arg = function->getArgumentVar(i); + if (!arg || !Token::Match(arg->typeStartToken(), "%type% %var% ,|)")) { + if (settings->debugwarnings) + bailout(tokenlist, errorLogger, tok, "function return; unhandled argument type"); + programMemory.clear(); + break; + } + programMemory[arg->declarationId()] = parvalues[i]; + } + if (programMemory.empty()) + continue; + + // Determine return value of subfunction.. + MathLib::bigint result = 0; + bool error = false; + execute(functionScope->classStart->next()->astOperand1(), + &programMemory, + &result, + &error); + if (!error) + setTokenValue(tok, ValueFlow::Value(result)); + } +} + void ValueFlow::setValues(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) { for (Token *tok = tokenlist->front(); tok; tok = tok->next()) tok->values.clear(); valueFlowNumber(tokenlist); + valueFlowFunctionReturn(tokenlist, errorLogger, settings); valueFlowBitAnd(tokenlist); valueFlowForLoop(tokenlist, errorLogger, settings); valueFlowBeforeCondition(tokenlist, errorLogger, settings); diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index e1ef4306e..657d056d2 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -59,6 +59,7 @@ private: TEST_CASE(valueFlowForLoop); TEST_CASE(valueFlowSubFunction); + TEST_CASE(valueFlowFunctionReturn); } bool testValueOfX(const char code[], unsigned int linenr, int value) { @@ -942,6 +943,26 @@ private: "void f2() { f1(0.5); }"; ASSERT_EQUALS(false, testValueOfX(code, 2U, 0)); } + + void valueFlowFunctionReturn() { + const char *code; + + code = "void f1(int x) {\n" + " return x+1;\n" + "}\n" + "void f2() {\n" + " x = 10 - f1(2);\n" + "}"; + ASSERT_EQUALS(7, valueOfTok(code, "-").intvalue); + + code = "void add(int x, int y) {\n" + " return x+y;\n" + "}\n" + "void f2() {\n" + " x = 1 * add(10+1,4);\n" + "}"; + ASSERT_EQUALS(15, valueOfTok(code, "*").intvalue); + } }; REGISTER_TEST(TestValueFlow)