|
| 1 | +/** |
| 2 | + * Finds expressions which seem to try rounding down a value `a` to the next smaller |
| 3 | + * multiple of `b`, but which seem to be incorrectly implemented. |
| 4 | + * |
| 5 | + * The correct expression is `a / b * b` (where `a` and `b` are integral numbers). |
| 6 | + * The following incorrect expressions are detected: |
| 7 | + * - `a / b` producing a floating point number; in that case `a / b * b` is most |
| 8 | + * likely the same as `a` (except for some floating point precision loss), |
| 9 | + * or possibly brackets are missing and it should have been `a / (b * b)` |
| 10 | + * - `a / b * a`; the `* a` seems incorrect and should probably be `* b` |
| 11 | + * |
| 12 | + * @id todo |
| 13 | + * @kind problem |
| 14 | + */ |
| 15 | + |
| 16 | +import java |
| 17 | +import lib.VarAccess |
| 18 | + |
| 19 | +predicate haveSameValue(Expr a, Expr b) { |
| 20 | + a.getType() = b.getType() and a.(Literal).getValue() = b.(Literal).getValue() |
| 21 | + or |
| 22 | + accessSameVarOfSameOwner(a, b) |
| 23 | +} |
| 24 | + |
| 25 | +from DivExpr div, Expr divisor, MulExpr mul, Expr mulOperand |
| 26 | +where |
| 27 | + // Match `... / divisor * mulOperand` |
| 28 | + mul.getLeftOperand() = div and |
| 29 | + mulOperand = mul.getRightOperand() and |
| 30 | + div.getRightOperand() = divisor and |
| 31 | + ( |
| 32 | + // Redundant division because result is floating point, e.g. `(a / 2.0) * 2` (= `a`, with some floating point precision loss) |
| 33 | + div.getType() instanceof FloatingPointType and |
| 34 | + haveSameValue(divisor, mulOperand) |
| 35 | + or |
| 36 | + // TODO: Maybe remove this case (also from documentation of query)? At least Variant Analysis did not find any case of this |
| 37 | + |
| 38 | + // Or accidental `(a / b) * a` when it should probably have been `(a / b) * b` |
| 39 | + haveSameValue(div.getLeftOperand(), mulOperand) and |
| 40 | + // Ignore if this calculates square of expression, e.g. `a / b * a / b` |
| 41 | + not exists(DivExpr rightDiv | |
| 42 | + rightDiv.getLeftOperand() = mul and |
| 43 | + haveSameValue(rightDiv.getRightOperand(), divisor) |
| 44 | + ) |
| 45 | + ) |
| 46 | +select mul, "Performs incorrect rounding division" |
0 commit comments