Refactor ProgramMemory to store the expression tokens instead of exprIds (#3798)
This commit is contained in:
parent
569332a50a
commit
f2a419653c
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue