mirror of
https://github.com/github/codeql.git
synced 2026-06-08 14:42:30 +02:00
Preparatory refactor for the shared-CFG dataflow migration. Adds the new Python CFG library additively, without changing any production behaviour. Library additions: - semmle.python.controlflow.internal.AstNodeImpl — mediates between the Python AST and the shared codeql.controlflow.ControlFlowGraph signature. 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). - semmle.python.controlflow.internal.Cfg — public facade re-exposing the same API surface as semmle/python/Flow.qll (ControlFlowNode, CallNode, BasicBlock, NameNode, DefinitionNode, CompareNode, ...), backed by the shared CFG. - 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. Shared library: - shared.controlflow.ControlFlowGraph — adds two defaulted getWhileElse / getForeachElse predicates to AstSig so Python can model while-else / for-else (no behavioural change for other languages). Test additions: - ControlFlow/bindings/* — annotation-driven SSA-binding tests for the new CFG (annassign, compound, comprehension, decorated, except_handler, imports, match_pattern, parameters, simple, type_params, walrus_starred, with_stmt, dead_under_no_raise). - ControlFlow/store-load/* — basic store/load coverage. - 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 — that lands in follow-up PRs. The new CFG library has zero callers in lib/ and src/. Verified by: - All lib + src + consistency-queries compile clean (367 queries). - All 56 ControlFlow library-tests pass. - All 474 dataflow + PointsTo library-tests + consistency tests pass. - syntax_error/CONSISTENCY/CfgConsistency passes. 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]
|