@@ -108,7 +108,7 @@ private predicate goto(ControlFlowElement cfe, GotoCompletion gc, string label,
108108 // Special case: when a `goto` happens inside a `try` statement with a
109109 // `finally` block, flow does not go directly to the target, but instead
110110 // to the `finally` block (and from there possibly to the target)
111- not cfe = any ( Statements:: TryStmtTree t | t .hasFinally ( ) ) .getBlockOrCatchFinallyPred ( _ ) and
111+ not cfe = any ( Statements:: TryStmtTree t | t .hasFinally ( ) ) .getAFinallyPredecessor ( _ , true ) and
112112 label = gc .getLabel ( ) and
113113 enclosing = cfe .getEnclosingCallable ( )
114114}
@@ -1355,26 +1355,30 @@ module Statements {
13551355 /**
13561356 * Gets a last element from a `try` or `catch` block of this `try` statement
13571357 * that may finish with completion `c`, such that control may be transferred
1358- * to the `finally` block (if it exists).
1358+ * to the `finally` block (if it exists), but only if `finalizable = true` .
13591359 */
13601360 pragma [ nomagic]
1361- ControlFlowElement getBlockOrCatchFinallyPred ( Completion c ) {
1362- this .lastBlock ( result , c ) and
1361+ ControlFlowElement getAFinallyPredecessor ( Completion c , boolean finalizable ) {
1362+ // Exit completions skip the `finally` block
1363+ ( if c instanceof ExitCompletion then finalizable = false else finalizable = true ) and
13631364 (
1364- // Any non-throw completion from the `try` block will always continue directly
1365- // to the `finally` block
1366- not c instanceof ThrowCompletion
1365+ this .lastBlock ( result , c ) and
1366+ (
1367+ // Any non-throw completion from the `try` block will always continue directly
1368+ // to the `finally` block
1369+ not c instanceof ThrowCompletion
1370+ or
1371+ // Any completion from the `try` block will continue to the `finally` block
1372+ // when there are no catch clauses
1373+ not exists ( this .getACatchClause ( ) )
1374+ )
1375+ or
1376+ // Last element from any of the `catch` clause blocks continues to the `finally` block
1377+ result = lastCatchClauseBlock ( this .getACatchClause ( ) , c )
13671378 or
1368- // Any completion from the `try` block will continue to the `finally` block
1369- // when there are no catch clauses
1370- not exists ( this .getACatchClause ( ) )
1379+ // Last element of last `catch` clause continues to the `finally` block
1380+ result = lastLastCatchClause ( this .getACatchClause ( ) , c )
13711381 )
1372- or
1373- // Last element from any of the `catch` clause blocks continues to the `finally` block
1374- result = lastCatchClauseBlock ( this .getACatchClause ( ) , c )
1375- or
1376- // Last element of last `catch` clause continues to the `finally` block
1377- result = lastLastCatchClause ( this .getACatchClause ( ) , c )
13781382 }
13791383
13801384 pragma [ nomagic]
@@ -1387,19 +1391,19 @@ module Statements {
13871391 ControlFlowElement last , NormalCompletion finally , Completion outer , int nestLevel
13881392 ) {
13891393 this .lastFinally0 ( last , finally ) and
1390- exists ( this .getBlockOrCatchFinallyPred ( any ( Completion c0 | outer = c0 .getOuterCompletion ( ) ) ) ) and
1394+ exists (
1395+ this .getAFinallyPredecessor ( any ( Completion c0 | outer = c0 .getOuterCompletion ( ) ) , true )
1396+ ) and
13911397 nestLevel = this .nestLevel ( )
13921398 }
13931399
13941400 final override predicate last ( ControlFlowElement last , Completion c ) {
1395- last = this .getBlockOrCatchFinallyPred ( c ) and
1396- (
1401+ exists ( boolean finalizable | last = this .getAFinallyPredecessor ( c , finalizable ) |
13971402 // If there is no `finally` block, last elements are from the body, from
13981403 // the blocks of one of the `catch` clauses, or from the last `catch` clause
13991404 not this .hasFinally ( )
14001405 or
1401- // Exit completions ignore the `finally` block
1402- c instanceof ExitCompletion
1406+ finalizable = false
14031407 )
14041408 or
14051409 this .lastFinally ( last , c , any ( NormalCompletion nc ) , _)
@@ -1433,43 +1437,22 @@ module Statements {
14331437 first ( this .getCatchClause ( 0 ) , succ )
14341438 or
14351439 exists ( CatchClause cc , int i | cc = this .getCatchClause ( i ) |
1440+ // Flow from one `catch` clause to the next
14361441 pred = cc and
14371442 last ( this .getCatchClause ( i ) , cc , c ) and
1438- (
1439- // Flow from one `catch` clause to the next
1440- first ( this .getCatchClause ( i + 1 ) , succ ) and
1441- c = any ( MatchingCompletion mc | not mc .isMatch ( ) )
1442- or
1443- // Flow from last `catch` clause to first element of `finally` block
1444- this .getCatchClause ( i ) .isLast ( ) and
1445- first ( this .getFinally ( ) , succ ) and
1446- c instanceof ThrowCompletion // inherited from `try` block
1447- )
1443+ first ( this .getCatchClause ( i + 1 ) , succ ) and
1444+ c = any ( MatchingCompletion mc | not mc .isMatch ( ) )
14481445 or
1446+ // Flow from last element of `catch` clause filter to next `catch` clause
14491447 last ( this .getCatchClause ( i ) , pred , c ) and
14501448 last ( cc .getFilterClause ( ) , pred , _) and
1451- (
1452- // Flow from last element of `catch` clause filter to next `catch` clause
1453- first ( this .getCatchClause ( i + 1 ) , succ ) and
1454- c instanceof FalseCompletion
1455- or
1456- // Flow from last element of `catch` clause filter, of last clause, to first
1457- // element of `finally` block
1458- this .getCatchClause ( i ) .isLast ( ) and
1459- first ( this .getFinally ( ) , succ ) and
1460- c instanceof ThrowCompletion // inherited from `try` block
1461- )
1462- or
1463- // Flow from last element of a `catch` block to first element of `finally` block
1464- pred = lastCatchClauseBlock ( cc , c ) and
1465- first ( this .getFinally ( ) , succ )
1449+ first ( this .getCatchClause ( i + 1 ) , succ ) and
1450+ c instanceof FalseCompletion
14661451 )
14671452 or
1468- // Flow from last element of `try` block to first element of `finally` block
1469- this .lastBlock ( pred , c ) and
1470- first ( this .getFinally ( ) , succ ) and
1471- not c instanceof ExitCompletion and
1472- ( c instanceof ThrowCompletion implies not exists ( this .getACatchClause ( ) ) )
1453+ // Flow into `finally` block
1454+ pred = getAFinallyPredecessor ( c , true ) and
1455+ first ( this .getFinally ( ) , succ )
14731456 }
14741457 }
14751458
0 commit comments