Refactor: Allow parse to return multiple values for a condition (#3361)

This commit is contained in:
Paul Fultz II 2021-07-26 15:23:19 -05:00 committed by GitHub
parent c34691ff56
commit 737b6199ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 50 additions and 45 deletions

View File

@ -4272,7 +4272,7 @@ struct ConditionHandler {
TokenList* tokenlist, TokenList* tokenlist,
const Settings* settings) const = 0; const Settings* settings) const = 0;
virtual Condition parse(const Token* tok, const Settings* settings) const = 0; virtual std::vector<Condition> parse(const Token* tok, const Settings* settings) const = 0;
void traverseCondition( void traverseCondition(
TokenList* tokenlist, TokenList* tokenlist,
@ -4295,33 +4295,35 @@ struct ConditionHandler {
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;
// *INDENT-OFF*
Condition cond = parse(tok, settings); for (const Condition& cond : parse(tok, settings)) {
if (!cond.vartok) if (!cond.vartok)
continue; continue;
if (cond.vartok->hasKnownIntValue()) if (cond.vartok->hasKnownIntValue())
continue; continue;
if (cond.true_values.empty() || cond.false_values.empty()) if (cond.true_values.empty() || cond.false_values.empty())
continue; continue;
if (!isConstExpression(cond.vartok, settings->library, true, tokenlist->isCPP())) if (!isConstExpression(cond.vartok, settings->library, true, tokenlist->isCPP()))
continue; continue;
std::vector<const Variable*> vars = getExprVariables(cond.vartok, tokenlist, symboldatabase, settings); std::vector<const Variable*> vars =
if (std::any_of(vars.begin(), vars.end(), [](const Variable* var) { getExprVariables(cond.vartok, tokenlist, symboldatabase, settings);
return !var; if (std::any_of(vars.begin(), vars.end(), [](const Variable* var) { return !var; }))
})) continue;
continue; if (!vars.empty() && (vars.front())) {
if (!vars.empty() && (vars.front())) if (std::any_of(vars.begin(), vars.end(), [&](const Variable* var) {
if (std::any_of(vars.begin(), vars.end(), [&](const Variable* var) { return var && aliased.find(var->declarationId()) != aliased.end();
return var && aliased.find(var->declarationId()) != aliased.end(); })) {
})) { if (settings->debugwarnings)
if (settings->debugwarnings) bailout(tokenlist,
bailout(tokenlist, errorLogger,
errorLogger, cond.vartok,
cond.vartok, "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);
} }
f(cond, tok, scope, vars); // *INDENT-ON*
} }
} }
} }
@ -4710,20 +4712,21 @@ struct SimpleConditionHandler : ConditionHandler {
return valueFlowReverse(start, endToken, exprTok, values, tokenlist, settings); return valueFlowReverse(start, endToken, exprTok, values, tokenlist, settings);
} }
virtual Condition parse(const Token* tok, const Settings*) const OVERRIDE { virtual std::vector<Condition> parse(const Token* tok, const Settings*) const OVERRIDE
{
Condition cond; 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);
if (vartok) { if (vartok) {
if (vartok->hasKnownValue()) if (vartok->hasKnownValue())
return cond; return {};
if (vartok->str() == "=" && vartok->astOperand1() && vartok->astOperand2()) if (vartok->str() == "=" && vartok->astOperand1() && vartok->astOperand2())
vartok = vartok->astOperand1(); vartok = vartok->astOperand1();
cond.true_values.push_back(true_value); cond.true_values.push_back(true_value);
cond.false_values.push_back(false_value); cond.false_values.push_back(false_value);
cond.vartok = vartok; cond.vartok = vartok;
return cond; return {cond};
} }
if (tok->str() == "!") { if (tok->str() == "!") {
@ -4738,12 +4741,12 @@ struct SimpleConditionHandler : ConditionHandler {
} }
if (!vartok) if (!vartok)
return cond; return {};
cond.true_values.emplace_back(tok, 0LL); cond.true_values.emplace_back(tok, 0LL);
cond.false_values.emplace_back(tok, 0LL); cond.false_values.emplace_back(tok, 0LL);
cond.vartok = vartok; cond.vartok = vartok;
return cond; return {cond};
} }
}; };
@ -6234,7 +6237,8 @@ static std::list<ValueFlow::Value> getIteratorValues(std::list<ValueFlow::Value>
} }
struct IteratorConditionHandler : SimpleConditionHandler { struct IteratorConditionHandler : SimpleConditionHandler {
virtual Condition parse(const Token* tok, const Settings*) const OVERRIDE { virtual std::vector<Condition> parse(const Token* tok, const Settings*) const OVERRIDE
{
Condition cond; Condition cond;
ValueFlow::Value true_value; ValueFlow::Value true_value;
@ -6242,7 +6246,7 @@ struct IteratorConditionHandler : SimpleConditionHandler {
if (Token::Match(tok, "==|!=")) { if (Token::Match(tok, "==|!=")) {
if (!tok->astOperand1() || !tok->astOperand2()) if (!tok->astOperand1() || !tok->astOperand2())
return cond; return {};
ValueFlow::Value::ValueKind kind = ValueFlow::Value::ValueKind::Known; ValueFlow::Value::ValueKind kind = ValueFlow::Value::ValueKind::Known;
std::list<ValueFlow::Value> values = getIteratorValues(tok->astOperand1()->values(), &kind); std::list<ValueFlow::Value> values = getIteratorValues(tok->astOperand1()->values(), &kind);
@ -6261,7 +6265,7 @@ struct IteratorConditionHandler : SimpleConditionHandler {
cond.false_values = values; cond.false_values = values;
} }
return cond; return {cond};
} }
}; };
@ -6450,7 +6454,8 @@ struct ContainerConditionHandler : ConditionHandler {
return valueFlowContainerReverse(start, endTok, exprTok, values, tokenlist, settings); return valueFlowContainerReverse(start, endTok, exprTok, values, tokenlist, settings);
} }
virtual Condition parse(const Token* tok, const Settings*) const OVERRIDE { virtual std::vector<Condition> parse(const Token* tok, const Settings*) const OVERRIDE
{
Condition cond; Condition cond;
ValueFlow::Value true_value; ValueFlow::Value true_value;
ValueFlow::Value false_value; ValueFlow::Value false_value;
@ -6458,13 +6463,13 @@ struct ContainerConditionHandler : ConditionHandler {
if (vartok) { if (vartok) {
vartok = vartok->tokAt(-3); vartok = vartok->tokAt(-3);
if (!isContainerSize(vartok)) if (!isContainerSize(vartok))
return cond; return {};
true_value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; true_value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
false_value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; false_value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
cond.true_values.push_back(true_value); cond.true_values.push_back(true_value);
cond.false_values.push_back(false_value); cond.false_values.push_back(false_value);
cond.vartok = vartok; cond.vartok = vartok;
return cond; return {cond};
} }
// Empty check // Empty check
@ -6472,11 +6477,11 @@ struct ContainerConditionHandler : ConditionHandler {
vartok = tok->tokAt(-3); vartok = tok->tokAt(-3);
// TODO: Handle .size() // TODO: Handle .size()
if (!isContainerEmpty(vartok)) if (!isContainerEmpty(vartok))
return cond; return {};
const Token *parent = tok->astParent(); const Token *parent = tok->astParent();
while (parent) { while (parent) {
if (Token::Match(parent, "%comp%")) if (Token::Match(parent, "%comp%"))
return cond; return {};
parent = parent->astParent(); parent = parent->astParent();
} }
ValueFlow::Value value(tok, 0LL); ValueFlow::Value value(tok, 0LL);
@ -6485,7 +6490,7 @@ struct ContainerConditionHandler : ConditionHandler {
cond.false_values.emplace_back(std::move(value)); cond.false_values.emplace_back(std::move(value));
cond.vartok = vartok; cond.vartok = vartok;
cond.inverted = true; cond.inverted = true;
return cond; return {cond};
} }
// String compare // String compare
if (Token::Match(tok, "==|!=")) { if (Token::Match(tok, "==|!=")) {
@ -6498,17 +6503,17 @@ struct ContainerConditionHandler : ConditionHandler {
vartok = tok->astOperand1(); vartok = tok->astOperand1();
} }
if (!strtok) if (!strtok)
return cond; return {};
if (!astIsContainer(vartok)) if (!astIsContainer(vartok))
return cond; return {};
ValueFlow::Value value(tok, Token::getStrLength(strtok)); ValueFlow::Value value(tok, Token::getStrLength(strtok));
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
cond.false_values.emplace_back(value); cond.false_values.emplace_back(value);
cond.true_values.emplace_back(std::move(value)); cond.true_values.emplace_back(std::move(value));
cond.vartok = vartok; cond.vartok = vartok;
return cond; return {cond};
} }
return cond; return {};
} }
}; };