Refactor ProgramMemory to store the expression tokens instead of exprIds (#3798)

This commit is contained in:
Paul Fultz II 2022-02-06 13:15:45 -06:00 committed by GitHub
parent 569332a50a
commit f2a419653c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 185 additions and 97 deletions

View File

@ -38,14 +38,22 @@
#include <utility>
#include <vector>
void ProgramMemory::setValue(nonneg int exprid, const ValueFlow::Value& value)
nonneg int ExprIdToken::getExpressionId() const {
return tok ? tok->exprId() : exprid;
}
std::size_t ExprIdToken::Hash::operator()(ExprIdToken etok) const
{
values[exprid] = value;
return std::hash<nonneg int>()(etok.getExpressionId());
}
void ProgramMemory::setValue(const Token* expr, const ValueFlow::Value& value) {
mValues[expr] = value;
}
const ValueFlow::Value* ProgramMemory::getValue(nonneg int exprid, bool impossible) const
{
const ProgramMemory::Map::const_iterator it = values.find(exprid);
const bool found = it != values.end() && (impossible || !it->second.isImpossible());
const ProgramMemory::Map::const_iterator it = mValues.find(exprid);
const bool found = it != mValues.end() && (impossible || !it->second.isImpossible());
if (found)
return &it->second;
else
@ -63,12 +71,12 @@ bool ProgramMemory::getIntValue(nonneg int exprid, MathLib::bigint* result) cons
return false;
}
void ProgramMemory::setIntValue(nonneg int exprid, MathLib::bigint value, bool impossible)
void ProgramMemory::setIntValue(const Token* expr, MathLib::bigint value, bool impossible)
{
ValueFlow::Value v(value);
if (impossible)
v.setImpossible();
values[exprid] = v;
mValues[expr] = v;
}
bool ProgramMemory::getTokValue(nonneg int exprid, const Token** result) const
@ -107,51 +115,67 @@ bool ProgramMemory::getContainerEmptyValue(nonneg int exprid, MathLib::bigint* r
return false;
}
void ProgramMemory::setContainerSizeValue(nonneg int exprid, MathLib::bigint value, bool isEqual)
void ProgramMemory::setContainerSizeValue(const Token* expr, MathLib::bigint value, bool isEqual)
{
ValueFlow::Value v(value);
v.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
if (!isEqual)
v.valueKind = ValueFlow::Value::ValueKind::Impossible;
values[exprid] = v;
mValues[expr] = v;
}
void ProgramMemory::setUnknown(nonneg int exprid)
{
values[exprid].valueType = ValueFlow::Value::ValueType::UNINIT;
void ProgramMemory::setUnknown(const Token* expr) {
mValues[expr].valueType = ValueFlow::Value::ValueType::UNINIT;
}
bool ProgramMemory::hasValue(nonneg int exprid)
{
return values.find(exprid) != values.end();
return mValues.find(exprid) != mValues.end();
}
const ValueFlow::Value& ProgramMemory::at(nonneg int exprid) const {
return mValues.at(exprid);
}
ValueFlow::Value& ProgramMemory::at(nonneg int exprid) {
return mValues.at(exprid);
}
void ProgramMemory::erase_if(const std::function<bool(const ExprIdToken&)>& pred)
{
for (auto it = mValues.begin(); it != mValues.end();) {
if (pred(it->first))
it = mValues.erase(it);
else
++it;
}
}
void ProgramMemory::swap(ProgramMemory &pm)
{
values.swap(pm.values);
mValues.swap(pm.mValues);
}
void ProgramMemory::clear()
{
values.clear();
mValues.clear();
}
bool ProgramMemory::empty() const
{
return values.empty();
return mValues.empty();
}
void ProgramMemory::replace(const ProgramMemory &pm)
{
for (auto&& p : pm.values) {
values[p.first] = p.second;
for (auto&& p : pm.mValues) {
mValues[p.first] = p.second;
}
}
void ProgramMemory::insert(const ProgramMemory &pm)
{
for (auto&& p:pm.values)
values.insert(p);
for (auto&& p : pm)
mValues.insert(p);
}
bool evaluateCondition(const std::string& op,
@ -216,10 +240,10 @@ void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Toke
if (endTok && isExpressionChanged(vartok, tok->next(), endTok, settings, true))
return;
bool impossible = (tok->str() == "==" && !then) || (tok->str() == "!=" && then);
pm.setIntValue(vartok->exprId(), then ? truevalue.intvalue : falsevalue.intvalue, impossible);
pm.setIntValue(vartok, then ? truevalue.intvalue : falsevalue.intvalue, impossible);
const Token* containerTok = settings->library.getContainerFromYield(vartok, Library::Container::Yield::SIZE);
if (containerTok)
pm.setContainerSizeValue(containerTok->exprId(), then ? truevalue.intvalue : falsevalue.intvalue, !impossible);
pm.setContainerSizeValue(containerTok, then ? truevalue.intvalue : falsevalue.intvalue, !impossible);
} else if (Token::simpleMatch(tok, "!")) {
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, !then);
} else if (then && Token::simpleMatch(tok, "&&")) {
@ -240,10 +264,10 @@ void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Toke
} else if (tok->exprId() > 0) {
if (endTok && isExpressionChanged(tok, tok->next(), endTok, settings, true))
return;
pm.setIntValue(tok->exprId(), 0, then);
pm.setIntValue(tok, 0, then);
const Token* containerTok = settings->library.getContainerFromYield(tok, Library::Container::Yield::EMPTY);
if (containerTok)
pm.setContainerSizeValue(containerTok->exprId(), 0, then);
pm.setContainerSizeValue(containerTok, 0, then);
}
}
@ -286,7 +310,7 @@ static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok
continue;
if (vartok == tok)
continue;
pm.setValue(vartok->exprId(), p.second);
pm.setValue(vartok, p.second);
setvar = true;
}
if (!setvar) {
@ -295,14 +319,14 @@ static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok
bool error = false;
execute(valuetok, &pm, &result, &error);
if (!error)
pm.setIntValue(vartok->exprId(), result);
pm.setIntValue(vartok, result);
else
pm.setUnknown(vartok->exprId());
pm.setUnknown(vartok);
}
}
} else if (tok2->exprId() > 0 && Token::Match(tok2, ".|(|[|*|%var%") && !pm.hasValue(tok2->exprId()) &&
isVariableChanged(tok2, 0, nullptr, true)) {
pm.setUnknown(tok2->exprId());
pm.setUnknown(tok2);
}
if (tok2->str() == "{") {
@ -339,13 +363,9 @@ static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok
static void removeModifiedVars(ProgramMemory& pm, const Token* tok, const Token* origin)
{
for (auto i = pm.values.begin(), last = pm.values.end(); i != last;) {
if (isVariableChanged(origin, tok, i->first, false, nullptr, true)) {
i = pm.values.erase(i);
} else {
++i;
}
}
pm.erase_if([&](const ExprIdToken& e) {
return isVariableChanged(origin, tok, e.getExpressionId(), false, nullptr, true);
});
}
static ProgramMemory getInitialProgramState(const Token* tok,
@ -367,27 +387,24 @@ ProgramMemoryState::ProgramMemoryState(const Settings* s) : state(), origins(),
void ProgramMemoryState::insert(const ProgramMemory &pm, const Token* origin)
{
if (origin)
for (auto&& p:pm.values)
origins.insert(std::make_pair(p.first, origin));
for (auto&& p : pm)
origins.insert(std::make_pair(p.first.getExpressionId(), origin));
state.insert(pm);
}
void ProgramMemoryState::replace(const ProgramMemory &pm, const Token* origin)
{
if (origin)
for (auto&& p:pm.values)
origins[p.first] = origin;
for (auto&& p : pm)
origins[p.first.getExpressionId()] = origin;
state.replace(pm);
}
static void addVars(ProgramMemory& pm, const ProgramMemory::Map& vars)
{
for (const auto& p:vars) {
nonneg int exprid = p.first;
const ValueFlow::Value &value = p.second;
pm.setValue(exprid, value);
if (value.varId)
pm.setIntValue(value.varId, value.varvalue);
pm.setValue(p.first.tok, value);
}
}
@ -406,7 +423,7 @@ void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty)
{
ProgramMemory pm = state;
if (isEmpty)
pm.setContainerSizeValue(tok->exprId(), 0, b);
pm.setContainerSizeValue(tok, 0, b);
else
programMemoryParseCondition(pm, tok, nullptr, settings, b);
const Token* origin = tok;
@ -418,16 +435,15 @@ void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty)
void ProgramMemoryState::removeModifiedVars(const Token* tok)
{
for (auto i = state.values.begin(), last = state.values.end(); i != last;) {
const Token* start = origins[i->first];
const Token* expr = findExpression(start ? start : tok, i->first);
state.erase_if([&](const ExprIdToken& e) {
const Token* start = origins[e.getExpressionId()];
const Token* expr = e.tok;
if (!expr || isExpressionChanged(expr, start, tok, settings, true)) {
origins.erase(i->first);
i = state.values.erase(i);
} else {
++i;
origins.erase(e.getExpressionId());
return true;
}
}
return false;
});
}
ProgramMemory ProgramMemoryState::get(const Token* tok, const Token* ctx, const ProgramMemory::Map& vars) const
@ -459,28 +475,23 @@ ProgramMemory getProgramMemory(const Token *tok, const ProgramMemory::Map& vars)
fillProgramMemoryFromConditions(programMemory, tok, nullptr);
ProgramMemory state;
for (const auto& p:vars) {
nonneg int exprid = p.first;
const ValueFlow::Value &value = p.second;
programMemory.setValue(exprid, value);
if (value.varId)
programMemory.setIntValue(value.varId, value.varvalue);
programMemory.setValue(p.first.tok, value);
}
state = programMemory;
fillProgramMemoryFromAssignments(programMemory, tok, state, vars);
return programMemory;
}
ProgramMemory getProgramMemory(const Token* tok, nonneg int exprid, const ValueFlow::Value& value, const Settings *settings)
ProgramMemory getProgramMemory(const Token* tok, const Token* expr, const ValueFlow::Value& value, const Settings* settings)
{
ProgramMemory programMemory;
programMemory.replace(getInitialProgramState(tok, value.tokvalue));
programMemory.replace(getInitialProgramState(tok, value.condition));
fillProgramMemoryFromConditions(programMemory, tok, settings);
programMemory.setValue(exprid, value);
if (value.varId)
programMemory.setIntValue(value.varId, value.varvalue);
programMemory.setValue(expr, value);
const ProgramMemory state = programMemory;
fillProgramMemoryFromAssignments(programMemory, tok, state, {{exprid, value}});
fillProgramMemoryFromAssignments(programMemory, tok, state, {{expr, value}});
return programMemory;
}
@ -590,7 +601,7 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Sett
if (expr->str() != "=") {
if (!pm.hasValue(expr->astOperand1()->exprId()))
return unknown;
ValueFlow::Value& lhs = pm.values.at(expr->astOperand1()->exprId());
ValueFlow::Value& lhs = pm.at(expr->astOperand1()->exprId());
rhs = evaluate(removeAssign(expr->str()), lhs, rhs);
if (lhs.isIntValue())
ValueFlow::Value::visitValue(rhs, std::bind(assign{}, std::ref(lhs.intvalue), std::placeholders::_1));
@ -600,7 +611,7 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Sett
return unknown;
return lhs;
} else {
pm.values[expr->astOperand1()->exprId()] = rhs;
pm.setValue(expr->astOperand1(), rhs);
return rhs;
}
} else if (expr->str() == "&&" && expr->astOperand1() && expr->astOperand2()) {
@ -623,7 +634,7 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Sett
} else if (Token::Match(expr, "++|--") && expr->astOperand1() && expr->astOperand1()->exprId() != 0) {
if (!pm.hasValue(expr->astOperand1()->exprId()))
return unknown;
ValueFlow::Value& lhs = pm.values.at(expr->astOperand1()->exprId());
ValueFlow::Value& lhs = pm.at(expr->astOperand1()->exprId());
if (!lhs.isIntValue())
return unknown;
// overflow
@ -705,7 +716,7 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Sett
return execute(expr->astOperand1(), pm);
}
if (expr->exprId() > 0 && pm.hasValue(expr->exprId())) {
ValueFlow::Value result = pm.values.at(expr->exprId());
ValueFlow::Value result = pm.at(expr->exprId());
if (result.isImpossible() && result.isIntValue() && result.intvalue == 0 && isUsedAsBool(expr)) {
result.intvalue = !result.intvalue;
result.setKnown();
@ -716,7 +727,7 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Sett
if (Token::Match(expr->previous(), ">|%name% {|(")) {
visitAstNodes(expr->astOperand2(), [&](const Token* child) {
if (child->exprId() > 0 && pm.hasValue(child->exprId())) {
ValueFlow::Value& v = pm.values.at(child->exprId());
ValueFlow::Value& v = pm.at(child->exprId());
if (v.valueType == ValueFlow::Value::ValueType::CONTAINER_SIZE) {
if (isContainerSizeChanged(child, settings))
v = unknown;

View File

@ -28,25 +28,62 @@
class Token;
class Settings;
struct ProgramMemory {
using Map = std::unordered_map<nonneg int, ValueFlow::Value>;
Map values;
// Class used to handle heterogeneous lookup in unordered_map(since we can't use C++20 yet)
struct ExprIdToken {
const Token* tok = nullptr;
nonneg int exprid = 0;
void setValue(nonneg int exprid, const ValueFlow::Value& value);
ExprIdToken() = default;
// cppcheck-suppress noExplicitConstructor
ExprIdToken(const Token* tok) : tok(tok) {}
// TODO: Make this constructor only available from ProgramMemory
// cppcheck-suppress noExplicitConstructor
ExprIdToken(nonneg int exprid) : exprid(exprid) {}
nonneg int getExpressionId() const;
bool operator==(const ExprIdToken& rhs) const {
return getExpressionId() == rhs.getExpressionId();
}
template<class T, class U>
friend bool operator!=(const T& lhs, const U& rhs)
{
return !(lhs == rhs);
}
struct Hash {
std::size_t operator()(ExprIdToken etok) const;
};
};
struct ProgramMemory {
using Map = std::unordered_map<ExprIdToken, ValueFlow::Value, ExprIdToken::Hash>;
ProgramMemory() = default;
explicit ProgramMemory(const Map& values) : mValues(values) {}
void setValue(const Token* expr, const ValueFlow::Value& value);
const ValueFlow::Value* getValue(nonneg int exprid, bool impossible = false) const;
bool getIntValue(nonneg int exprid, MathLib::bigint* result) const;
void setIntValue(nonneg int exprid, MathLib::bigint value, bool impossible = false);
void setIntValue(const Token* expr, MathLib::bigint value, bool impossible = false);
bool getContainerSizeValue(nonneg int exprid, MathLib::bigint* result) const;
bool getContainerEmptyValue(nonneg int exprid, MathLib::bigint* result) const;
void setContainerSizeValue(nonneg int exprid, MathLib::bigint value, bool isEqual = true);
void setContainerSizeValue(const Token* expr, MathLib::bigint value, bool isEqual = true);
void setUnknown(nonneg int exprid);
void setUnknown(const Token* expr);
bool getTokValue(nonneg int exprid, const Token** result) const;
bool hasValue(nonneg int exprid);
const ValueFlow::Value& at(nonneg int exprid) const;
ValueFlow::Value& at(nonneg int exprid);
void erase_if(const std::function<bool(const ExprIdToken&)>& pred);
void swap(ProgramMemory &pm);
void clear();
@ -56,6 +93,25 @@ struct ProgramMemory {
void replace(const ProgramMemory &pm);
void insert(const ProgramMemory &pm);
Map::iterator begin() {
return mValues.begin();
}
Map::iterator end() {
return mValues.end();
}
Map::const_iterator begin() const {
return mValues.begin();
}
Map::const_iterator end() const {
return mValues.end();
}
private:
Map mValues;
};
void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Token* endTok, const Settings* settings, bool then);
@ -102,7 +158,7 @@ bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings* s
/**
* Get program memory by looking backwards from given token.
*/
ProgramMemory getProgramMemory(const Token* tok, nonneg int exprid, const ValueFlow::Value& value, const Settings *settings);
ProgramMemory getProgramMemory(const Token* tok, const Token* expr, const ValueFlow::Value& value, const Settings* settings);
ProgramMemory getProgramMemory(const Token *tok, const ProgramMemory::Map& vars);

View File

@ -1967,7 +1967,7 @@ struct ValueFlowAnalyzer : Analyzer {
virtual bool isAlias(const Token* tok, bool& inconclusive) const = 0;
using ProgramState = std::unordered_map<nonneg int, ValueFlow::Value>;
using ProgramState = ProgramMemory::Map;
virtual ProgramState getProgramState() const = 0;
@ -2693,7 +2693,7 @@ struct ExpressionAnalyzer : SingleValueFlowAnalyzer {
virtual ProgramState getProgramState() const OVERRIDE {
ProgramState ps;
ps[expr->exprId()] = value;
ps[expr] = value;
return ps;
}
@ -5971,16 +5971,22 @@ static bool valueFlowForLoop2(const Token *tok,
return true;
}
static void valueFlowForLoopSimplify(Token * const bodyStart, const nonneg int varid, bool globalvar, const MathLib::bigint value, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
static void valueFlowForLoopSimplify(Token* const bodyStart,
const Token* expr,
bool globalvar,
const MathLib::bigint value,
TokenList* tokenlist,
ErrorLogger* errorLogger,
const Settings* settings)
{
const Token * const bodyEnd = bodyStart->link();
// Is variable modified inside for loop
if (isVariableChanged(bodyStart, bodyEnd, varid, globalvar, settings, tokenlist->isCPP()))
if (isVariableChanged(bodyStart, bodyEnd, expr->varId(), globalvar, settings, tokenlist->isCPP()))
return;
for (Token *tok2 = bodyStart->next(); tok2 != bodyEnd; tok2 = tok2->next()) {
if (tok2->varId() == varid) {
if (tok2->varId() == expr->varId()) {
const Token * parent = tok2->astParent();
while (parent) {
const Token * const p = parent;
@ -6005,7 +6011,7 @@ static void valueFlowForLoopSimplify(Token * const bodyStart, const nonneg int v
}
if (Token::Match(tok2, "%oror%|&&")) {
const ProgramMemory programMemory(getProgramMemory(tok2->astTop(), varid, ValueFlow::Value(value), settings));
const ProgramMemory programMemory(getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), settings));
if ((tok2->str() == "&&" && !conditionIsTrue(tok2->astOperand1(), programMemory)) ||
(tok2->str() == "||" && !conditionIsFalse(tok2->astOperand1(), programMemory))) {
// Skip second expression..
@ -6022,12 +6028,16 @@ static void valueFlowForLoopSimplify(Token * const bodyStart, const nonneg int v
}
}
if ((tok2->str() == "&&" && conditionIsFalse(tok2->astOperand1(), getProgramMemory(tok2->astTop(), varid, ValueFlow::Value(value), settings))) ||
(tok2->str() == "||" && conditionIsTrue(tok2->astOperand1(), getProgramMemory(tok2->astTop(), varid, ValueFlow::Value(value), settings))))
if ((tok2->str() == "&&" &&
conditionIsFalse(tok2->astOperand1(),
getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), settings))) ||
(tok2->str() == "||" &&
conditionIsTrue(tok2->astOperand1(),
getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), settings))))
break;
else if (Token::simpleMatch(tok2, ") {") && Token::findmatch(tok2->link(), "%varid%", tok2, varid)) {
if (Token::findmatch(tok2, "continue|break|return", tok2->linkAt(1), varid)) {
else if (Token::simpleMatch(tok2, ") {") && Token::findmatch(tok2->link(), "%varid%", tok2, expr->varId())) {
if (Token::findmatch(tok2, "continue|break|return", tok2->linkAt(1), expr->varId())) {
if (settings->debugwarnings)
bailout(tokenlist, errorLogger, tok2, "For loop variable bailout on conditional continue|break|return");
break;
@ -6036,7 +6046,7 @@ static void valueFlowForLoopSimplify(Token * const bodyStart, const nonneg int v
bailout(tokenlist, errorLogger, tok2, "For loop variable skipping conditional scope");
tok2 = tok2->next()->link();
if (Token::simpleMatch(tok2, "} else {")) {
if (Token::findmatch(tok2, "continue|break|return", tok2->linkAt(2), varid)) {
if (Token::findmatch(tok2, "continue|break|return", tok2->linkAt(2), expr->varId())) {
if (settings->debugwarnings)
bailout(tokenlist, errorLogger, tok2, "For loop variable bailout on conditional continue|break|return");
break;
@ -6132,20 +6142,23 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas
ProgramMemory mem1, mem2, memAfter;
if (valueFlowForLoop2(tok, &mem1, &mem2, &memAfter)) {
ProgramMemory::Map::const_iterator it;
for (it = mem1.values.begin(); it != mem1.values.end(); ++it) {
for (it = mem1.begin(); it != mem1.end(); ++it) {
if (!it->second.isIntValue())
continue;
valueFlowForLoopSimplify(bodyStart, it->first, false, it->second.intvalue, tokenlist, errorLogger, settings);
valueFlowForLoopSimplify(
bodyStart, it->first.tok, false, it->second.intvalue, tokenlist, errorLogger, settings);
}
for (it = mem2.values.begin(); it != mem2.values.end(); ++it) {
for (it = mem2.begin(); it != mem2.end(); ++it) {
if (!it->second.isIntValue())
continue;
valueFlowForLoopSimplify(bodyStart, it->first, false, it->second.intvalue, tokenlist, errorLogger, settings);
valueFlowForLoopSimplify(
bodyStart, it->first.tok, false, it->second.intvalue, tokenlist, errorLogger, settings);
}
for (it = memAfter.values.begin(); it != memAfter.values.end(); ++it) {
for (it = memAfter.begin(); it != memAfter.end(); ++it) {
if (!it->second.isIntValue())
continue;
valueFlowForLoopSimplifyAfter(tok, it->first, it->second.intvalue, tokenlist, settings);
valueFlowForLoopSimplifyAfter(
tok, it->first.getExpressionId(), it->second.intvalue, tokenlist, settings);
}
}
}
@ -6289,13 +6302,15 @@ struct MultiValueFlowAnalyzer : ValueFlowAnalyzer {
virtual ProgramState getProgramState() const OVERRIDE {
ProgramState ps;
for (const auto& p:values)
ps[p.first] = p.second;
for (const auto& p : values) {
const Variable* var = vars.at(p.first);
ps[var->nameToken()] = p.second;
}
return ps;
}
virtual void forkScope(const Token* endBlock) OVERRIDE {
ProgramMemory pm = {getProgramState()};
ProgramMemory pm{getProgramState()};
const Scope* scope = endBlock->scope();
const Token* condTok = getCondTokFromEnd(endBlock);
if (scope && condTok)
@ -6306,8 +6321,8 @@ struct MultiValueFlowAnalyzer : ValueFlowAnalyzer {
pm.replace(endMemory);
}
// ProgramMemory pm = pms.get(endBlock->link()->next(), getProgramState());
for (const auto& p:pm.values) {
nonneg int varid = p.first;
for (const auto& p : pm) {
nonneg int varid = p.first.getExpressionId();
if (symboldatabase && !symboldatabase->isVarId(varid))
continue;
ValueFlow::Value value = p.second;
@ -6544,11 +6559,13 @@ static void valueFlowLibraryFunction(Token *tok, const std::string &returnValue,
return;
// set varids
std::unordered_map<nonneg int, const Token*> lookupVarId;
for (Token* tok2 = tokenList.front(); tok2; tok2 = tok2->next()) {
if (tok2->str().compare(0, 3, "arg") != 0)
continue;
nonneg int id = std::atoi(tok2->str().c_str() + 3);
tok2->varId(id);
lookupVarId[id] = tok2;
}
// Evaluate expression
@ -6557,7 +6574,11 @@ static void valueFlowLibraryFunction(Token *tok, const std::string &returnValue,
ValueFlow::valueFlowConstantFoldAST(expr, settings);
productParams(argValues, [&](const std::unordered_map<nonneg int, ValueFlow::Value>& arg) {
ProgramMemory pm{arg};
ProgramMemory pm{};
for (const auto& p : arg) {
const Token* tok = lookupVarId[p.first];
pm.setValue(tok, p.second);
}
MathLib::bigint result = 0;
bool error = false;
execute(expr, &pm, &result, &error);
@ -6758,7 +6779,7 @@ static void valueFlowFunctionReturn(TokenList *tokenlist, ErrorLogger *errorLogg
programMemory.clear();
break;
}
programMemory.setIntValue(arg->declarationId(), parvalues[i]);
programMemory.setIntValue(arg->nameToken(), parvalues[i]);
}
if (programMemory.empty() && !parvalues.empty())
continue;