Skip to content

Commit a8f9f10

Browse files
committed
Python: Add ConsecutiveTimestamps test
This one is potentially a bit iffy -- it checks for a very powerful propetry (that implies many of the other queries), but as the test results show, it can produce false positives when there is in fact no problem. We may want to get rid of it entirely, if it becomes too noisy.
1 parent 06de5e7 commit a8f9f10

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| test_if.py:51:9:51:16 | BinaryExpr | $@ in $@ has no consecutive successor (expected 6) | test_if.py:51:15:51:15 | IntegerLiteral | Timestamp 5 | test_if.py:43:1:43:31 | Function test_if_elif_else_first | test_if_elif_else_first |
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Checks that consecutive annotated nodes have consecutive timestamps:
3+
* for each annotation with timestamp `a`, some CFG node for that annotation
4+
* must have a next annotation containing `a + 1`.
5+
*
6+
* Handles CFG splitting (e.g., finally blocks duplicated for normal/exceptional
7+
* flow) by checking that at least one split has the required successor.
8+
*
9+
* Only applies to functions where all annotations are in the function's
10+
* own scope (excludes tests with generators, async, comprehensions, or
11+
* lambdas that have annotations in nested scopes).
12+
*/
13+
14+
import python
15+
import TimerUtils
16+
17+
/**
18+
* Holds if function `f` has an annotation in a nested scope
19+
* (generator, async function, comprehension, lambda).
20+
*/
21+
private predicate hasNestedScopeAnnotation(TestFunction f) {
22+
exists(TimerAnnotation a |
23+
a.getTestFunction() = f and
24+
a.getExpr().getScope() != f
25+
)
26+
}
27+
28+
from TimerAnnotation ann, int a
29+
where
30+
not hasNestedScopeAnnotation(ann.getTestFunction()) and
31+
not ann.isDead() and
32+
a = ann.getATimestamp() and
33+
not exists(TimerCfgNode x, TimerCfgNode y |
34+
ann.getExpr() = x.getNode() and
35+
nextTimerAnnotation(x, y) and
36+
(a + 1) = y.getATimestamp()
37+
) and
38+
// Exclude the maximum timestamp in the function (it has no successor)
39+
not a = max(TimerAnnotation other |
40+
other.getTestFunction() = ann.getTestFunction()
41+
| other.getATimestamp())
42+
select ann,
43+
"$@ in $@ has no consecutive successor (expected " + (a + 1) + ")",
44+
ann.getTimestampExpr(a), "Timestamp " + a,
45+
ann.getTestFunction(), ann.getTestFunction().getName()

0 commit comments

Comments
 (0)