ValueFlow: Extended handling of float values

This commit is contained in:
Daniel Marjamäki 2016-11-14 06:42:52 +01:00
parent e1e9eacccc
commit 1e31c6c01c
1 changed files with 104 additions and 60 deletions

View File

@ -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);
}
} }
} }
} }