From 35ac66d3aa591a3521ba6a2ea2470acf0ee0e1a0 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 10 Mar 2026 10:39:32 +0100 Subject: [PATCH] Cfg: Move getCaseControlFlowOrder to shared code. --- .../lib/semmle/code/java/ControlFlowGraph.qll | 11 ++----- .../codeql/controlflow/ControlFlowGraph.qll | 29 ++++++++++++------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll index d6e675c8ab9..26672a22ed5 100644 --- a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll @@ -134,15 +134,6 @@ private module Ast implements AstSig { } } - int getCaseControlFlowOrder(Switch s, Case c) { - exists(int pos | s.getCase(pos) = c | - // if a default case is not last in the AST, move it last in the CFG order - if c instanceof DefaultCase and exists(s.getCase(pos + 1)) - then result = strictcount(s.getCase(_)) - else result = pos - ) - } - private Stmt getSwitchStmt(Switch s, int i) { result = s.(SwitchStmt).getStmt(i) or result = s.(SwitchExpr).getStmt(i) @@ -191,6 +182,8 @@ private module Ast implements AstSig { } } + class DefaultCase extends Case instanceof J::DefaultCase { } + predicate fallsThrough(Case c) { not c.(J::SwitchCase).isRule() } class ConditionalExpr = J::ConditionalExpr; diff --git a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll index 56a909a006c..1d070564f1c 100644 --- a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll +++ b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll @@ -226,16 +226,6 @@ signature module AstSig { Case getCase(int index); } - /** - * Gets an integer indicating the control flow order of a case within a switch. - * This is most often the same as the AST order, but can be different in some - * languages if the language allows a default case to appear before other - * cases. - * - * The values do not need to be contiguous; only the relative ordering matters. - */ - default int getCaseControlFlowOrder(Switch s, Case c) { s.getCase(result) = c } - /** A case in a switch. */ class Case extends AstNode { /** Gets a pattern being matched by this case. */ @@ -253,6 +243,8 @@ signature module AstSig { AstNode getBodyElement(int index); } + class DefaultCase extends Case; + /** * Holds if this case can fall through to the next case if it is not * otherwise prevented with a `break` or similar. @@ -938,7 +930,7 @@ module Make0 Ast> { * * A match-all case can still ultimately fail to match if it has a guard. */ - default predicate matchAll(Case c) { none() } + default predicate matchAll(Case c) { c instanceof DefaultCase } /** * Holds if `ast` may result in an abrupt completion `c` originating at @@ -1096,6 +1088,21 @@ module Make0 Ast> { ) } + /** + * Gets an integer indicating the control flow order of a case within a + * switch. This is equal to the AST order, except that default cases are + * always last in control flow order, even if some languages allow them + * to appear before other cases in the AST. + */ + private int getCaseControlFlowOrder(Switch s, Case c) { + exists(int pos | s.getCase(pos) = c | + // if a default case is not last in the AST, move it last in the CFG order + if c instanceof DefaultCase and exists(s.getCase(pos + 1)) + then result = strictcount(s.getCase(_)) + else result = pos + ) + } + private Case getRankedCaseCfgOrder(Switch s, int rnk) { result = rank[rnk](Case c, int i | getCaseControlFlowOrder(s, c) = i | c order by i) }