Fixed #5959 (ValueFlow: return value from subfunction)

This commit is contained in:
Daniel Marjamäki 2014-06-29 18:04:38 +02:00
parent 893996d182
commit 4f43e4f9aa
2 changed files with 86 additions and 0 deletions

View File

@ -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<MathLib::bigint> 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<unsigned int, MathLib::bigint> 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) void ValueFlow::setValues(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
{ {
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) for (Token *tok = tokenlist->front(); tok; tok = tok->next())
tok->values.clear(); tok->values.clear();
valueFlowNumber(tokenlist); valueFlowNumber(tokenlist);
valueFlowFunctionReturn(tokenlist, errorLogger, settings);
valueFlowBitAnd(tokenlist); valueFlowBitAnd(tokenlist);
valueFlowForLoop(tokenlist, errorLogger, settings); valueFlowForLoop(tokenlist, errorLogger, settings);
valueFlowBeforeCondition(tokenlist, errorLogger, settings); valueFlowBeforeCondition(tokenlist, errorLogger, settings);

View File

@ -59,6 +59,7 @@ private:
TEST_CASE(valueFlowForLoop); TEST_CASE(valueFlowForLoop);
TEST_CASE(valueFlowSubFunction); TEST_CASE(valueFlowSubFunction);
TEST_CASE(valueFlowFunctionReturn);
} }
bool testValueOfX(const char code[], unsigned int linenr, int value) { bool testValueOfX(const char code[], unsigned int linenr, int value) {
@ -942,6 +943,26 @@ private:
"void f2() { f1(0.5); }"; "void f2() { f1(0.5); }";
ASSERT_EQUALS(false, testValueOfX(code, 2U, 0)); 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) REGISTER_TEST(TestValueFlow)