Refactor afterCondition handlers into to seperate classes (#2975)
This commit is contained in:
parent
aad723bf3a
commit
7861aa00cf
|
@ -4130,7 +4130,7 @@ static std::vector<const Variable*> getExprVariables(const Token* expr,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ValueFlowConditionHandler {
|
struct ConditionHandler {
|
||||||
struct Condition {
|
struct Condition {
|
||||||
const Token *vartok;
|
const Token *vartok;
|
||||||
std::list<ValueFlow::Value> true_values;
|
std::list<ValueFlow::Value> true_values;
|
||||||
|
@ -4139,14 +4139,24 @@ struct ValueFlowConditionHandler {
|
||||||
|
|
||||||
Condition() : vartok(nullptr), true_values(), false_values(), inverted(false) {}
|
Condition() : vartok(nullptr), true_values(), false_values(), inverted(false) {}
|
||||||
};
|
};
|
||||||
std::function<bool(Token* start, const Token* stop, const Token* exprTok, const std::list<ValueFlow::Value>& values, bool constValue)>
|
|
||||||
forward;
|
|
||||||
std::function<Condition(Token *tok)> parse;
|
|
||||||
|
|
||||||
void afterCondition(TokenList *tokenlist,
|
virtual bool forward(Token* start,
|
||||||
|
const Token* stop,
|
||||||
|
const Token* exprTok,
|
||||||
|
const std::list<ValueFlow::Value>& values,
|
||||||
|
TokenList* tokenlist,
|
||||||
|
const Settings* settings) const = 0;
|
||||||
|
|
||||||
|
virtual Condition parse(const Token* tok, const Settings* settings) const = 0;
|
||||||
|
|
||||||
|
void traverseCondition(
|
||||||
|
TokenList* tokenlist,
|
||||||
SymbolDatabase* symboldatabase,
|
SymbolDatabase* symboldatabase,
|
||||||
ErrorLogger* errorLogger,
|
ErrorLogger* errorLogger,
|
||||||
const Settings *settings) const {
|
const Settings* settings,
|
||||||
|
const std::function<
|
||||||
|
void(const Condition& cond, Token* tok, const Scope* scope, const std::vector<const Variable*>& vars)>& f) const
|
||||||
|
{
|
||||||
for (const Scope *scope : symboldatabase->functionScopes) {
|
for (const Scope *scope : symboldatabase->functionScopes) {
|
||||||
std::set<unsigned> aliased;
|
std::set<unsigned> aliased;
|
||||||
for (Token *tok = const_cast<Token *>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
|
for (Token *tok = const_cast<Token *>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
|
||||||
|
@ -4162,7 +4172,7 @@ struct ValueFlowConditionHandler {
|
||||||
if (!Token::Match(top->previous(), "if|while|for (") && !Token::Match(tok->astParent(), "&&|%oror%"))
|
if (!Token::Match(top->previous(), "if|while|for (") && !Token::Match(tok->astParent(), "&&|%oror%"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Condition cond = parse(tok);
|
Condition cond = parse(tok, settings);
|
||||||
if (!cond.vartok)
|
if (!cond.vartok)
|
||||||
continue;
|
continue;
|
||||||
if (cond.vartok->variable() && cond.vartok->variable()->isVolatile())
|
if (cond.vartok->variable() && cond.vartok->variable()->isVolatile())
|
||||||
|
@ -4188,6 +4198,23 @@ struct ValueFlowConditionHandler {
|
||||||
"variable is aliased so we just skip all valueflow after condition");
|
"variable is aliased so we just skip all valueflow after condition");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
f(cond, tok, scope, vars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void afterCondition(TokenList* tokenlist,
|
||||||
|
SymbolDatabase* symboldatabase,
|
||||||
|
ErrorLogger* errorLogger,
|
||||||
|
const Settings* settings) const
|
||||||
|
{
|
||||||
|
traverseCondition(
|
||||||
|
tokenlist,
|
||||||
|
symboldatabase,
|
||||||
|
errorLogger,
|
||||||
|
settings,
|
||||||
|
[&](const Condition& cond, Token* tok, const Scope* scope, const std::vector<const Variable*>& vars) {
|
||||||
|
const Token* top = tok->astTop();
|
||||||
|
|
||||||
std::list<ValueFlow::Value> thenValues;
|
std::list<ValueFlow::Value> thenValues;
|
||||||
std::list<ValueFlow::Value> elseValues;
|
std::list<ValueFlow::Value> elseValues;
|
||||||
|
@ -4245,7 +4272,7 @@ struct ValueFlowConditionHandler {
|
||||||
return ChildrenToVisit::op1_and_op2;
|
return ChildrenToVisit::op1_and_op2;
|
||||||
});
|
});
|
||||||
if (assign)
|
if (assign)
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4271,7 +4298,7 @@ struct ValueFlowConditionHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mixedOperators) {
|
if (mixedOperators) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4281,7 +4308,7 @@ struct ValueFlowConditionHandler {
|
||||||
isVariablesChanged(top, top->link(), 0, vars, settings, tokenlist->isCPP())) {
|
isVariablesChanged(top, top->link(), 0, vars, settings, tokenlist->isCPP())) {
|
||||||
if (settings->debugwarnings)
|
if (settings->debugwarnings)
|
||||||
bailout(tokenlist, errorLogger, tok, "assignment in condition");
|
bailout(tokenlist, errorLogger, tok, "assignment in condition");
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// start token of conditional code
|
// start token of conditional code
|
||||||
|
@ -4317,7 +4344,7 @@ struct ValueFlowConditionHandler {
|
||||||
valueFlowSetConditionToKnown(tok, values, i == 0);
|
valueFlowSetConditionToKnown(tok, values, i == 0);
|
||||||
|
|
||||||
// TODO: The endToken should not be startTokens[i]->link() in the valueFlowForwardVariable call
|
// TODO: The endToken should not be startTokens[i]->link() in the valueFlowForwardVariable call
|
||||||
if (forward(startTokens[i], startTokens[i]->link(), cond.vartok, values, true))
|
if (forward(startTokens[i], startTokens[i]->link(), cond.vartok, values, tokenlist, settings))
|
||||||
changeBlock = i;
|
changeBlock = i;
|
||||||
changeKnownToPossible(values);
|
changeKnownToPossible(values);
|
||||||
}
|
}
|
||||||
|
@ -4329,7 +4356,7 @@ struct ValueFlowConditionHandler {
|
||||||
startTokens[changeBlock]->link(),
|
startTokens[changeBlock]->link(),
|
||||||
"valueFlowAfterCondition: " + cond.vartok->expressionString() +
|
"valueFlowAfterCondition: " + cond.vartok->expressionString() +
|
||||||
" is changed in conditional block");
|
" is changed in conditional block");
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// After conditional code..
|
// After conditional code..
|
||||||
|
@ -4345,7 +4372,7 @@ struct ValueFlowConditionHandler {
|
||||||
if (!dead_if && unknownFunction) {
|
if (!dead_if && unknownFunction) {
|
||||||
if (settings->debugwarnings)
|
if (settings->debugwarnings)
|
||||||
bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope");
|
bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope");
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Token::simpleMatch(after, "} else {")) {
|
if (Token::simpleMatch(after, "} else {")) {
|
||||||
|
@ -4355,12 +4382,12 @@ struct ValueFlowConditionHandler {
|
||||||
if (!dead_else && unknownFunction) {
|
if (!dead_else && unknownFunction) {
|
||||||
if (settings->debugwarnings)
|
if (settings->debugwarnings)
|
||||||
bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope");
|
bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope");
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dead_if && dead_else)
|
if (dead_if && dead_else)
|
||||||
continue;
|
return;
|
||||||
|
|
||||||
std::list<ValueFlow::Value> values;
|
std::list<ValueFlow::Value> values;
|
||||||
if (dead_if) {
|
if (dead_if) {
|
||||||
|
@ -4383,30 +4410,38 @@ struct ValueFlowConditionHandler {
|
||||||
valueFlowSetConditionToKnown(tok, values, true);
|
valueFlowSetConditionToKnown(tok, values, true);
|
||||||
valueFlowSetConditionToKnown(tok, values, false);
|
valueFlowSetConditionToKnown(tok, values, false);
|
||||||
}
|
}
|
||||||
// TODO: constValue could be true if there are no assignments in the conditional blocks and
|
forward(after, scope->bodyEnd, cond.vartok, values, tokenlist, settings);
|
||||||
// perhaps if there are no && and no || in the condition
|
|
||||||
bool constValue = false;
|
|
||||||
forward(after, scope->bodyEnd, cond.vartok, values, constValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
virtual ~ConditionHandler() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void valueFlowAfterCondition(TokenList *tokenlist,
|
static void valueFlowCondition(const ValuePtr<ConditionHandler>& handler,
|
||||||
|
TokenList* tokenlist,
|
||||||
SymbolDatabase* symboldatabase,
|
SymbolDatabase* symboldatabase,
|
||||||
ErrorLogger* errorLogger,
|
ErrorLogger* errorLogger,
|
||||||
const Settings* settings)
|
const Settings* settings)
|
||||||
{
|
{
|
||||||
ValueFlowConditionHandler handler;
|
handler->afterCondition(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
handler.forward =
|
}
|
||||||
[&](Token* start, const Token* stop, const Token* vartok, const std::list<ValueFlow::Value>& values, bool) {
|
|
||||||
return valueFlowForward(start->next(), stop, vartok, values, tokenlist, settings).isModified();
|
struct SimpleConditionHandler : ConditionHandler {
|
||||||
};
|
virtual bool forward(Token* start,
|
||||||
handler.parse = [&](const Token *tok) {
|
const Token* stop,
|
||||||
ValueFlowConditionHandler::Condition cond;
|
const Token* exprTok,
|
||||||
|
const std::list<ValueFlow::Value>& values,
|
||||||
|
TokenList* tokenlist,
|
||||||
|
const Settings* settings) const OVERRIDE
|
||||||
|
{
|
||||||
|
return valueFlowForward(start->next(), stop, exprTok, values, tokenlist, settings).isModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Condition parse(const Token* tok, const Settings*) const OVERRIDE
|
||||||
|
{
|
||||||
|
Condition cond;
|
||||||
ValueFlow::Value true_value;
|
ValueFlow::Value true_value;
|
||||||
ValueFlow::Value false_value;
|
ValueFlow::Value false_value;
|
||||||
const Token *vartok = parseCompareInt(tok, true_value, false_value);
|
const Token *vartok = parseCompareInt(tok, true_value, false_value);
|
||||||
|
@ -4439,9 +4474,8 @@ static void valueFlowAfterCondition(TokenList *tokenlist,
|
||||||
cond.vartok = vartok;
|
cond.vartok = vartok;
|
||||||
|
|
||||||
return cond;
|
return cond;
|
||||||
};
|
|
||||||
handler.afterCondition(tokenlist, symboldatabase, errorLogger, settings);
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static bool isInBounds(const ValueFlow::Value& value, MathLib::bigint x)
|
static bool isInBounds(const ValueFlow::Value& value, MathLib::bigint x)
|
||||||
{
|
{
|
||||||
|
@ -5908,18 +5942,10 @@ static std::list<ValueFlow::Value> getIteratorValues(std::list<ValueFlow::Value>
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void valueFlowIteratorAfterCondition(TokenList *tokenlist,
|
struct IteratorConditionHandler : SimpleConditionHandler {
|
||||||
SymbolDatabase *symboldatabase,
|
virtual Condition parse(const Token* tok, const Settings*) const OVERRIDE
|
||||||
ErrorLogger *errorLogger,
|
|
||||||
const Settings *settings)
|
|
||||||
{
|
{
|
||||||
ValueFlowConditionHandler handler;
|
Condition cond;
|
||||||
handler.forward =
|
|
||||||
[&](Token* start, const Token* stop, const Token* vartok, const std::list<ValueFlow::Value>& values, bool) {
|
|
||||||
return valueFlowForward(start->next(), stop, vartok, values, tokenlist, settings).isModified();
|
|
||||||
};
|
|
||||||
handler.parse = [&](const Token *tok) {
|
|
||||||
ValueFlowConditionHandler::Condition cond;
|
|
||||||
|
|
||||||
ValueFlow::Value true_value;
|
ValueFlow::Value true_value;
|
||||||
ValueFlow::Value false_value;
|
ValueFlow::Value false_value;
|
||||||
|
@ -5946,9 +5972,8 @@ static void valueFlowIteratorAfterCondition(TokenList *tokenlist,
|
||||||
}
|
}
|
||||||
|
|
||||||
return cond;
|
return cond;
|
||||||
};
|
|
||||||
handler.afterCondition(tokenlist, symboldatabase, errorLogger, settings);
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static void valueFlowIteratorInfer(TokenList *tokenlist, const Settings *settings)
|
static void valueFlowIteratorInfer(TokenList *tokenlist, const Settings *settings)
|
||||||
{
|
{
|
||||||
|
@ -6107,24 +6132,26 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void valueFlowContainerAfterCondition(TokenList *tokenlist,
|
struct ContainerConditionHandler : ConditionHandler {
|
||||||
SymbolDatabase *symboldatabase,
|
virtual bool forward(Token* start,
|
||||||
ErrorLogger *errorLogger,
|
const Token* stop,
|
||||||
const Settings *settings)
|
const Token* exprTok,
|
||||||
|
const std::list<ValueFlow::Value>& values,
|
||||||
|
TokenList* tokenlist,
|
||||||
|
const Settings*) const OVERRIDE
|
||||||
{
|
{
|
||||||
ValueFlowConditionHandler handler;
|
|
||||||
handler.forward =
|
|
||||||
[&](Token* start, const Token* stop, const Token* vartok, const std::list<ValueFlow::Value>& values, bool) {
|
|
||||||
// TODO: Forward multiple values
|
// TODO: Forward multiple values
|
||||||
if (values.empty())
|
if (values.empty())
|
||||||
return false;
|
return false;
|
||||||
const Variable* var = vartok->variable();
|
const Variable* var = exprTok->variable();
|
||||||
if (!var)
|
if (!var)
|
||||||
return false;
|
return false;
|
||||||
return valueFlowContainerForward(start->next(), stop, var, values.front(), tokenlist).isModified();
|
return valueFlowContainerForward(start->next(), stop, var, values.front(), tokenlist).isModified();
|
||||||
};
|
}
|
||||||
handler.parse = [&](const Token *tok) {
|
|
||||||
ValueFlowConditionHandler::Condition cond;
|
virtual Condition parse(const Token* tok, const Settings*) const OVERRIDE
|
||||||
|
{
|
||||||
|
Condition cond;
|
||||||
ValueFlow::Value true_value;
|
ValueFlow::Value true_value;
|
||||||
ValueFlow::Value false_value;
|
ValueFlow::Value false_value;
|
||||||
const Token *vartok = parseCompareInt(tok, true_value, false_value);
|
const Token *vartok = parseCompareInt(tok, true_value, false_value);
|
||||||
|
@ -6182,9 +6209,8 @@ static void valueFlowContainerAfterCondition(TokenList *tokenlist,
|
||||||
return cond;
|
return cond;
|
||||||
}
|
}
|
||||||
return cond;
|
return cond;
|
||||||
};
|
|
||||||
handler.afterCondition(tokenlist, symboldatabase, errorLogger, settings);
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static void valueFlowFwdAnalysis(const TokenList *tokenlist, const Settings *settings)
|
static void valueFlowFwdAnalysis(const TokenList *tokenlist, const Settings *settings)
|
||||||
{
|
{
|
||||||
|
@ -6600,7 +6626,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
|
||||||
valueFlowTerminatingCondition(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowTerminatingCondition(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowBeforeCondition(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowBeforeCondition(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowAfterMove(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowAfterMove(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowAfterCondition(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowCondition(SimpleConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowInferCondition(tokenlist, settings);
|
valueFlowInferCondition(tokenlist, settings);
|
||||||
valueFlowAfterAssign(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowAfterAssign(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
|
@ -6613,10 +6639,10 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
|
||||||
if (tokenlist->isCPP()) {
|
if (tokenlist->isCPP()) {
|
||||||
valueFlowSmartPointer(tokenlist, errorLogger, settings);
|
valueFlowSmartPointer(tokenlist, errorLogger, settings);
|
||||||
valueFlowIterators(tokenlist, settings);
|
valueFlowIterators(tokenlist, settings);
|
||||||
valueFlowIteratorAfterCondition(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowCondition(IteratorConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowIteratorInfer(tokenlist, settings);
|
valueFlowIteratorInfer(tokenlist, settings);
|
||||||
valueFlowContainerSize(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowContainerSize(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowContainerAfterCondition(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowCondition(ContainerConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings);
|
||||||
}
|
}
|
||||||
valueFlowSafeFunctions(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowSafeFunctions(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
n--;
|
n--;
|
||||||
|
|
Loading…
Reference in New Issue