Skip to content

Commit 7d66ec0

Browse files
committed
Ruby: Clarify AST.
1 parent 6fbb572 commit 7d66ec0

2 files changed

Lines changed: 25 additions & 20 deletions

File tree

ruby/ql/lib/codeql/ruby/ast/Expr.qll

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ class Pair extends Expr instanceof PairImpl {
281281
}
282282

283283
/**
284-
* A list of exception types in a rescue clause. For example, the exception list
284+
* A disjunctive exception pattern match in a rescue clause. For example, the exception list
285285
* `FirstError, SecondError` in:
286286
* ```rb
287287
* begin
@@ -290,7 +290,6 @@ class Pair extends Expr instanceof PairImpl {
290290
* handle_error(e)
291291
* end
292292
* ```
293-
* This node is only present when there are two or more exceptions in the list.
294293
*/
295294
class ExceptionList extends Expr, TExceptionList {
296295
private Ruby::Exceptions g;
@@ -327,16 +326,18 @@ class RescueClause extends Expr, TRescueClause {
327326

328327
final override string getAPrimaryQlClass() { result = "RescueClause" }
329328

329+
/** Gets the exception list pattern when there are multiple exception expressions. */
330+
private ExceptionList getExceptions() { result = TExceptionList(g.getExceptions()) }
331+
330332
/**
331333
* Gets the `n`th exception to match, if any. For example `FirstError` or `SecondError` in:
332334
* ```rb
333335
* begin
334-
* do_something
336+
* do_something
335337
* rescue FirstError, SecondError => e
336338
* handle_error(e)
337339
* end
338340
* ```
339-
* When there are two or more exceptions, use `getExceptions()` to get the `ExceptionList` node.
340341
*/
341342
final Expr getException(int n) {
342343
// 0 or 1 exception: no ExceptionList node, access directly
@@ -351,7 +352,7 @@ class RescueClause extends Expr, TRescueClause {
351352
* Gets an exception to match, if any. For example `FirstError` or `SecondError` in:
352353
* ```rb
353354
* begin
354-
* do_something
355+
* do_something
355356
* rescue FirstError, SecondError => e
356357
* handle_error(e)
357358
* end
@@ -360,24 +361,34 @@ class RescueClause extends Expr, TRescueClause {
360361
final Expr getAnException() { result = this.getException(_) }
361362

362363
/**
363-
* Gets the exception list node when there are two or more exceptions to match. For example,
364-
* the exception list `FirstError, SecondError` in:
364+
* Gets the exception pattern to match, if any.
365+
*
366+
* This is either a single exception expression, or an `ExceptionList`
367+
* representing a disjunctive match of multiple exceptions when there are two
368+
* or more exceptions expressions.
369+
*
370+
* For example, in the following code, the exception pattern is the
371+
* exception list `FirstError, SecondError`:
365372
* ```rb
366373
* begin
367-
* do_something
374+
* do_something
368375
* rescue FirstError, SecondError => e
369376
* handle_error(e)
370377
* end
371378
* ```
372379
*/
373-
final ExceptionList getExceptions() { result = TExceptionList(g.getExceptions()) }
380+
final Expr getPattern() {
381+
result = this.getExceptions()
382+
or
383+
not exists(this.getExceptions()) and result = this.getAnException()
384+
}
374385

375386
/**
376387
* Gets the variable to which to assign the matched exception, if any.
377388
* For example `err` in:
378389
* ```rb
379390
* begin
380-
* do_something
391+
* do_something
381392
* rescue StandardError => err
382393
* handle_error(err)
383394
* end
@@ -395,13 +406,7 @@ class RescueClause extends Expr, TRescueClause {
395406
final override AstNode getAChild(string pred) {
396407
result = super.getAChild(pred)
397408
or
398-
// For 0 or 1 exceptions, exceptions are direct children
399-
not exists(this.getExceptions()) and
400-
pred = "getException" and
401-
result = this.getException(_)
402-
or
403-
// For 2+ exceptions, the ExceptionList node is the direct child
404-
pred = "getExceptions" and result = this.getExceptions()
409+
pred = "getPattern" and result = this.getPattern()
405410
or
406411
pred = "getVariableExpr" and result = this.getVariableExpr()
407412
or

ruby/ql/test/library-tests/ast/Ast.expected

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -433,21 +433,21 @@ calls/calls.rb:
433433
# 246| getReceiver: [ConstantReadAccess] X
434434
# 249| getStmt: [BeginExpr] begin ...
435435
# 250| getRescue: [RescueClause] rescue ...
436-
# 250| getException: [MethodCall] call to foo
436+
# 250| getPattern: [MethodCall] call to foo
437437
# 250| getReceiver: [SelfVariableAccess] self
438438
# 251| getEnsure: [StmtSequence] ensure ...
439439
# 251| getStmt: [MethodCall] call to bar
440440
# 251| getReceiver: [SelfVariableAccess] self
441441
# 253| getStmt: [BeginExpr] begin ...
442442
# 254| getRescue: [RescueClause] rescue ...
443-
# 254| getException: [MethodCall] call to foo
443+
# 254| getPattern: [MethodCall] call to foo
444444
# 254| getReceiver: [ConstantReadAccess] X
445445
# 255| getEnsure: [StmtSequence] ensure ...
446446
# 255| getStmt: [MethodCall] call to bar
447447
# 255| getReceiver: [ConstantReadAccess] X
448448
# 257| getStmt: [BeginExpr] begin ...
449449
# 258| getRescue: [RescueClause] rescue ...
450-
# 258| getExceptions: [ExceptionList] ..., ...
450+
# 258| getPattern: [ExceptionList] ..., ...
451451
# 258| getException: [MethodCall] call to foo
452452
# 258| getReceiver: [SelfVariableAccess] self
453453
# 258| getException: [MethodCall] call to bar

0 commit comments

Comments
 (0)