Add ExceptionList AST node for rescue clauses with 2+ exceptions

This commit is contained in:
copilot-swe-agent[bot]
2026-06-19 09:50:14 +00:00
committed by Anders Schack-Mulligen
parent 0834e640bb
commit 65b4a4346b
7 changed files with 145 additions and 53 deletions

View File

@@ -0,0 +1,4 @@
---
category: breaking
---
* When a `rescue` clause has two or more exception types, the exceptions are no longer direct children of the `RescueClause` node. Instead, a new `ExceptionList` AST node wraps the exceptions. Use `RescueClause.getExceptions()` to get the `ExceptionList` node, and `ExceptionList.getException(int n)` to access the individual exceptions. For `rescue` clauses with zero or one exception, the behavior is unchanged and `RescueClause.getException(int n)` continues to work as before.

View File

@@ -280,6 +280,37 @@ class Pair extends Expr instanceof PairImpl {
final override string getAPrimaryQlClass() { result = "Pair" }
}
/**
* A list of exception types in a rescue clause. For example, the exception list
* `FirstError, SecondError` in:
* ```rb
* begin
* do_something
* rescue FirstError, SecondError => e
* handle_error(e)
* end
* ```
* This node is only present when there are two or more exceptions in the list.
*/
class ExceptionList extends Expr, TExceptionList {
private Ruby::Exceptions g;
ExceptionList() { this = TExceptionList(g) }
final override string getAPrimaryQlClass() { result = "ExceptionList" }
/** Gets the `n`th exception in this list. */
final Expr getException(int n) { toGenerated(result) = g.getChild(n) }
final override string toString() { result = "..., ..." }
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = "getException" and result = this.getException(_)
}
}
/**
* A rescue clause. For example:
* ```rb
@@ -305,8 +336,16 @@ class RescueClause extends Expr, TRescueClause {
* handle_error(e)
* end
* ```
* When there are two or more exceptions, use `getExceptions()` to get the `ExceptionList` node.
*/
final Expr getException(int n) { toGenerated(result) = g.getExceptions().getChild(n) }
final Expr getException(int n) {
// 0 or 1 exception: no ExceptionList node, access directly
not exists(this.getExceptions()) and
toGenerated(result) = g.getExceptions().getChild(n)
or
// 2+ exceptions: delegate through ExceptionList
result = this.getExceptions().getException(n)
}
/**
* Gets an exception to match, if any. For example `FirstError` or `SecondError` in:
@@ -320,6 +359,19 @@ class RescueClause extends Expr, TRescueClause {
*/
final Expr getAnException() { result = this.getException(_) }
/**
* Gets the exception list node when there are two or more exceptions to match. For example,
* the exception list `FirstError, SecondError` in:
* ```rb
* begin
* do_something
* rescue FirstError, SecondError => e
* handle_error(e)
* end
* ```
*/
final ExceptionList getExceptions() { result = TExceptionList(g.getExceptions()) }
/**
* Gets the variable to which to assign the matched exception, if any.
* For example `err` in:
@@ -343,8 +395,13 @@ class RescueClause extends Expr, TRescueClause {
final override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
// For 0 or 1 exceptions, exceptions are direct children
not exists(this.getExceptions()) and
pred = "getException" and result = this.getException(_)
or
// For 2+ exceptions, the ExceptionList node is the direct child
pred = "getExceptions" and result = this.getExceptions()
or
pred = "getVariableExpr" and result = this.getVariableExpr()
or
pred = "getBody" and result = this.getBody()

View File

@@ -155,6 +155,7 @@ private module Cached {
TEndBlock(Ruby::EndBlock g) or
TEnsure(Ruby::Ensure g) or
TEqExpr(Ruby::Binary g) { g instanceof @ruby_binary_equalequal } or
TExceptionList(Ruby::Exceptions g) { strictcount(g.getChild(_)) > 1 } or
TExponentExprReal(Ruby::Binary g) { g instanceof @ruby_binary_starstar } or
TExponentExprSynth(Ast::AstNode parent, int i) { mkSynthChild(ExponentExprKind(), parent, i) } or
TFalseLiteral(Ruby::False g) or
@@ -375,7 +376,8 @@ private module Cached {
TClassVariableAccessReal or TComplementExpr or TComplexLiteral or TDefinedExprReal or
TDelimitedSymbolLiteral or TDestructuredLeftAssignment or TDestructuredParameter or
TDivExprReal or TDo or TDoBlock or TElementReference or TElseReal or TElsif or TEmptyStmt or
TEncoding or TEndBlock or TEnsure or TEqExpr or TExponentExprReal or TFalseLiteral or
TEncoding or TEndBlock or TEnsure or TEqExpr or TExceptionList or TExponentExprReal or
TFalseLiteral or
TFile or TFindPattern or TFloatLiteral or TForExpr or TForwardParameter or
TForwardArgument or TGEExpr or TGTExpr or TGlobalVariableAccessReal or
THashKeySymbolLiteral or THashLiteral or THashPattern or THashSplatExprReal or
@@ -475,6 +477,7 @@ private module Cached {
n = TEndBlock(result) or
n = TEnsure(result) or
n = TEqExpr(result) or
n = TExceptionList(result) or
n = TExponentExprReal(result) or
n = TFalseLiteral(result) or
n = TFile(result) or
@@ -765,7 +768,7 @@ class TExpr =
TSelf or TArgumentList or TRescueClause or TRescueModifierExpr or TPair or TStringConcatenation or
TCall or TBlockArgument or TConstantAccess or TControlExpr or TLiteral or TCallable or
TVariableAccess or TStmtSequence or TOperation or TForwardArgument or TDestructuredLhsExpr or
TMatchPattern or TTestPattern;
TMatchPattern or TTestPattern or TExceptionList;
class TSplatExpr = TSplatExprReal or TSplatExprSynth;

View File

@@ -445,6 +445,16 @@ calls/calls.rb:
# 255| getEnsure: [StmtSequence] ensure ...
# 255| getStmt: [MethodCall] call to bar
# 255| getReceiver: [ConstantReadAccess] X
# 257| getStmt: [BeginExpr] begin ...
# 258| getRescue: [RescueClause] rescue ...
# 258| getExceptions: [ExceptionList] ..., ...
# 258| getException: [MethodCall] call to foo
# 258| getReceiver: [SelfVariableAccess] self
# 258| getException: [MethodCall] call to bar
# 258| getReceiver: [ConstantReadAccess] X
# 259| getEnsure: [StmtSequence] ensure ...
# 259| getStmt: [MethodCall] call to baz
# 259| getReceiver: [SelfVariableAccess] self
# 263| getStmt: [RescueModifierExpr] ... rescue ...
# 263| getBody: [MethodCall] call to foo
# 263| getReceiver: [SelfVariableAccess] self

View File

@@ -715,11 +715,26 @@ calls/calls.rb:
# 255| 1: [ReservedWord] ::
# 255| 2: [Identifier] bar
# 256| 3: [ReservedWord] end
# 263| 76: [RescueModifier] RescueModifier
# 257| 76: [Begin] Begin
# 257| 0: [ReservedWord] begin
# 258| 1: [Rescue] Rescue
# 258| 0: [ReservedWord] rescue
# 258| 1: [Exceptions] Exceptions
# 258| 0: [Identifier] foo
# 258| 1: [ReservedWord] ,
# 258| 2: [Call] Call
# 258| 0: [Constant] X
# 258| 1: [ReservedWord] ::
# 258| 2: [Identifier] bar
# 259| 2: [Ensure] Ensure
# 259| 0: [ReservedWord] ensure
# 259| 1: [Identifier] baz
# 260| 3: [ReservedWord] end
# 263| 77: [RescueModifier] RescueModifier
# 263| 0: [Identifier] foo
# 263| 1: [ReservedWord] rescue
# 263| 2: [Identifier] bar
# 264| 77: [RescueModifier] RescueModifier
# 264| 78: [RescueModifier] RescueModifier
# 264| 0: [Call] Call
# 264| 0: [Constant] X
# 264| 1: [ReservedWord] ::
@@ -729,7 +744,7 @@ calls/calls.rb:
# 264| 0: [Constant] X
# 264| 1: [ReservedWord] ::
# 264| 2: [Identifier] bar
# 267| 78: [Call] Call
# 267| 79: [Call] Call
# 267| 0: [Identifier] foo
# 267| 1: [ArgumentList] ArgumentList
# 267| 0: [ReservedWord] (
@@ -737,7 +752,7 @@ calls/calls.rb:
# 267| 0: [ReservedWord] &
# 267| 1: [Identifier] bar
# 267| 2: [ReservedWord] )
# 268| 79: [Call] Call
# 268| 80: [Call] Call
# 268| 0: [Identifier] foo
# 268| 1: [ArgumentList] ArgumentList
# 268| 0: [ReservedWord] (
@@ -748,14 +763,14 @@ calls/calls.rb:
# 268| 1: [ReservedWord] ::
# 268| 2: [Identifier] bar
# 268| 2: [ReservedWord] )
# 269| 80: [Call] Call
# 269| 81: [Call] Call
# 269| 0: [Identifier] foo
# 269| 1: [ArgumentList] ArgumentList
# 269| 0: [ReservedWord] (
# 269| 1: [BlockArgument] BlockArgument
# 269| 0: [ReservedWord] &
# 269| 2: [ReservedWord] )
# 271| 81: [Call] Call
# 271| 82: [Call] Call
# 271| 0: [Identifier] foo
# 271| 1: [ArgumentList] ArgumentList
# 271| 0: [ReservedWord] (
@@ -763,7 +778,7 @@ calls/calls.rb:
# 271| 0: [ReservedWord] *
# 271| 1: [Identifier] bar
# 271| 2: [ReservedWord] )
# 272| 82: [Call] Call
# 272| 83: [Call] Call
# 272| 0: [Identifier] foo
# 272| 1: [ArgumentList] ArgumentList
# 272| 0: [ReservedWord] (
@@ -774,14 +789,14 @@ calls/calls.rb:
# 272| 1: [ReservedWord] ::
# 272| 2: [Identifier] bar
# 272| 2: [ReservedWord] )
# 273| 83: [Call] Call
# 273| 84: [Call] Call
# 273| 0: [Identifier] foo
# 273| 1: [ArgumentList] ArgumentList
# 273| 0: [ReservedWord] (
# 273| 1: [SplatArgument] SplatArgument
# 273| 0: [ReservedWord] *
# 273| 2: [ReservedWord] )
# 276| 84: [Call] Call
# 276| 85: [Call] Call
# 276| 0: [Identifier] foo
# 276| 1: [ArgumentList] ArgumentList
# 276| 0: [ReservedWord] (
@@ -789,7 +804,7 @@ calls/calls.rb:
# 276| 0: [ReservedWord] **
# 276| 1: [Identifier] bar
# 276| 2: [ReservedWord] )
# 277| 85: [Call] Call
# 277| 86: [Call] Call
# 277| 0: [Identifier] foo
# 277| 1: [ArgumentList] ArgumentList
# 277| 0: [ReservedWord] (
@@ -800,14 +815,14 @@ calls/calls.rb:
# 277| 1: [ReservedWord] ::
# 277| 2: [Identifier] bar
# 277| 2: [ReservedWord] )
# 278| 86: [Call] Call
# 278| 87: [Call] Call
# 278| 0: [Identifier] foo
# 278| 1: [ArgumentList] ArgumentList
# 278| 0: [ReservedWord] (
# 278| 1: [HashSplatArgument] HashSplatArgument
# 278| 0: [ReservedWord] **
# 278| 2: [ReservedWord] )
# 281| 87: [Call] Call
# 281| 88: [Call] Call
# 281| 0: [Identifier] foo
# 281| 1: [ArgumentList] ArgumentList
# 281| 0: [ReservedWord] (
@@ -816,7 +831,7 @@ calls/calls.rb:
# 281| 1: [ReservedWord] :
# 281| 2: [Identifier] bar
# 281| 2: [ReservedWord] )
# 282| 88: [Call] Call
# 282| 89: [Call] Call
# 282| 0: [Identifier] foo
# 282| 1: [ArgumentList] ArgumentList
# 282| 0: [ReservedWord] (
@@ -828,7 +843,7 @@ calls/calls.rb:
# 282| 1: [ReservedWord] ::
# 282| 2: [Identifier] bar
# 282| 2: [ReservedWord] )
# 287| 89: [Class] Class
# 287| 90: [Class] Class
# 287| 0: [ReservedWord] class
# 287| 1: [Constant] MyClass
# 288| 2: [BodyStatement] BodyStatement
@@ -923,7 +938,7 @@ calls/calls.rb:
# 296| 3: [ReservedWord] end
# 297| 3: [ReservedWord] end
# 298| 3: [ReservedWord] end
# 304| 90: [Class] Class
# 304| 91: [Class] Class
# 304| 0: [ReservedWord] class
# 304| 1: [Constant] AnotherClass
# 305| 2: [BodyStatement] BodyStatement
@@ -945,27 +960,27 @@ calls/calls.rb:
# 308| 2: [Identifier] super
# 309| 3: [ReservedWord] end
# 310| 3: [ReservedWord] end
# 313| 91: [Call] Call
# 313| 92: [Call] Call
# 313| 0: [Identifier] foo
# 313| 1: [ReservedWord] .
# 313| 2: [ArgumentList] ArgumentList
# 313| 0: [ReservedWord] (
# 313| 1: [ReservedWord] )
# 314| 92: [Call] Call
# 314| 93: [Call] Call
# 314| 0: [Identifier] foo
# 314| 1: [ReservedWord] .
# 314| 2: [ArgumentList] ArgumentList
# 314| 0: [ReservedWord] (
# 314| 1: [Integer] 1
# 314| 2: [ReservedWord] )
# 317| 93: [Assignment] Assignment
# 317| 94: [Assignment] Assignment
# 317| 0: [Call] Call
# 317| 0: [Self] self
# 317| 1: [ReservedWord] .
# 317| 2: [Identifier] foo
# 317| 1: [ReservedWord] =
# 317| 2: [Integer] 10
# 318| 94: [Assignment] Assignment
# 318| 95: [Assignment] Assignment
# 318| 0: [ElementReference] ElementReference
# 318| 0: [Identifier] foo
# 318| 1: [ReservedWord] [
@@ -973,7 +988,7 @@ calls/calls.rb:
# 318| 3: [ReservedWord] ]
# 318| 1: [ReservedWord] =
# 318| 2: [Integer] 10
# 319| 95: [Assignment] Assignment
# 319| 96: [Assignment] Assignment
# 319| 0: [LeftAssignmentList] LeftAssignmentList
# 319| 0: [Call] Call
# 319| 0: [Self] self
@@ -1003,7 +1018,7 @@ calls/calls.rb:
# 319| 6: [ReservedWord] ,
# 319| 7: [Integer] 4
# 319| 8: [ReservedWord] ]
# 320| 96: [Assignment] Assignment
# 320| 97: [Assignment] Assignment
# 320| 0: [LeftAssignmentList] LeftAssignmentList
# 320| 0: [Identifier] a
# 320| 1: [ReservedWord] ,
@@ -1023,14 +1038,14 @@ calls/calls.rb:
# 320| 4: [ReservedWord] ,
# 320| 5: [Integer] 3
# 320| 6: [ReservedWord] ]
# 321| 97: [OperatorAssignment] OperatorAssignment
# 321| 98: [OperatorAssignment] OperatorAssignment
# 321| 0: [Call] Call
# 321| 0: [Self] self
# 321| 1: [ReservedWord] .
# 321| 2: [Identifier] count
# 321| 1: [ReservedWord] +=
# 321| 2: [Integer] 1
# 322| 98: [OperatorAssignment] OperatorAssignment
# 322| 99: [OperatorAssignment] OperatorAssignment
# 322| 0: [ElementReference] ElementReference
# 322| 0: [Identifier] foo
# 322| 1: [ReservedWord] [
@@ -1038,7 +1053,7 @@ calls/calls.rb:
# 322| 3: [ReservedWord] ]
# 322| 1: [ReservedWord] +=
# 322| 2: [Integer] 1
# 323| 99: [OperatorAssignment] OperatorAssignment
# 323| 100: [OperatorAssignment] OperatorAssignment
# 323| 0: [ElementReference] ElementReference
# 323| 0: [Call] Call
# 323| 0: [Identifier] foo
@@ -1062,12 +1077,12 @@ calls/calls.rb:
# 323| 7: [ReservedWord] ]
# 323| 1: [ReservedWord] *=
# 323| 2: [Integer] 2
# 326| 100: [Method] Method
# 326| 101: [Method] Method
# 326| 0: [ReservedWord] def
# 326| 1: [Identifier] foo
# 326| 2: [ReservedWord] =
# 326| 3: [Identifier] bar
# 327| 101: [Method] Method
# 327| 102: [Method] Method
# 327| 0: [ReservedWord] def
# 327| 1: [Identifier] foo
# 327| 2: [MethodParameters] MethodParameters
@@ -1075,7 +1090,7 @@ calls/calls.rb:
# 327| 1: [ReservedWord] )
# 327| 3: [ReservedWord] =
# 327| 4: [Identifier] bar
# 328| 102: [Method] Method
# 328| 103: [Method] Method
# 328| 0: [ReservedWord] def
# 328| 1: [Identifier] foo
# 328| 2: [MethodParameters] MethodParameters
@@ -1084,14 +1099,14 @@ calls/calls.rb:
# 328| 2: [ReservedWord] )
# 328| 3: [ReservedWord] =
# 328| 4: [Identifier] bar
# 329| 103: [SingletonMethod] SingletonMethod
# 329| 104: [SingletonMethod] SingletonMethod
# 329| 0: [ReservedWord] def
# 329| 1: [Constant] Object
# 329| 2: [ReservedWord] .
# 329| 3: [Identifier] foo
# 329| 4: [ReservedWord] =
# 329| 5: [Identifier] bar
# 330| 104: [SingletonMethod] SingletonMethod
# 330| 105: [SingletonMethod] SingletonMethod
# 330| 0: [ReservedWord] def
# 330| 1: [Constant] Object
# 330| 2: [ReservedWord] .
@@ -1102,7 +1117,7 @@ calls/calls.rb:
# 330| 2: [ReservedWord] )
# 330| 5: [ReservedWord] =
# 330| 6: [Identifier] bar
# 331| 105: [Method] Method
# 331| 106: [Method] Method
# 331| 0: [ReservedWord] def
# 331| 1: [Identifier] foo
# 331| 2: [MethodParameters] MethodParameters
@@ -1122,7 +1137,7 @@ calls/calls.rb:
# 331| 1: [StringContent] error
# 331| 2: [ReservedWord] "
# 331| 2: [ReservedWord] )
# 334| 106: [Method] Method
# 334| 107: [Method] Method
# 334| 0: [ReservedWord] def
# 334| 1: [Identifier] foo
# 334| 2: [MethodParameters] MethodParameters
@@ -1139,7 +1154,7 @@ calls/calls.rb:
# 335| 0: [ReservedWord] ...
# 335| 2: [ReservedWord] )
# 336| 4: [ReservedWord] end
# 338| 107: [Method] Method
# 338| 108: [Method] Method
# 338| 0: [ReservedWord] def
# 338| 1: [Identifier] foo
# 338| 2: [MethodParameters] MethodParameters
@@ -1162,7 +1177,7 @@ calls/calls.rb:
# 339| 0: [ReservedWord] ...
# 339| 4: [ReservedWord] )
# 340| 4: [ReservedWord] end
# 343| 108: [For] For
# 343| 109: [For] For
# 343| 0: [ReservedWord] for
# 343| 1: [LeftAssignmentList] LeftAssignmentList
# 343| 0: [Identifier] x
@@ -1202,7 +1217,7 @@ calls/calls.rb:
# 344| 3: [ReservedWord] ,
# 344| 4: [Identifier] z
# 345| 1: [ReservedWord] end
# 347| 109: [Call] Call
# 347| 110: [Call] Call
# 347| 0: [Identifier] foo
# 347| 1: [ArgumentList] ArgumentList
# 347| 0: [ReservedWord] (
@@ -1211,7 +1226,7 @@ calls/calls.rb:
# 347| 1: [ReservedWord] :
# 347| 2: [Integer] 42
# 347| 2: [ReservedWord] )
# 348| 110: [Call] Call
# 348| 111: [Call] Call
# 348| 0: [Identifier] foo
# 348| 1: [ArgumentList] ArgumentList
# 348| 0: [ReservedWord] (
@@ -1223,7 +1238,7 @@ calls/calls.rb:
# 348| 0: [HashKeySymbol] novar
# 348| 1: [ReservedWord] :
# 348| 4: [ReservedWord] )
# 349| 111: [Call] Call
# 349| 112: [Call] Call
# 349| 0: [Identifier] foo
# 349| 1: [ArgumentList] ArgumentList
# 349| 0: [ReservedWord] (
@@ -1232,7 +1247,7 @@ calls/calls.rb:
# 349| 1: [ReservedWord] :
# 349| 2: [Integer] 42
# 349| 2: [ReservedWord] )
# 350| 112: [Call] Call
# 350| 113: [Call] Call
# 350| 0: [Identifier] foo
# 350| 1: [ArgumentList] ArgumentList
# 350| 0: [ReservedWord] (
@@ -1240,11 +1255,11 @@ calls/calls.rb:
# 350| 0: [HashKeySymbol] X
# 350| 1: [ReservedWord] :
# 350| 2: [ReservedWord] )
# 353| 113: [Assignment] Assignment
# 353| 114: [Assignment] Assignment
# 353| 0: [Identifier] y
# 353| 1: [ReservedWord] =
# 353| 2: [Integer] 1
# 354| 114: [Assignment] Assignment
# 354| 115: [Assignment] Assignment
# 354| 0: [Identifier] one
# 354| 1: [ReservedWord] =
# 354| 2: [Lambda] Lambda
@@ -1258,7 +1273,7 @@ calls/calls.rb:
# 354| 1: [BlockBody] BlockBody
# 354| 0: [Identifier] y
# 354| 2: [ReservedWord] }
# 355| 115: [Assignment] Assignment
# 355| 116: [Assignment] Assignment
# 355| 0: [Identifier] f
# 355| 1: [ReservedWord] =
# 355| 2: [Lambda] Lambda
@@ -1275,7 +1290,7 @@ calls/calls.rb:
# 355| 1: [ArgumentList] ArgumentList
# 355| 0: [Identifier] x
# 355| 2: [ReservedWord] }
# 356| 116: [Assignment] Assignment
# 356| 117: [Assignment] Assignment
# 356| 0: [Identifier] g
# 356| 1: [ReservedWord] =
# 356| 2: [Lambda] Lambda
@@ -1289,7 +1304,7 @@ calls/calls.rb:
# 356| 1: [BlockBody] BlockBody
# 356| 0: [Identifier] unknown_call
# 356| 2: [ReservedWord] }
# 357| 117: [Assignment] Assignment
# 357| 118: [Assignment] Assignment
# 357| 0: [Identifier] h
# 357| 1: [ReservedWord] =
# 357| 2: [Lambda] Lambda
@@ -1305,19 +1320,19 @@ calls/calls.rb:
# 359| 1: [Identifier] y
# 360| 2: [Identifier] unknown_call
# 361| 2: [ReservedWord] end
# 364| 118: [Call] Call
# 364| 119: [Call] Call
# 364| 0: [Identifier] list
# 364| 1: [ReservedWord] .
# 364| 2: [Identifier] empty?
# 365| 119: [Call] Call
# 365| 120: [Call] Call
# 365| 0: [Identifier] list
# 365| 1: [ReservedWord] &.
# 365| 2: [Identifier] empty?
# 366| 120: [Call] Call
# 366| 121: [Call] Call
# 366| 0: [Identifier] list
# 366| 1: [ReservedWord] ::
# 366| 2: [Identifier] empty?
# 367| 121: [Call] Call
# 367| 122: [Call] Call
# 367| 0: [Identifier] foo
# 367| 1: [ReservedWord] &.
# 367| 2: [Identifier] bar

View File

@@ -282,6 +282,9 @@ callsWithReceiver
| calls.rb:251:8:251:10 | call to bar | calls.rb:251:8:251:10 | self |
| calls.rb:254:8:254:13 | call to foo | calls.rb:254:8:254:8 | X |
| calls.rb:255:8:255:13 | call to bar | calls.rb:255:8:255:8 | X |
| calls.rb:258:8:258:10 | call to foo | calls.rb:258:8:258:10 | self |
| calls.rb:258:13:258:18 | call to bar | calls.rb:258:13:258:13 | X |
| calls.rb:259:8:259:10 | call to baz | calls.rb:259:8:259:10 | self |
| calls.rb:263:1:263:3 | call to foo | calls.rb:263:1:263:3 | self |
| calls.rb:263:12:263:14 | call to bar | calls.rb:263:12:263:14 | self |
| calls.rb:264:1:264:6 | call to foo | calls.rb:264:1:264:1 | X |

View File

@@ -254,10 +254,10 @@ begin
rescue X::foo
ensure X::bar
end
begin
rescue foo, X::bar
ensure baz
end
# rescue-modifier body and handler
foo rescue bar