11private import codeql.ruby.AST
22private import internal.AST
3+ private import internal.Control
34private import internal.TreeSitter
45
56/**
@@ -308,13 +309,36 @@ class TernaryIfExpr extends ConditionalExpr, TTernaryIfExpr {
308309 }
309310}
310311
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 {
318342 /**
319343 * Gets the expression being compared, if any. For example, `foo` in the following example.
320344 * ```rb
@@ -334,22 +358,25 @@ class CaseExpr extends ControlExpr, TCaseExpr {
334358 * end
335359 * ```
336360 */
337- final Expr getValue ( ) { toGenerated ( result ) = g .getValue ( ) }
361+ final Expr getValue ( ) { result = super .getValue ( ) }
338362
339363 /**
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`.
342366 */
343- final Expr getBranch ( int n ) { toGenerated ( result ) = g . getChild ( n ) }
367+ final Expr getBranch ( int n ) { result = super . getBranch ( n ) }
344368
345369 /**
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 `.
348372 */
349373 final Expr getABranch ( ) { result = this .getBranch ( _) }
350374
375+ /** Gets the `n`th `when` branch of this case expression. */
376+ deprecated final WhenExpr getWhenBranch ( int n ) { result = this .getBranch ( n ) }
377+
351378 /** Gets a `when` branch of this case expression. */
352- final WhenExpr getAWhenBranch ( ) { result = this .getABranch ( ) }
379+ deprecated final WhenExpr getAWhenBranch ( ) { result = this .getABranch ( ) }
353380
354381 /** Gets the `else` branch of this case expression, if any. */
355382 final StmtSequence getElseBranch ( ) { result = this .getABranch ( ) }
@@ -359,14 +386,18 @@ class CaseExpr extends ControlExpr, TCaseExpr {
359386 */
360387 final int getNumberOfBranches ( ) { result = count ( this .getBranch ( _) ) }
361388
389+ final override string getAPrimaryQlClass ( ) { result = "CaseExpr" }
390+
362391 final override string toString ( ) { result = "case ..." }
363392
364393 override AstNode getAChild ( string pred ) {
365- result = super .getAChild ( pred )
394+ result = ControlExpr . super .getAChild ( pred )
366395 or
367396 pred = "getValue" and result = this .getValue ( )
368397 or
369398 pred = "getBranch" and result = this .getBranch ( _)
399+ or
400+ pred = "getElseBranch" and result = this .getElseBranch ( )
370401 }
371402}
372403
@@ -422,6 +453,81 @@ class WhenExpr extends Expr, TWhenExpr {
422453 }
423454}
424455
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+
425531/**
426532 * A loop. That is, a `for` loop, a `while` or `until` loop, or their
427533 * expression-modifier variants.
0 commit comments