From b682877968e0957a848579ef2226ef071d7bfe16 Mon Sep 17 00:00:00 2001 From: Copilot Date: Thu, 7 May 2026 17:13:50 +0000 Subject: [PATCH] Python: simplify TBlockStmt char pred via exclusion list Replace the 14-disjunct allow-list with a 2-conjunct exclusion list. Of the 17 Py::StmtList getters in AstGenerated.qll, only Try.getHandlers() and MatchStmt.getCases() should not be wrapped as BlockStmts (they are iterated individually by the shared library's Try/Switch logic via getCatch(int) and getCase(int)). All other StmtLists are imperative block bodies. No behaviour change: all 24 NewCfg evaluation-order tests pass; all 11 shared-CFG consistency queries report 0 violations on CPython. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../controlflow/internal/AstNodeImpl.qll | 37 ++++--------------- 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll index a4ea9575565..2c43802948d 100644 --- a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll +++ b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll @@ -35,38 +35,15 @@ module Ast implements AstSig { * A synthetic block statement, wrapping a `Py::StmtList`. Each list of * statements that represents an imperative block (a function/class/module * body, an `if`/`while`/`for` branch, a `try`/`except`/`finally` body, - * etc.) becomes one `BlockStmt` node in the CFG. Lists used in other - * roles (e.g. `Try.getHandlers()`, which is iterated as catch clauses) - * are excluded. + * etc.) becomes one `BlockStmt` node in the CFG. `Py::StmtList`s used + * in other roles - `Try.getHandlers()` (iterated via `getCatch`) and + * `MatchStmt.getCases()` (iterated via `getCase`) - are excluded, as + * the shared library's `Try`/`Switch` logic walks their items + * individually. */ TBlockStmt(Py::StmtList sl) { - sl = any(Py::Scope p).getBody() - or - sl = any(Py::If p).getBody() - or - sl = any(Py::If p).getOrelse() - or - sl = any(Py::While p).getBody() - or - sl = any(Py::While p).getOrelse() - or - sl = any(Py::For p).getBody() - or - sl = any(Py::For p).getOrelse() - or - sl = any(Py::With p).getBody() - or - sl = any(Py::Try p).getBody() - or - sl = any(Py::Try p).getOrelse() - or - sl = any(Py::Try p).getFinalbody() - or - sl = any(Py::Case p).getBody() - or - sl = any(Py::ExceptStmt p).getBody() - or - sl = any(Py::ExceptGroupStmt p).getBody() + not sl = any(Py::Try t).getHandlers() and + not sl = any(Py::MatchStmt m).getCases() } /**