Skip to content

Commit 4af0c4b

Browse files
committed
Ruby: desugar one-line pattern matches
1 parent 3c15fd2 commit 4af0c4b

File tree

6 files changed

+213
-31
lines changed

6 files changed

+213
-31
lines changed

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

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -478,15 +478,11 @@ class WhenClause extends AstNode, TWhenClause {
478478
* end
479479
* ```
480480
*/
481-
class InClause extends AstNode, TInClause {
482-
private Ruby::InClause g;
483-
484-
InClause() { this = TInClause(g) }
485-
481+
class InClause extends AstNode instanceof InClauseImpl {
486482
final override string getAPrimaryQlClass() { result = "InClause" }
487483

488484
/** Gets the body of this case-in expression. */
489-
final Stmt getBody() { toGenerated(result) = g.getBody() }
485+
final Stmt getBody() { result = super.getBody() }
490486

491487
/**
492488
* Gets the pattern in this case-in expression. In the
@@ -498,7 +494,7 @@ class InClause extends AstNode, TInClause {
498494
* end
499495
* ```
500496
*/
501-
final CasePattern getPattern() { toGenerated(result) = g.getPattern() }
497+
final CasePattern getPattern() { result = super.getPattern() }
502498

503499
/**
504500
* Gets the pattern guard condition in this case-in expression. In the
@@ -510,7 +506,7 @@ class InClause extends AstNode, TInClause {
510506
* end
511507
* ```
512508
*/
513-
final Expr getCondition() { toGenerated(result) = g.getGuard().getAFieldOrChild() }
509+
final Expr getCondition() { result = super.getCondition() }
514510

515511
/**
516512
* Holds if the pattern guard in this case-in expression is an `if` condition. For example:
@@ -520,7 +516,7 @@ class InClause extends AstNode, TInClause {
520516
* end
521517
* ```
522518
*/
523-
predicate hasIfCondition() { g.getGuard() instanceof Ruby::IfGuard }
519+
predicate hasIfCondition() { super.hasIfCondition() }
524520

525521
/**
526522
* Holds if the pattern guard in this case-in expression is an `unless` condition. For example:
@@ -530,12 +526,12 @@ class InClause extends AstNode, TInClause {
530526
* end
531527
* ```
532528
*/
533-
predicate hasUnlessCondition() { g.getGuard() instanceof Ruby::UnlessGuard }
529+
predicate hasUnlessCondition() { super.hasUnlessCondition() }
534530

535531
final override string toString() { result = "in ... then ..." }
536532

537533
final override AstNode getAChild(string pred) {
538-
result = super.getAChild(pred)
534+
result = AstNode.super.getAChild(pred)
539535
or
540536
pred = "getBody" and result = this.getBody()
541537
or

ruby/ql/lib/codeql/ruby/ast/internal/AST.qll

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,16 @@ private module Cached {
9797
} or
9898
TBlockArgument(Ruby::BlockArgument g) or
9999
TBlockParameter(Ruby::BlockParameter g) or
100+
TBooleanLiteralSynth(Ast::AstNode parent, int i, boolean value) {
101+
mkSynthChild(BooleanLiteralKind(value), parent, i)
102+
} or
100103
TBraceBlockSynth(Ast::AstNode parent, int i) { mkSynthChild(BraceBlockKind(), parent, i) } or
101104
TBraceBlockReal(Ruby::Block g) { not g.getParent() instanceof Ruby::Lambda } or
102105
TBreakStmt(Ruby::Break g) or
103106
TCaseEqExpr(Ruby::Binary g) { g instanceof @ruby_binary_equalequalequal } or
104107
TCaseExpr(Ruby::Case g) or
105-
TCaseMatch(Ruby::CaseMatch g) or
108+
TCaseMatchReal(Ruby::CaseMatch g) or
109+
TCaseMatchSynth(Ast::AstNode parent, int i) { mkSynthChild(CaseMatchKind(), parent, i) } or
106110
TCharacterLiteral(Ruby::Character g) or
107111
TClassDeclaration(Ruby::Class g) or
108112
TClassVariableAccessReal(Ruby::ClassVariable g, Ast::ClassVariable v) {
@@ -130,6 +134,7 @@ private module Cached {
130134
TDoBlock(Ruby::DoBlock g) { not g.getParent() instanceof Ruby::Lambda } or
131135
TElementReference(Ruby::ElementReference g) or
132136
TElse(Ruby::Else g) or
137+
TElseSynth(Ast::AstNode parent, int i) { mkSynthChild(ElseKind(), parent, i) } or
133138
TElsif(Ruby::Elsif g) or
134139
TEmptyStmt(Ruby::EmptyStatement g) or
135140
TEncoding(Ruby::Encoding g) or
@@ -168,7 +173,8 @@ private module Cached {
168173
TIfReal(Ruby::If g) or
169174
TIfSynth(Ast::AstNode parent, int i) { mkSynthChild(IfKind(), parent, i) } or
170175
TIfModifierExpr(Ruby::IfModifier g) or
171-
TInClause(Ruby::InClause g) or
176+
TInClauseReal(Ruby::InClause g) or
177+
TInClauseSynth(Ast::AstNode parent, int i) { mkSynthChild(InClauseKind(), parent, i) } or
172178
TInstanceVariableAccessReal(Ruby::InstanceVariable g, Ast::InstanceVariable v) {
173179
InstanceVariableAccess::range(g, v)
174180
} or
@@ -346,7 +352,7 @@ private module Cached {
346352
TAssignMulExpr or TAssignRShiftExpr or TAssignSubExpr or TBareStringLiteral or
347353
TBareSymbolLiteral or TBeginBlock or TBeginExpr or TBitwiseAndExprReal or
348354
TBitwiseOrExprReal or TBitwiseXorExprReal or TBlockArgument or TBlockParameter or
349-
TBraceBlockReal or TBreakStmt or TCaseEqExpr or TCaseExpr or TCaseMatch or
355+
TBraceBlockReal or TBreakStmt or TCaseEqExpr or TCaseExpr or TCaseMatchReal or
350356
TCharacterLiteral or TClassDeclaration or TClassVariableAccessReal or TComplementExpr or
351357
TComplexLiteral or TDefinedExpr or TDelimitedSymbolLiteral or TDestructuredLeftAssignment or
352358
TDestructuredParameter or TDivExprReal or TDo or TDoBlock or TElementReference or TElse or
@@ -355,7 +361,7 @@ private module Cached {
355361
TForwardArgument or TGEExpr or TGTExpr or TGlobalVariableAccessReal or
356362
THashKeySymbolLiteral or THashLiteral or THashPattern or THashSplatExpr or
357363
THashSplatNilParameter or THashSplatParameter or THereDoc or TIdentifierMethodCall or
358-
TIfReal or TIfModifierExpr or TInClause or TInstanceVariableAccessReal or
364+
TIfReal or TIfModifierExpr or TInClauseReal or TInstanceVariableAccessReal or
359365
TIntegerLiteralReal or TKeywordParameter or TLEExpr or TLShiftExprReal or TLTExpr or
360366
TLambda or TLeftAssignmentList or TLine or TLocalVariableAccessReal or
361367
TLogicalAndExprReal or TLogicalOrExprReal or TMethod or TMatchPattern or
@@ -377,14 +383,14 @@ private module Cached {
377383

378384
class TAstNodeSynth =
379385
TAddExprSynth or TAssignExprSynth or TBitwiseAndExprSynth or TBitwiseOrExprSynth or
380-
TBitwiseXorExprSynth or TBraceBlockSynth or TClassVariableAccessSynth or
381-
TConstantReadAccessSynth or TConstantWriteAccessSynth or TDivExprSynth or
382-
TExponentExprSynth or TGlobalVariableAccessSynth or TIfSynth or
383-
TInstanceVariableAccessSynth or TIntegerLiteralSynth or TLShiftExprSynth or
384-
TLocalVariableAccessSynth or TLogicalAndExprSynth or TLogicalOrExprSynth or
385-
TMethodCallSynth or TModuloExprSynth or TMulExprSynth or TNilLiteralSynth or
386-
TRShiftExprSynth or TRangeLiteralSynth or TSelfSynth or TSimpleParameterSynth or
387-
TSplatExprSynth or TStmtSequenceSynth or TSubExprSynth;
386+
TBitwiseXorExprSynth or TBraceBlockSynth or TBooleanLiteralSynth or TCaseMatchSynth or
387+
TClassVariableAccessSynth or TConstantReadAccessSynth or TConstantWriteAccessSynth or
388+
TDivExprSynth or TElseSynth or TExponentExprSynth or TGlobalVariableAccessSynth or
389+
TIfSynth or TInClauseSynth or TInstanceVariableAccessSynth or TIntegerLiteralSynth or
390+
TLShiftExprSynth or TLocalVariableAccessSynth or TLogicalAndExprSynth or
391+
TLogicalOrExprSynth or TMethodCallSynth or TModuloExprSynth or TMulExprSynth or
392+
TNilLiteralSynth or TRShiftExprSynth or TRangeLiteralSynth or TSelfSynth or
393+
TSimpleParameterSynth or TSplatExprSynth or TStmtSequenceSynth or TSubExprSynth;
388394

389395
/**
390396
* Gets the underlying TreeSitter entity for a given AST node. This does not
@@ -426,7 +432,7 @@ private module Cached {
426432
n = TBreakStmt(result) or
427433
n = TCaseEqExpr(result) or
428434
n = TCaseExpr(result) or
429-
n = TCaseMatch(result) or
435+
n = TCaseMatchReal(result) or
430436
n = TCharacterLiteral(result) or
431437
n = TClassDeclaration(result) or
432438
n = TClassVariableAccessReal(result, _) or
@@ -467,7 +473,7 @@ private module Cached {
467473
n = TIdentifierMethodCall(result) or
468474
n = TIfModifierExpr(result) or
469475
n = TIfReal(result) or
470-
n = TInClause(result) or
476+
n = TInClauseReal(result) or
471477
n = TInstanceVariableAccessReal(result, _) or
472478
n = TIntegerLiteralReal(result) or
473479
n = TKeywordParameter(result) or
@@ -567,8 +573,12 @@ private module Cached {
567573
or
568574
result = TBitwiseXorExprSynth(parent, i)
569575
or
576+
result = TBooleanLiteralSynth(parent, i, _)
577+
or
570578
result = TBraceBlockSynth(parent, i)
571579
or
580+
result = TCaseMatchSynth(parent, i)
581+
or
572582
result = TClassVariableAccessSynth(parent, i, _)
573583
or
574584
result = TConstantReadAccessSynth(parent, i, _)
@@ -577,12 +587,16 @@ private module Cached {
577587
or
578588
result = TDivExprSynth(parent, i)
579589
or
590+
result = TElseSynth(parent, i)
591+
or
580592
result = TExponentExprSynth(parent, i)
581593
or
582594
result = TGlobalVariableAccessSynth(parent, i, _)
583595
or
584596
result = TIfSynth(parent, i)
585597
or
598+
result = TInClauseSynth(parent, i)
599+
or
586600
result = TInstanceVariableAccessSynth(parent, i, _)
587601
or
588602
result = TIntegerLiteralSynth(parent, i, _)
@@ -673,8 +687,12 @@ TAstNodeReal fromGenerated(Ruby::AstNode n) { n = toGenerated(result) }
673687

674688
class TCall = TMethodCall or TYieldCall;
675689

690+
class TCaseMatch = TCaseMatchReal or TCaseMatchSynth;
691+
676692
class TCase = TCaseExpr or TCaseMatch;
677693

694+
class TInClause = TInClauseReal or TInClauseSynth;
695+
678696
class TMethodCall =
679697
TMethodCallSynth or TIdentifierMethodCall or TRegularMethodCall or TElementReference or
680698
TSuperCall or TUnaryOperation or TBinaryOperation;
@@ -685,7 +703,7 @@ class TConstantAccess =
685703
TTokenConstantAccess or TScopeResolutionConstantAccess or TNamespace or
686704
TConstantReadAccessSynth or TConstantWriteAccessSynth;
687705

688-
class TControlExpr = TConditionalExpr or TCaseExpr or TCaseMatch or TLoop;
706+
class TControlExpr = TConditionalExpr or TCaseExpr or TCaseMatchReal or TCaseMatchSynth or TLoop;
689707

690708
class TConditionalExpr =
691709
TIfExpr or TUnlessExpr or TIfModifierExpr or TUnlessModifierExpr or TTernaryIfExpr;
@@ -711,8 +729,9 @@ class TExpr =
711729
class TSplatExpr = TSplatExprReal or TSplatExprSynth;
712730

713731
class TStmtSequence =
714-
TBeginBlock or TEndBlock or TThen or TElse or TDo or TEnsure or TStringInterpolationComponent or
715-
TBlock or TBodyStmt or TParenthesizedExpr or TStmtSequenceSynth;
732+
TBeginBlock or TEndBlock or TThen or TElse or TElseSynth or TDo or TEnsure or
733+
TStringInterpolationComponent or TBlock or TBodyStmt or TParenthesizedExpr or
734+
TStmtSequenceSynth;
716735

717736
class TBodyStmt = TBeginExpr or TModuleBase or TMethod or TLambda or TDoBlock or TSingletonMethod;
718737

@@ -727,7 +746,7 @@ class TNumericLiteral = TIntegerLiteral or TFloatLiteral or TRationalLiteral or
727746

728747
class TIntegerLiteral = TIntegerLiteralReal or TIntegerLiteralSynth;
729748

730-
class TBooleanLiteral = TTrueLiteral or TFalseLiteral;
749+
class TBooleanLiteral = TTrueLiteral or TFalseLiteral or TBooleanLiteralSynth;
731750

732751
class TStringTextComponentNonRegexp =
733752
TStringTextComponentNonRegexpStringOrHeredocContent or

ruby/ql/lib/codeql/ruby/ast/internal/Control.qll

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ class CaseWhenClause extends CaseExprImpl, TCaseExpr {
2121
}
2222
}
2323

24-
class CaseMatch extends CaseExprImpl, TCaseMatch {
24+
class CaseMatch extends CaseExprImpl, TCaseMatchReal {
2525
private Ruby::CaseMatch g;
2626

27-
CaseMatch() { this = TCaseMatch(g) }
27+
CaseMatch() { this = TCaseMatchReal(g) }
2828

2929
final override Expr getValue() { toGenerated(result) = g.getValue() }
3030

@@ -34,3 +34,53 @@ class CaseMatch extends CaseExprImpl, TCaseMatch {
3434
n = count(g.getClauses(_)) and toGenerated(result) = g.getElse()
3535
}
3636
}
37+
38+
class CaseMatchSynth extends CaseExprImpl, TCaseMatchSynth {
39+
CaseMatchSynth() { this = TCaseMatchSynth(_, _) }
40+
41+
final override Expr getValue() { synthChild(this, 0, result) }
42+
43+
final override AstNode getBranch(int n) { n >= 0 and synthChild(this, n + 1, result) }
44+
}
45+
46+
abstract class InClauseImpl extends AstNode, TInClause {
47+
abstract Stmt getBody();
48+
49+
abstract CasePattern getPattern();
50+
51+
Expr getCondition() { none() }
52+
53+
predicate hasIfCondition() { none() }
54+
55+
predicate hasUnlessCondition() { none() }
56+
}
57+
58+
class InClauseReal extends InClauseImpl, TInClauseReal {
59+
private Ruby::InClause g;
60+
61+
InClauseReal() { this = TInClauseReal(g) }
62+
63+
final override Stmt getBody() { toGenerated(result) = g.getBody() }
64+
65+
final override CasePattern getPattern() { toGenerated(result) = g.getPattern() }
66+
67+
final override Expr getCondition() { toGenerated(result) = g.getGuard().getAFieldOrChild() }
68+
69+
final override predicate hasIfCondition() { g.getGuard() instanceof Ruby::IfGuard }
70+
71+
final override predicate hasUnlessCondition() { g.getGuard() instanceof Ruby::UnlessGuard }
72+
}
73+
74+
class InClauseSynth extends InClauseImpl, TInClauseSynth {
75+
InClauseSynth() { this = TInClauseSynth(_, _) }
76+
77+
final override Stmt getBody() { synthChild(this, 1, result) }
78+
79+
final override CasePattern getPattern() { synthChild(this, 0, result) }
80+
81+
final override Expr getCondition() { none() }
82+
83+
final override predicate hasIfCondition() { none() }
84+
85+
final override predicate hasUnlessCondition() { none() }
86+
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ class Else extends StmtSequence, TElse {
2929
final override string toString() { result = "else ..." }
3030
}
3131

32+
class ElseSynth extends StmtSequence, TElseSynth {
33+
ElseSynth() { this = TElseSynth(_, _) }
34+
35+
override Stmt getStmt(int n) { synthChild(this, n, result) }
36+
37+
final override string toString() { result = "else ..." }
38+
}
39+
3240
class Do extends StmtSequence, TDo {
3341
private Ruby::Do g;
3442

ruby/ql/lib/codeql/ruby/ast/internal/Literal.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ class FalseLiteral extends BooleanLiteralImpl, TFalseLiteral {
149149
final override boolean getValue() { result = false }
150150
}
151151

152+
class BooleanLiteralSynth extends BooleanLiteralImpl, TBooleanLiteralSynth {
153+
final override string toString() { result = this.getValue().toString() }
154+
155+
final override boolean getValue() { this = TBooleanLiteralSynth(_, _, result) }
156+
}
157+
152158
class EncodingLiteralImpl extends Expr, TEncoding {
153159
private Ruby::Encoding g;
154160

0 commit comments

Comments
 (0)