I have now seen two cases where experienced Java developers wrote something like
int rawInput = …;
int valid = Math.min(0, Math.max(100, rawInput));
This looks right as a casual glance—you are specifying the minimum and maximum values—but in fact always sets valid to 0! They meant to write:
int rawInput = …;
int valid = Math.max(0, Math.min(100, rawInput));
Similarly,
int rawInput = …;
int valid = Math.max(100, Math.min(0, rawInput));
always sets it to 100, and should be corrected to
int rawInput = …;
int valid = Math.min(100, Math.max(0, rawInput));
It seems like it should be straightforward to detect the bad idioms, at least for arguments of type int or long, so long as the bounds are given as constants. There might be subtleties for float- or double-valued calls, so probably the check should just be skipped if either bound is -0 or NaN.
(It would be helpful to have a library function that does the combined bounding operation, yet Math does not have it, nor does Guava nor Apache Commons Lang.)
Interesting idea. Will try to implement.
Implemented:
https://code.google.com/p/findbugs/source/detail?r=09ffa973c6fe5c4ebd88aa0a4e1948f7be4a0114
After scanning our collection of 33 open source projects, the new pattern was found only once in Hudson project: obviously a bug. No false-positives were found. New pattern name is DM_INVALID_MIN_MAX. Please check.
Nice.
For the test, I noticed that all the
@NoWarningtests hadMath.maxwrapped inMath.min. It would be a good idea to also assert@NoWarningon correct cases ofMath.minwrapped inMath.max.The occurrence you found was one of the two cases that inspired this RFE, from Jenkins PR 1514. (The other also involved Jenkins code, but written after the fork from Hudson, by a different person.)
More tests added:
https://code.google.com/p/findbugs/source/detail?r=234cbfd2a3a7b51ea6bf65ec184820278a75520a
The second case from jenkins-junit is also properly detected.