ValueFlow: Improve bailout for structs etc in loops
This commit is contained in:
parent
6b662c7353
commit
607b3daca8
|
@ -1419,6 +1419,31 @@ bool reaches(const Token * start, const Token * dest, const Library& library, Er
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool isUnchanged(const Token *startToken, const Token *endToken, const std::set<int> &exprVarIds, bool local)
|
||||
{
|
||||
for (const Token *tok = startToken; tok != endToken; tok = tok->next()) {
|
||||
if (!local && Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {"))
|
||||
// TODO: this is a quick bailout
|
||||
return false;
|
||||
if (tok->varId() <= 0 || exprVarIds.find(tok->varId()) == exprVarIds.end())
|
||||
continue;
|
||||
const Token *parent = tok;
|
||||
while (parent->astParent() && !parent->astParent()->isAssignmentOp() && parent->astParent()->tokType() != Token::Type::eIncDecOp) {
|
||||
if (parent->str() == "," || parent->isUnaryOp("&"))
|
||||
// TODO: This is a quick bailout
|
||||
return false;
|
||||
parent = parent->astParent();
|
||||
}
|
||||
if (parent->astParent()) {
|
||||
if (parent->astParent()->tokType() == Token::Type::eIncDecOp)
|
||||
return false;
|
||||
else if (parent->astParent()->isAssignmentOp() && parent == parent->astParent()->astOperand1())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set<int> &exprVarIds, bool local, bool inInnerClass)
|
||||
{
|
||||
// Parse the given tokens
|
||||
|
@ -1515,8 +1540,25 @@ struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const
|
|||
return Result(Result::Type::BAILOUT);
|
||||
|
||||
if (mWhat == What::ValueFlow && (Token::Match(tok, "while|for (") || Token::simpleMatch(tok, "do {"))) {
|
||||
// TODO: only bailout if expr is reassigned in loop
|
||||
return Result(Result::Type::BAILOUT);
|
||||
const Token *bodyStart = nullptr;
|
||||
const Token *conditionStart = nullptr;
|
||||
if (Token::simpleMatch(tok, "do {")) {
|
||||
bodyStart = tok->next();
|
||||
if (Token::simpleMatch(bodyStart->link(), "} while ("))
|
||||
conditionStart = bodyStart->link()->tokAt(2);
|
||||
} else {
|
||||
conditionStart = tok->next();
|
||||
if (Token::simpleMatch(conditionStart->link(), ") {"))
|
||||
bodyStart = conditionStart->link()->next();
|
||||
}
|
||||
|
||||
// Is expr changed in condition?
|
||||
if (!isUnchanged(conditionStart, conditionStart->link(), exprVarIds, local))
|
||||
return Result(Result::Type::BAILOUT);
|
||||
|
||||
// Is expr changed in loop body?
|
||||
if (!isUnchanged(bodyStart, bodyStart->link(), exprVarIds, local))
|
||||
return Result(Result::Type::BAILOUT);
|
||||
}
|
||||
|
||||
if (!local && Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {")) {
|
||||
|
@ -1527,7 +1569,6 @@ struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const
|
|||
if (expr->isName() && Token::Match(tok, "%name% (") && tok->str().find("<") != std::string::npos && tok->str().find(expr->str()) != std::string::npos)
|
||||
return Result(Result::Type::BAILOUT);
|
||||
|
||||
|
||||
if (exprVarIds.find(tok->varId()) != exprVarIds.end()) {
|
||||
const Token *parent = tok;
|
||||
bool other = false;
|
||||
|
|
|
@ -2567,6 +2567,19 @@ private:
|
|||
values = tokenValues(code, "<");
|
||||
ASSERT_EQUALS(true, values.empty());
|
||||
|
||||
code = "void f() {\n"
|
||||
" S s;\n"
|
||||
" s.x = 37;\n"
|
||||
" int y = 10;\n"
|
||||
" while (s.x < y)\n" // s.x has a known value
|
||||
" y--;\n"
|
||||
"}";
|
||||
values = tokenValues(code, ". x <");
|
||||
ASSERT(values.size() == 1 &&
|
||||
values.front().isKnown() &&
|
||||
values.front().isIntValue() &&
|
||||
values.front().intvalue == 37);
|
||||
|
||||
code = "void f() {\n"
|
||||
" Hints hints;\n"
|
||||
" hints.x = 1;\n"
|
||||
|
|
Loading…
Reference in New Issue