Fix 11096: FP knownConditionTrueFalse in do while loop (#4192)
* Check for loop * Improve handling of exit values * Add more checks to test * Simplify * Remove unnecessary test * Fix typo * Format * Use simpleMatch
This commit is contained in:
parent
829ca9ab7f
commit
c9b85010f9
|
@ -4768,6 +4768,23 @@ static std::vector<const Token*> getConditions(const Token* tok, const char* op)
|
||||||
return conds;
|
return conds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isBreakOrContinueScope(const Token* endToken)
|
||||||
|
{
|
||||||
|
if (!Token::simpleMatch(endToken, "}"))
|
||||||
|
return false;
|
||||||
|
return Token::Match(endToken->tokAt(-2), "break|continue ;");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Scope* getLoopScope(const Token* tok)
|
||||||
|
{
|
||||||
|
if (!tok)
|
||||||
|
return nullptr;
|
||||||
|
const Scope* scope = tok->scope();
|
||||||
|
while (scope && scope->type != Scope::eWhile && scope->type != Scope::eFor && scope->type != Scope::eDo)
|
||||||
|
scope = scope->nestedIn;
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
static void valueFlowConditionExpressions(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
|
static void valueFlowConditionExpressions(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
|
||||||
{
|
{
|
||||||
|
@ -4828,13 +4845,20 @@ static void valueFlowConditionExpressions(TokenList *tokenlist, SymbolDatabase*
|
||||||
|
|
||||||
// Check if the block terminates early
|
// Check if the block terminates early
|
||||||
if (isEscapeScope(blockTok, tokenlist)) {
|
if (isEscapeScope(blockTok, tokenlist)) {
|
||||||
|
const Scope* scope2 = scope;
|
||||||
|
// If escaping a loop then only use the loop scope
|
||||||
|
if (isBreakOrContinueScope(blockTok->link())) {
|
||||||
|
scope2 = getLoopScope(blockTok->link());
|
||||||
|
if (!scope2)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (const Token* condTok2:conds) {
|
for (const Token* condTok2:conds) {
|
||||||
ExpressionAnalyzer a1(condTok2, makeConditionValue(0, condTok2, false), tokenlist);
|
ExpressionAnalyzer a1(condTok2, makeConditionValue(0, condTok2, false), tokenlist);
|
||||||
valueFlowGenericForward(startTok->link()->next(), scope->bodyEnd, a1, settings);
|
valueFlowGenericForward(startTok->link()->next(), scope2->bodyEnd, a1, settings);
|
||||||
|
|
||||||
if (is1) {
|
if (is1) {
|
||||||
OppositeExpressionAnalyzer a2(true, condTok2, makeConditionValue(1, condTok2, false), tokenlist);
|
OppositeExpressionAnalyzer a2(true, condTok2, makeConditionValue(1, condTok2, false), tokenlist);
|
||||||
valueFlowGenericForward(startTok->link()->next(), scope->bodyEnd, a2, settings);
|
valueFlowGenericForward(startTok->link()->next(), scope2->bodyEnd, a2, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6049,6 +6073,27 @@ struct ConditionHandler {
|
||||||
}
|
}
|
||||||
if (values.empty())
|
if (values.empty())
|
||||||
return;
|
return;
|
||||||
|
bool isKnown = std::any_of(values.begin(), values.end(), [&](const ValueFlow::Value& v) {
|
||||||
|
return v.isKnown() || v.isImpossible();
|
||||||
|
});
|
||||||
|
if (isKnown && isBreakOrContinueScope(after)) {
|
||||||
|
const Scope* loopScope = getLoopScope(cond.vartok);
|
||||||
|
if (loopScope) {
|
||||||
|
Analyzer::Result r = forward(after, loopScope->bodyEnd, cond.vartok, values, tokenlist);
|
||||||
|
if (r.terminate != Analyzer::Terminate::None)
|
||||||
|
return;
|
||||||
|
if (r.action.isModified())
|
||||||
|
return;
|
||||||
|
Token* start = const_cast<Token*>(loopScope->bodyEnd);
|
||||||
|
if (Token::simpleMatch(start, "} while (")) {
|
||||||
|
start = start->tokAt(2);
|
||||||
|
forward(start, start->link(), cond.vartok, values, tokenlist);
|
||||||
|
start = start->link();
|
||||||
|
}
|
||||||
|
values.remove_if(std::mem_fn(&ValueFlow::Value::isImpossible));
|
||||||
|
changeKnownToPossible(values);
|
||||||
|
}
|
||||||
|
}
|
||||||
forward(after, getEndOfExprScope(cond.vartok, scope), cond.vartok, values, tokenlist);
|
forward(after, getEndOfExprScope(cond.vartok, scope), cond.vartok, values, tokenlist);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1444,6 +1444,8 @@ private:
|
||||||
" if (x) {}\n"
|
" if (x) {}\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
ASSERT_EQUALS(false, testValueOfX(code, 5U, 0));
|
ASSERT_EQUALS(false, testValueOfX(code, 5U, 0));
|
||||||
|
ASSERT_EQUALS(false, testValueOfXKnown(code, 3U, 1));
|
||||||
|
TODO_ASSERT_EQUALS(true, false, testValueOfX(code, 6U, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueFlowBeforeConditionAssignIncDec() { // assignment / increment
|
void valueFlowBeforeConditionAssignIncDec() { // assignment / increment
|
||||||
|
|
Loading…
Reference in New Issue