@@ -7,6 +7,7 @@ import java
7
7
private import semmle.code.java.controlflow.Dominance
8
8
private import semmle.code.java.controlflow.internal.GuardsLogic
9
9
private import semmle.code.java.controlflow.internal.Preconditions
10
+ private import semmle.code.java.controlflow.internal.SwitchCases
10
11
11
12
/**
12
13
* A basic block that terminates in a condition, splitting the subsequent control flow.
@@ -72,6 +73,35 @@ class ConditionBlock extends BasicBlock {
72
73
}
73
74
}
74
75
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
+
75
105
/**
76
106
* A condition that can be evaluated to either true or false. This can either
77
107
* 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 {
113
143
result = this .( Expr ) .getBasicBlock ( )
114
144
or
115
145
// 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 ( )
122
147
or
123
148
// 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
127
150
result = this .( SwitchCase ) .getSelectorExpr ( ) .getBasicBlock ( )
128
151
}
129
152
0 commit comments