mirror of
https://github.com/github/codeql.git
synced 2026-06-25 06:37:07 +02:00
Preparatory refactor for the shared-CFG dataflow migration. Adds the adapter that mediates between the Python AST and the shared codeql.controlflow.ControlFlowGraph signature, plus the test suites that validate the new CFG directly against this adapter. The public facade is added in the following commit. Library additions: - semmle.python.controlflow.internal.AstNodeImpl — wraps Python's Stmt/Expr/Scope/Pattern and adds two synthetic kinds of node (BlockStmt for body slots, intermediate nodes for multi-operand boolean expressions) to satisfy the shared CFG signature. - lib/printCfgNew.ql — debug/visualisation query for the new CFG. - consistency-queries/CfgConsistency.ql — consistency query running the shared CFG's standard checks against Python. Test additions (all driven directly off AstNodeImpl): - ControlFlow/bindings/* — annotation-driven SSA-binding tests (annassign, compound, comprehension, decorated, except_handler, imports, match_pattern, parameters, simple, type_params, walrus_starred, with_stmt, dead_under_no_raise). - ControlFlow/evaluation-order/NewCfg*.ql — mirrors of the existing OldCfg evaluation-order self-validation suite, run against the new CFG via NewCfgImpl.qll. - Minor extensions to existing test_if.py / test_boolean.py + cosmetic .expected churn on a handful of OldCfg tests. No dataflow, SSA, or production query is migrated yet. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
109 lines
1.9 KiB
Python
109 lines
1.9 KiB
Python
"""If/elif/else control flow evaluation order."""
|
|
|
|
from timer import test, dead
|
|
|
|
|
|
@test
|
|
def test_if_true(t):
|
|
x = True @ t[0]
|
|
if x @ t[1]:
|
|
y = 1 @ t[2]
|
|
z = 0 @ t[3]
|
|
|
|
|
|
@test
|
|
def test_if_false(t):
|
|
x = False @ t[0]
|
|
if x @ t[1]:
|
|
y = 1 @ t[dead(2)]
|
|
z = 0 @ t[2]
|
|
|
|
|
|
@test
|
|
def test_if_else_true(t):
|
|
x = True @ t[0]
|
|
if x @ t[1]:
|
|
y = 1 @ t[2]
|
|
else:
|
|
y = 2 @ t[dead(2)]
|
|
z = 0 @ t[3]
|
|
|
|
|
|
@test
|
|
def test_if_else_false(t):
|
|
x = False @ t[0]
|
|
if x @ t[1]:
|
|
y = 1 @ t[dead(2)]
|
|
else:
|
|
y = 2 @ t[2]
|
|
z = 0 @ t[3]
|
|
|
|
|
|
@test
|
|
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)]
|
|
else:
|
|
y = "third" @ t[dead(4)]
|
|
z = 0 @ t[5]
|
|
|
|
|
|
@test
|
|
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)]
|
|
elif (x @ t[4] == 2 @ t[5]) @ t[6]:
|
|
y = "second" @ t[7]
|
|
else:
|
|
y = "third" @ t[dead(7)]
|
|
z = 0 @ t[8]
|
|
|
|
|
|
@test
|
|
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)]
|
|
elif (x @ t[4] == 2 @ t[5]) @ t[6]:
|
|
y = "second" @ t[dead(7)]
|
|
else:
|
|
y = "third" @ t[7]
|
|
z = 0 @ t[8]
|
|
|
|
|
|
@test
|
|
def test_nested_if_else(t):
|
|
x = True @ t[0]
|
|
y = True @ t[1]
|
|
if x @ t[2]:
|
|
if y @ t[3]:
|
|
z = 1 @ t[4]
|
|
else:
|
|
z = 2 @ t[dead(4)]
|
|
else:
|
|
z = 3 @ t[dead(3), dead(4)]
|
|
w = 0 @ t[5]
|
|
|
|
|
|
@test
|
|
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)]
|
|
else:
|
|
z = 2 @ t[5]
|
|
w = 0 @ t[6]
|
|
|
|
|
|
@test
|
|
def test_if_pass(t):
|
|
x = True @ t[0]
|
|
if x @ t[1]:
|
|
pass
|
|
z = 0 @ t[2]
|