ValueFlow: Extended handling of float values
This commit is contained in:
parent
e1e9eacccc
commit
1e31c6c01c
|
@ -28,51 +28,46 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct ProgramMemory {
|
struct ProgramMemory {
|
||||||
std::map<unsigned int, MathLib::bigint> intvalues;
|
std::map<unsigned int, ValueFlow::Value> values;
|
||||||
std::map<unsigned int, const Token *> tokvalues;
|
|
||||||
|
|
||||||
void setValue(unsigned int varid, const ValueFlow::Value &value) {
|
void setValue(unsigned int varid, const ValueFlow::Value &value) {
|
||||||
switch (value.valueType) {
|
values[varid] = value;
|
||||||
case ValueFlow::Value::INT:
|
|
||||||
intvalues[varid] = value.intvalue;
|
|
||||||
tokvalues.erase(varid);
|
|
||||||
break;
|
|
||||||
case ValueFlow::Value::TOK:
|
|
||||||
intvalues.erase(varid);
|
|
||||||
tokvalues[varid] = value.tokvalue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getIntValue(unsigned int varid, MathLib::bigint* result) const {
|
bool getIntValue(unsigned int varid, MathLib::bigint* result) const {
|
||||||
const std::map<unsigned int, MathLib::bigint>::const_iterator it = intvalues.find(varid);
|
const std::map<unsigned int, ValueFlow::Value>::const_iterator it = values.find(varid);
|
||||||
if (it != intvalues.end())
|
bool found = it != values.end() && it->second.isIntValue();
|
||||||
*result = it->second;
|
if (found)
|
||||||
return (it != intvalues.end());
|
*result = it->second.intvalue;
|
||||||
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setIntValue(unsigned int varid, MathLib::bigint value) {
|
void setIntValue(unsigned int varid, MathLib::bigint value) {
|
||||||
intvalues[varid] = value;
|
values[varid] = ValueFlow::Value(value);
|
||||||
tokvalues.erase(varid);
|
}
|
||||||
|
|
||||||
|
bool getTokValue(unsigned int varid, const Token** result) const {
|
||||||
|
const std::map<unsigned int, ValueFlow::Value>::const_iterator it = values.find(varid);
|
||||||
|
bool found = it != values.end() && it->second.isTokValue();
|
||||||
|
if (found)
|
||||||
|
*result = it->second.tokvalue;
|
||||||
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasValue(unsigned int varid) {
|
bool hasValue(unsigned int varid) {
|
||||||
return intvalues.find(varid) != intvalues.end() ||
|
return values.find(varid) != values.end();
|
||||||
tokvalues.find(varid) != tokvalues.end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap(ProgramMemory &pm) {
|
void swap(ProgramMemory &pm) {
|
||||||
intvalues.swap(pm.intvalues);
|
values.swap(pm.values);
|
||||||
tokvalues.swap(pm.tokvalues);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
intvalues.clear();
|
values.clear();
|
||||||
tokvalues.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const {
|
bool empty() const {
|
||||||
return intvalues.empty() && tokvalues.empty();
|
return values.empty();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -371,9 +366,13 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti
|
||||||
|
|
||||||
std::list<ValueFlow::Value>::const_iterator value1, value2;
|
std::list<ValueFlow::Value>::const_iterator value1, value2;
|
||||||
for (value1 = parent->astOperand1()->values.begin(); value1 != parent->astOperand1()->values.end(); ++value1) {
|
for (value1 = parent->astOperand1()->values.begin(); value1 != parent->astOperand1()->values.end(); ++value1) {
|
||||||
|
if (!value1->isIntValue() && !value1->isFloatValue() && !value1->isTokValue())
|
||||||
|
continue;
|
||||||
if (value1->isTokValue() && (!parent->isComparisonOp() || value1->tokvalue->tokType() != Token::eString))
|
if (value1->isTokValue() && (!parent->isComparisonOp() || value1->tokvalue->tokType() != Token::eString))
|
||||||
continue;
|
continue;
|
||||||
for (value2 = parent->astOperand2()->values.begin(); value2 != parent->astOperand2()->values.end(); ++value2) {
|
for (value2 = parent->astOperand2()->values.begin(); value2 != parent->astOperand2()->values.end(); ++value2) {
|
||||||
|
if (!value2->isIntValue() && !value2->isFloatValue() && !value2->isTokValue())
|
||||||
|
continue;
|
||||||
if (value2->isTokValue() && (!parent->isComparisonOp() || value2->tokvalue->tokType() != Token::eString || value1->isTokValue()))
|
if (value2->isTokValue() && (!parent->isComparisonOp() || value2->tokvalue->tokType() != Token::eString || value1->isTokValue()))
|
||||||
continue;
|
continue;
|
||||||
if (known || value1->varId == 0U || value2->varId == 0U ||
|
if (known || value1->varId == 0U || value2->varId == 0U ||
|
||||||
|
@ -385,26 +384,58 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti
|
||||||
result.varvalue = (result.varId == value1->varId) ? value1->intvalue : value2->intvalue;
|
result.varvalue = (result.varId == value1->varId) ? value1->intvalue : value2->intvalue;
|
||||||
if (value1->valueKind == value2->valueKind)
|
if (value1->valueKind == value2->valueKind)
|
||||||
result.valueKind = value1->valueKind;
|
result.valueKind = value1->valueKind;
|
||||||
|
const float floatValue1 = value1->isIntValue() ? value1->intvalue : value1->floatValue;
|
||||||
|
const float floatValue2 = value2->isIntValue() ? value2->intvalue : value2->floatValue;
|
||||||
switch (parent->str()[0]) {
|
switch (parent->str()[0]) {
|
||||||
case '+':
|
case '+':
|
||||||
result.intvalue = value1->intvalue + value2->intvalue;
|
if (value1->isTokValue() || value2->isTokValue())
|
||||||
|
break;
|
||||||
|
if (value1->isFloatValue() || value2->isFloatValue()) {
|
||||||
|
result.valueType = ValueFlow::Value::FLOAT;
|
||||||
|
result.floatValue = floatValue1 + floatValue2;
|
||||||
|
} else {
|
||||||
|
result.intvalue = value1->intvalue + value2->intvalue;
|
||||||
|
}
|
||||||
setTokenValue(parent, result, settings);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
result.intvalue = value1->intvalue - value2->intvalue;
|
if (value1->isTokValue() || value2->isTokValue())
|
||||||
|
break;
|
||||||
|
if (value1->isFloatValue() || value2->isFloatValue()) {
|
||||||
|
result.valueType = ValueFlow::Value::FLOAT;
|
||||||
|
result.floatValue = floatValue1 - floatValue2;
|
||||||
|
} else {
|
||||||
|
result.intvalue = value1->intvalue - value2->intvalue;
|
||||||
|
}
|
||||||
setTokenValue(parent, result, settings);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
case '*':
|
case '*':
|
||||||
result.intvalue = value1->intvalue * value2->intvalue;
|
if (value1->isTokValue() || value2->isTokValue())
|
||||||
|
break;
|
||||||
|
if (value1->isFloatValue() || value2->isFloatValue()) {
|
||||||
|
result.valueType = ValueFlow::Value::FLOAT;
|
||||||
|
result.floatValue = floatValue1 * floatValue2;
|
||||||
|
} else {
|
||||||
|
result.intvalue = value1->intvalue * value2->intvalue;
|
||||||
|
}
|
||||||
setTokenValue(parent, result, settings);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
if (value2->intvalue == 0)
|
if (value1->isTokValue() || value2->isTokValue())
|
||||||
break;
|
break;
|
||||||
result.intvalue = value1->intvalue / value2->intvalue;
|
if (value1->isFloatValue() || value2->isFloatValue()) {
|
||||||
|
result.valueType = ValueFlow::Value::FLOAT;
|
||||||
|
result.floatValue = floatValue1 / floatValue2;
|
||||||
|
} else if (value2->intvalue == 0) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
result.intvalue = value1->intvalue / value2->intvalue;
|
||||||
|
}
|
||||||
setTokenValue(parent, result, settings);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
|
if (!value1->isIntValue() || !value2->isIntValue())
|
||||||
|
break;
|
||||||
if (value2->intvalue == 0)
|
if (value2->intvalue == 0)
|
||||||
break;
|
break;
|
||||||
result.intvalue = value1->intvalue % value2->intvalue;
|
result.intvalue = value1->intvalue % value2->intvalue;
|
||||||
|
@ -434,32 +465,36 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '>':
|
case '>': {
|
||||||
if (!value1->isIntValue() || !value2->isIntValue())
|
const bool f = value1->isFloatValue() || value2->isFloatValue();
|
||||||
|
if (!f && !value1->isIntValue() && !value1->isIntValue())
|
||||||
break;
|
break;
|
||||||
if (parent->str() == ">")
|
if (parent->str() == ">")
|
||||||
result.intvalue = value1->intvalue > value2->intvalue;
|
result.intvalue = f ? floatValue1 > floatValue2 : value1->intvalue > value2->intvalue;
|
||||||
else if (parent->str() == ">=")
|
else if (parent->str() == ">=")
|
||||||
result.intvalue = value1->intvalue >= value2->intvalue;
|
result.intvalue = f ? floatValue1 >= floatValue2 : value1->intvalue >= value2->intvalue;
|
||||||
else if (parent->str() == ">>" && value1->intvalue >= 0 && value2->intvalue >= 0 && value2->intvalue < 64)
|
else if (!f && parent->str() == ">>" && value1->intvalue >= 0 && value2->intvalue >= 0 && value2->intvalue < 64)
|
||||||
result.intvalue = value1->intvalue >> value2->intvalue;
|
result.intvalue = value1->intvalue >> value2->intvalue;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
setTokenValue(parent, result, settings);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
case '<':
|
}
|
||||||
if (!value1->isIntValue() || !value2->isIntValue())
|
case '<': {
|
||||||
|
const bool f = value1->isFloatValue() || value2->isFloatValue();
|
||||||
|
if (!f && !value1->isIntValue() && !value1->isIntValue())
|
||||||
break;
|
break;
|
||||||
if (parent->str() == "<")
|
if (parent->str() == "<")
|
||||||
result.intvalue = value1->intvalue < value2->intvalue;
|
result.intvalue = f ? floatValue1 < floatValue2 : value1->intvalue < value2->intvalue;
|
||||||
else if (parent->str() == "<=")
|
else if (parent->str() == "<=")
|
||||||
result.intvalue = value1->intvalue <= value2->intvalue;
|
result.intvalue = f ? floatValue1 <= floatValue2 : value1->intvalue <= value2->intvalue;
|
||||||
else if (parent->str() == "<<" && value1->intvalue >= 0 && value2->intvalue >= 0 && value2->intvalue < 64)
|
else if (!f && parent->str() == "<<" && value1->intvalue >= 0 && value2->intvalue >= 0 && value2->intvalue < 64)
|
||||||
result.intvalue = value1->intvalue << value2->intvalue;
|
result.intvalue = value1->intvalue << value2->intvalue;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
setTokenValue(parent, result, settings);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case '&':
|
case '&':
|
||||||
if (!value1->isIntValue() || !value2->isIntValue())
|
if (!value1->isIntValue() || !value2->isIntValue())
|
||||||
break;
|
break;
|
||||||
|
@ -533,10 +568,13 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti
|
||||||
else if (parent->str() == "-" && !parent->astOperand2()) {
|
else if (parent->str() == "-" && !parent->astOperand2()) {
|
||||||
std::list<ValueFlow::Value>::const_iterator it;
|
std::list<ValueFlow::Value>::const_iterator it;
|
||||||
for (it = tok->values.begin(); it != tok->values.end(); ++it) {
|
for (it = tok->values.begin(); it != tok->values.end(); ++it) {
|
||||||
if (!it->isIntValue())
|
if (!it->isIntValue() && !it->isFloatValue())
|
||||||
continue;
|
continue;
|
||||||
ValueFlow::Value v(*it);
|
ValueFlow::Value v(*it);
|
||||||
v.intvalue = -v.intvalue;
|
if (v.isIntValue())
|
||||||
|
v.intvalue = -v.intvalue;
|
||||||
|
else
|
||||||
|
v.floatValue = -v.floatValue;
|
||||||
setTokenValue(parent, v, settings);
|
setTokenValue(parent, v, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1920,17 +1958,17 @@ static void execute(const Token *expr,
|
||||||
if (!expr->astOperand1() || expr->astOperand1()->varId() == 0U)
|
if (!expr->astOperand1() || expr->astOperand1()->varId() == 0U)
|
||||||
*error = true;
|
*error = true;
|
||||||
else {
|
else {
|
||||||
std::map<unsigned int, MathLib::bigint>::iterator var = programMemory->intvalues.find(expr->astOperand1()->varId());
|
long long i;
|
||||||
if (var == programMemory->intvalues.end())
|
if (!programMemory->getIntValue(expr->astOperand1()->varId(), &i))
|
||||||
*error = true;
|
*error = true;
|
||||||
else {
|
else {
|
||||||
if (var->second == 0 &&
|
if (i == 0 &&
|
||||||
expr->str() == "--" &&
|
expr->str() == "--" &&
|
||||||
expr->astOperand1()->variable() &&
|
expr->astOperand1()->variable() &&
|
||||||
expr->astOperand1()->variable()->typeStartToken()->isUnsigned())
|
expr->astOperand1()->variable()->typeStartToken()->isUnsigned())
|
||||||
*error = true; // overflow
|
*error = true; // overflow
|
||||||
*result = var->second + (expr->str() == "++" ? 1 : -1);
|
*result = i + (expr->str() == "++" ? 1 : -1);
|
||||||
var->second = *result;
|
programMemory->setIntValue(expr->astOperand1()->varId(), *result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1994,12 +2032,9 @@ static void execute(const Token *expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (expr->str() == "[" && expr->astOperand1() && expr->astOperand2()) {
|
else if (expr->str() == "[" && expr->astOperand1() && expr->astOperand2()) {
|
||||||
const Token *tokvalue = nullptr;
|
const Token *tokvalue;
|
||||||
std::map<unsigned int, const Token *>::iterator var = programMemory->tokvalues.find(expr->astOperand1()->varId());
|
if (!programMemory->getTokValue(expr->astOperand1()->varId(), &tokvalue)) {
|
||||||
if (var != programMemory->tokvalues.end()) {
|
if (expr->astOperand1()->values.size() != 1U || !expr->astOperand1()->values.front().isTokValue()) {
|
||||||
tokvalue = var->second;
|
|
||||||
} else {
|
|
||||||
if (expr->astOperand1()->values.size() != 1U) {
|
|
||||||
*error = true;
|
*error = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2260,13 +2295,22 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas
|
||||||
} else {
|
} else {
|
||||||
ProgramMemory mem1, mem2, memAfter;
|
ProgramMemory mem1, mem2, memAfter;
|
||||||
if (valueFlowForLoop2(tok, &mem1, &mem2, &memAfter)) {
|
if (valueFlowForLoop2(tok, &mem1, &mem2, &memAfter)) {
|
||||||
std::map<unsigned int, MathLib::bigint>::const_iterator it;
|
std::map<unsigned int, ValueFlow::Value>::const_iterator it;
|
||||||
for (it = mem1.intvalues.begin(); it != mem1.intvalues.end(); ++it)
|
for (it = mem1.values.begin(); it != mem1.values.end(); ++it) {
|
||||||
valueFlowForLoopSimplify(bodyStart, it->first, it->second, tokenlist, errorLogger, settings);
|
if (!it->second.isIntValue())
|
||||||
for (it = mem2.intvalues.begin(); it != mem2.intvalues.end(); ++it)
|
continue;
|
||||||
valueFlowForLoopSimplify(bodyStart, it->first, it->second, tokenlist, errorLogger, settings);
|
valueFlowForLoopSimplify(bodyStart, it->first, it->second.intvalue, tokenlist, errorLogger, settings);
|
||||||
for (it = memAfter.intvalues.begin(); it != memAfter.intvalues.end(); ++it)
|
}
|
||||||
valueFlowForLoopSimplifyAfter(tok, it->first, it->second, tokenlist, errorLogger, settings);
|
for (it = mem2.values.begin(); it != mem2.values.end(); ++it) {
|
||||||
|
if (!it->second.isIntValue())
|
||||||
|
continue;
|
||||||
|
valueFlowForLoopSimplify(bodyStart, it->first, it->second.intvalue, tokenlist, errorLogger, settings);
|
||||||
|
}
|
||||||
|
for (it = memAfter.values.begin(); it != memAfter.values.end(); ++it) {
|
||||||
|
if (!it->second.isIntValue())
|
||||||
|
continue;
|
||||||
|
valueFlowForLoopSimplifyAfter(tok, it->first, it->second.intvalue, tokenlist, errorLogger, settings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue