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;
|
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)
|
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
|
// Parse the given tokens
|
||||||
|
@ -1515,8 +1540,25 @@ struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const
|
||||||
return Result(Result::Type::BAILOUT);
|
return Result(Result::Type::BAILOUT);
|
||||||
|
|
||||||
if (mWhat == What::ValueFlow && (Token::Match(tok, "while|for (") || Token::simpleMatch(tok, "do {"))) {
|
if (mWhat == What::ValueFlow && (Token::Match(tok, "while|for (") || Token::simpleMatch(tok, "do {"))) {
|
||||||
// TODO: only bailout if expr is reassigned in loop
|
const Token *bodyStart = nullptr;
|
||||||
return Result(Result::Type::BAILOUT);
|
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), ") {")) {
|
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)
|
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);
|
return Result(Result::Type::BAILOUT);
|
||||||
|
|
||||||
|
|
||||||
if (exprVarIds.find(tok->varId()) != exprVarIds.end()) {
|
if (exprVarIds.find(tok->varId()) != exprVarIds.end()) {
|
||||||
const Token *parent = tok;
|
const Token *parent = tok;
|
||||||
bool other = false;
|
bool other = false;
|
||||||
|
|
|
@ -2567,6 +2567,19 @@ private:
|
||||||
values = tokenValues(code, "<");
|
values = tokenValues(code, "<");
|
||||||
ASSERT_EQUALS(true, values.empty());
|
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"
|
code = "void f() {\n"
|
||||||
" Hints hints;\n"
|
" Hints hints;\n"
|
||||||
" hints.x = 1;\n"
|
" hints.x = 1;\n"
|
||||||
|
|
Loading…
Reference in New Issue