2424#include " symboldatabase.h"
2525#include " tokenlist.h"
2626#include " utils.h"
27+ #include " valueflow.h"
2728
2829#include < algorithm>
2930#include < cassert>
3031#include < cctype>
3132#include < cstring>
33+ #include < functional>
3234#include < iostream>
3335#include < map>
3436#include < set>
@@ -1947,6 +1949,25 @@ const Token *Token::getValueTokenDeadPointer() const
19471949 return nullptr ;
19481950}
19491951
1952+ static bool isAdjacent (const ValueFlow::Value& x, const ValueFlow::Value& y)
1953+ {
1954+ if (x.bound != ValueFlow::Value::Bound::Point && x.bound == y.bound )
1955+ return true ;
1956+ if (x.valueType == ValueFlow::Value::ValueType::FLOAT)
1957+ return false ;
1958+ return std::abs (x.intvalue - y.intvalue ) == 1 ;
1959+ }
1960+
1961+ static bool removePointValue (std::list<ValueFlow::Value>& values, ValueFlow::Value& x)
1962+ {
1963+ const bool isPoint = x.bound == ValueFlow::Value::Bound::Point;
1964+ if (!isPoint)
1965+ x.decreaseRange ();
1966+ else
1967+ values.remove (x);
1968+ return isPoint;
1969+ }
1970+
19501971static bool removeContradiction (std::list<ValueFlow::Value>& values)
19511972{
19521973 bool result = false ;
@@ -1962,26 +1983,110 @@ static bool removeContradiction(std::list<ValueFlow::Value>& values)
19621983 continue ;
19631984 if (x.isImpossible () == y.isImpossible ())
19641985 continue ;
1965- if (!x.equalValue (y))
1986+ if (!x.equalValue (y)) {
1987+ auto compare = [](const ValueFlow::Value& x, const ValueFlow::Value& y) {
1988+ return x.compareValue (y, ValueFlow::less{});
1989+ };
1990+ const ValueFlow::Value& maxValue = std::max (x, y, compare);
1991+ const ValueFlow::Value& minValue = std::min (x, y, compare);
1992+ // TODO: Adjust non-points instead of removing them
1993+ if (maxValue.isImpossible () && maxValue.bound == ValueFlow::Value::Bound::Upper) {
1994+ values.remove (minValue);
1995+ return true ;
1996+ }
1997+ if (minValue.isImpossible () && minValue.bound == ValueFlow::Value::Bound::Lower) {
1998+ values.remove (maxValue);
1999+ return true ;
2000+ }
19662001 continue ;
1967- if (x. bound == y. bound ||
1968- (x. bound != ValueFlow::Value::Bound::Point && y. bound != ValueFlow::Value::Bound::Point)) {
1969- const bool removex = !x .isImpossible () || y .isKnown ();
1970- const bool removey = !y. isImpossible () || x. isKnown ();
2002+ }
2003+ const bool removex = !x. isImpossible () || y. isKnown ();
2004+ const bool removey = !y .isImpossible () || x .isKnown ();
2005+ if (x. bound == y. bound ) {
19712006 if (removex)
19722007 values.remove (x);
19732008 if (removey)
19742009 values.remove (y);
19752010 return true ;
1976- } else if (x.bound == ValueFlow::Value::Bound::Point) {
1977- y.decreaseRange ();
1978- result = true ;
2011+ } else {
2012+ result = removex || removey;
2013+ bool bail = false ;
2014+ if (removex && removePointValue (values, x))
2015+ bail = true ;
2016+ if (removey && removePointValue (values, y))
2017+ bail = true ;
2018+ if (bail)
2019+ return true ;
19792020 }
19802021 }
19812022 }
19822023 return result;
19832024}
19842025
2026+ using ValueIterator = std::list<ValueFlow::Value>::iterator;
2027+
2028+ template <class Iterator >
2029+ static ValueIterator removeAdjacentValues (std::list<ValueFlow::Value>& values, ValueIterator x, Iterator start, Iterator last)
2030+ {
2031+ if (!isAdjacent (*x, **start))
2032+ return std::next (x);
2033+ auto it = std::adjacent_find (start, last, [](ValueIterator x, ValueIterator y) { return !isAdjacent (*x, *y); });
2034+ if (it == last)
2035+ it--;
2036+ (*it)->bound = x->bound ;
2037+ std::for_each (start, it, [&](ValueIterator y) { values.erase (y); });
2038+ return values.erase (x);
2039+ }
2040+
2041+ static void mergeAdjacent (std::list<ValueFlow::Value>& values)
2042+ {
2043+ for (auto x = values.begin (); x != values.end ();) {
2044+ if (x->isNonValue ()) {
2045+ x++;
2046+ continue ;
2047+ }
2048+ if (x->bound == ValueFlow::Value::Bound::Point) {
2049+ x++;
2050+ continue ;
2051+ }
2052+ std::vector<ValueIterator> adjValues;
2053+ for (auto y = values.begin (); y != values.end (); y++) {
2054+ if (x == y)
2055+ continue ;
2056+ if (y->isNonValue ())
2057+ continue ;
2058+ if (x->valueType != y->valueType )
2059+ continue ;
2060+ if (x->valueKind != y->valueKind )
2061+ continue ;
2062+ if (x->bound != y->bound ) {
2063+ // No adjacent points for floating points
2064+ if (x->valueType == ValueFlow::Value::ValueType::FLOAT)
2065+ continue ;
2066+ if (y->bound != ValueFlow::Value::Bound::Point)
2067+ continue ;
2068+ }
2069+ if (x->bound == ValueFlow::Value::Bound::Lower && !y->compareValue (*x, ValueFlow::less{}))
2070+ continue ;
2071+ if (x->bound == ValueFlow::Value::Bound::Upper && !x->compareValue (*y, ValueFlow::less{}))
2072+ continue ;
2073+ adjValues.push_back (y);
2074+ }
2075+ if (adjValues.empty ()) {
2076+ x++;
2077+ continue ;
2078+ }
2079+ std::sort (adjValues.begin (), adjValues.end (), [&values](ValueIterator xx, ValueIterator yy) {
2080+ assert (xx != values.end () && yy != values.end ());
2081+ return xx->compareValue (*yy, ValueFlow::less{});
2082+ });
2083+ if (x->bound == ValueFlow::Value::Bound::Lower)
2084+ x = removeAdjacentValues (values, x, adjValues.rbegin (), adjValues.rend ());
2085+ else if (x->bound == ValueFlow::Value::Bound::Upper)
2086+ x = removeAdjacentValues (values, x, adjValues.begin (), adjValues.end ());
2087+ }
2088+ }
2089+
19852090static void removeOverlaps (std::list<ValueFlow::Value>& values)
19862091{
19872092 for (ValueFlow::Value& x : values) {
@@ -2005,12 +2110,14 @@ static void removeOverlaps(std::list<ValueFlow::Value>& values)
20052110 return true ;
20062111 });
20072112 }
2113+ mergeAdjacent (values);
20082114}
20092115
20102116// Removing contradictions is an NP-hard problem. Instead we run multiple
20112117// passes to try to catch most contradictions
20122118static void removeContradictions (std::list<ValueFlow::Value>& values)
20132119{
2120+ removeOverlaps (values);
20142121 for (int i = 0 ; i < 4 ; i++) {
20152122 if (!removeContradiction (values))
20162123 return ;
0 commit comments