Refactor valueflow forward and reverse functions and unify them (#4127)
* Move functions around * Make it a template to handle both overloads * Simplify forward * Remove container forward * Remove unused settings params * Format * Remove valueFlowForwardExpression * Format * Remove init list * Make const ref * Remove braces * Remove braces
This commit is contained in:
parent
5999b35130
commit
7405ea039d
|
@ -1827,20 +1827,78 @@ static void valueFlowGlobalStaticVar(TokenList *tokenList, const Settings *setti
|
|||
}
|
||||
}
|
||||
|
||||
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist);
|
||||
ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist);
|
||||
|
||||
static Analyzer::Result valueFlowForward(Token* startToken,
|
||||
const Token* endToken,
|
||||
const Token* exprTok,
|
||||
const ValueFlow::Value& value,
|
||||
TokenList* const tokenlist)
|
||||
{
|
||||
return valueFlowGenericForward(startToken, endToken, makeAnalyzer(exprTok, value, tokenlist), tokenlist->getSettings());
|
||||
}
|
||||
|
||||
static Analyzer::Result valueFlowForward(Token* startToken,
|
||||
const Token* endToken,
|
||||
const Token* exprTok,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* const tokenlist,
|
||||
const Settings* settings);
|
||||
TokenList* const tokenlist)
|
||||
{
|
||||
Analyzer::Result result{};
|
||||
for (const ValueFlow::Value& v : values) {
|
||||
result.update(valueFlowForward(startToken, endToken, exprTok, v, tokenlist));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class ValueOrValues>
|
||||
static Analyzer::Result valueFlowForward(Token* startToken, const Token* exprTok, const ValueOrValues& v, TokenList* tokenlist)
|
||||
{
|
||||
const Token* endToken = nullptr;
|
||||
const Function* f = Scope::nestedInFunction(startToken->scope());
|
||||
if (f && f->functionScope)
|
||||
endToken = f->functionScope->bodyEnd;
|
||||
return valueFlowForward(startToken, endToken, exprTok, v, tokenlist);
|
||||
}
|
||||
|
||||
static Analyzer::Result valueFlowForwardRecursive(Token* top,
|
||||
const Token* exprTok,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* const tokenlist)
|
||||
{
|
||||
Analyzer::Result result{};
|
||||
for (const ValueFlow::Value& v : values) {
|
||||
result.update(valueFlowGenericForward(top, makeAnalyzer(exprTok, v, tokenlist), tokenlist->getSettings()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void valueFlowReverse(Token* tok,
|
||||
const Token* const endToken,
|
||||
const Token* const varToken,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* tokenlist)
|
||||
{
|
||||
for (const ValueFlow::Value& v : values) {
|
||||
valueFlowGenericReverse(tok, endToken, makeReverseAnalyzer(varToken, v, tokenlist), tokenlist->getSettings());
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
static void valueFlowReverse(TokenList* tokenlist,
|
||||
Token* tok,
|
||||
const Token* const varToken,
|
||||
ValueFlow::Value val,
|
||||
const ValueFlow::Value& val2,
|
||||
ErrorLogger* errorLogger,
|
||||
const Settings* settings);
|
||||
ErrorLogger* /*errorLogger*/,
|
||||
const Settings* = nullptr)
|
||||
{
|
||||
std::list<ValueFlow::Value> values = {val};
|
||||
if (val2.varId != 0)
|
||||
values.push_back(val2);
|
||||
valueFlowReverse(tok, nullptr, varToken, values, tokenlist);
|
||||
}
|
||||
|
||||
static bool isConditionKnown(const Token* tok, bool then)
|
||||
{
|
||||
|
@ -2647,8 +2705,6 @@ struct ValueFlowAnalyzer : Analyzer {
|
|||
}
|
||||
};
|
||||
|
||||
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist);
|
||||
|
||||
struct SingleValueFlowAnalyzer : ValueFlowAnalyzer {
|
||||
std::unordered_map<nonneg int, const Variable*> varids;
|
||||
std::unordered_map<nonneg int, const Variable*> aliases;
|
||||
|
@ -2944,162 +3000,6 @@ struct MemberExpressionAnalyzer : SubExpressionAnalyzer {
|
|||
}
|
||||
};
|
||||
|
||||
static Analyzer::Result valueFlowForwardExpression(Token* startToken,
|
||||
const Token* endToken,
|
||||
const Token* exprTok,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
const TokenList* const tokenlist,
|
||||
const Settings* settings)
|
||||
{
|
||||
Analyzer::Result result{};
|
||||
for (const ValueFlow::Value& v : values) {
|
||||
ExpressionAnalyzer a(exprTok, v, tokenlist);
|
||||
result.update(valueFlowGenericForward(startToken, endToken, a, settings));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static const Token* parseBinaryIntOp(const Token* expr,
|
||||
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
|
||||
MathLib::bigint& known)
|
||||
{
|
||||
if (!expr)
|
||||
return nullptr;
|
||||
if (!expr->astOperand1() || !expr->astOperand2())
|
||||
return nullptr;
|
||||
if (expr->astOperand1()->exprId() == 0 && expr->astOperand2()->exprId() == 0)
|
||||
return nullptr;
|
||||
std::vector<MathLib::bigint> x1 = eval(expr->astOperand1());
|
||||
std::vector<MathLib::bigint> x2 = eval(expr->astOperand2());
|
||||
if (expr->astOperand1()->exprId() == 0 && x1.empty())
|
||||
return nullptr;
|
||||
if (expr->astOperand2()->exprId() == 0 && x2.empty())
|
||||
return nullptr;
|
||||
const Token* varTok = nullptr;
|
||||
if (!x1.empty() && x2.empty()) {
|
||||
varTok = expr->astOperand2();
|
||||
known = x1.front();
|
||||
} else if (x1.empty() && !x2.empty()) {
|
||||
varTok = expr->astOperand1();
|
||||
known = x2.front();
|
||||
}
|
||||
return varTok;
|
||||
}
|
||||
|
||||
const Token* solveExprValue(const Token* expr,
|
||||
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
|
||||
ValueFlow::Value& value)
|
||||
{
|
||||
if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
|
||||
return expr;
|
||||
if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
|
||||
return expr;
|
||||
MathLib::bigint intval;
|
||||
const Token* binaryTok = parseBinaryIntOp(expr, eval, intval);
|
||||
bool rhs = astIsRHS(binaryTok);
|
||||
// If its on the rhs, then -1 multiplication is needed, which is not possible with simple delta analysis used currently for symbolic values
|
||||
if (value.isSymbolicValue() && rhs && Token::simpleMatch(expr, "-"))
|
||||
return expr;
|
||||
if (binaryTok && expr->str().size() == 1) {
|
||||
switch (expr->str()[0]) {
|
||||
case '+': {
|
||||
value.intvalue -= intval;
|
||||
return solveExprValue(binaryTok, eval, value);
|
||||
}
|
||||
case '-': {
|
||||
if (rhs)
|
||||
value.intvalue = intval - value.intvalue;
|
||||
else
|
||||
value.intvalue += intval;
|
||||
return solveExprValue(binaryTok, eval, value);
|
||||
}
|
||||
case '*': {
|
||||
if (intval == 0)
|
||||
break;
|
||||
value.intvalue /= intval;
|
||||
return solveExprValue(binaryTok, eval, value);
|
||||
}
|
||||
case '^': {
|
||||
value.intvalue ^= intval;
|
||||
return solveExprValue(binaryTok, eval, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
|
||||
{
|
||||
return solveExprValue(
|
||||
expr,
|
||||
[](const Token* tok) -> std::vector<MathLib::bigint> {
|
||||
if (tok->hasKnownIntValue())
|
||||
return {tok->values().front().intvalue};
|
||||
return {};
|
||||
},
|
||||
value);
|
||||
}
|
||||
|
||||
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist)
|
||||
{
|
||||
const Token* expr = solveExprValue(exprTok, value);
|
||||
return ExpressionAnalyzer(expr, value, tokenlist);
|
||||
}
|
||||
|
||||
static Analyzer::Result valueFlowForward(Token* startToken,
|
||||
const Token* endToken,
|
||||
const Token* exprTok,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* const tokenlist,
|
||||
const Settings* settings)
|
||||
{
|
||||
Analyzer::Result result{};
|
||||
for (const ValueFlow::Value& v : values) {
|
||||
result.update(valueFlowGenericForward(startToken, endToken, makeAnalyzer(exprTok, v, tokenlist), settings));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Analyzer::Result valueFlowForward(Token* top,
|
||||
const Token* exprTok,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* const tokenlist,
|
||||
const Settings* settings)
|
||||
{
|
||||
Analyzer::Result result{};
|
||||
for (const ValueFlow::Value& v : values) {
|
||||
result.update(valueFlowGenericForward(top, makeAnalyzer(exprTok, v, tokenlist), settings));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void valueFlowReverse(Token* tok,
|
||||
const Token* const endToken,
|
||||
const Token* const varToken,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* tokenlist,
|
||||
const Settings* settings)
|
||||
{
|
||||
for (const ValueFlow::Value& v : values) {
|
||||
ExpressionAnalyzer a(varToken, v, tokenlist);
|
||||
valueFlowGenericReverse(tok, endToken, a, settings);
|
||||
}
|
||||
}
|
||||
|
||||
static void valueFlowReverse(TokenList* tokenlist,
|
||||
Token* tok,
|
||||
const Token* const varToken,
|
||||
ValueFlow::Value val,
|
||||
const ValueFlow::Value& val2,
|
||||
ErrorLogger* /*errorLogger*/,
|
||||
const Settings* settings)
|
||||
{
|
||||
std::list<ValueFlow::Value> values = {val};
|
||||
if (val2.varId != 0)
|
||||
values.push_back(val2);
|
||||
valueFlowReverse(tok, nullptr, varToken, values, tokenlist, settings);
|
||||
}
|
||||
|
||||
enum class LifetimeCapture { Undefined, ByValue, ByReference };
|
||||
|
||||
std::string lifetimeType(const Token *tok, const ValueFlow::Value *val)
|
||||
|
@ -3591,7 +3491,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog
|
|||
if (Token::Match(tok->previous(), "%var% {|(") && isVariableDecl(tok->previous())) {
|
||||
std::list<ValueFlow::Value> values = tok->values();
|
||||
values.remove_if(&isNotLifetimeValue);
|
||||
valueFlowForward(nextAfterAstRightmostLeaf(tok), getEndOfExprScope(tok), tok->previous(), values, tokenlist, settings);
|
||||
valueFlowForward(nextAfterAstRightmostLeaf(tok), getEndOfExprScope(tok), tok->previous(), values, tokenlist);
|
||||
return;
|
||||
}
|
||||
Token *parent = tok->astParent();
|
||||
|
@ -3631,12 +3531,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog
|
|||
const Token *nextExpression = nextAfterAstRightmostLeaf(parent);
|
||||
|
||||
if (expr->exprId() > 0) {
|
||||
valueFlowForwardExpression(const_cast<Token*>(nextExpression),
|
||||
endOfVarScope->next(),
|
||||
expr,
|
||||
values,
|
||||
tokenlist,
|
||||
settings);
|
||||
valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope->next(), expr, values, tokenlist);
|
||||
|
||||
for (ValueFlow::Value& val : values) {
|
||||
if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::Address)
|
||||
|
@ -3647,12 +3542,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog
|
|||
const Token* parentLifetime =
|
||||
getParentLifetime(tokenlist->isCPP(), parent->astOperand1()->astOperand2(), &settings->library);
|
||||
if (parentLifetime && parentLifetime->exprId() > 0) {
|
||||
valueFlowForward(const_cast<Token*>(nextExpression),
|
||||
endOfVarScope,
|
||||
parentLifetime,
|
||||
values,
|
||||
tokenlist,
|
||||
settings);
|
||||
valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, parentLifetime, values, tokenlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3673,7 +3563,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog
|
|||
const Token *nextExpression = nextAfterAstRightmostLeaf(parent);
|
||||
// Only forward lifetime values
|
||||
values.remove_if(&isNotLifetimeValue);
|
||||
valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, tok, values, tokenlist, settings);
|
||||
valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, tok, values, tokenlist);
|
||||
// Cast
|
||||
} else if (parent->isCast()) {
|
||||
std::list<ValueFlow::Value> values = tok->values();
|
||||
|
@ -4724,7 +4614,7 @@ static void valueFlowAfterMove(TokenList* tokenlist, SymbolDatabase* symboldatab
|
|||
continue;
|
||||
const Token * const endOfVarScope = var->scope()->bodyEnd;
|
||||
setTokenValue(varTok, value, settings);
|
||||
valueFlowForward(varTok->next(), endOfVarScope, varTok, values, tokenlist, settings);
|
||||
valueFlowForward(varTok->next(), endOfVarScope, varTok, values, tokenlist);
|
||||
continue;
|
||||
}
|
||||
ValueFlow::Value::MoveKind moveKind;
|
||||
|
@ -4760,8 +4650,7 @@ static void valueFlowAfterMove(TokenList* tokenlist, SymbolDatabase* symboldatab
|
|||
const Token * openParentesisOfMove = findOpenParentesisOfMove(varTok);
|
||||
const Token * endOfFunctionCall = findEndOfFunctionCallForParameter(openParentesisOfMove);
|
||||
if (endOfFunctionCall)
|
||||
valueFlowForward(
|
||||
const_cast<Token*>(endOfFunctionCall), endOfVarScope, varTok, values, tokenlist, settings);
|
||||
valueFlowForward(const_cast<Token*>(endOfFunctionCall), endOfVarScope, varTok, values, tokenlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4981,13 +4870,13 @@ static void valueFlowSymbolic(TokenList* tokenlist, SymbolDatabase* symboldataba
|
|||
rhs.errorPath.emplace_back(tok,
|
||||
tok->astOperand1()->expressionString() + " is assigned '" +
|
||||
tok->astOperand2()->expressionString() + "' here.");
|
||||
valueFlowForward(start, end, tok->astOperand1(), {rhs}, tokenlist, tokenlist->getSettings());
|
||||
valueFlowForward(start, end, tok->astOperand1(), rhs, tokenlist);
|
||||
|
||||
ValueFlow::Value lhs = makeSymbolic(tok->astOperand1());
|
||||
lhs.errorPath.emplace_back(tok,
|
||||
tok->astOperand1()->expressionString() + " is assigned '" +
|
||||
tok->astOperand2()->expressionString() + "' here.");
|
||||
valueFlowForward(start, end, tok->astOperand2(), {lhs}, tokenlist, tokenlist->getSettings());
|
||||
valueFlowForward(start, end, tok->astOperand2(), lhs, tokenlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5267,7 +5156,7 @@ static void valueFlowForwardAssign(Token* const tok,
|
|||
constValues.splice(constValues.end(), values, it, values.end());
|
||||
valueFlowForwardConst(const_cast<Token*>(nextExpression), endOfVarScope, expr->variable(), constValues, settings);
|
||||
}
|
||||
valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, expr, values, tokenlist, settings);
|
||||
valueFlowForward(const_cast<Token*>(nextExpression), endOfVarScope, expr, values, tokenlist);
|
||||
}
|
||||
|
||||
static void valueFlowForwardAssign(Token* const tok,
|
||||
|
@ -5439,7 +5328,7 @@ static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldat
|
|||
value.errorPath.emplace_back(tok,
|
||||
tok->astOperand1()->expressionString() + " is assigned '" +
|
||||
tok->astOperand2()->expressionString() + "' here.");
|
||||
valueFlowForward(start, end, expr, {value}, tokenlist, settings);
|
||||
valueFlowForward(start, end, expr, value, tokenlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5545,27 +5434,33 @@ struct ConditionHandler {
|
|||
Condition() : vartok(nullptr), true_values(), false_values(), inverted(false), impossible(true) {}
|
||||
};
|
||||
|
||||
virtual std::vector<Condition> parse(const Token* tok, const Settings* settings) const = 0;
|
||||
|
||||
virtual Analyzer::Result forward(Token* start,
|
||||
const Token* stop,
|
||||
const Token* exprTok,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* tokenlist,
|
||||
const Settings* settings) const = 0;
|
||||
TokenList* tokenlist) const
|
||||
{
|
||||
return valueFlowForward(start->next(), stop, exprTok, values, tokenlist);
|
||||
}
|
||||
|
||||
virtual Analyzer::Result forward(Token* top,
|
||||
const Token* exprTok,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* tokenlist,
|
||||
const Settings* settings) const = 0;
|
||||
TokenList* tokenlist) const
|
||||
{
|
||||
return valueFlowForwardRecursive(top, exprTok, values, tokenlist);
|
||||
}
|
||||
|
||||
virtual void reverse(Token* start,
|
||||
const Token* endToken,
|
||||
const Token* exprTok,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* tokenlist,
|
||||
const Settings* settings) const = 0;
|
||||
|
||||
virtual std::vector<Condition> parse(const Token* tok, const Settings* settings) const = 0;
|
||||
TokenList* tokenlist) const
|
||||
{
|
||||
return valueFlowReverse(start, endToken, exprTok, values, tokenlist);
|
||||
}
|
||||
|
||||
void traverseCondition(TokenList* tokenlist,
|
||||
SymbolDatabase* symboldatabase,
|
||||
|
@ -5686,7 +5581,7 @@ struct ConditionHandler {
|
|||
})) {
|
||||
// Start at the end of the loop body
|
||||
Token* bodyTok = top->link()->next();
|
||||
reverse(bodyTok->link(), bodyTok, cond.vartok, values, tokenlist, settings);
|
||||
reverse(bodyTok->link(), bodyTok, cond.vartok, values, tokenlist);
|
||||
}
|
||||
if (settings->debugwarnings)
|
||||
bailout(tokenlist,
|
||||
|
@ -5705,7 +5600,7 @@ struct ConditionHandler {
|
|||
if (!startTok)
|
||||
startTok = tok->previous();
|
||||
|
||||
reverse(startTok, nullptr, cond.vartok, values, tokenlist, settings);
|
||||
reverse(startTok, nullptr, cond.vartok, values, tokenlist);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -5792,7 +5687,7 @@ struct ConditionHandler {
|
|||
return v.isImpossible();
|
||||
});
|
||||
for (Token* start:nextExprs) {
|
||||
Analyzer::Result r = forward(start, cond.vartok, values, tokenlist, settings);
|
||||
Analyzer::Result r = forward(start, cond.vartok, values, tokenlist);
|
||||
if (r.terminate != Analyzer::Terminate::None)
|
||||
return;
|
||||
}
|
||||
|
@ -5852,8 +5747,8 @@ struct ConditionHandler {
|
|||
|
||||
if (Token::simpleMatch(condTop, "?")) {
|
||||
Token* colon = condTop->astOperand2();
|
||||
forward(colon->astOperand1(), cond.vartok, thenValues, tokenlist, settings);
|
||||
forward(colon->astOperand2(), cond.vartok, elseValues, tokenlist, settings);
|
||||
forward(colon->astOperand1(), cond.vartok, thenValues, tokenlist);
|
||||
forward(colon->astOperand2(), cond.vartok, elseValues, tokenlist);
|
||||
// TODO: Handle after condition
|
||||
return;
|
||||
}
|
||||
|
@ -5937,8 +5832,7 @@ struct ConditionHandler {
|
|||
std::list<ValueFlow::Value>& values = (i == 0 ? thenValues : elseValues);
|
||||
valueFlowSetConditionToKnown(condTok, values, i == 0);
|
||||
|
||||
Analyzer::Result r =
|
||||
forward(startTokens[i], startTokens[i]->link(), cond.vartok, values, tokenlist, settings);
|
||||
Analyzer::Result r = forward(startTokens[i], startTokens[i]->link(), cond.vartok, values, tokenlist);
|
||||
deadBranch[i] = r.terminate == Analyzer::Terminate::Escape;
|
||||
if (r.action.isModified() && !deadBranch[i])
|
||||
changeBlock = i;
|
||||
|
@ -6040,7 +5934,7 @@ struct ConditionHandler {
|
|||
}
|
||||
if (values.empty())
|
||||
return;
|
||||
forward(after, getEndOfExprScope(cond.vartok, scope), cond.vartok, values, tokenlist, settings);
|
||||
forward(after, getEndOfExprScope(cond.vartok, scope), cond.vartok, values, tokenlist);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -6058,32 +5952,6 @@ static void valueFlowCondition(const ValuePtr<ConditionHandler>& handler,
|
|||
}
|
||||
|
||||
struct SimpleConditionHandler : ConditionHandler {
|
||||
virtual Analyzer::Result forward(Token* start,
|
||||
const Token* stop,
|
||||
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);
|
||||
}
|
||||
|
||||
virtual Analyzer::Result forward(Token* top,
|
||||
const Token* exprTok,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* tokenlist,
|
||||
const Settings* settings) const override {
|
||||
return valueFlowForward(top, exprTok, values, tokenlist, settings);
|
||||
}
|
||||
|
||||
virtual void reverse(Token* start,
|
||||
const Token* endToken,
|
||||
const Token* exprTok,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* tokenlist,
|
||||
const Settings* settings) const override {
|
||||
return valueFlowReverse(start, endToken, exprTok, values, tokenlist, settings);
|
||||
}
|
||||
|
||||
virtual std::vector<Condition> parse(const Token* tok, const Settings*) const override {
|
||||
Condition cond;
|
||||
ValueFlow::Value true_value;
|
||||
|
@ -6453,11 +6321,7 @@ static void valueFlowForLoopSimplify(Token* const bodyStart,
|
|||
}
|
||||
}
|
||||
|
||||
static void valueFlowForLoopSimplifyAfter(Token* fortok,
|
||||
nonneg int varid,
|
||||
const MathLib::bigint num,
|
||||
TokenList* tokenlist,
|
||||
const Settings* settings)
|
||||
static void valueFlowForLoopSimplifyAfter(Token* fortok, nonneg int varid, const MathLib::bigint num, TokenList* tokenlist)
|
||||
{
|
||||
const Token *vartok = nullptr;
|
||||
for (const Token *tok = fortok; tok; tok = tok->next()) {
|
||||
|
@ -6482,7 +6346,7 @@ static void valueFlowForLoopSimplifyAfter(Token* fortok,
|
|||
values.back().errorPath.emplace_back(fortok,"After for loop, " + var->name() + " has value " + values.back().infoString());
|
||||
|
||||
if (blockTok != endToken) {
|
||||
valueFlowForward(blockTok->next(), endToken, vartok, values, tokenlist, settings);
|
||||
valueFlowForward(blockTok->next(), endToken, vartok, values, tokenlist);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6510,8 +6374,7 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas
|
|||
std::list<ValueFlow::Value> initValues;
|
||||
initValues.emplace_back(initValue, ValueFlow::Value::Bound::Lower);
|
||||
initValues.push_back(asImpossible(initValues.back()));
|
||||
Analyzer::Result result =
|
||||
valueFlowForward(bodyStart, bodyStart->link(), vartok, initValues, tokenlist, settings);
|
||||
Analyzer::Result result = valueFlowForward(bodyStart, bodyStart->link(), vartok, initValues, tokenlist);
|
||||
|
||||
if (!result.action.isModified()) {
|
||||
std::list<ValueFlow::Value> lastValues;
|
||||
|
@ -6520,11 +6383,11 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas
|
|||
lastValues.push_back(asImpossible(lastValues.back()));
|
||||
if (stepValue != 1)
|
||||
lastValues.pop_front();
|
||||
valueFlowForward(bodyStart, bodyStart->link(), vartok, lastValues, tokenlist, settings);
|
||||
valueFlowForward(bodyStart, bodyStart->link(), vartok, lastValues, tokenlist);
|
||||
}
|
||||
}
|
||||
const MathLib::bigint afterValue = executeBody ? lastValue + stepValue : initValue;
|
||||
valueFlowForLoopSimplifyAfter(tok, varid, afterValue, tokenlist, settings);
|
||||
valueFlowForLoopSimplifyAfter(tok, varid, afterValue, tokenlist);
|
||||
} else {
|
||||
ProgramMemory mem1, mem2, memAfter;
|
||||
if (valueFlowForLoop2(tok, &mem1, &mem2, &memAfter)) {
|
||||
|
@ -6547,7 +6410,7 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas
|
|||
continue;
|
||||
if (p.first.tok->varId() == 0)
|
||||
continue;
|
||||
valueFlowForLoopSimplifyAfter(tok, p.first.getExpressionId(), p.second.intvalue, tokenlist, settings);
|
||||
valueFlowForLoopSimplifyAfter(tok, p.first.getExpressionId(), p.second.intvalue, tokenlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6804,7 +6667,6 @@ static void valueFlowInjectParameter(TokenList* tokenlist,
|
|||
}
|
||||
|
||||
static void valueFlowInjectParameter(TokenList* tokenlist,
|
||||
const Settings* settings,
|
||||
const Variable* arg,
|
||||
const Scope* functionScope,
|
||||
const std::list<ValueFlow::Value>& argvalues)
|
||||
|
@ -6822,8 +6684,7 @@ static void valueFlowInjectParameter(TokenList* tokenlist,
|
|||
functionScope->bodyEnd,
|
||||
arg->nameToken(),
|
||||
argvalues,
|
||||
tokenlist,
|
||||
settings);
|
||||
tokenlist);
|
||||
}
|
||||
|
||||
static void valueFlowSwitchVariable(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
|
||||
|
@ -7046,7 +6907,7 @@ static void valueFlowSubFunction(TokenList* tokenlist, SymbolDatabase* symboldat
|
|||
}
|
||||
}
|
||||
|
||||
static void valueFlowFunctionDefaultParameter(TokenList* tokenlist, SymbolDatabase* symboldatabase, const Settings* settings)
|
||||
static void valueFlowFunctionDefaultParameter(TokenList* tokenlist, SymbolDatabase* symboldatabase)
|
||||
{
|
||||
if (!tokenlist->isCPP())
|
||||
return;
|
||||
|
@ -7068,7 +6929,7 @@ static void valueFlowFunctionDefaultParameter(TokenList* tokenlist, SymbolDataba
|
|||
argvalues.push_back(v);
|
||||
}
|
||||
if (!argvalues.empty())
|
||||
valueFlowInjectParameter(tokenlist, settings, var, scope, argvalues);
|
||||
valueFlowInjectParameter(tokenlist, var, scope, argvalues);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7264,7 +7125,7 @@ static void valueFlowUninit(TokenList* tokenlist, SymbolDatabase* /*symbolDataba
|
|||
if (partial)
|
||||
continue;
|
||||
|
||||
valueFlowForward(tok->next(), tok->scope()->bodyEnd, var->nameToken(), {uninitValue}, tokenlist, settings);
|
||||
valueFlowForward(tok->next(), tok->scope()->bodyEnd, var->nameToken(), uninitValue, tokenlist);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7422,48 +7283,100 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
|
|||
}
|
||||
};
|
||||
|
||||
static Analyzer::Result valueFlowContainerForward(Token* startToken,
|
||||
const Token* endToken,
|
||||
const Token* exprTok,
|
||||
const ValueFlow::Value& value,
|
||||
TokenList* tokenlist)
|
||||
static const Token* parseBinaryIntOp(const Token* expr,
|
||||
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
|
||||
MathLib::bigint& known)
|
||||
{
|
||||
ContainerExpressionAnalyzer a(exprTok, value, tokenlist);
|
||||
return valueFlowGenericForward(startToken, endToken, a, tokenlist->getSettings());
|
||||
}
|
||||
|
||||
static Analyzer::Result valueFlowContainerForwardRecursive(Token* top,
|
||||
const Token* exprTok,
|
||||
const ValueFlow::Value& value,
|
||||
TokenList* tokenlist)
|
||||
{
|
||||
ContainerExpressionAnalyzer a(exprTok, value, tokenlist);
|
||||
return valueFlowGenericForward(top, a, tokenlist->getSettings());
|
||||
}
|
||||
|
||||
static Analyzer::Result valueFlowContainerForward(Token* startToken,
|
||||
const Token* exprTok,
|
||||
const ValueFlow::Value& value,
|
||||
TokenList* tokenlist)
|
||||
{
|
||||
const Token* endToken = nullptr;
|
||||
const Function* f = Scope::nestedInFunction(startToken->scope());
|
||||
if (f && f->functionScope)
|
||||
endToken = f->functionScope->bodyEnd;
|
||||
return valueFlowContainerForward(startToken, endToken, exprTok, value, tokenlist);
|
||||
}
|
||||
|
||||
static void valueFlowContainerReverse(Token* tok,
|
||||
const Token* const endToken,
|
||||
const Token* const varToken,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* tokenlist,
|
||||
const Settings* settings)
|
||||
{
|
||||
for (const ValueFlow::Value& value : values) {
|
||||
ContainerExpressionAnalyzer a(varToken, value, tokenlist);
|
||||
valueFlowGenericReverse(tok, endToken, a, settings);
|
||||
if (!expr)
|
||||
return nullptr;
|
||||
if (!expr->astOperand1() || !expr->astOperand2())
|
||||
return nullptr;
|
||||
if (expr->astOperand1()->exprId() == 0 && expr->astOperand2()->exprId() == 0)
|
||||
return nullptr;
|
||||
std::vector<MathLib::bigint> x1 = eval(expr->astOperand1());
|
||||
std::vector<MathLib::bigint> x2 = eval(expr->astOperand2());
|
||||
if (expr->astOperand1()->exprId() == 0 && x1.empty())
|
||||
return nullptr;
|
||||
if (expr->astOperand2()->exprId() == 0 && x2.empty())
|
||||
return nullptr;
|
||||
const Token* varTok = nullptr;
|
||||
if (!x1.empty() && x2.empty()) {
|
||||
varTok = expr->astOperand2();
|
||||
known = x1.front();
|
||||
} else if (x1.empty() && !x2.empty()) {
|
||||
varTok = expr->astOperand1();
|
||||
known = x2.front();
|
||||
}
|
||||
return varTok;
|
||||
}
|
||||
|
||||
const Token* solveExprValue(const Token* expr,
|
||||
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
|
||||
ValueFlow::Value& value)
|
||||
{
|
||||
if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
|
||||
return expr;
|
||||
if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
|
||||
return expr;
|
||||
MathLib::bigint intval;
|
||||
const Token* binaryTok = parseBinaryIntOp(expr, eval, intval);
|
||||
bool rhs = astIsRHS(binaryTok);
|
||||
// If its on the rhs, then -1 multiplication is needed, which is not possible with simple delta analysis used currently for symbolic values
|
||||
if (value.isSymbolicValue() && rhs && Token::simpleMatch(expr, "-"))
|
||||
return expr;
|
||||
if (binaryTok && expr->str().size() == 1) {
|
||||
switch (expr->str()[0]) {
|
||||
case '+': {
|
||||
value.intvalue -= intval;
|
||||
return solveExprValue(binaryTok, eval, value);
|
||||
}
|
||||
case '-': {
|
||||
if (rhs)
|
||||
value.intvalue = intval - value.intvalue;
|
||||
else
|
||||
value.intvalue += intval;
|
||||
return solveExprValue(binaryTok, eval, value);
|
||||
}
|
||||
case '*': {
|
||||
if (intval == 0)
|
||||
break;
|
||||
value.intvalue /= intval;
|
||||
return solveExprValue(binaryTok, eval, value);
|
||||
}
|
||||
case '^': {
|
||||
value.intvalue ^= intval;
|
||||
return solveExprValue(binaryTok, eval, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
|
||||
{
|
||||
return solveExprValue(
|
||||
expr,
|
||||
[](const Token* tok) -> std::vector<MathLib::bigint> {
|
||||
if (tok->hasKnownIntValue())
|
||||
return {tok->values().front().intvalue};
|
||||
return {};
|
||||
},
|
||||
value);
|
||||
}
|
||||
|
||||
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist)
|
||||
{
|
||||
if (value.isContainerSizeValue())
|
||||
return ContainerExpressionAnalyzer(exprTok, value, tokenlist);
|
||||
const Token* expr = solveExprValue(exprTok, value);
|
||||
return ExpressionAnalyzer(expr, value, tokenlist);
|
||||
}
|
||||
|
||||
ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist)
|
||||
{
|
||||
if (value.isContainerSizeValue())
|
||||
return ContainerExpressionAnalyzer(exprTok, value, tokenlist);
|
||||
return ExpressionAnalyzer(exprTok, value, tokenlist);
|
||||
}
|
||||
|
||||
bool isContainerSizeChanged(const Token* tok, const Settings* settings, int depth)
|
||||
|
@ -7879,7 +7792,7 @@ static void valueFlowContainerSize(TokenList* tokenlist,
|
|||
if (constSize)
|
||||
valueFlowForwardConst(var->nameToken()->next(), var->scope()->bodyEnd, var, values, settings);
|
||||
else
|
||||
valueFlowContainerForward(var->nameToken()->next(), var->nameToken(), value, tokenlist);
|
||||
valueFlowForward(var->nameToken()->next(), var->nameToken(), value, tokenlist);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7894,7 +7807,7 @@ static void valueFlowContainerSize(TokenList* tokenlist,
|
|||
ValueFlow::Value value(Token::getStrLength(containerTok->tokAt(2)));
|
||||
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||
value.setKnown();
|
||||
valueFlowContainerForward(containerTok->next(), containerTok, value, tokenlist);
|
||||
valueFlowForward(containerTok->next(), containerTok, value, tokenlist);
|
||||
}
|
||||
} else if (Token::Match(tok, "%name%|;|{|}|> %var% = {") && Token::simpleMatch(tok->linkAt(3), "} ;")) {
|
||||
const Token* containerTok = tok->next();
|
||||
|
@ -7904,7 +7817,7 @@ static void valueFlowContainerSize(TokenList* tokenlist,
|
|||
std::vector<ValueFlow::Value> values =
|
||||
getInitListSize(tok->tokAt(3), containerTok->valueType(), settings);
|
||||
for (const ValueFlow::Value& value : values)
|
||||
valueFlowContainerForward(containerTok->next(), containerTok, value, tokenlist);
|
||||
valueFlowForward(containerTok->next(), containerTok, value, tokenlist);
|
||||
}
|
||||
} else if (Token::Match(tok, ". %name% (") && tok->astOperand1() && tok->astOperand1()->valueType() &&
|
||||
tok->astOperand1()->valueType()->container) {
|
||||
|
@ -7916,13 +7829,13 @@ static void valueFlowContainerSize(TokenList* tokenlist,
|
|||
ValueFlow::Value value(0);
|
||||
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||
value.setKnown();
|
||||
valueFlowContainerForward(tok->next(), containerTok, value, tokenlist);
|
||||
valueFlowForward(tok->next(), containerTok, value, tokenlist);
|
||||
} else if (action == Library::Container::Action::RESIZE && tok->tokAt(2)->astOperand2() &&
|
||||
tok->tokAt(2)->astOperand2()->hasKnownIntValue()) {
|
||||
ValueFlow::Value value(tok->tokAt(2)->astOperand2()->values().front());
|
||||
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||
value.setKnown();
|
||||
valueFlowContainerForward(tok->next(), containerTok, value, tokenlist);
|
||||
valueFlowForward(tok->next(), containerTok, value, tokenlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7930,38 +7843,6 @@ static void valueFlowContainerSize(TokenList* tokenlist,
|
|||
}
|
||||
|
||||
struct ContainerConditionHandler : ConditionHandler {
|
||||
virtual Analyzer::Result forward(Token* start,
|
||||
const Token* stop,
|
||||
const Token* exprTok,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* tokenlist,
|
||||
const Settings*) const override {
|
||||
Analyzer::Result result{};
|
||||
for (const ValueFlow::Value& value : values)
|
||||
result.update(valueFlowContainerForward(start->next(), stop, exprTok, value, tokenlist));
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual Analyzer::Result forward(Token* top,
|
||||
const Token* exprTok,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* tokenlist,
|
||||
const Settings*) const override {
|
||||
Analyzer::Result result{};
|
||||
for (const ValueFlow::Value& value : values)
|
||||
result.update(valueFlowContainerForwardRecursive(top, exprTok, value, tokenlist));
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void reverse(Token* start,
|
||||
const Token* endTok,
|
||||
const Token* exprTok,
|
||||
const std::list<ValueFlow::Value>& values,
|
||||
TokenList* tokenlist,
|
||||
const Settings* settings) const override {
|
||||
return valueFlowContainerReverse(start, endTok, exprTok, values, tokenlist, settings);
|
||||
}
|
||||
|
||||
virtual std::vector<Condition> parse(const Token* tok, const Settings* settings) const override
|
||||
{
|
||||
Condition cond;
|
||||
|
@ -8127,7 +8008,7 @@ static void valueFlowDynamicBufferSize(TokenList* tokenlist, SymbolDatabase* sym
|
|||
value.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE;
|
||||
value.setKnown();
|
||||
const std::list<ValueFlow::Value> values{value};
|
||||
valueFlowForward(const_cast<Token*>(rhs), functionScope->bodyEnd, tok->next(), values, tokenlist, settings);
|
||||
valueFlowForward(const_cast<Token*>(rhs), functionScope->bodyEnd, tok->next(), values, tokenlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8228,8 +8109,7 @@ static void valueFlowSafeFunctions(TokenList* tokenlist, SymbolDatabase* symbold
|
|||
argValues.back().errorPath.emplace_back(arg.nameToken(), "Assuming " + arg.name() + " size is 1000000");
|
||||
argValues.back().safe = true;
|
||||
for (const ValueFlow::Value &value : argValues)
|
||||
valueFlowContainerForward(
|
||||
const_cast<Token*>(functionScope->bodyStart), arg.nameToken(), value, tokenlist);
|
||||
valueFlowForward(const_cast<Token*>(functionScope->bodyStart), arg.nameToken(), value, tokenlist);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -8267,8 +8147,7 @@ static void valueFlowSafeFunctions(TokenList* tokenlist, SymbolDatabase* symbold
|
|||
functionScope->bodyEnd,
|
||||
arg.nameToken(),
|
||||
argValues,
|
||||
tokenlist,
|
||||
settings);
|
||||
tokenlist);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -8290,8 +8169,7 @@ static void valueFlowSafeFunctions(TokenList* tokenlist, SymbolDatabase* symbold
|
|||
functionScope->bodyEnd,
|
||||
arg.nameToken(),
|
||||
argValues,
|
||||
tokenlist,
|
||||
settings);
|
||||
tokenlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8519,7 +8397,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
|
|||
valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings);
|
||||
valueFlowFunctionReturn(tokenlist, errorLogger);
|
||||
valueFlowLifetime(tokenlist, symboldatabase, errorLogger, settings);
|
||||
valueFlowFunctionDefaultParameter(tokenlist, symboldatabase, settings);
|
||||
valueFlowFunctionDefaultParameter(tokenlist, symboldatabase);
|
||||
valueFlowUninit(tokenlist, symboldatabase, settings);
|
||||
if (tokenlist->isCPP()) {
|
||||
valueFlowAfterMove(tokenlist, symboldatabase, settings);
|
||||
|
|
Loading…
Reference in New Issue