ValueFlow: Use FwdAnalysisAllPaths in ValueFlow to track complex expressions

This commit is contained in:
Daniel Marjamäki 2018-12-31 17:05:46 +01:00
parent fd8f599802
commit 141ce7cd63
5 changed files with 63 additions and 4 deletions

View File

@ -1165,11 +1165,14 @@ struct FwdAnalysisAllPaths::Result FwdAnalysisAllPaths::checkRecursive(const Tok
if (exprVarIds.find(tok->varId()) != exprVarIds.end()) {
const Token *parent = tok;
bool other = false;
bool same = false;
bool same = tok->astParent() && isSameExpression(mCpp, false, expr, tok, mLibrary, false, false, nullptr);
while (Token::Match(parent->astParent(), "*|.|::|[")) {
parent = parent->astParent();
if (parent && isSameExpression(mCpp, false, expr, parent->astOperand1(), mLibrary, false, false, nullptr))
if (parent && isSameExpression(mCpp, false, expr, parent, mLibrary, false, false, nullptr)) {
same = true;
if (mWhat == What::ValueFlow)
mValueFlow.push_back(parent);
}
if (!same && Token::Match(parent, ". %var%") && parent->next()->varId() && exprVarIds.find(parent->next()->varId()) == exprVarIds.end()) {
other = true;
break;
@ -1356,6 +1359,13 @@ bool FwdAnalysisAllPaths::unusedValue(const Token *expr, const Token *startToken
return (result.type == FwdAnalysisAllPaths::Result::Type::NONE || result.type == FwdAnalysisAllPaths::Result::Type::RETURN) && !possiblyAliased(expr, startToken);
}
std::vector<const Token *> FwdAnalysisAllPaths::valueFlow(const Token *expr, const Token *startToken, const Token *endToken)
{
mWhat = What::ValueFlow;
check(expr, startToken, endToken);
return mValueFlow;
}
bool FwdAnalysisAllPaths::possiblyAliased(const Token *expr, const Token *startToken) const
{
if (expr->isUnaryOp("*"))

View File

@ -191,6 +191,8 @@ public:
*/
bool unusedValue(const Token *expr, const Token *startToken, const Token *endToken);
std::vector<const Token *> valueFlow(const Token *expr, const Token *startToken, const Token *endToken);
/** Is there some possible alias for given expression */
bool possiblyAliased(const Token *expr, const Token *startToken) const;
@ -213,7 +215,8 @@ private:
const bool mCpp;
const Library &mLibrary;
enum class What { Reassign, UnusedValue } mWhat;
enum class What { Reassign, UnusedValue, ValueFlow } mWhat;
std::vector<const Token *> mValueFlow;
};
#endif // astutilsH

View File

@ -4654,6 +4654,33 @@ static void valueFlowContainerAfterCondition(TokenList *tokenlist,
handler.afterCondition(tokenlist, symboldatabase, errorLogger, settings);
}
static void valueFlowFwdAnalysis(const TokenList *tokenlist, const Settings *settings)
{
for (const Token *tok = tokenlist->front(); tok; tok = tok->next()) {
if (tok->str() != "=" || !tok->astOperand1() || !tok->astOperand2())
continue;
if (!tok->scope()->isExecutable())
continue;
if (!tok->astOperand2()->hasKnownIntValue())
continue;
ValueFlow::Value v(tok->astOperand2()->values().front());
v.errorPath.emplace_back(tok, tok->astOperand1()->expressionString() + " is assigned value " + MathLib::toString(v.intvalue));
FwdAnalysisAllPaths fwdAnalysis(tokenlist->isCPP(), settings->library);
const Token *startToken = tok->findExpressionStartEndTokens().second->next();
const Scope *functionScope = tok->scope();
while (functionScope->nestedIn && functionScope->nestedIn->isExecutable())
functionScope = functionScope->nestedIn;
const Token *endToken = functionScope->bodyEnd;
for (const Token *tok2 : fwdAnalysis.valueFlow(tok->astOperand1(), startToken, endToken)) {
const Scope *s = tok2->scope();
while (s && s != tok->scope())
s = s->nestedIn;
v.valueKind = s ? ValueFlow::Value::ValueKind::Known : ValueFlow::Value::ValueKind::Possible;
setTokenValue(const_cast<Token *>(tok2), v, settings);
}
}
}
ValueFlow::Value::Value(const Token *c, long long val)
: valueType(INT),
intvalue(val),
@ -4724,6 +4751,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
valueFlowFunctionReturn(tokenlist, errorLogger);
valueFlowBitAnd(tokenlist);
valueFlowSameExpressions(tokenlist);
valueFlowFwdAnalysis(tokenlist, settings);
// Temporary hack.. run valueflow until there is nothing to update or timeout expires
const std::time_t timeout = std::time(0) + TIMEOUT;

View File

@ -151,7 +151,7 @@ namespace ValueFlow {
}
/** How known is this value */
enum ValueKind {
enum class ValueKind {
/** This value is possible, other unlisted values may also be possible */
Possible,
/** Only listed values are possible */

View File

@ -87,6 +87,8 @@ private:
TEST_CASE(valueFlowForwardTernary);
TEST_CASE(valueFlowForwardLambda);
TEST_CASE(valueFlowFwdAnalysis);
TEST_CASE(valueFlowSwitchVariable);
TEST_CASE(valueFlowForLoop);
@ -2353,6 +2355,22 @@ private:
ASSERT_EQUALS(true, testValueOfX(code,3U,0));
}
void valueFlowFwdAnalysis() {
const char *code;
std::list<ValueFlow::Value> values;
code = "void f() {\n"
" struct Foo foo;\n"
" foo.x = 1;\n"
" x = 0 + foo.x;\n" // <- foo.x is 1
"}";
values = tokenValues(code, "+");
ASSERT_EQUALS(1U, values.size());
ASSERT_EQUALS(true, values.front().isKnown());
ASSERT_EQUALS(true, values.front().isIntValue());
ASSERT_EQUALS(1, values.front().intvalue);
}
void valueFlowSwitchVariable() {
const char *code;
code = "void f(int x) {\n"