Skip to content

Commit edbba85

Browse files
committed
Ruby: add one-line pattern matches to AST
1 parent e390ca5 commit edbba85

File tree

4 files changed

+112
-17
lines changed

4 files changed

+112
-17
lines changed

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

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,88 @@ class InClause extends AstNode, TInClause {
545545
}
546546
}
547547

548+
/**
549+
* A one-line pattern match using the `=>` operator. For example:
550+
* ```rb
551+
* foo => Point{ x:, y: }
552+
* ```
553+
*/
554+
class MatchPattern extends Expr, TMatchPattern {
555+
private Ruby::MatchPattern g;
556+
557+
MatchPattern() { this = TMatchPattern(g) }
558+
559+
final override string getAPrimaryQlClass() { result = "MatchPattern" }
560+
561+
/**
562+
* Gets the expression being compared, if any. For example, `foo` in the following example.
563+
* ```rb
564+
* case foo => Point{ x:, y: }
565+
* ```
566+
*/
567+
final Expr getValue() { toGenerated(result) = g.getValue() }
568+
569+
/**
570+
* Gets the pattern in this `=>` expression. In the
571+
* following example, the pattern is `Point{ x:, y: }`.
572+
* ```rb
573+
* foo => Point{ x:, y: }
574+
* ```
575+
*/
576+
final CasePattern getPattern() { toGenerated(result) = g.getPattern() }
577+
578+
final override string toString() { result = "... => ..." }
579+
580+
final override AstNode getAChild(string pred) {
581+
result = super.getAChild(pred)
582+
or
583+
pred = "getPattern" and result = this.getPattern()
584+
or
585+
pred = "getValue" and result = this.getValue()
586+
}
587+
}
588+
589+
/**
590+
* A one-line pattern match using the `in` operator. For example:
591+
* ```rb
592+
* foo in Point{ x:, y: }
593+
* ```
594+
*/
595+
class TestPattern extends Expr, TTestPattern {
596+
private Ruby::TestPattern g;
597+
598+
TestPattern() { this = TTestPattern(g) }
599+
600+
final override string getAPrimaryQlClass() { result = "TestPattern" }
601+
602+
/**
603+
* Gets the expression being compared, if any. For example, `foo` in the following example.
604+
* ```rb
605+
* case foo in Point{ x:, y: }
606+
* ```
607+
*/
608+
final Expr getValue() { toGenerated(result) = g.getValue() }
609+
610+
/**
611+
* Gets the pattern in this `=>` expression. In the
612+
* following example, the pattern is `Point{ x:, y: }`.
613+
* ```rb
614+
* foo in Point{ x:, y: }
615+
* ```
616+
*/
617+
final CasePattern getPattern() { toGenerated(result) = g.getPattern() }
618+
619+
final override string toString() { result = "... in ..." }
620+
621+
final override AstNode getAChild(string pred) {
622+
result = super.getAChild(pred)
623+
or
624+
pred = "getPattern" and result = this.getPattern()
625+
or
626+
pred = "getValue" and result = this.getValue()
627+
}
628+
}
629+
548630
/**
549631
* A loop. That is, a `for` loop, a `while` or `until` loop, or their
550632
* expression-modifier variants.

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

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ private module Cached {
207207
g instanceof @ruby_binary_or or g instanceof @ruby_binary_pipepipe
208208
} or
209209
TLogicalOrExprSynth(Ast::AstNode parent, int i) { mkSynthChild(LogicalOrExprKind(), parent, i) } or
210+
TMatchPattern(Ruby::MatchPattern g) or
210211
TMethod(Ruby::Method g) or
211212
TMethodCallSynth(Ast::AstNode parent, int i, string name, boolean setter, int arity) {
212213
mkSynthChild(MethodCallKind(name, setter, arity), parent, i)
@@ -305,6 +306,7 @@ private module Cached {
305306
TSubshellLiteral(Ruby::Subshell g) or
306307
TSymbolArrayLiteral(Ruby::SymbolArray g) or
307308
TTernaryIfExpr(Ruby::Conditional g) or
309+
TTestPattern(Ruby::TestPattern g) or
308310
TThen(Ruby::Then g) or
309311
TTokenConstantAccess(Ruby::Constant g) {
310312
// A tree-sitter `constant` token is a read of that constant in any context
@@ -356,22 +358,22 @@ private module Cached {
356358
TIfReal or TIfModifierExpr or TInClause or TInstanceVariableAccessReal or
357359
TIntegerLiteralReal or TKeywordParameter or TLEExpr or TLShiftExprReal or TLTExpr or
358360
TLambda or TLeftAssignmentList or TLine or TLocalVariableAccessReal or
359-
TLogicalAndExprReal or TLogicalOrExprReal or TMethod or TModuleDeclaration or
360-
TModuloExprReal or TMulExprReal or TNEExpr or TNextStmt or TNilLiteralReal or
361-
TNoRegExpMatchExpr or TNotExpr or TOptionalParameter or TPair or TParenthesizedExpr or
362-
TParenthesizedPattern or TRShiftExprReal or TRangeLiteralReal or TRationalLiteral or
363-
TRedoStmt or TRegExpLiteral or TRegExpMatchExpr or TRegularArrayLiteral or
364-
TRegularMethodCall or TRegularStringLiteral or TRegularSuperCall or TRescueClause or
365-
TRescueModifierExpr or TRetryStmt or TReturnStmt or TScopeResolutionConstantAccess or
366-
TSelfReal or TSimpleParameterReal or TSimpleSymbolLiteral or TSingletonClass or
367-
TSingletonMethod or TSpaceshipExpr or TSplatExprReal or TSplatParameter or
368-
TStringArrayLiteral or TStringConcatenation or TStringEscapeSequenceComponent or
369-
TStringInterpolationComponent or TStringTextComponent or TSubExprReal or TSubshellLiteral or
370-
TSymbolArrayLiteral or TTernaryIfExpr or TThen or TTokenConstantAccess or
371-
TTokenMethodName or TTokenSuperCall or TToplevel or TTrueLiteral or TUnaryMinusExpr or
372-
TUnaryPlusExpr or TUndefStmt or TUnlessExpr or TUnlessModifierExpr or TUntilExpr or
373-
TUntilModifierExpr or TReferencePattern or TWhenClause or TWhileExpr or
374-
TWhileModifierExpr or TYieldCall;
361+
TLogicalAndExprReal or TLogicalOrExprReal or TMethod or TMatchPattern or
362+
TModuleDeclaration or TModuloExprReal or TMulExprReal or TNEExpr or TNextStmt or
363+
TNilLiteralReal or TNoRegExpMatchExpr or TNotExpr or TOptionalParameter or TPair or
364+
TParenthesizedExpr or TParenthesizedPattern or TRShiftExprReal or TRangeLiteralReal or
365+
TRationalLiteral or TRedoStmt or TRegExpLiteral or TRegExpMatchExpr or
366+
TRegularArrayLiteral or TRegularMethodCall or TRegularStringLiteral or TRegularSuperCall or
367+
TRescueClause or TRescueModifierExpr or TRetryStmt or TReturnStmt or
368+
TScopeResolutionConstantAccess or TSelfReal or TSimpleParameterReal or
369+
TSimpleSymbolLiteral or TSingletonClass or TSingletonMethod or TSpaceshipExpr or
370+
TSplatExprReal or TSplatParameter or TStringArrayLiteral or TStringConcatenation or
371+
TStringEscapeSequenceComponent or TStringInterpolationComponent or TStringTextComponent or
372+
TSubExprReal or TSubshellLiteral or TSymbolArrayLiteral or TTernaryIfExpr or TTestPattern or
373+
TThen or TTokenConstantAccess or TTokenMethodName or TTokenSuperCall or TToplevel or
374+
TTrueLiteral or TUnaryMinusExpr or TUnaryPlusExpr or TUndefStmt or TUnlessExpr or
375+
TUnlessModifierExpr or TUntilExpr or TUntilModifierExpr or TReferencePattern or
376+
TWhenClause or TWhileExpr or TWhileModifierExpr or TYieldCall;
375377

376378
class TAstNodeSynth =
377379
TAddExprSynth or TAssignExprSynth or TBitwiseAndExprSynth or TBitwiseOrExprSynth or
@@ -478,6 +480,7 @@ private module Cached {
478480
n = TLogicalOrExprReal(result) or
479481
n = TLShiftExprReal(result) or
480482
n = TLTExpr(result) or
483+
n = TMatchPattern(result) or
481484
n = TMethod(result) or
482485
n = TModuleDeclaration(result) or
483486
n = TModuloExprReal(result) or
@@ -528,6 +531,7 @@ private module Cached {
528531
n = TSubshellLiteral(result) or
529532
n = TSymbolArrayLiteral(result) or
530533
n = TTernaryIfExpr(result) or
534+
n = TTestPattern(result) or
531535
n = TThen(result) or
532536
n = TTokenConstantAccess(result) or
533537
n = TTokenMethodName(result) or
@@ -701,7 +705,8 @@ class TDestructuredLhsExpr = TDestructuredLeftAssignment or TLeftAssignmentList;
701705
class TExpr =
702706
TSelf or TArgumentList or TRescueClause or TRescueModifierExpr or TPair or TStringConcatenation or
703707
TCall or TBlockArgument or TConstantAccess or TControlExpr or TLiteral or TCallable or
704-
TVariableAccess or TStmtSequence or TOperation or TForwardArgument or TDestructuredLhsExpr;
708+
TVariableAccess or TStmtSequence or TOperation or TForwardArgument or TDestructuredLhsExpr or
709+
TMatchPattern or TTestPattern;
705710

706711
class TSplatExpr = TSplatExprReal or TSplatExprSynth;
707712

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ deprecated class TuplePatternImpl extends Ruby::AstNode {
2727
* Holds if `node` is a case pattern.
2828
*/
2929
predicate casePattern(Ruby::AstNode node) {
30+
node = any(Ruby::TestPattern parent).getPattern()
31+
or
32+
node = any(Ruby::MatchPattern parent).getPattern()
33+
or
3034
node = any(Ruby::InClause parent).getPattern()
3135
or
3236
node = any(Ruby::ArrayPattern parent).getChild(_).(Ruby::UnderscorePatternExpr)

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ private module Cached {
247247
or
248248
i = any(Ruby::KeywordParameter x).getValue()
249249
or
250+
i = any(Ruby::MatchPattern x).getValue()
251+
or
250252
i = any(Ruby::Method x).getBody()
251253
or
252254
i = any(Ruby::OperatorAssignment x).getRight()
@@ -285,6 +287,8 @@ private module Cached {
285287
or
286288
i = any(Ruby::Superclass x).getChild()
287289
or
290+
i = any(Ruby::TestPattern x).getValue()
291+
or
288292
i = any(Ruby::Then x).getChild(_)
289293
or
290294
i = any(Ruby::Unary x).getOperand()

0 commit comments

Comments
 (0)