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)
|
||||
{
|
||||
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);
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue