ValueFlow: Use FwdAnalysisAllPaths in ValueFlow to track complex expressions
This commit is contained in:
parent
fd8f599802
commit
141ce7cd63
|
@ -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("*"))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue