Fixed #5959 (ValueFlow: return value from subfunction)
This commit is contained in:
parent
893996d182
commit
4f43e4f9aa
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue