29 #include <unordered_set>
34 template<
class Predicate,
class Compare>
53 std::vector<MathLib::bigint> minvalue, maxvalue;
54 std::vector<const ValueFlow::Value*> minRef, maxRef;
70 bool isLessThan(
MathLib::bigint x, std::vector<const ValueFlow::Value*>* ref =
nullptr)
const
72 if (!this->maxvalue.empty() && this->maxvalue.front() < x) {
80 bool isGreaterThan(
MathLib::bigint x, std::vector<const ValueFlow::Value*>* ref =
nullptr)
const
82 if (!this->minvalue.empty() && this->minvalue.front() > x) {
90 bool isScalar()
const {
91 return minvalue.size() == 1 && minvalue == maxvalue;
95 return minvalue.empty() && maxvalue.empty();
98 bool isScalarOrEmpty()
const {
99 return empty() || isScalar();
105 return minvalue.front();
108 std::vector<const ValueFlow::Value*> getScalarRef()
const
111 if (minRef != maxRef)
112 return merge(minRef, maxRef);
119 result.setMinValue(x, ref);
120 result.setMaxValue(x, ref);
124 template<
class Predicate>
125 static Interval fromValues(
const std::list<ValueFlow::Value>&
values, Predicate predicate)
131 result.setMinValue(minValue->
intvalue + 1, minValue);
133 result.setMinValue(minValue->
intvalue, minValue);
135 std::count_if(
values.begin(),
values.end(), predicate) == 1)
136 return Interval::fromInt(minValue->
intvalue, minValue);
141 result.setMaxValue(maxValue->
intvalue - 1, maxValue);
143 result.setMaxValue(maxValue->
intvalue, maxValue);
149 static Interval fromValues(
const std::list<ValueFlow::Value>&
values)
157 static std::vector<MathLib::bigint> apply(
const std::vector<MathLib::bigint>& x,
158 const std::vector<MathLib::bigint>& y,
165 return {f(x.front(), y.front())};
168 static std::vector<const ValueFlow::Value*> merge(std::vector<const ValueFlow::Value*> x,
169 const std::vector<const ValueFlow::Value*>& y)
171 x.insert(x.end(), y.cbegin(), y.cend());
175 friend Interval
operator-(
const Interval& lhs,
const Interval& rhs)
178 result.minvalue = Interval::apply(lhs.minvalue, rhs.maxvalue, std::minus<MathLib::bigint>{});
179 result.maxvalue = Interval::apply(lhs.maxvalue, rhs.minvalue, std::minus<MathLib::bigint>{});
180 if (!result.minvalue.empty())
181 result.minRef = merge(lhs.minRef, rhs.maxRef);
182 if (!result.maxvalue.empty())
183 result.maxRef = merge(lhs.maxRef, rhs.minRef);
187 static std::vector<int> equal(
const Interval& lhs,
189 std::vector<const ValueFlow::Value*>* ref =
nullptr)
196 *ref = merge(lhs.getScalarRef(), rhs.getScalarRef());
197 return {lhs.minvalue == rhs.minvalue};
200 static std::vector<int> compare(
const Interval& lhs,
202 std::vector<const ValueFlow::Value*>* ref =
nullptr)
204 Interval diff = lhs - rhs;
205 if (diff.isGreaterThan(0, ref))
207 if (diff.isLessThan(0, ref))
209 std::vector<int> eq = Interval::equal(lhs, rhs, ref);
215 if (diff.isGreaterThan(-1, ref))
217 if (diff.isLessThan(1, ref))
222 static std::vector<bool> compare(
const std::string& op,
225 std::vector<const ValueFlow::Value*>* ref =
nullptr)
227 std::vector<int> r = compare(lhs, rhs, ref);
231 if (std::all_of(r.cbegin() + 1, r.cend(), [&](
int i) {
232 return b == calculate(op, i, 0);
242 std::unordered_set<const Token*> locations;
246 std::copy_if(ref->errorPath.cbegin(),
247 ref->errorPath.cend(),
250 return locations.insert(e.first).second;
252 std::copy_if(ref->debugPath.cbegin(),
253 ref->debugPath.cend(),
256 return locations.insert(e.first).second;
263 bool isPossible =
false;
264 bool isInconclusive =
false;
266 if (ref->isPossible())
268 if (ref->isInconclusive())
269 isInconclusive =
true;
281 return std::any_of(values.cbegin(), values.cend(), [&](
const ValueFlow::Value& value) {
282 return value.isImpossible() && value.intvalue == x;
287 const std::string& op,
288 std::list<ValueFlow::Value> lhsValues,
289 std::list<ValueFlow::Value> rhsValues)
291 std::vector<ValueFlow::Value> result;
293 return !model->match(value);
295 lhsValues.remove_if(notMatch);
296 rhsValues.remove_if(notMatch);
297 if (lhsValues.empty() || rhsValues.empty())
300 Interval lhs = Interval::fromValues(lhsValues);
301 Interval rhs = Interval::fromValues(rhsValues);
304 Interval diff = lhs - rhs;
305 if (diff.isScalar()) {
306 std::vector<const ValueFlow::Value*> refs = diff.getScalarRef();
310 result.push_back(std::move(value));
312 if (!diff.minvalue.empty()) {
317 result.push_back(std::move(value));
319 if (!diff.maxvalue.empty()) {
324 result.push_back(std::move(value));
327 }
else if ((op ==
"!=" || op ==
"==") && lhs.isScalarOrEmpty() && rhs.isScalarOrEmpty()) {
328 if (lhs.isScalar() && rhs.isScalar()) {
329 std::vector<const ValueFlow::Value*> refs = Interval::merge(lhs.getScalarRef(), rhs.getScalarRef());
333 result.push_back(std::move(value));
335 std::vector<const ValueFlow::Value*> refs;
336 if (lhs.isScalar() &&
inferNotEqual(rhsValues, lhs.getScalar()))
337 refs = lhs.getScalarRef();
338 else if (rhs.isScalar() &&
inferNotEqual(lhsValues, rhs.getScalar()))
339 refs = rhs.getScalarRef();
344 result.push_back(std::move(value));
348 std::vector<const ValueFlow::Value*> refs;
349 std::vector<bool> r = Interval::compare(op, lhs, rhs, &refs);
354 result.push_back(std::move(value));
362 const std::string& op,
364 std::list<ValueFlow::Value> rhsValues)
366 return infer(model, op, {model->yield(lhs)}, std::move(rhsValues));
370 const std::string& op,
371 std::list<ValueFlow::Value> lhsValues,
374 return infer(model, op, std::move(lhsValues), {model->yield(rhs)});
380 return model->match(v);
386 return model->match(v);
R calculate(const std::string &s, const T &x, const T &y, bool *error=nullptr)
The token list that the TokenList generates is a linked-list of this class.
const std::list< ValueFlow::Value > & values() const
Bound bound
The value bound
bool isImpossible() const
const Token * condition
Condition that this value depends on.
long long intvalue
int value (or sometimes bool value?)
void setInconclusive(bool inconclusive=true)
std::pair< const Token *, std::string > ErrorPathItem
MathLib::value operator-(const MathLib::value &v1, const MathLib::value &v2)
std::vector< MathLib::bigint > getMinValue(const ValuePtr< InferModel > &model, const std::list< ValueFlow::Value > &values)
static const ValueFlow::Value * getCompareValue(const std::list< ValueFlow::Value > &values, Predicate pred, Compare compare)
static void addToErrorPath(ValueFlow::Value &value, const std::vector< const ValueFlow::Value * > &refs)
static void setValueKind(ValueFlow::Value &value, const std::vector< const ValueFlow::Value * > &refs)
std::vector< MathLib::bigint > getMaxValue(const ValuePtr< InferModel > &model, const std::list< ValueFlow::Value > &values)
static bool inferNotEqual(const std::list< ValueFlow::Value > &values, MathLib::bigint x)
std::vector< ValueFlow::Value > infer(const ValuePtr< InferModel > &model, const std::string &op, std::list< ValueFlow::Value > lhsValues, std::list< ValueFlow::Value > rhsValues)