1
1
private import codeql.ruby.AST
2
2
private import internal.AST
3
+ private import internal.Control
3
4
private import internal.TreeSitter
4
5
5
6
/**
@@ -308,13 +309,36 @@ class TernaryIfExpr extends ConditionalExpr, TTernaryIfExpr {
308
309
}
309
310
}
310
311
311
- class CaseExpr extends ControlExpr , TCaseExpr {
312
- private Ruby:: Case g ;
313
-
314
- CaseExpr ( ) { this = TCaseExpr ( g ) }
315
-
316
- final override string getAPrimaryQlClass ( ) { result = "CaseExpr" }
317
-
312
+ /**
313
+ * A `case` statement. There are three forms of `case` statements:
314
+ * ```rb
315
+ * # a value-less case expression acting like an if-elsif expression:
316
+ * case
317
+ * when x == 0 then puts "zero"
318
+ * when x > 0 then puts "positive"
319
+ * else puts "negative"
320
+ * end
321
+ *
322
+ * # a case expression that matches a value using `when` clauses:
323
+ * case value
324
+ * when 1, 2 then puts "a is one or two"
325
+ * when 3 then puts "a is three"
326
+ * else puts "I don't know what a is"
327
+ * end
328
+ *
329
+ * # a case expression that matches a value against patterns using `in` clauses:
330
+ * config = {db: {user: 'admin', password: 'abc123'}}
331
+ * case config
332
+ * in db: {user:} # matches subhash and puts matched value in variable user
333
+ * puts "Connect with user '#{user}'"
334
+ * in connection: {username: } unless username == 'admin'
335
+ * puts "Connect with user '#{username}'"
336
+ * else
337
+ * puts "Unrecognized structure of config"
338
+ * end
339
+ * ```
340
+ */
341
+ class CaseExpr extends ControlExpr instanceof CaseExprImpl {
318
342
/**
319
343
* Gets the expression being compared, if any. For example, `foo` in the following example.
320
344
* ```rb
@@ -334,22 +358,25 @@ class CaseExpr extends ControlExpr, TCaseExpr {
334
358
* end
335
359
* ```
336
360
*/
337
- final Expr getValue ( ) { toGenerated ( result ) = g .getValue ( ) }
361
+ final Expr getValue ( ) { result = super .getValue ( ) }
338
362
339
363
/**
340
- * Gets the `n`th branch of this case expression, either a `WhenExpr` or a
341
- * `StmtSequence`.
364
+ * Gets the `n`th branch of this case expression, either a `WhenExpr`, an
365
+ * `InClause`, or a ` StmtSequence`.
342
366
*/
343
- final Expr getBranch ( int n ) { toGenerated ( result ) = g . getChild ( n ) }
367
+ final Expr getBranch ( int n ) { result = super . getBranch ( n ) }
344
368
345
369
/**
346
- * Gets a branch of this case expression, either a `WhenExpr` or an
347
- * `ElseExpr `.
370
+ * Gets a branch of this case expression, either a `WhenExpr`, an
371
+ * `InClause`, or a `StmtSequence `.
348
372
*/
349
373
final Expr getABranch ( ) { result = this .getBranch ( _) }
350
374
375
+ /** Gets the `n`th `when` branch of this case expression. */
376
+ deprecated final WhenExpr getWhenBranch ( int n ) { result = this .getBranch ( n ) }
377
+
351
378
/** Gets a `when` branch of this case expression. */
352
- final WhenExpr getAWhenBranch ( ) { result = this .getABranch ( ) }
379
+ deprecated final WhenExpr getAWhenBranch ( ) { result = this .getABranch ( ) }
353
380
354
381
/** Gets the `else` branch of this case expression, if any. */
355
382
final StmtSequence getElseBranch ( ) { result = this .getABranch ( ) }
@@ -359,14 +386,18 @@ class CaseExpr extends ControlExpr, TCaseExpr {
359
386
*/
360
387
final int getNumberOfBranches ( ) { result = count ( this .getBranch ( _) ) }
361
388
389
+ final override string getAPrimaryQlClass ( ) { result = "CaseExpr" }
390
+
362
391
final override string toString ( ) { result = "case ..." }
363
392
364
393
override AstNode getAChild ( string pred ) {
365
- result = super .getAChild ( pred )
394
+ result = ControlExpr . super .getAChild ( pred )
366
395
or
367
396
pred = "getValue" and result = this .getValue ( )
368
397
or
369
398
pred = "getBranch" and result = this .getBranch ( _)
399
+ or
400
+ pred = "getElseBranch" and result = this .getElseBranch ( )
370
401
}
371
402
}
372
403
@@ -422,6 +453,81 @@ class WhenExpr extends Expr, TWhenExpr {
422
453
}
423
454
}
424
455
456
+ /**
457
+ * An `in` clause of a `case` expression.
458
+ * ```rb
459
+ * case foo
460
+ * in [ a ] then a
461
+ * end
462
+ * ```
463
+ */
464
+ class InClause extends Expr , TInClause {
465
+ private Ruby:: InClause g ;
466
+
467
+ InClause ( ) { this = TInClause ( g ) }
468
+
469
+ final override string getAPrimaryQlClass ( ) { result = "InClause" }
470
+
471
+ /** Gets the body of this case-in expression. */
472
+ final Stmt getBody ( ) { toGenerated ( result ) = g .getBody ( ) }
473
+
474
+ /**
475
+ * Gets the pattern in this case-in expression. In the
476
+ * following example, the pattern is `Point{ x:, y: }`.
477
+ * ```rb
478
+ * case foo
479
+ * in Point{ x:, y: }
480
+ * x + y
481
+ * end
482
+ * ```
483
+ */
484
+ final CasePattern getPattern ( ) { toGenerated ( result ) = g .getPattern ( ) }
485
+
486
+ /**
487
+ * Gets the pattern guard condition in this case-in expression. In the
488
+ * following example, there are two pattern guard conditions `x > 10` and `x < 0`.
489
+ * ```rb
490
+ * case foo
491
+ * in [ x ] if x > 10 then ...
492
+ * in [ x ] unless x < 0 then ...
493
+ * end
494
+ * ```
495
+ */
496
+ final Expr getCondition ( ) { toGenerated ( result ) = g .getGuard ( ) .getAFieldOrChild ( ) }
497
+
498
+ /**
499
+ * Holds if the pattern guard in this case-in expression is an `if` condition. For example:
500
+ * ```rb
501
+ * case foo
502
+ * in [ x ] if x > 10 then ...
503
+ * end
504
+ * ```
505
+ */
506
+ predicate hasIfCondition ( ) { g .getGuard ( ) instanceof Ruby:: IfGuard }
507
+
508
+ /**
509
+ * Holds if the pattern guard in this case-in expression is an `unless` condition. For example:
510
+ * ```rb
511
+ * case foo
512
+ * in [ x ] unless x < 10 then ...
513
+ * end
514
+ * ```
515
+ */
516
+ predicate hasUnlessCondition ( ) { g .getGuard ( ) instanceof Ruby:: UnlessGuard }
517
+
518
+ final override string toString ( ) { result = "in ... then ..." }
519
+
520
+ override AstNode getAChild ( string pred ) {
521
+ result = super .getAChild ( pred )
522
+ or
523
+ pred = "getBody" and result = this .getBody ( )
524
+ or
525
+ pred = "getPattern" and result = this .getPattern ( )
526
+ or
527
+ pred = "getCondition" and result = this .getCondition ( )
528
+ }
529
+ }
530
+
425
531
/**
426
532
* A loop. That is, a `for` loop, a `while` or `until` loop, or their
427
533
* expression-modifier variants.
0 commit comments