Fix 10464: FP: knownConditionTrueFalse (#3452)
This commit is contained in:
parent
47f5e5d145
commit
b0b3f7ec2d
|
@ -41,6 +41,15 @@ struct SelectMapValues {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Enum hash for C++11. This is not needed in C++14
|
||||||
|
struct EnumClassHash {
|
||||||
|
template<typename T>
|
||||||
|
std::size_t operator()(T t) const
|
||||||
|
{
|
||||||
|
return static_cast<std::size_t>(t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
inline bool endsWith(const std::string &str, char c)
|
inline bool endsWith(const std::string &str, char c)
|
||||||
{
|
{
|
||||||
return str[str.size()-1U] == c;
|
return str[str.size()-1U] == c;
|
||||||
|
|
|
@ -115,6 +115,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -306,6 +307,10 @@ static ValueFlow::Value castValue(ValueFlow::Value value, const ValueType::Sign
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isNumeric(const ValueFlow::Value& value) {
|
||||||
|
return value.isIntValue() || value.isFloatValue();
|
||||||
|
}
|
||||||
|
|
||||||
static void combineValueProperties(const ValueFlow::Value &value1, const ValueFlow::Value &value2, ValueFlow::Value *result)
|
static void combineValueProperties(const ValueFlow::Value &value1, const ValueFlow::Value &value2, ValueFlow::Value *result)
|
||||||
{
|
{
|
||||||
if (value1.isKnown() && value2.isKnown())
|
if (value1.isKnown() && value2.isKnown())
|
||||||
|
@ -316,6 +321,14 @@ static void combineValueProperties(const ValueFlow::Value &value1, const ValueFl
|
||||||
result->setInconclusive();
|
result->setInconclusive();
|
||||||
else
|
else
|
||||||
result->setPossible();
|
result->setPossible();
|
||||||
|
if (value1.isSymbolicValue()) {
|
||||||
|
result->valueType = value1.valueType;
|
||||||
|
result->tokvalue = value1.tokvalue;
|
||||||
|
}
|
||||||
|
if (value2.isSymbolicValue()) {
|
||||||
|
result->valueType = value2.valueType;
|
||||||
|
result->tokvalue = value2.tokvalue;
|
||||||
|
}
|
||||||
if (value1.isIteratorValue())
|
if (value1.isIteratorValue())
|
||||||
result->valueType = value1.valueType;
|
result->valueType = value1.valueType;
|
||||||
if (value2.isIteratorValue())
|
if (value2.isIteratorValue())
|
||||||
|
@ -420,14 +433,14 @@ static R calculate(const std::string& s, const T& x, const T& y, bool* error = n
|
||||||
case '<':
|
case '<':
|
||||||
return wrap(x < y);
|
return wrap(x < y);
|
||||||
case '<<':
|
case '<<':
|
||||||
if (y >= sizeof(MathLib::bigint) * 8) {
|
if (y >= sizeof(MathLib::bigint) * 8 || y < 0 || x < 0) {
|
||||||
if (error)
|
if (error)
|
||||||
*error = true;
|
*error = true;
|
||||||
return R{};
|
return R{};
|
||||||
}
|
}
|
||||||
return wrap(MathLib::bigint(x) << MathLib::bigint(y));
|
return wrap(MathLib::bigint(x) << MathLib::bigint(y));
|
||||||
case '>>':
|
case '>>':
|
||||||
if (y >= sizeof(MathLib::bigint) * 8) {
|
if (y >= sizeof(MathLib::bigint) * 8 || y < 0 || x < 0) {
|
||||||
if (error)
|
if (error)
|
||||||
*error = true;
|
*error = true;
|
||||||
return R{};
|
return R{};
|
||||||
|
@ -458,8 +471,35 @@ static T calculate(const std::string& s, const T& x, const T& y, bool* error = n
|
||||||
/** Set token value for cast */
|
/** Set token value for cast */
|
||||||
static void setTokenValueCast(Token *parent, const ValueType &valueType, const ValueFlow::Value &value, const Settings *settings);
|
static void setTokenValueCast(Token *parent, const ValueType &valueType, const ValueFlow::Value &value, const Settings *settings);
|
||||||
|
|
||||||
|
static bool isCompatibleValueTypes(ValueFlow::Value::ValueType x, ValueFlow::Value::ValueType y)
|
||||||
|
{
|
||||||
|
static const std::unordered_map<ValueFlow::Value::ValueType,
|
||||||
|
std::unordered_set<ValueFlow::Value::ValueType, EnumClassHash>,
|
||||||
|
EnumClassHash>
|
||||||
|
compatibleTypes = {
|
||||||
|
{ValueFlow::Value::ValueType::INT,
|
||||||
|
{ValueFlow::Value::ValueType::FLOAT,
|
||||||
|
ValueFlow::Value::ValueType::SYMBOLIC,
|
||||||
|
ValueFlow::Value::ValueType::TOK}},
|
||||||
|
{ValueFlow::Value::ValueType::FLOAT, {ValueFlow::Value::ValueType::INT}},
|
||||||
|
{ValueFlow::Value::ValueType::TOK, {ValueFlow::Value::ValueType::INT}},
|
||||||
|
{ValueFlow::Value::ValueType::ITERATOR_START, {ValueFlow::Value::ValueType::INT}},
|
||||||
|
{ValueFlow::Value::ValueType::ITERATOR_END, {ValueFlow::Value::ValueType::INT}},
|
||||||
|
};
|
||||||
|
if (x == y)
|
||||||
|
return true;
|
||||||
|
auto it = compatibleTypes.find(x);
|
||||||
|
if (it == compatibleTypes.end())
|
||||||
|
return false;
|
||||||
|
return it->second.count(y) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
static bool isCompatibleValues(const ValueFlow::Value& value1, const ValueFlow::Value& value2)
|
static bool isCompatibleValues(const ValueFlow::Value& value1, const ValueFlow::Value& value2)
|
||||||
{
|
{
|
||||||
|
if (value1.isSymbolicValue() && value2.isSymbolicValue() && value1.tokvalue->exprId() != value2.tokvalue->exprId())
|
||||||
|
return false;
|
||||||
|
if (!isCompatibleValueTypes(value1.valueType, value2.valueType))
|
||||||
|
return false;
|
||||||
if (value1.isKnown() || value2.isKnown())
|
if (value1.isKnown() || value2.isKnown())
|
||||||
return true;
|
return true;
|
||||||
if (value1.isImpossible() || value2.isImpossible())
|
if (value1.isImpossible() || value2.isImpossible())
|
||||||
|
@ -744,15 +784,18 @@ static void setTokenValue(Token* tok, ValueFlow::Value value, const Settings* se
|
||||||
continue;
|
continue;
|
||||||
ValueFlow::Value result(0);
|
ValueFlow::Value result(0);
|
||||||
combineValueProperties(value1, value2, &result);
|
combineValueProperties(value1, value2, &result);
|
||||||
const double floatValue1 = value1.isIntValue() ? value1.intvalue : value1.floatValue;
|
if (astIsFloat(parent, false)) {
|
||||||
const double floatValue2 = value2.isIntValue() ? value2.intvalue : value2.floatValue;
|
if (!result.isIntValue() && !result.isFloatValue())
|
||||||
const bool isFloat = value1.isFloatValue() || value2.isFloatValue();
|
|
||||||
if (isFloat && Token::Match(parent, "&|^|%|<<|>>|%or%"))
|
|
||||||
continue;
|
continue;
|
||||||
if (Token::Match(parent, "<<|>>") &&
|
result.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||||
!(value1.intvalue >= 0 && value2.intvalue >= 0 && value2.intvalue < MathLib::bigint_bits))
|
}
|
||||||
continue;
|
const double floatValue1 = value1.isFloatValue() ? value1.floatValue : value1.intvalue;
|
||||||
if (Token::Match(parent, "/|%") && isZero<double>(floatValue2))
|
const double floatValue2 = value2.isFloatValue() ? value2.floatValue : value2.intvalue;
|
||||||
|
const MathLib::bigint intValue1 =
|
||||||
|
value1.isFloatValue() ? static_cast<MathLib::bigint>(value1.floatValue) : value1.intvalue;
|
||||||
|
const MathLib::bigint intValue2 =
|
||||||
|
value2.isFloatValue() ? static_cast<MathLib::bigint>(value2.floatValue) : value2.intvalue;
|
||||||
|
if ((value1.isFloatValue() || value2.isFloatValue()) && Token::Match(parent, "&|^|%|<<|>>|==|!=|%or%"))
|
||||||
continue;
|
continue;
|
||||||
if (Token::Match(parent, "==|!=")) {
|
if (Token::Match(parent, "==|!=")) {
|
||||||
if ((value1.isIntValue() && value2.isTokValue()) || (value1.isTokValue() && value2.isIntValue())) {
|
if ((value1.isIntValue() && value2.isTokValue()) || (value1.isTokValue() && value2.isIntValue())) {
|
||||||
|
@ -761,28 +804,30 @@ static void setTokenValue(Token* tok, ValueFlow::Value value, const Settings* se
|
||||||
else if (parent->str() == "!=")
|
else if (parent->str() == "!=")
|
||||||
result.intvalue = 1;
|
result.intvalue = 1;
|
||||||
} else if (value1.isIntValue() && value2.isIntValue()) {
|
} else if (value1.isIntValue() && value2.isIntValue()) {
|
||||||
result.intvalue = calculate(parent->str(), value1.intvalue, value2.intvalue);
|
bool error = false;
|
||||||
|
result.intvalue = calculate(parent->str(), intValue1, intValue2, &error);
|
||||||
|
if (error)
|
||||||
|
continue;
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
setTokenValue(parent, result, settings);
|
setTokenValue(parent, result, settings);
|
||||||
} else if (Token::Match(parent, "%comp%")) {
|
|
||||||
if (!isFloat && !value1.isIntValue() && !value2.isIntValue())
|
|
||||||
continue;
|
|
||||||
if (isFloat)
|
|
||||||
result.intvalue = calculate(parent->str(), floatValue1, floatValue2);
|
|
||||||
else
|
|
||||||
result.intvalue = calculate(parent->str(), value1.intvalue, value2.intvalue);
|
|
||||||
setTokenValue(parent, result, settings);
|
|
||||||
} else if (Token::Match(parent, "%op%")) {
|
} else if (Token::Match(parent, "%op%")) {
|
||||||
|
if (Token::Match(parent, "%comp%")) {
|
||||||
|
if (!result.isFloatValue() && !value1.isIntValue() && !value2.isIntValue())
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
if (value1.isTokValue() || value2.isTokValue())
|
if (value1.isTokValue() || value2.isTokValue())
|
||||||
break;
|
break;
|
||||||
if (isFloat) {
|
|
||||||
result.valueType = ValueFlow::Value::ValueType::FLOAT;
|
|
||||||
result.floatValue = calculate(parent->str(), floatValue1, floatValue2);
|
|
||||||
} else {
|
|
||||||
result.intvalue = calculate(parent->str(), value1.intvalue, value2.intvalue);
|
|
||||||
}
|
}
|
||||||
|
bool error = false;
|
||||||
|
if (result.isFloatValue()) {
|
||||||
|
result.floatValue = calculate(parent->str(), floatValue1, floatValue2, &error);
|
||||||
|
} else {
|
||||||
|
result.intvalue = calculate(parent->str(), intValue1, intValue2, &error);
|
||||||
|
}
|
||||||
|
if (error)
|
||||||
|
continue;
|
||||||
// If the bound comes from the second value then invert the bound when subtracting
|
// If the bound comes from the second value then invert the bound when subtracting
|
||||||
if (Token::simpleMatch(parent, "-") && value2.bound == result.bound &&
|
if (Token::simpleMatch(parent, "-") && value2.bound == result.bound &&
|
||||||
value2.bound != ValueFlow::Value::Bound::Point)
|
value2.bound != ValueFlow::Value::Bound::Point)
|
||||||
|
@ -945,14 +990,13 @@ static void setTokenValueCast(Token *parent, const ValueType &valueType, const V
|
||||||
setTokenValue(parent, castValue(value, valueType.sign, settings->long_bit), settings);
|
setTokenValue(parent, castValue(value, valueType.sign, settings->long_bit), settings);
|
||||||
else if (valueType.type == ValueType::Type::LONGLONG)
|
else if (valueType.type == ValueType::Type::LONGLONG)
|
||||||
setTokenValue(parent, castValue(value, valueType.sign, settings->long_long_bit), settings);
|
setTokenValue(parent, castValue(value, valueType.sign, settings->long_long_bit), settings);
|
||||||
else if (valueType.isFloat()) {
|
else if (valueType.isFloat() && isNumeric(value)) {
|
||||||
ValueFlow::Value floatValue = value;
|
ValueFlow::Value floatValue = value;
|
||||||
floatValue.valueType = ValueFlow::Value::ValueType::FLOAT;
|
floatValue.valueType = ValueFlow::Value::ValueType::FLOAT;
|
||||||
if (value.isIntValue())
|
if (value.isIntValue())
|
||||||
floatValue.floatValue = value.intvalue;
|
floatValue.floatValue = value.intvalue;
|
||||||
setTokenValue(parent, floatValue, settings);
|
setTokenValue(parent, floatValue, settings);
|
||||||
}
|
} else if (value.isIntValue()) {
|
||||||
else if (value.isIntValue()) {
|
|
||||||
const long long charMax = settings->signedCharMax();
|
const long long charMax = settings->signedCharMax();
|
||||||
const long long charMin = settings->signedCharMin();
|
const long long charMin = settings->signedCharMin();
|
||||||
if (charMin <= value.intvalue && value.intvalue <= charMax) {
|
if (charMin <= value.intvalue && value.intvalue <= charMax) {
|
||||||
|
|
|
@ -826,6 +826,12 @@ private:
|
||||||
ASSERT(tokenValues(";10>>-1;",">>").empty());
|
ASSERT(tokenValues(";10>>-1;",">>").empty());
|
||||||
ASSERT(tokenValues(";10>>64;",">>").empty());
|
ASSERT(tokenValues(";10>>64;",">>").empty());
|
||||||
|
|
||||||
|
code = "float f(const uint16_t& value) {\n"
|
||||||
|
" const uint16_t uVal = value; \n"
|
||||||
|
" return static_cast<float>(uVal) / 2;\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(true, tokenValues(code, "/").empty());
|
||||||
|
|
||||||
// calculation using 1,2 variables/values
|
// calculation using 1,2 variables/values
|
||||||
code = "void f(int x) {\n"
|
code = "void f(int x) {\n"
|
||||||
" a = x+456;\n"
|
" a = x+456;\n"
|
||||||
|
|
Loading…
Reference in New Issue