@@ -7,6 +7,7 @@ import java
77private import semmle.code.java.controlflow.Dominance
88private import semmle.code.java.controlflow.internal.GuardsLogic
99private import semmle.code.java.controlflow.internal.Preconditions
10+ private import semmle.code.java.controlflow.internal.SwitchCases
1011
1112/**
1213 * A basic block that terminates in a condition, splitting the subsequent control flow.
@@ -72,6 +73,35 @@ class ConditionBlock extends BasicBlock {
7273 }
7374}
7475
76+ // Join order engineering -- first determine the switch block and the case indices required, then retrieve them.
77+ bindingset [ switch, i]
78+ pragma [ inline_late]
79+ private predicate isNthCaseOf ( StmtParent switch , SwitchCase c , int i ) { c .isNthCaseOf ( switch , i ) }
80+
81+ /**
82+ * Gets a switch case >= pred, up to but not including `pred`'s successor pattern case,
83+ * where `pred` is declared on `switch`.
84+ */
85+ private SwitchCase getACaseUpToNextPattern ( PatternCase pred , StmtParent switch ) {
86+ // Note we do include `case null, default` (as well as plain old `default`) here.
87+ not result .( ConstCase ) .getValue ( _) instanceof NullLiteral and
88+ exists ( int maxCaseIndex |
89+ switch = pred .getParent ( ) and
90+ if exists ( getNextPatternCase ( pred ) )
91+ then maxCaseIndex = getNextPatternCase ( pred ) .getCaseIndex ( ) - 1
92+ else maxCaseIndex = lastCaseIndex ( switch )
93+ |
94+ isNthCaseOf ( switch , result , [ pred .getCaseIndex ( ) .. maxCaseIndex ] )
95+ )
96+ }
97+
98+ /**
99+ * Gets the closest pattern case preceding `case`, including `case` itself, if any.
100+ */
101+ private PatternCase getClosestPrecedingPatternCase ( SwitchCase case ) {
102+ case = getACaseUpToNextPattern ( result , _)
103+ }
104+
75105/**
76106 * A condition that can be evaluated to either true or false. This can either
77107 * be an `Expr` of boolean type that isn't a boolean literal, or a case of a
@@ -113,17 +143,10 @@ class Guard extends ExprParent {
113143 result = this .( Expr ) .getBasicBlock ( )
114144 or
115145 // Return the closest pattern case statement before this one, including this one.
116- result =
117- max ( int i , PatternCase c |
118- c = this .( SwitchCase ) .getSiblingCase ( i ) and i <= this .( SwitchCase ) .getCaseIndex ( )
119- |
120- c order by i
121- ) .getBasicBlock ( )
146+ result = getClosestPrecedingPatternCase ( this ) .getBasicBlock ( )
122147 or
123148 // Not a pattern case and no preceding pattern case -- return the top of the switch block.
124- not exists ( PatternCase c , int i |
125- c = this .( SwitchCase ) .getSiblingCase ( i ) and i <= this .( SwitchCase ) .getCaseIndex ( )
126- ) and
149+ not exists ( getClosestPrecedingPatternCase ( this ) ) and
127150 result = this .( SwitchCase ) .getSelectorExpr ( ) .getBasicBlock ( )
128151 }
129152
0 commit comments