Refactor: Allow parse to return multiple values for a condition (#3361)
This commit is contained in:
parent
c34691ff56
commit
737b6199ba
|
@ -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 {};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue