That FIXME, and indeed the code to support case ranges, actually predates RangeConstraintManager, which implements most of what the FIXME is referring to. (That is, the technical/historical reason we couldn’t do it symbolically is “it wasn’t implemented yet”.) So your change is in fact on the right track.
However, what you’ve done is construct the expression “$x >= LOWER && $x <= UPPER”. This is correct, but it’s not a form that RangeConstraintManager will actually handle right now:
void clang_analyzer_eval(int);
void test(int i) {
switch (i) {
case 1 … 5:
return;
}
clang_analyzer_eval(x == 2); // should print FALSE, but will print UNKNOWN with your patch.
}
(clang_analyzer_eval is a special function used to probe the analyzer state, handled by the debug.ExprInspection checker.)
The easiest way to fix this would be to use assumeDual on each expression individually. Then you end up with three cases: $x < LOWER, $x is in range, and $x > UPPER. Unfortunately, you’d then have to restructure the whole function, which currently assumes that you end up with exactly one state that can end up in the “default” branch. That wouldn’t be too hard.
The harder way to solve this is to actually teach [Range]ConstraintManager to recognize constraints like this, and do the right thing. The implementation is already set up to handle disjoint sets of ranges, so you could actually do this without changing everything. It’s probably more messy than you’d like, though.
The sneaky way to do this is to realize that “$x >= LOWER && $x <= UPPER” is actually equivalent to “$x - (LOWER - MIN) <= UPPER - (LOWER - MIN)”, where MIN is the minimum value for the integer type, for integers with wraparound semantics. (RangeConstraintManager actually takes advantage of this in reverse to translate “$x - OFFSET <= VALUE” back into a pair of range disjunctions.) The only trouble with doing something like this is that wraparound is Hard™ and you/we will want to be very careful that this actually handles everything correctly, for all the integer types we care about. A definite benefit of this is that we’re back to only having one state, which prevents potential exponential explosion as analysis continues.
What do you think we should do here?
Jordan