|
6 | 6 | import java
|
7 | 7 | import semmle.code.java.dataflow.RangeAnalysis
|
8 | 8 | private import TestUtilities.InlineExpectationsTest as IET
|
| 9 | +private import semmle.code.java.dataflow.DataFlow |
9 | 10 |
|
10 | 11 | module RangeTest implements IET::TestSig {
|
11 | 12 | string getARelevantTag() { result = "bound" }
|
12 | 13 |
|
13 | 14 | predicate hasActualResult(Location location, string element, string tag, string value) {
|
14 | 15 | tag = "bound" and
|
15 |
| - exists(Expr e, int lower, int upper | |
16 |
| - constrained(e, lower, upper) and |
17 |
| - e instanceof VarRead and |
18 |
| - e.getCompilationUnit().fromSource() |
19 |
| - | |
20 |
| - location = e.getLocation() and |
21 |
| - element = e.toString() and |
22 |
| - if lower = upper |
23 |
| - then value = "\"" + e.toString() + " = " + lower.toString() + "\"" |
24 |
| - else |
25 |
| - value = "\"" + e.toString() + " in [" + lower.toString() + ".." + upper.toString() + "]\"" |
| 16 | + ( |
| 17 | + // simple integer bounds (`ZeroBound`s) |
| 18 | + exists(Expr e, int lower, int upper | |
| 19 | + constrained(e, lower, upper) and |
| 20 | + e instanceof VarRead and |
| 21 | + e.getCompilationUnit().fromSource() |
| 22 | + | |
| 23 | + location = e.getLocation() and |
| 24 | + element = e.toString() and |
| 25 | + if lower = upper |
| 26 | + then value = "\"" + e.toString() + " = " + lower.toString() + "\"" |
| 27 | + else |
| 28 | + value = "\"" + e.toString() + " in [" + lower.toString() + ".." + upper.toString() + "]\"" |
| 29 | + ) |
| 30 | + or |
| 31 | + // advanced bounds |
| 32 | + exists( |
| 33 | + Expr e, int delta, string deltaStr, boolean upper, string cmp, Bound b, Expr boundExpr |
| 34 | + | |
| 35 | + annotatedBound(e, b, boundExpr, delta, upper) and |
| 36 | + e instanceof VarRead and |
| 37 | + e.getCompilationUnit().fromSource() and |
| 38 | + ( |
| 39 | + if delta = 0 |
| 40 | + then deltaStr = "" |
| 41 | + else |
| 42 | + if delta > 0 |
| 43 | + then deltaStr = " + " + delta.toString() |
| 44 | + else deltaStr = " - " + delta.abs().toString() |
| 45 | + ) and |
| 46 | + if upper = true then cmp = "<=" else cmp = ">=" |
| 47 | + | |
| 48 | + location = e.getLocation() and |
| 49 | + element = e.toString() and |
| 50 | + value = "\"" + e.toString() + " " + cmp + " " + boundExpr.toString() + deltaStr + "\"" |
| 51 | + ) |
26 | 52 | )
|
27 | 53 | }
|
28 | 54 |
|
29 | 55 | private predicate constrained(Expr e, int lower, int upper) {
|
30 | 56 | bounded(e, any(ZeroBound z), lower, false, _) and
|
31 | 57 | bounded(e, any(ZeroBound z), upper, true, _)
|
32 | 58 | }
|
| 59 | + |
| 60 | + private predicate annotatedBound(Expr e, Bound b, Expr boundExpr, int delta, boolean upper) { |
| 61 | + bounded(e, b, delta, upper, _) and |
| 62 | + // the expression for the bound is explicitly requested as being annotated |
| 63 | + // via a call such as |
| 64 | + // ```java |
| 65 | + // bound(expr); |
| 66 | + // ``` |
| 67 | + boundExpr = b.getExpr() and |
| 68 | + exists(Call c | c.getCallee().getName() = "bound" and c.getArgument(0) = boundExpr) and |
| 69 | + // non-trivial bound |
| 70 | + (DataFlow::localFlow(DataFlow::exprNode(boundExpr), DataFlow::exprNode(e)) implies delta != 0) |
| 71 | + } |
33 | 72 | }
|
34 | 73 |
|
35 | 74 | import IET::MakeTest<RangeTest>
|
0 commit comments