This commit is contained in:
Taus
2026-04-28 14:12:13 +00:00
committed by yoff
parent 1af415bec3
commit a33b49a3f3
23 changed files with 668 additions and 181 deletions

View File

@@ -1 +1,13 @@
| test_comprehensions.py:21:29:21:40 | ControlFlowNode for BinaryExpr | Basic block ordering: $@ appears before $@ | test_comprehensions.py:21:35:21:35 | IntegerLiteral | timestamp 9 | test_comprehensions.py:21:21:21:21 | IntegerLiteral | timestamp 8 |
| test_boolean.py:9:10:9:43 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:9:59:9:59 | IntegerLiteral | timestamp 2 | test_boolean.py:9:19:9:19 | IntegerLiteral | timestamp 0 |
| test_boolean.py:15:10:15:43 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:15:50:15:50 | IntegerLiteral | timestamp 1 | test_boolean.py:15:20:15:20 | IntegerLiteral | timestamp 0 |
| test_boolean.py:21:10:21:42 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:21:49:21:49 | IntegerLiteral | timestamp 1 | test_boolean.py:21:19:21:19 | IntegerLiteral | timestamp 0 |
| test_boolean.py:27:10:27:43 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:27:59:27:59 | IntegerLiteral | timestamp 2 | test_boolean.py:27:20:27:20 | IntegerLiteral | timestamp 0 |
| test_boolean.py:40:10:40:61 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:40:86:40:86 | IntegerLiteral | timestamp 3 | test_boolean.py:40:16:40:16 | IntegerLiteral | timestamp 0 |
| test_boolean.py:46:10:46:61 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:46:86:46:86 | IntegerLiteral | timestamp 3 | test_boolean.py:46:16:46:16 | IntegerLiteral | timestamp 0 |
| test_boolean.py:52:10:52:95 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:52:120:52:120 | IntegerLiteral | timestamp 4 | test_boolean.py:52:20:52:20 | IntegerLiteral | timestamp 0 |
| test_boolean.py:52:10:52:95 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:52:120:52:120 | IntegerLiteral | timestamp 4 | test_boolean.py:52:63:52:63 | IntegerLiteral | timestamp 2 |
| test_boolean.py:52:11:52:47 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:52:63:52:63 | IntegerLiteral | timestamp 2 | test_boolean.py:52:20:52:20 | IntegerLiteral | timestamp 0 |
| test_boolean.py:64:10:64:52 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:64:59:64:59 | IntegerLiteral | timestamp 6 | test_boolean.py:64:17:64:17 | IntegerLiteral | timestamp 0 |
| test_boolean.py:64:10:64:52 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:64:59:64:59 | IntegerLiteral | timestamp 6 | test_boolean.py:64:27:64:27 | IntegerLiteral | timestamp 2 |
| test_boolean.py:76:10:76:51 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:76:58:76:58 | IntegerLiteral | timestamp 6 | test_boolean.py:76:17:76:17 | IntegerLiteral | timestamp 0 |
| test_boolean.py:76:10:76:51 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:76:58:76:58 | IntegerLiteral | timestamp 6 | test_boolean.py:76:27:76:27 | IntegerLiteral | timestamp 2 |

View File

@@ -1 +1,9 @@
| 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 |
| test_boolean.py:9:26:9:27 | IntegerLiteral | $@ in $@ has no consecutive successor (expected 2) | test_boolean.py:9:33:9:33 | IntegerLiteral | Timestamp 1 | test_boolean.py:7:1:7:27 | Function test_and_both_sides | test_and_both_sides |
| test_boolean.py:15:10:15:14 | False | $@ in $@ has no consecutive successor (expected 1) | test_boolean.py:15:20:15:20 | IntegerLiteral | Timestamp 0 | test_boolean.py:13:1:13:30 | Function test_and_short_circuit | test_and_short_circuit |
| test_boolean.py:21:10:21:13 | True | $@ in $@ has no consecutive successor (expected 1) | test_boolean.py:21:19:21:19 | IntegerLiteral | Timestamp 0 | test_boolean.py:19:1:19:29 | Function test_or_short_circuit | test_or_short_circuit |
| test_boolean.py:27:26:27:27 | IntegerLiteral | $@ in $@ has no consecutive successor (expected 2) | test_boolean.py:27:33:27:33 | IntegerLiteral | Timestamp 1 | test_boolean.py:25:1:25:26 | Function test_or_both_sides | test_or_both_sides |
| test_boolean.py:40:45:40:45 | IntegerLiteral | $@ in $@ has no consecutive successor (expected 3) | test_boolean.py:40:51:40:51 | IntegerLiteral | Timestamp 2 | test_boolean.py:38:1:38:24 | Function test_chained_and | test_chained_and |
| test_boolean.py:46:44:46:45 | IntegerLiteral | $@ in $@ has no consecutive successor (expected 3) | test_boolean.py:46:51:46:51 | IntegerLiteral | Timestamp 2 | test_boolean.py:44:1:44:23 | Function test_chained_or | test_chained_or |
| test_boolean.py:52:11:52:47 | BoolExpr | $@ in $@ has no consecutive successor (expected 3) | test_boolean.py:52:63:52:63 | IntegerLiteral | Timestamp 2 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or |
| test_boolean.py:52:27:52:31 | False | $@ in $@ has no consecutive successor (expected 2) | test_boolean.py:52:37:52:37 | IntegerLiteral | Timestamp 1 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or |
| test_boolean.py:52:78:52:79 | IntegerLiteral | $@ in $@ has no consecutive successor (expected 4) | test_boolean.py:52:85:52:85 | IntegerLiteral | Timestamp 3 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or |

View File

@@ -1,2 +1,2 @@
| test_match.py:159:13:159:23 | BinaryExpr | Node annotated with t.never is reachable in $@ | test_match.py:151:1:151:42 | Function test_match_exhaustive_return_first | test_match_exhaustive_return_first |
| test_match.py:172:13:172:23 | BinaryExpr | Node annotated with t.never is reachable in $@ | test_match.py:164:1:164:45 | Function test_match_exhaustive_return_wildcard | test_match_exhaustive_return_wildcard |
| test_match.py:159:13:159:13 | IntegerLiteral | Node annotated with t.never is reachable in $@ | test_match.py:151:1:151:42 | Function test_match_exhaustive_return_first | test_match_exhaustive_return_first |
| test_match.py:172:13:172:13 | IntegerLiteral | Node annotated with t.never is reachable in $@ | test_match.py:164:1:164:45 | Function test_match_exhaustive_return_wildcard | test_match_exhaustive_return_wildcard |

View File

@@ -12,7 +12,7 @@ private module Utils = EvalOrderCfgUtils<OldCfg>;
private import Utils::CfgTests
from NeverTimerAnnotation ann
from TimerAnnotation ann
where neverReachable(ann)
select ann, "Node annotated with t.never is reachable in $@", ann.getTestFunction(),
ann.getTestFunction().getName()

View File

@@ -0,0 +1,282 @@
| test_assert_raise.py:51:20:51:53 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_assert_raise.py:48:1:48:25 | Function test_bare_reraise | test_bare_reraise |
| test_assert_raise.py:51:20:51:53 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_assert_raise.py:48:1:48:25 | Function test_bare_reraise | test_bare_reraise |
| test_assert_raise.py:51:20:51:53 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_assert_raise.py:48:1:48:25 | Function test_bare_reraise | test_bare_reraise |
| test_assert_raise.py:51:20:51:53 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_assert_raise.py:48:1:48:25 | Function test_bare_reraise | test_bare_reraise |
| test_loops.py:10:12:10:52 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop |
| test_loops.py:10:12:10:52 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop |
| test_loops.py:10:12:10:52 | After Compare | Timestamp 10 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop |
| test_loops.py:10:12:10:52 | After Compare | Timestamp 10 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop |
| test_loops.py:10:12:10:52 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop |
| test_loops.py:10:12:10:52 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop |
| test_loops.py:10:12:10:52 | After Compare | Timestamp 22 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop |
| test_loops.py:10:12:10:52 | After Compare | Timestamp 22 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop |
| test_loops.py:19:12:19:46 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break |
| test_loops.py:19:12:19:46 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break |
| test_loops.py:19:12:19:46 | After Compare | Timestamp 13 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break |
| test_loops.py:19:12:19:46 | After Compare | Timestamp 13 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break |
| test_loops.py:19:12:19:46 | After Compare | Timestamp 22 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break |
| test_loops.py:19:12:19:46 | After Compare | Timestamp 22 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break |
| test_loops.py:19:12:19:46 | After Compare | Timestamp 25 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break |
| test_loops.py:19:12:19:46 | After Compare | Timestamp 25 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break |
| test_loops.py:20:13:20:48 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break |
| test_loops.py:20:13:20:48 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break |
| test_loops.py:20:13:20:48 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break |
| test_loops.py:20:13:20:48 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break |
| test_loops.py:20:13:20:48 | After Compare | Timestamp 25 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break |
| test_loops.py:20:13:20:48 | After Compare | Timestamp 25 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break |
| test_loops.py:31:12:31:54 | After Compare | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:31:12:31:54 | After Compare | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:31:12:31:54 | After Compare | Timestamp 17 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:31:12:31:54 | After Compare | Timestamp 17 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:31:12:31:54 | After Compare | Timestamp 26 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:31:12:31:54 | After Compare | Timestamp 26 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:31:12:31:54 | After Compare | Timestamp 38 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:31:12:31:54 | After Compare | Timestamp 38 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:33:13:33:48 | After Compare | Timestamp 2 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:33:13:33:48 | After Compare | Timestamp 2 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:33:13:33:48 | After Compare | Timestamp 11 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:33:13:33:48 | After Compare | Timestamp 11 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:33:13:33:48 | After Compare | Timestamp 14 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:33:13:33:48 | After Compare | Timestamp 14 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:33:13:33:48 | After Compare | Timestamp 23 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:33:13:33:48 | After Compare | Timestamp 23 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:33:13:33:48 | After Compare | Timestamp 32 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:33:13:33:48 | After Compare | Timestamp 32 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:33:13:33:48 | After Compare | Timestamp 35 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:33:13:33:48 | After Compare | Timestamp 35 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue |
| test_loops.py:43:12:43:44 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:41:1:41:23 | Function test_while_else | test_while_else |
| test_loops.py:43:12:43:44 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:41:1:41:23 | Function test_while_else | test_while_else |
| test_loops.py:43:12:43:44 | After Compare | Timestamp 10 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:41:1:41:23 | Function test_while_else | test_while_else |
| test_loops.py:43:12:43:44 | After Compare | Timestamp 10 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:41:1:41:23 | Function test_while_else | test_while_else |
| test_loops.py:43:12:43:44 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:41:1:41:23 | Function test_while_else | test_while_else |
| test_loops.py:43:12:43:44 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:41:1:41:23 | Function test_while_else | test_while_else |
| test_loops.py:53:12:53:38 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break |
| test_loops.py:53:12:53:38 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break |
| test_loops.py:53:12:53:38 | After Compare | Timestamp 13 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break |
| test_loops.py:53:12:53:38 | After Compare | Timestamp 13 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break |
| test_loops.py:53:12:53:38 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break |
| test_loops.py:53:12:53:38 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break |
| test_loops.py:54:13:54:40 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break |
| test_loops.py:54:13:54:40 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break |
| test_loops.py:54:13:54:40 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break |
| test_loops.py:54:13:54:40 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break |
| test_loops.py:65:14:65:43 | After List | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:65:14:65:43 | After List | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:65:14:65:43 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:65:14:65:43 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:65:14:65:43 | After List | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:65:14:65:43 | After List | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:65:14:65:43 | After List | Timestamp 7 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:65:14:65:43 | After List | Timestamp 7 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:66:9:66:9 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:66:9:66:9 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:66:9:66:9 | x | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:66:9:66:9 | x | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:66:9:66:9 | x | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:66:9:66:9 | x | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:66:9:66:9 | x | Timestamp 7 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:66:9:66:9 | x | Timestamp 7 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list |
| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:74:9:74:9 | i | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:74:9:74:9 | i | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:74:9:74:9 | i | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:74:9:74:9 | i | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:74:9:74:9 | i | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:74:9:74:9 | i | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:74:9:74:9 | i | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:74:9:74:9 | i | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range |
| test_loops.py:81:14:81:53 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:81:14:81:53 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:81:14:81:53 | After List | Timestamp 9 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:81:14:81:53 | After List | Timestamp 9 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:81:14:81:53 | After List | Timestamp 13 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:81:14:81:53 | After List | Timestamp 13 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:81:14:81:53 | After List | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:81:14:81:53 | After List | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:82:13:82:47 | After Compare | Timestamp 8 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:82:13:82:47 | After Compare | Timestamp 8 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:82:13:82:47 | After Compare | Timestamp 12 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:82:13:82:47 | After Compare | Timestamp 12 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:82:13:82:47 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:82:13:82:47 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:84:9:84:9 | x | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:84:9:84:9 | x | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:84:9:84:9 | x | Timestamp 9 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:84:9:84:9 | x | Timestamp 9 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:84:9:84:9 | x | Timestamp 13 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:84:9:84:9 | x | Timestamp 13 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:84:9:84:9 | x | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:84:9:84:9 | x | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break |
| test_loops.py:92:14:92:43 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:92:14:92:43 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:92:14:92:43 | After List | Timestamp 11 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:92:14:92:43 | After List | Timestamp 11 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:92:14:92:43 | After List | Timestamp 14 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:92:14:92:43 | After List | Timestamp 14 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:92:14:92:43 | After List | Timestamp 20 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:92:14:92:43 | After List | Timestamp 20 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:93:13:93:48 | After Compare | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:93:13:93:48 | After Compare | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:93:13:93:48 | After Compare | Timestamp 8 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:93:13:93:48 | After Compare | Timestamp 8 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:93:13:93:48 | After Compare | Timestamp 11 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:93:13:93:48 | After Compare | Timestamp 11 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:93:13:93:48 | After Compare | Timestamp 14 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:93:13:93:48 | After Compare | Timestamp 14 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:93:13:93:48 | After Compare | Timestamp 17 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:93:13:93:48 | After Compare | Timestamp 17 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:93:13:93:48 | After Compare | Timestamp 20 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:93:13:93:48 | After Compare | Timestamp 20 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 11 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 11 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 14 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 14 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 20 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 20 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue |
| test_loops.py:102:14:102:33 | After List | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else |
| test_loops.py:102:14:102:33 | After List | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else |
| test_loops.py:102:14:102:33 | After List | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else |
| test_loops.py:102:14:102:33 | After List | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else |
| test_loops.py:102:14:102:33 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else |
| test_loops.py:102:14:102:33 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else |
| test_loops.py:103:9:103:9 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else |
| test_loops.py:103:9:103:9 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else |
| test_loops.py:103:9:103:9 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else |
| test_loops.py:103:9:103:9 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else |
| test_loops.py:103:9:103:9 | x | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else |
| test_loops.py:103:9:103:9 | x | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else |
| test_loops.py:111:14:111:43 | After List | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:111:14:111:43 | After List | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:111:14:111:43 | After List | Timestamp 8 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:111:14:111:43 | After List | Timestamp 8 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:111:14:111:43 | After List | Timestamp 11 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:111:14:111:43 | After List | Timestamp 11 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:112:13:112:38 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:112:13:112:38 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:112:13:112:38 | After Compare | Timestamp 11 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:112:13:112:38 | After Compare | Timestamp 11 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:114:9:114:9 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:114:9:114:9 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:114:9:114:9 | x | Timestamp 8 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:114:9:114:9 | x | Timestamp 8 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:114:9:114:9 | x | Timestamp 11 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:114:9:114:9 | x | Timestamp 11 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break |
| test_loops.py:123:14:123:33 | After List | Timestamp 21 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:123:14:123:33 | After List | Timestamp 21 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:124:18:124:47 | After List | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:124:18:124:47 | After List | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:124:18:124:47 | After List | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:124:18:124:47 | After List | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:124:18:124:47 | After List | Timestamp 9 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:124:18:124:47 | After List | Timestamp 9 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:124:18:124:47 | After List | Timestamp 12 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:124:18:124:47 | After List | Timestamp 12 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:124:18:124:47 | After List | Timestamp 15 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:124:18:124:47 | After List | Timestamp 15 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:124:18:124:47 | After List | Timestamp 18 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:124:18:124:47 | After List | Timestamp 18 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:124:18:124:47 | After List | Timestamp 21 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:124:18:124:47 | After List | Timestamp 21 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 9 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 9 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 12 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 12 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 15 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 15 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 18 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 18 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 21 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 21 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops |
| test_loops.py:133:11:133:14 | True | Timestamp 2 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:133:11:133:14 | True | Timestamp 2 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:133:11:133:14 | True | Timestamp 9 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:133:11:133:14 | True | Timestamp 9 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:133:11:133:14 | True | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:133:11:133:14 | True | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:133:11:133:14 | True | Timestamp 22 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:133:11:133:14 | True | Timestamp 22 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:135:13:135:48 | After Compare | Timestamp 1 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:135:13:135:48 | After Compare | Timestamp 1 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:135:13:135:48 | After Compare | Timestamp 8 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:135:13:135:48 | After Compare | Timestamp 8 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:135:13:135:48 | After Compare | Timestamp 15 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:135:13:135:48 | After Compare | Timestamp 15 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:135:13:135:48 | After Compare | Timestamp 22 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:135:13:135:48 | After Compare | Timestamp 22 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break |
| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 8 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 8 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 10 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 10 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 12 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 12 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:145:9:145:11 | val | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:145:9:145:11 | val | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:145:9:145:11 | val | Timestamp 8 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:145:9:145:11 | val | Timestamp 8 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:145:9:145:11 | val | Timestamp 10 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:145:9:145:11 | val | Timestamp 10 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:145:9:145:11 | val | Timestamp 12 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_loops.py:145:9:145:11 | val | Timestamp 12 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate |
| test_match.py:16:11:16:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:14:1:14:26 | Function test_match_literal | test_match_literal |
| test_match.py:16:11:16:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:14:1:14:26 | Function test_match_literal | test_match_literal |
| test_match.py:16:11:16:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:14:1:14:26 | Function test_match_literal | test_match_literal |
| test_match.py:16:11:16:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:14:1:14:26 | Function test_match_literal | test_match_literal |
| test_match.py:27:11:27:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:25:1:25:38 | Function test_match_literal_fallthrough | test_match_literal_fallthrough |
| test_match.py:27:11:27:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:25:1:25:38 | Function test_match_literal_fallthrough | test_match_literal_fallthrough |
| test_match.py:27:11:27:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:25:1:25:38 | Function test_match_literal_fallthrough | test_match_literal_fallthrough |
| test_match.py:27:11:27:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:25:1:25:38 | Function test_match_literal_fallthrough | test_match_literal_fallthrough |
| test_match.py:51:11:51:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:49:1:49:26 | Function test_match_capture | test_match_capture |
| test_match.py:51:11:51:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:49:1:49:26 | Function test_match_capture | test_match_capture |
| test_match.py:51:11:51:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:49:1:49:26 | Function test_match_capture | test_match_capture |
| test_match.py:51:11:51:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:49:1:49:26 | Function test_match_capture | test_match_capture |
| test_match.py:71:11:71:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:69:1:69:24 | Function test_match_guard | test_match_guard |
| test_match.py:71:11:71:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:69:1:69:24 | Function test_match_guard | test_match_guard |
| test_match.py:82:11:82:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:80:1:80:32 | Function test_match_class_pattern | test_match_class_pattern |
| test_match.py:82:11:82:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:80:1:80:32 | Function test_match_class_pattern | test_match_class_pattern |
| test_match.py:82:11:82:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:80:1:80:32 | Function test_match_class_pattern | test_match_class_pattern |
| test_match.py:82:11:82:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:80:1:80:32 | Function test_match_class_pattern | test_match_class_pattern |
| test_match.py:93:11:93:11 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:91:1:91:27 | Function test_match_sequence | test_match_sequence |
| test_match.py:93:11:93:11 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:91:1:91:27 | Function test_match_sequence | test_match_sequence |
| test_try.py:95:16:95:36 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:92:1:92:41 | Function test_try_except_finally_exception | test_try_except_finally_exception |
| test_try.py:95:16:95:36 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:92:1:92:41 | Function test_try_except_finally_exception | test_try_except_finally_exception |
| test_try.py:95:16:95:36 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:92:1:92:41 | Function test_try_except_finally_exception | test_try_except_finally_exception |
| test_try.py:95:16:95:36 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:92:1:92:41 | Function test_try_except_finally_exception | test_try_except_finally_exception |
| test_try.py:147:20:147:40 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:142:1:142:30 | Function test_nested_try_except | test_nested_try_except |
| test_try.py:147:20:147:40 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:142:1:142:30 | Function test_nested_try_except | test_nested_try_except |
| test_try.py:162:17:162:52 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:158:1:158:24 | Function test_try_in_loop | test_try_in_loop |
| test_try.py:162:17:162:52 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:158:1:158:24 | Function test_try_in_loop | test_try_in_loop |
| test_try.py:162:17:162:52 | After Compare | Timestamp 14 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:158:1:158:24 | Function test_try_in_loop | test_try_in_loop |
| test_try.py:162:17:162:52 | After Compare | Timestamp 14 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:158:1:158:24 | Function test_try_in_loop | test_try_in_loop |
| test_try.py:162:17:162:52 | After Compare | Timestamp 23 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:158:1:158:24 | Function test_try_in_loop | test_try_in_loop |
| test_try.py:162:17:162:52 | After Compare | Timestamp 23 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:158:1:158:24 | Function test_try_in_loop | test_try_in_loop |
| test_try.py:176:20:176:40 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:172:1:172:20 | Function test_reraise | test_reraise |
| test_try.py:176:20:176:40 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:172:1:172:20 | Function test_reraise | test_reraise |
| test_try.py:176:20:176:40 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:172:1:172:20 | Function test_reraise | test_reraise |
| test_try.py:176:20:176:40 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:172:1:172:20 | Function test_reraise | test_reraise |
| test_with.py:55:14:55:33 | After List | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop |
| test_with.py:55:14:55:33 | After List | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop |
| test_with.py:55:14:55:33 | After List | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop |
| test_with.py:55:14:55:33 | After List | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop |
| test_with.py:55:14:55:33 | After List | Timestamp 9 on true/false branch is missing a dead() annotation on the false successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop |
| test_with.py:55:14:55:33 | After List | Timestamp 9 on true/false branch is missing a dead() annotation on the true successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop |
| test_with.py:57:17:57:17 | i | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop |
| test_with.py:57:17:57:17 | i | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop |
| test_with.py:57:17:57:17 | i | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop |
| test_with.py:57:17:57:17 | i | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop |
| test_with.py:57:17:57:17 | i | Timestamp 9 on true/false branch is missing a dead() annotation on the false successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop |
| test_with.py:57:17:57:17 | i | Timestamp 9 on true/false branch is missing a dead() annotation on the true successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop |

View File

@@ -0,0 +1,23 @@
/**
* New-CFG version of BranchTimestamps.
*
* Checks that when a node has both a true and false successor, the
* live timestamps on one branch are marked as dead on the other.
* This ensures that boolean branches are fully annotated with dead()
* markers for the paths not taken.
*/
import python
import TimerUtils
import NewCfgImpl
private module Utils = EvalOrderCfgUtils<NewCfg>;
private import Utils
private import Utils::CfgTests
from TimerCfgNode node, int ts, string branch
where missingBranchTimestamp(node, ts, branch)
select node,
"Timestamp " + ts + " on true/false branch is missing a dead() annotation on the " + branch +
" successor in $@", node.getTestFunction(), node.getTestFunction().getName()

View File

@@ -0,0 +1,22 @@
/**
* New-CFG version of ConsecutivePredecessorTimestamps.
*
* Checks that each annotated node (except the minimum timestamp) has
* a predecessor annotation with timestamp `a - 1`. This is the reverse
* of ConsecutiveTimestamps: it catches nodes that are reachable but
* arrived at from the wrong place (skipping an intermediate node).
*/
import python
import TimerUtils
import NewCfgImpl
private module Utils = EvalOrderCfgUtils<NewCfg>;
private import Utils
private import Utils::CfgTests
from TimerAnnotation ann, int a
where consecutivePredecessorTimestamps(ann, a)
select ann, "$@ in $@ has no consecutive predecessor (expected " + (a - 1) + ")",
ann.getTimestampExpr(a), "Timestamp " + a, ann.getTestFunction(), ann.getTestFunction().getName()

View File

@@ -1 +0,0 @@
| test_if.py:51:9:51:9 | IntegerLiteral | $@ 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 |

View File

@@ -6,6 +6,7 @@
private import python as Py
import TimerUtils
private import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl
private import codeql.controlflow.SuccessorType
private class NewControlFlowNode = CfgImpl::ControlFlowNode;
@@ -31,6 +32,20 @@ module NewCfg implements EvalOrderCfgSig {
CfgNode getASuccessor() { nextCfgNode(this, result) }
CfgNode getATrueSuccessor() {
NewControlFlowNode.super.isAfterTrue(_) and
// Only where there's also a false branch (true boolean split)
exists(NewControlFlowNode other | other.isAfterFalse(NewControlFlowNode.super.getAstNode())) and
nextCfgNodeFrom(this, result)
}
CfgNode getAFalseSuccessor() {
NewControlFlowNode.super.isAfterFalse(_) and
// Only where there's also a true branch (true boolean split)
exists(NewControlFlowNode other | other.isAfterTrue(NewControlFlowNode.super.getAstNode())) and
nextCfgNodeFrom(this, result)
}
CfgNode getAnExceptionalSuccessor() {
exists(NewControlFlowNode mid |
mid = NewControlFlowNode.super.getAnExceptionSuccessor() and

View File

@@ -15,7 +15,7 @@ private module Utils = EvalOrderCfgUtils<NewCfg>;
private import Utils::CfgTests
from NeverTimerAnnotation ann
from TimerAnnotation ann
where neverReachable(ann)
select ann, "Node annotated with t.never is reachable in $@", ann.getTestFunction(),
ann.getTestFunction().getName()

View File

@@ -0,0 +1,10 @@
| test_boolean.py:9:10:9:43 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:9:59:9:59 | IntegerLiteral | 2 | test_boolean.py:9:10:9:13 | ControlFlowNode for True | True | test_boolean.py:9:19:9:19 | IntegerLiteral | 0 |
| test_boolean.py:15:10:15:43 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:15:50:15:50 | IntegerLiteral | 1 | test_boolean.py:15:10:15:14 | ControlFlowNode for False | False | test_boolean.py:15:20:15:20 | IntegerLiteral | 0 |
| test_boolean.py:21:10:21:42 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:21:49:21:49 | IntegerLiteral | 1 | test_boolean.py:21:10:21:13 | ControlFlowNode for True | True | test_boolean.py:21:19:21:19 | IntegerLiteral | 0 |
| test_boolean.py:27:10:27:43 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:27:59:27:59 | IntegerLiteral | 2 | test_boolean.py:27:10:27:14 | ControlFlowNode for False | False | test_boolean.py:27:20:27:20 | IntegerLiteral | 0 |
| test_boolean.py:40:10:40:61 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:40:86:40:86 | IntegerLiteral | 3 | test_boolean.py:40:10:40:10 | ControlFlowNode for IntegerLiteral | IntegerLiteral | test_boolean.py:40:16:40:16 | IntegerLiteral | 0 |
| test_boolean.py:46:10:46:61 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:46:86:46:86 | IntegerLiteral | 3 | test_boolean.py:46:10:46:10 | ControlFlowNode for IntegerLiteral | IntegerLiteral | test_boolean.py:46:16:46:16 | IntegerLiteral | 0 |
| test_boolean.py:52:10:52:95 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:52:120:52:120 | IntegerLiteral | 4 | test_boolean.py:52:11:52:47 | ControlFlowNode for BoolExpr | BoolExpr | test_boolean.py:52:63:52:63 | IntegerLiteral | 2 |
| test_boolean.py:52:11:52:47 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:52:63:52:63 | IntegerLiteral | 2 | test_boolean.py:52:11:52:14 | ControlFlowNode for True | True | test_boolean.py:52:20:52:20 | IntegerLiteral | 0 |
| test_boolean.py:64:10:64:52 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:64:59:64:59 | IntegerLiteral | 6 | test_boolean.py:64:11:64:11 | ControlFlowNode for f | f | test_boolean.py:64:17:64:17 | IntegerLiteral | 0 |
| test_boolean.py:76:10:76:51 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:76:58:76:58 | IntegerLiteral | 6 | test_boolean.py:76:11:76:11 | ControlFlowNode for f | f | test_boolean.py:76:17:76:17 | IntegerLiteral | 0 |

View File

@@ -0,0 +1,10 @@
| test_boolean.py:9:10:9:43 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:9:59:9:59 | IntegerLiteral | timestamp 2 | test_boolean.py:9:19:9:19 | IntegerLiteral | timestamp 0 |
| test_boolean.py:15:10:15:43 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:15:50:15:50 | IntegerLiteral | timestamp 1 | test_boolean.py:15:20:15:20 | IntegerLiteral | timestamp 0 |
| test_boolean.py:21:10:21:42 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:21:49:21:49 | IntegerLiteral | timestamp 1 | test_boolean.py:21:19:21:19 | IntegerLiteral | timestamp 0 |
| test_boolean.py:27:10:27:43 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:27:59:27:59 | IntegerLiteral | timestamp 2 | test_boolean.py:27:20:27:20 | IntegerLiteral | timestamp 0 |
| test_boolean.py:40:10:40:61 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:40:86:40:86 | IntegerLiteral | timestamp 3 | test_boolean.py:40:16:40:16 | IntegerLiteral | timestamp 0 |
| test_boolean.py:46:10:46:61 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:46:86:46:86 | IntegerLiteral | timestamp 3 | test_boolean.py:46:16:46:16 | IntegerLiteral | timestamp 0 |
| test_boolean.py:52:10:52:95 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:52:120:52:120 | IntegerLiteral | timestamp 4 | test_boolean.py:52:63:52:63 | IntegerLiteral | timestamp 2 |
| test_boolean.py:52:11:52:47 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:52:63:52:63 | IntegerLiteral | timestamp 2 | test_boolean.py:52:20:52:20 | IntegerLiteral | timestamp 0 |
| test_boolean.py:64:10:64:52 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:64:59:64:59 | IntegerLiteral | timestamp 6 | test_boolean.py:64:17:64:17 | IntegerLiteral | timestamp 0 |
| test_boolean.py:76:10:76:51 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:76:58:76:58 | IntegerLiteral | timestamp 6 | test_boolean.py:76:17:76:17 | IntegerLiteral | timestamp 0 |

View File

@@ -29,9 +29,40 @@ private IntegerLiteral timestampLiteral(Expr timestamps) {
result = timestamps.(Tuple).getAnElt()
}
/**
* Gets an element from a timestamp subscript index. Each element is either
* an `IntegerLiteral` (live), a `Call` to `dead` (dead), a `Name("never")`
* (never), or a tuple containing any mix of these.
*/
private Expr timestampElement(Expr timestamps) {
result = timestamps and not timestamps instanceof Tuple
or
result = timestamps.(Tuple).getAnElt()
}
/** Gets a live timestamp value from a subscript index expression. */
private IntegerLiteral liveTimestampLiteral(Expr timestamps) {
result = timestampElement(timestamps) and
not result = any(Call c).getAnArg()
}
/** Gets a dead timestamp value from a subscript index expression. */
private IntegerLiteral deadTimestampLiteral(Expr timestamps) {
exists(Call c |
c = timestampElement(timestamps) and
c.getFunc().(Name).getId() = "dead" and
result = c.getArg(0)
)
}
/** Holds if the subscript index contains `never`. */
private predicate hasNever(Expr timestamps) {
timestampElement(timestamps).(Name).getId() = "never"
}
/** A timer annotation in the AST. */
private newtype TTimerAnnotation =
/** `expr @ t[n]` or `expr @ t[n, m, ...]` */
/** `expr @ t[n]` or `expr @ t[n, m, ...]` or `expr @ t[dead(n), m, never]` */
TMatmulAnnotation(TestFunction func, Expr annotated, Expr timestamps) {
exists(BinaryExpr be |
be.getOp() instanceof MatMult and
@@ -49,40 +80,29 @@ private newtype TTimerAnnotation =
annotated = call.getArg(0) and
timestamps = call.getArg(1)
)
} or
/** `expr @ t.dead[n]` — dead-code annotation */
TDeadAnnotation(TestFunction func, Expr annotated, Expr timestamps) {
exists(BinaryExpr be |
be.getOp() instanceof MatMult and
be.getRight().(Subscript).getObject().(Attribute).getObject("dead").(Name).getId() =
func.getTimerParamName() and
be.getScope().getEnclosingScope*() = func and
annotated = be.getLeft() and
timestamps = be.getRight().(Subscript).getIndex()
)
} or
/** `expr @ t.never` — annotation for code that should never be evaluated */
TNeverAnnotation(TestFunction func, Expr annotated) {
exists(BinaryExpr be |
be.getOp() instanceof MatMult and
be.getRight().(Attribute).getObject("never").(Name).getId() = func.getTimerParamName() and
be.getScope().getEnclosingScope*() = func and
annotated = be.getLeft()
)
}
/** A timer annotation (wrapping the newtype for a clean API). */
class TimerAnnotation extends TTimerAnnotation {
/** Gets a timestamp value from this annotation. */
/** Gets a live timestamp value from this annotation. */
int getATimestamp() { exists(this.getTimestampExpr(result)) }
/** Gets the source expression for timestamp value `ts`. */
/** Gets the source expression for live timestamp value `ts`. */
IntegerLiteral getTimestampExpr(int ts) {
result = timestampLiteral(this.getTimestampsExpr()) and
result = liveTimestampLiteral(this.getTimestampsExpr()) and
result.getValue() = ts
}
/** Gets the raw timestamp expression (single int or tuple). */
/** Gets a dead timestamp value from this annotation. */
int getADeadTimestamp() { exists(this.getDeadTimestampExpr(result)) }
/** Gets the source expression for dead timestamp value `ts`. */
IntegerLiteral getDeadTimestampExpr(int ts) {
result = deadTimestampLiteral(this.getTimestampsExpr()) and
result.getValue() = ts
}
/** Gets the raw timestamp expression (single element or tuple). */
abstract Expr getTimestampsExpr();
/** Gets the test function this annotation belongs to. */
@@ -94,18 +114,25 @@ class TimerAnnotation extends TTimerAnnotation {
/** Gets the enclosing annotation expression (the `BinaryExpr` or `Call`). */
abstract Expr getTimerExpr();
/** Holds if this is a dead-code annotation (`t.dead[n]`). */
predicate isDead() { this instanceof DeadTimerAnnotation }
/** Holds if timestamp `ts` is marked as dead in this annotation. */
predicate isDeadTimestamp(int ts) { ts = this.getADeadTimestamp() }
/** Holds if this is a never-evaluated annotation (`t.never`). */
predicate isNever() { this instanceof NeverTimerAnnotation }
/** Holds if all timestamps in this annotation are dead (no live timestamps). */
predicate isDead() {
not exists(this.getATimestamp()) and
not this.isNever() and
exists(this.getADeadTimestamp())
}
/** Holds if this is a never-evaluated annotation (contains `never`). */
predicate isNever() { hasNever(this.getTimestampsExpr()) }
string toString() { result = this.getAnnotatedExpr().toString() }
Location getLocation() { result = this.getAnnotatedExpr().getLocation() }
}
/** A matmul-based timer annotation: `expr @ t[n]`. */
/** A matmul-based timer annotation: `expr @ t[...]`. */
class MatmulTimerAnnotation extends TMatmulAnnotation, TimerAnnotation {
TestFunction func;
Expr annotated;
@@ -139,39 +166,6 @@ class CallTimerAnnotation extends TCallAnnotation, TimerAnnotation {
override Call getTimerExpr() { result.getArg(0) = annotated }
}
/** A dead-code timer annotation: `expr @ t.dead[n]`. */
class DeadTimerAnnotation extends TDeadAnnotation, TimerAnnotation {
TestFunction func;
Expr annotated;
Expr timestamps;
DeadTimerAnnotation() { this = TDeadAnnotation(func, annotated, timestamps) }
override Expr getTimestampsExpr() { result = timestamps }
override TestFunction getTestFunction() { result = func }
override Expr getAnnotatedExpr() { result = annotated }
override BinaryExpr getTimerExpr() { result.getLeft() = annotated }
}
/** A never-evaluated annotation: `expr @ t.never`. */
class NeverTimerAnnotation extends TNeverAnnotation, TimerAnnotation {
TestFunction func;
Expr annotated;
NeverTimerAnnotation() { this = TNeverAnnotation(func, annotated) }
override Expr getTimestampsExpr() { none() }
override TestFunction getTestFunction() { result = func }
override Expr getAnnotatedExpr() { result = annotated }
override BinaryExpr getTimerExpr() { result.getLeft() = annotated }
}
/**
* Signature module defining the CFG interface needed by evaluation-order tests.
* This allows the test utilities to be instantiated with different CFG implementations.
@@ -191,6 +185,12 @@ signature module EvalOrderCfgSig {
/** Gets a successor of this CFG node (including exceptional). */
CfgNode getASuccessor();
/** Gets a true-branch successor of this CFG node, if any. */
CfgNode getATrueSuccessor();
/** Gets a false-branch successor of this CFG node, if any. */
CfgNode getAFalseSuccessor();
/** Gets an exceptional successor of this CFG node. */
CfgNode getAnExceptionalSuccessor();
@@ -251,7 +251,10 @@ module EvalOrderCfgUtils<EvalOrderCfgSig Input> {
/** Gets the test function this annotation belongs to. */
TestFunction getTestFunction() { result = annot.getTestFunction() }
/** Holds if this is a dead-code annotation. */
/** Holds if timestamp `ts` is marked as dead. */
predicate isDeadTimestamp(int ts) { annot.isDeadTimestamp(ts) }
/** Holds if all timestamps in this annotation are dead. */
predicate isDead() { annot.isDead() }
/** Holds if this is a never-evaluated annotation. */
@@ -275,6 +278,42 @@ module EvalOrderCfgUtils<EvalOrderCfgSig Input> {
)
}
/**
* Holds if `next` is the next timer annotation reachable from `n` via
* the true branch, skipping non-annotated intermediaries and after-value
* nodes for the same AST node.
*/
predicate nextTimerAnnotationFromTrue(CfgNode n, TimerCfgNode next) {
exists(CfgNode trueSucc |
trueSucc = n.getATrueSuccessor() and
trueSucc.getScope() = n.getScope()
|
// If the true successor is a different annotated node, use it
next = trueSucc and next.getNode() != n.getNode()
or
// Otherwise skip through it (it's an after-value node for the same expr)
nextTimerAnnotation(trueSucc, next)
)
}
/**
* Holds if `next` is the next timer annotation reachable from `n` via
* the false branch, skipping non-annotated intermediaries and after-value
* nodes for the same AST node.
*/
predicate nextTimerAnnotationFromFalse(CfgNode n, TimerCfgNode next) {
exists(CfgNode falseSucc |
falseSucc = n.getAFalseSuccessor() and
falseSucc.getScope() = n.getScope()
|
// If the false successor is a different annotated node, use it
next = falseSucc and next.getNode() != n.getNode()
or
// Otherwise skip through it (it's an after-value node for the same expr)
nextTimerAnnotation(falseSucc, next)
)
}
/** CFG-dependent test predicates, one per evaluation-order query. */
module CfgTests {
/**
@@ -352,7 +391,8 @@ module EvalOrderCfgUtils<EvalOrderCfgSig Input> {
* Holds if the expression annotated with `t.never` is reachable from
* its scope's entry.
*/
predicate neverReachable(NeverTimerAnnotation ann) {
predicate neverReachable(TimerAnnotation ann) {
ann.isNever() and
exists(CfgNode n, Scope s |
n.getNode() = ann.getAnnotatedExpr() and
s = n.getScope() and
@@ -438,6 +478,61 @@ module EvalOrderCfgUtils<EvalOrderCfgSig Input> {
predicate annotationWithCfgNode(TimerAnnotation ann) {
exists(CfgNode n | n.getNode() = ann.getAnnotatedExpr())
}
/**
* Holds if annotation `ann` with timestamp `a` has no consecutive
* predecessor (expected `a - 1`) in the CFG.
*/
predicate consecutivePredecessorTimestamps(TimerAnnotation ann, int a) {
not hasNestedScopeAnnotation(ann.getTestFunction()) and
not ann.isDead() and
a = ann.getATimestamp() and
not exists(TimerCfgNode x, TimerCfgNode y |
ann.getAnnotatedExpr() = y.getNode() and
nextTimerAnnotation(x, y) and
(a - 1) = x.getATimestamp()
) and
// Exclude the minimum timestamp in the function (it has no predecessor)
not a =
min(TimerAnnotation other |
other.getTestFunction() = ann.getTestFunction() and
not other.isDead()
|
other.getATimestamp()
)
}
/**
* Holds if `node` has both a true and false successor, but the true
* successor's timestamp `ts` is not marked as dead on the false
* successor (or vice versa).
*
* This checks that boolean branches are properly annotated: when a
* condition splits into true/false paths, the next annotated node
* on each side should account for the other side's timestamps as dead.
*/
predicate missingBranchTimestamp(TimerCfgNode node, int ts, string branch) {
not hasNestedScopeAnnotation(node.getTestFunction()) and
exists(TimerCfgNode trueNext, TimerCfgNode falseNext |
nextTimerAnnotationFromTrue(node, trueNext) and
nextTimerAnnotationFromFalse(node, falseNext) and
trueNext != falseNext
|
// True successor has live timestamp ts, but false successor
// doesn't have it as dead
ts = trueNext.getATimestamp() and
not falseNext.isDeadTimestamp(ts) and
not ts = falseNext.getATimestamp() and
branch = "false"
or
// False successor has live timestamp ts, but true successor
// doesn't have it as dead
ts = falseNext.getATimestamp() and
not trueNext.isDeadTimestamp(ts) and
not ts = trueNext.getATimestamp() and
branch = "true"
)
}
}
}

View File

@@ -1,6 +1,6 @@
"""Assert and raise statement evaluation order."""
from timer import test
from timer import test, dead
@test
@@ -13,7 +13,7 @@ def test_assert_true(t):
@test
def test_assert_true_with_message(t):
x = True @ t[0]
assert x @ t[1], "msg" @ t.dead[2]
assert x @ t[1], "msg" @ t[dead(2)]
y = 1 @ t[2]

View File

@@ -8,7 +8,7 @@ Every evaluated expression has a timestamp annotation, except the
timer mechanism itself (t[n], t.dead[n]).
"""
from timer import test
from timer import test, never
@test
@@ -178,7 +178,7 @@ def test_unreachable_after_return(t):
def f():
x = 1 @ t[1]
return x @ t[2]
y = 2 @ t.never
y = 2 @ t[never]
result = (f @ t[0])() @ t[3]

View File

@@ -1,30 +1,30 @@
"""Short-circuit boolean operators and evaluation order."""
from timer import test
from timer import test, dead
@test
def test_and_both_sides(t):
# True and X — both operands evaluated, result is X
x = (True @ t[0] and 42 @ t[1]) @ t[2]
x = (True @ t[0] and 42 @ t[1, dead(2)]) @ t[dead(1), 2]
@test
def test_and_short_circuit(t):
# False and ... — right side never evaluated
x = (False @ t[0] and True @ t.dead[1]) @ t[1]
x = (False @ t[0] and True @ t[dead(1)]) @ t[1, dead(2)]
@test
def test_or_short_circuit(t):
# True or ... — right side never evaluated
x = (True @ t[0] or False @ t.dead[1]) @ t[1]
x = (True @ t[0] or False @ t[dead(1)]) @ t[1, dead(2)]
@test
def test_or_both_sides(t):
# False or X — both operands evaluated, result is X
x = (False @ t[0] or 42 @ t[1]) @ t[2]
x = (False @ t[0] or 42 @ t[1, dead(2)]) @ t[dead(1), 2]
@test
@@ -37,19 +37,19 @@ def test_not(t):
@test
def test_chained_and(t):
# 1 and 2 and 3 — all truthy, all evaluated left-to-right
x = (1 @ t[0] and 2 @ t[1] and 3 @ t[2]) @ t[3]
x = (1 @ t[0] and 2 @ t[1, dead(3)] and 3 @ t[2, dead(3)]) @ t[dead(1), dead(2), 3]
@test
def test_chained_or(t):
# 0 or "" or 42 — first two falsy, all evaluated until truthy found
x = (0 @ t[0] or "" @ t[1] or 42 @ t[2]) @ t[3]
x = (0 @ t[0] or "" @ t[1, dead(3)] or 42 @ t[2, dead(3)]) @ t[dead(1), dead(2), 3]
@test
def test_mixed_and_or(t):
# True and False or 42 => (True and False) or 42 => False or 42 => 42
x = ((True @ t[0] and False @ t[1]) @ t[2] or 42 @ t[3]) @ t[4]
x = ((True @ t[0] and False @ t[1, dead(2)]) @ t[dead(1), 2, dead(4)] or 42 @ t[3, dead(4)]) @ t[dead(2), dead(3), 4]
@test

View File

@@ -1,38 +1,38 @@
"""Ternary conditional expressions and evaluation order."""
from timer import test
from timer import test, dead
@test
def test_ternary_true(t):
# Condition is True — consequent evaluated, alternative skipped
x = (1 @ t[1] if True @ t[0] else 2 @ t.dead[1]) @ t[2]
x = (1 @ t[1] if True @ t[0] else 2 @ t[dead(1)]) @ t[2]
@test
def test_ternary_false(t):
# Condition is False — alternative evaluated, consequent skipped
x = (1 @ t.dead[1] if False @ t[0] else 2 @ t[1]) @ t[2]
x = (1 @ t[dead(1)] if False @ t[0] else 2 @ t[1]) @ t[2]
@test
def test_ternary_nested(t):
# Nested: outer condition True, inner condition True
# ((10 if C1 else 20) if C2 else 30) — C2 first, then C1, then 10
x = ((10 @ t[2] if True @ t[1] else 20 @ t.dead[2]) @ t[3] if True @ t[0] else 30 @ t.dead[1]) @ t[4]
x = ((10 @ t[2] if True @ t[1] else 20 @ t[dead(2)]) @ t[3] if True @ t[0] else 30 @ t[dead(1)]) @ t[4]
@test
def test_ternary_assignment(t):
# Ternary result assigned, then used in later expression
value = (100 @ t[1] if True @ t[0] else 200 @ t.dead[1]) @ t[2]
value = (100 @ t[1] if True @ t[0] else 200 @ t[dead(1)]) @ t[2]
result = (value @ t[3] + 1 @ t[4]) @ t[5]
@test
def test_ternary_complex_expressions(t):
# Complex sub-expressions in condition and consequent
x = ((1 @ t[3] + 2 @ t[4]) @ t[5] if (3 @ t[0] > 2 @ t[1]) @ t[2] else (4 @ t.dead[3] + 5 @ t.dead[4]) @ t.dead[5]) @ t[6]
x = ((1 @ t[3] + 2 @ t[4]) @ t[5] if (3 @ t[0] > 2 @ t[1]) @ t[2] else (4 @ t[dead(3)] + 5 @ t[dead(4)]) @ t[dead(5)]) @ t[6]
@test
@@ -41,4 +41,4 @@ def test_ternary_as_argument(t):
def f(a):
return a @ t[4]
result = (f @ t[0])((1 @ t[2] if True @ t[1] else 2 @ t.dead[2]) @ t[3]) @ t[5]
result = (f @ t[0])((1 @ t[2] if True @ t[1] else 2 @ t[dead(2)]) @ t[3]) @ t[5]

View File

@@ -1,6 +1,6 @@
"""If/elif/else control flow evaluation order."""
from timer import test
from timer import test, dead
@test
@@ -15,7 +15,7 @@ def test_if_true(t):
def test_if_false(t):
x = False @ t[0]
if x @ t[1]:
y = 1 @ t.dead[2]
y = 1 @ t[dead(2)]
z = 0 @ t[2]
@@ -25,7 +25,7 @@ def test_if_else_true(t):
if x @ t[1]:
y = 1 @ t[2]
else:
y = 2 @ t.dead[2]
y = 2 @ t[dead(2)]
z = 0 @ t[3]
@@ -33,7 +33,7 @@ def test_if_else_true(t):
def test_if_else_false(t):
x = False @ t[0]
if x @ t[1]:
y = 1 @ t.dead[2]
y = 1 @ t[dead(2)]
else:
y = 2 @ t[2]
z = 0 @ t[3]
@@ -44,10 +44,10 @@ def test_if_elif_else_first(t):
x = 1 @ t[0]
if (x @ t[1] == 1 @ t[2]) @ t[3]:
y = "first" @ t[4]
elif (x @ t.dead[4] == 2 @ t.dead[5]) @ t.dead[6]:
y = "second" @ t.dead[4]
elif (x @ t[dead(4)] == 2 @ t[dead(5)]) @ t[dead(6)]:
y = "second" @ t[dead(4)]
else:
y = "third" @ t.dead[4]
y = "third" @ t[dead(4)]
z = 0 @ t[5]
@@ -55,11 +55,11 @@ def test_if_elif_else_first(t):
def test_if_elif_else_second(t):
x = 2 @ t[0]
if (x @ t[1] == 1 @ t[2]) @ t[3]:
y = "first" @ t.dead[7]
y = "first" @ t[dead(7)]
elif (x @ t[4] == 2 @ t[5]) @ t[6]:
y = "second" @ t[7]
else:
y = "third" @ t.dead[7]
y = "third" @ t[dead(7)]
z = 0 @ t[8]
@@ -67,9 +67,9 @@ def test_if_elif_else_second(t):
def test_if_elif_else_third(t):
x = 3 @ t[0]
if (x @ t[1] == 1 @ t[2]) @ t[3]:
y = "first" @ t.dead[7]
y = "first" @ t[dead(7)]
elif (x @ t[4] == 2 @ t[5]) @ t[6]:
y = "second" @ t.dead[7]
y = "second" @ t[dead(7)]
else:
y = "third" @ t[7]
z = 0 @ t[8]
@@ -83,9 +83,9 @@ def test_nested_if_else(t):
if y @ t[3]:
z = 1 @ t[4]
else:
z = 2 @ t.dead[4]
z = 2 @ t[dead(4)]
else:
z = 3 @ t.dead[4]
z = 3 @ t[dead(4)]
w = 0 @ t[5]
@@ -94,7 +94,7 @@ def test_if_compound_condition(t):
x = True @ t[0]
y = False @ t[1]
if (x @ t[2] and y @ t[3]) @ t[4]:
z = 1 @ t.dead[5]
z = 1 @ t[dead(5)]
else:
z = 2 @ t[5]
w = 0 @ t[6]
@@ -106,3 +106,9 @@ def test_if_pass(t):
if x @ t[1]:
pass
z = 0 @ t[2]
@test
@test

View File

@@ -1,6 +1,6 @@
"""Loop control flow evaluation order tests."""
from timer import test
from timer import test, dead
# 1. Simple while loop (fixed iterations)
@@ -55,7 +55,7 @@ def test_while_else_break(t):
break
i = (i @ t[7] + 1 @ t[8]) @ t[9]
else:
never = True @ t.dead[16]
never = True @ t[dead(16)]
after = True @ t[16]
@@ -113,7 +113,7 @@ def test_for_else_break(t):
break
x @ t[7]
else:
never = True @ t.dead[11]
never = True @ t[dead(11)]
after = True @ t[11]
@@ -122,8 +122,8 @@ def test_for_else_break(t):
def test_nested_loops(t):
for i in [1 @ t[0], 2 @ t[1]] @ t[2]:
for j in [10 @ t[3, 12], 20 @ t[4, 13]] @ t[5, 14]:
(i @ t[6, 9, 15, 18] + j @ t[7, 10, 16, 19]) @ t[8, 11, 17, 20]
done = True @ t[21]
(i @ t[6, 9, 15, 18, dead(21)] + j @ t[7, 10, 16, 19]) @ t[8, 11, 17, 20]
done = True @ t[dead(3), dead(6), dead(9), dead(12), dead(15), dead(18), 21]
# 13. While True with conditional break

View File

@@ -7,7 +7,7 @@ if sys.version_info < (3, 10):
print("0/0 tests passed")
sys.exit(0)
from timer import test
from timer import test, dead, never
@test
@@ -17,7 +17,7 @@ def test_match_literal(t):
case 1:
y = "one" @ t[2]
case 2:
y = "two" @ t.dead[2]
y = "two" @ t[dead(2)]
z = y @ t[3]
@@ -26,9 +26,9 @@ def test_match_literal_fallthrough(t):
x = 3 @ t[0]
match x @ t[1]:
case 1:
y = "one" @ t.dead[2]
y = "one" @ t[dead(2)]
case 2:
y = "two" @ t.dead[2]
y = "two" @ t[dead(2)]
case 3:
y = "three" @ t[2]
z = y @ t[3]
@@ -39,7 +39,7 @@ def test_match_wildcard(t):
x = 42 @ t[0]
match x @ t[1]:
case 1:
y = "one" @ t.dead[2]
y = "one" @ t[dead(2)]
case _:
y = "other" @ t[2]
z = y @ t[3]
@@ -61,7 +61,7 @@ def test_match_or_pattern(t):
case 1 | 2:
y = "low" @ t[2]
case _:
y = "other" @ t.dead[2]
y = "other" @ t[dead(2)]
z = y @ t[3]
@@ -72,7 +72,7 @@ def test_match_guard(t):
case n if (n @ t[2] > 3 @ t[3]) @ t[4]:
y = n @ t[5]
case _:
y = 0 @ t.dead[5]
y = 0 @ t[dead(5)]
z = y @ t[6]
@@ -83,7 +83,7 @@ def test_match_class_pattern(t):
case int():
y = "integer" @ t[2]
case str():
y = "string" @ t.dead[2]
y = "string" @ t[dead(2)]
z = y @ t[3]
@@ -94,7 +94,7 @@ def test_match_sequence(t):
case [a, b]:
y = (a @ t[4] + b @ t[5]) @ t[6]
case _:
y = 0 @ t.dead[6]
y = 0 @ t[dead(6)]
z = y @ t[7]
@@ -105,7 +105,7 @@ def test_match_mapping(t):
case {"key": value}:
y = value @ t[4]
case _:
y = 0 @ t.dead[4]
y = 0 @ t[dead(4)]
z = y @ t[5]
@@ -116,7 +116,7 @@ def test_match_nested(t):
case {"users": [{"name": name}]}:
y = name @ t[7]
case _:
y = "unknown" @ t.dead[7]
y = "unknown" @ t[dead(7)]
z = y @ t[8]
@@ -129,7 +129,7 @@ def test_match_or_pattern_with_as(t):
result = ((uses @ t[2]).partition @ t[3])("@" @ t[4]) @ t[5]
x = (result @ t[6])[0 @ t[7]] @ t[8]
case _:
raise ((ValueError @ t.dead[2])(clause @ t.dead[3]) @ t.dead[4])
raise ((ValueError @ t[dead(2)])(clause @ t[dead(3)]) @ t[dead(4)])
y = x @ t[9]
@@ -140,7 +140,7 @@ def test_match_wildcard_raise(t):
try:
match clause @ t[1]:
case (str() as uses) | {"uses": uses}:
result = uses @ t.dead[2]
result = uses @ t[dead(2)]
case _:
raise ((ValueError @ t[2])(f"Invalid: {clause @ t[3]}" @ t[4]) @ t[5])
except ValueError:
@@ -155,8 +155,8 @@ def test_match_exhaustive_return_first(t):
case 1:
return "one" @ t[3]
case _:
return "other" @ t.dead[3]
y = 0 @ t.never
return "other" @ t[dead(3)]
y = 0 @ t[never]
result = (f @ t[0])(1 @ t[1]) @ t[4]
@@ -166,8 +166,8 @@ def test_match_exhaustive_return_wildcard(t):
def f(x):
match x @ t[2]:
case 1:
return "one" @ t.dead[3]
return "one" @ t[dead(3)]
case _:
return "other" @ t[3]
y = 0 @ t.never
y = 0 @ t[never]
result = (f @ t[0])(99 @ t[1]) @ t[4]

View File

@@ -1,6 +1,6 @@
"""Exception handling control flow: try/except/else/finally evaluation order."""
from timer import test
from timer import test, dead, never
# 1. try/except — no exception raised (except block skipped)
@@ -10,7 +10,7 @@ def test_try_no_exception(t):
x = 1 @ t[0]
y = 2 @ t[1]
except ValueError:
z = 3 @ t.dead[2]
z = 3 @ t[dead(2)]
after = 0 @ t[2]
@@ -20,7 +20,7 @@ def test_try_with_exception(t):
try:
x = 1 @ t[0]
raise ((ValueError @ t[1])() @ t[2])
y = 2 @ t.never
y = 2 @ t[never]
except ValueError:
z = 3 @ t[3]
after = 0 @ t[4]
@@ -32,7 +32,7 @@ def test_try_except_else_no_exception(t):
try:
x = 1 @ t[0]
except ValueError:
y = 2 @ t.dead[1]
y = 2 @ t[dead(1)]
else:
z = 3 @ t[1]
after = 0 @ t[2]
@@ -47,7 +47,7 @@ def test_try_except_else_with_exception(t):
except ValueError:
y = 2 @ t[3]
else:
z = 3 @ t.dead[3]
z = 3 @ t[dead(3)]
after = 0 @ t[4]
@@ -81,7 +81,7 @@ def test_try_except_finally_no_exception(t):
try:
x = 1 @ t[0]
except ValueError:
y = 2 @ t.dead[1]
y = 2 @ t[dead(1)]
finally:
z = 3 @ t[1]
after = 0 @ t[2]
@@ -109,7 +109,7 @@ def test_multiple_except_first(t):
except ValueError:
y = 2 @ t[3]
except TypeError:
z = 3 @ t.dead[3]
z = 3 @ t[dead(3)]
after = 0 @ t[4]
@@ -120,7 +120,7 @@ def test_multiple_except_second(t):
x = 1 @ t[0]
raise ((TypeError @ t[1])() @ t[2])
except ValueError:
y = 2 @ t.dead[3]
y = 2 @ t[dead(3)]
except TypeError:
z = 3 @ t[3]
after = 0 @ t[4]
@@ -149,7 +149,7 @@ def test_nested_try_except(t):
z = 3 @ t[4]
w = 4 @ t[5]
except TypeError:
v = 5 @ t.dead[6]
v = 5 @ t[dead(6)]
after = 0 @ t[6]

View File

@@ -5,7 +5,7 @@ that verify the order in which Python evaluates expressions.
Usage with @test decorator (preferred):
from timer import test
from timer import test, dead, never
@test
def test_sequential(t):
@@ -13,18 +13,14 @@ Usage with @test decorator (preferred):
y = 2 @ t[1]
z = (x + y) @ t[2]
Usage with context manager (manual):
from timer import Timer
with Timer("my_test") as t:
x = 1 @ t[0]
Timer API:
t[n] - assert current timestamp is n, return marker
t[n, m, ...] - assert current timestamp is one of {n, m, ...}
t["label"] - record current timestamp under label (development aid)
t(value, n) - equivalent to: value @ t[n]
Annotation forms:
t[n] - assert current timestamp is n, return marker
t[n, m, ...] - assert current timestamp is one of {n, m, ...}
t[dead(n)] - mark timestamp n as dead (fails if evaluated)
t[dead(n), m] - dead at n, live at m
t[never] - mark as never evaluated (fails if evaluated)
t["label"] - record current timestamp under label (development aid)
t(value, n) - equivalent to: value @ t[n]
Run a test file directly to self-validate: python test_file.py
"""
@@ -36,19 +32,41 @@ _results = []
class _Check:
"""Marker returned by t[n] — asserts the current timestamp."""
"""Marker returned by t[n] — asserts the current timestamp.
__slots__ = ("_timer", "_expected")
Receives the raw subscript elements: plain ints are live timestamps,
dead(n) markers are dead timestamps, and `never` means any evaluation
is an error.
"""
def __init__(self, timer, expected):
__slots__ = ("_timer", "_live", "_dead", "_never")
def __init__(self, timer, elements):
self._timer = timer
self._expected = expected
self._live = set()
self._dead = set()
self._never = False
for e in elements:
if isinstance(e, int):
self._live.add(e)
elif isinstance(e, _DeadMarker):
self._dead.add(e.timestamp)
elif isinstance(e, _NeverSentinel):
self._never = True
def __rmatmul__(self, value):
ts = self._timer._tick()
if ts not in self._expected:
if self._never:
self._timer._error(
f"expected {sorted(self._expected)}, got {ts}"
f"expression annotated with t[never] was evaluated (timestamp {ts})"
)
elif ts in self._dead:
self._timer._error(
f"timestamp {ts} is marked dead but was evaluated"
)
elif ts not in self._live:
self._timer._error(
f"expected {sorted(self._live)}, got {ts}"
)
return value
@@ -68,36 +86,24 @@ class _Label:
return value
class _NeverCheck:
"""Marker returned by t.never — fails if the expression is ever evaluated."""
class _DeadMarker:
"""Marker returned by dead(n) — used inside t[...] to mark a timestamp as dead."""
def __init__(self, timer):
self._timer = timer
def __rmatmul__(self, value):
self._timer._error("expression annotated with t.never was evaluated")
return value
def __init__(self, timestamp):
self.timestamp = timestamp
class _DeadCheck:
"""Marker returned by t.dead[n] — fails if the expression is ever evaluated."""
def __init__(self, timer):
self._timer = timer
def __rmatmul__(self, value):
self._timer._error("expression annotated with t.dead was evaluated")
return value
def dead(n):
"""Mark timestamp `n` as dead code inside a timer subscript: t[dead(1), 2]."""
return _DeadMarker(n)
class _DeadSubscript:
"""Subscriptable returned by t.dead — produces _DeadCheck markers."""
class _NeverSentinel:
"""Sentinel for never-evaluated annotations: t[never]."""
pass
def __init__(self, timer):
self._timer = timer
def __getitem__(self, key):
return _DeadCheck(self._timer)
never = _NeverSentinel()
class Timer:
@@ -113,8 +119,6 @@ class Timer:
self._counter = 0
self._errors = []
self._labels = {}
self.dead = _DeadSubscript(self)
self.never = _NeverCheck(self)
def __enter__(self):
return self
@@ -144,7 +148,7 @@ class Timer:
if isinstance(key, str):
return _Label(self, key)
elif isinstance(key, tuple):
return _Check(self, list(key))
return _Check(self, key)
else:
return _Check(self, [key])