@@ -194,7 +194,7 @@ private module ControlFlowGraphImpl {
194194 */
195195 private predicate uncheckedExceptionFromFinally ( ControlFlowNode n , ThrowableType t ) {
196196 exists ( TryStmt try |
197- n .getEnclosingStmt ( ) .getParent + ( ) = try .getBlock ( ) or
197+ n .getEnclosingStmt ( ) .getEnclosingStmt + ( ) = try .getBlock ( ) or
198198 n .( Expr ) .getParent * ( ) = try .getAResource ( )
199199 |
200200 exists ( try .getFinally ( ) ) and
@@ -208,7 +208,7 @@ private module ControlFlowGraphImpl {
208208 */
209209 private predicate uncheckedExceptionFromCatch ( ControlFlowNode n , ThrowableType t ) {
210210 exists ( TryStmt try , UncheckedThrowableSuperType caught |
211- n .getEnclosingStmt ( ) .getParent + ( ) = try .getBlock ( ) or
211+ n .getEnclosingStmt ( ) .getEnclosingStmt + ( ) = try .getBlock ( ) or
212212 n .( Expr ) .getParent * ( ) = try .getAResource ( )
213213 |
214214 t = caught .getAnUncheckedSubtype ( ) and
@@ -222,7 +222,7 @@ private module ControlFlowGraphImpl {
222222 */
223223 private ThrowableType thrownInBody ( TryStmt try ) {
224224 exists ( ControlFlowNode n | mayThrow ( n , result ) |
225- n .getEnclosingStmt ( ) .getParent + ( ) = try .getBlock ( ) or
225+ n .getEnclosingStmt ( ) .getEnclosingStmt + ( ) = try .getBlock ( ) or
226226 n .( Expr ) .getParent * ( ) = try .getAResource ( )
227227 )
228228 }
@@ -298,6 +298,11 @@ private module ControlFlowGraphImpl {
298298 inBooleanContext ( condexpr )
299299 )
300300 or
301+ exists ( SwitchExpr switch |
302+ inBooleanContext ( switch ) and
303+ switch .getAResult ( ) = b
304+ )
305+ or
301306 exists ( ConditionalStmt condstmt | condstmt .getCondition ( ) = b )
302307 }
303308
@@ -447,7 +452,7 @@ private module ControlFlowGraphImpl {
447452 or
448453 this .( Block ) .getNumStmt ( ) = 0
449454 or
450- this instanceof SwitchCase
455+ this instanceof SwitchCase and not this . ( SwitchCase ) . isRule ( )
451456 or
452457 this instanceof EmptyStmt
453458 or
@@ -551,7 +556,7 @@ private module ControlFlowGraphImpl {
551556 // somewhere inside this loop; we don't particularly care whether that
552557 // `continue` could actually target this loop, we just want to restrict
553558 // the size of the predicate
554- exists ( ContinueStmt cnt | cnt .getParent + ( ) = loop |
559+ exists ( ContinueStmt cnt | cnt .getEnclosingStmt + ( ) = loop |
555560 completion = anonymousContinueCompletion ( ) or
556561 completion = labelledContinueCompletion ( getLabel ( loop ) )
557562 )
@@ -651,8 +656,9 @@ private module ControlFlowGraphImpl {
651656 */
652657 private predicate last ( ControlFlowNode n , ControlFlowNode last , Completion completion ) {
653658 // Exceptions are propagated from any sub-expression.
659+ // As are any break, continue, or return completions.
654660 exists ( Expr e | e .getParent ( ) = n |
655- last ( e , last , completion ) and completion = ThrowCompletion ( _ )
661+ last ( e , last , completion ) and not completion instanceof NormalOrBooleanCompletion
656662 )
657663 or
658664 // If an expression doesn't finish with a throw completion, then it executes normally with
@@ -796,6 +802,28 @@ private module ControlFlowGraphImpl {
796802 completion = NormalCompletion ( )
797803 )
798804 or
805+ // handle `switch` expression
806+ exists ( SwitchExpr switch | switch = n |
807+ // value `break` terminates the `switch`
808+ last ( switch .getAStmt ( ) , last , ValueBreakCompletion ( completion ) )
809+ or
810+ // any other abnormal completion is propagated
811+ last ( switch .getAStmt ( ) , last , completion ) and
812+ not completion instanceof ValueBreakCompletion and
813+ completion != NormalCompletion ( )
814+ )
815+ or
816+ // the last node in a case rule is the last node in the right-hand side
817+ last ( n .( SwitchCase ) .getRuleStatement ( ) , last , completion )
818+ or
819+ // ...and if the rhs is an expression we wrap the completion as a value break
820+ exists ( Completion caseCompletion |
821+ last ( n .( SwitchCase ) .getRuleExpression ( ) , last , caseCompletion ) and
822+ if caseCompletion instanceof NormalOrBooleanCompletion
823+ then completion = ValueBreakCompletion ( caseCompletion )
824+ else completion = caseCompletion
825+ )
826+ or
799827 // the last statement of a synchronized statement is the last statement of its body
800828 last ( n .( SynchronizedStmt ) .getBlock ( ) , last , completion )
801829 or
@@ -805,13 +833,21 @@ private module ControlFlowGraphImpl {
805833 // `throw` statements or throwing calls give rise to ` Throw` completion
806834 exists ( ThrowableType tt | mayThrow ( n , tt ) | last = n and completion = ThrowCompletion ( tt ) )
807835 or
808- // `break` statements give rise to a `Break` completion
809- exists ( BreakStmt break | break = n and last = n |
836+ // `break` statements without value give rise to a `Break` completion
837+ exists ( BreakStmt break | break = n and last = n and not break . hasValue ( ) |
810838 completion = labelledBreakCompletion ( MkLabel ( break .getLabel ( ) ) )
811839 or
812840 not exists ( break .getLabel ( ) ) and completion = anonymousBreakCompletion ( )
813841 )
814842 or
843+ // value break statements get their completion wrapped as a value break
844+ exists ( Completion caseCompletion |
845+ last ( n .( BreakStmt ) .getValue ( ) , last , caseCompletion ) and
846+ if caseCompletion instanceof NormalOrBooleanCompletion
847+ then completion = ValueBreakCompletion ( caseCompletion )
848+ else completion = caseCompletion
849+ )
850+ or
815851 // `continue` statements give rise to a `Continue` completion
816852 exists ( ContinueStmt cont | cont = n and last = n |
817853 completion = labelledContinueCompletion ( MkLabel ( cont .getLabel ( ) ) )
@@ -1055,7 +1091,32 @@ private module ControlFlowGraphImpl {
10551091 )
10561092 )
10571093 or
1058- // No edges in a SwitchCase - the constant expression in a ConstCase isn't included in the CFG.
1094+ // Switch expressions
1095+ exists ( SwitchExpr switch | completion = NormalCompletion ( ) |
1096+ // From the entry point control is transferred first to the expression...
1097+ n = switch and result = first ( switch .getExpr ( ) )
1098+ or
1099+ // ...and then to one of the cases.
1100+ last ( switch .getExpr ( ) , n , completion ) and result = first ( switch .getACase ( ) )
1101+ or
1102+ // Statements within a switch body execute sequentially.
1103+ exists ( int i |
1104+ last ( switch .getStmt ( i ) , n , completion ) and result = first ( switch .getStmt ( i + 1 ) )
1105+ )
1106+ )
1107+ or
1108+ // No edges in a non-rule SwitchCase - the constant expression in a ConstCase isn't included in the CFG.
1109+ exists ( SwitchCase case | completion = NormalCompletion ( ) |
1110+ n = case and result = first ( case .getRuleExpression ( ) )
1111+ or
1112+ n = case and result = first ( case .getRuleStatement ( ) )
1113+ )
1114+ or
1115+ // Value break
1116+ exists ( BreakStmt break | completion = NormalCompletion ( ) |
1117+ n = break and result = first ( break .getValue ( ) )
1118+ )
1119+ or
10591120 // Synchronized statements execute their expression _before_ synchronization, so the CFG reflects that.
10601121 exists ( SynchronizedStmt synch | completion = NormalCompletion ( ) |
10611122 last ( synch .getExpr ( ) , n , completion ) and result = synch
0 commit comments