Skip to content

Commit 9ea8b20

Browse files
committed
Ruby: Deprecate Pattern classes
1 parent 1c79d1f commit 9ea8b20

File tree

18 files changed

+267
-139
lines changed

18 files changed

+267
-139
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ class ForExpr extends Loop, TForExpr {
692692
final override StmtSequence getBody() { toGenerated(result) = g.getBody() }
693693

694694
/** Gets the pattern representing the iteration argument. */
695-
final Pattern getPattern() { toGenerated(result) = g.getPattern() }
695+
final LhsExpr getPattern() { toGenerated(result) = g.getPattern() }
696696

697697
/**
698698
* Gets the value being iterated over. In the following example, the result

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

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,83 @@ class ArgumentList extends Expr, TArgumentList {
6666
}
6767
}
6868

69+
private class LhsExpr_ =
70+
TVariableAccess or TTokenConstantAccess or TScopeResolutionConstantAccess or TMethodCall or
71+
TDestructuredLhsExpr;
72+
73+
/**
74+
* A "left-hand-side" (LHS) expression. An `LhsExpr` can occur on the left-hand side of
75+
* operator assignments (`AssignOperation`), on the left-hand side of assignments
76+
* (`AssignExpr`), as patterns in for loops (`ForExpr`), and as exception variables
77+
* in `rescue` clauses (`RescueClause`).
78+
*
79+
* An `LhsExpr` can be a simple variable, a constant, a call, or an element reference:
80+
*
81+
* ```rb
82+
* var = 1
83+
* var += 1
84+
* E = 1
85+
* foo.bar = 1
86+
* foo[0] = 1
87+
* rescue E => var
88+
* ```
89+
*/
90+
class LhsExpr extends Expr, LhsExpr_ {
91+
LhsExpr() { lhsExpr(this) }
92+
93+
/** Gets a variable used in (or introduced by) this LHS. */
94+
Variable getAVariable() { result = this.(VariableAccess).getVariable() }
95+
}
96+
97+
/**
98+
* A "left-hand-side" (LHS) expression of a destructured assignment.
99+
*
100+
* Examples:
101+
* ```rb
102+
* a, self.b = value
103+
* (a, b), c[3] = value
104+
* a, b, *rest, c, d = value
105+
* ```
106+
*/
107+
class DestructuredLhsExpr extends LhsExpr, TDestructuredLhsExpr {
108+
override string getAPrimaryQlClass() { result = "DestructuredLhsExpr" }
109+
110+
private DestructuredLhsExprImpl getImpl() { result = toGenerated(this) }
111+
112+
private Ruby::AstNode getChild(int i) { result = this.getImpl().getChildNode(i) }
113+
114+
/** Gets the `i`th element in this destructured LHS. */
115+
final Expr getElement(int i) {
116+
exists(Ruby::AstNode c | c = this.getChild(i) |
117+
toGenerated(result) = c.(Ruby::RestAssignment).getChild()
118+
or
119+
toGenerated(result) = c
120+
)
121+
}
122+
123+
/** Gets an element in this destructured LHS. */
124+
final Expr getAnElement() { result = this.getElement(_) }
125+
126+
/**
127+
* Gets the index of the element with the `*` marker on it, if it exists.
128+
* In the example below the index is `2`.
129+
* ```rb
130+
* a, b, *rest, c, d = value
131+
* ```
132+
*/
133+
final int getRestIndex() { result = this.getImpl().getRestIndex() }
134+
135+
override Variable getAVariable() {
136+
result = this.getElement(_).(VariableWriteAccess).getVariable()
137+
or
138+
result = this.getElement(_).(DestructuredLhsExpr).getAVariable()
139+
}
140+
141+
override string toString() { result = "(..., ...)" }
142+
143+
override AstNode getAChild(string pred) { pred = "getElement" and result = this.getElement(_) }
144+
}
145+
69146
/** A sequence of expressions. */
70147
class StmtSequence extends Expr, TStmtSequence {
71148
override string getAPrimaryQlClass() { result = "StmtSequence" }

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ class NoRegExpMatchExpr extends BinaryOperation, TNoRegExpMatchExpr {
443443
*/
444444
class Assignment extends Operation instanceof AssignmentImpl {
445445
/** Gets the left hand side of this assignment. */
446-
final Pattern getLeftOperand() { result = super.getLeftOperandImpl() }
446+
final LhsExpr getLeftOperand() { result = super.getLeftOperandImpl() }
447447

448448
/** Gets the right hand side of this assignment. */
449449
final Expr getRightOperand() { result = super.getRightOperandImpl() }

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

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,59 @@ class Parameter extends AstNode, TParameter {
2323
}
2424

2525
/**
26+
* A parameter defined using destructuring. For example
27+
*
28+
* ```rb
29+
* def tuples((a,b))
30+
* puts "#{a} #{b}"
31+
* end
32+
* ```
33+
*/
34+
class DestructuredParameter extends Parameter, TDestructuredParameter {
35+
private DestructuredParameterImpl getImpl() { result = toGenerated(this) }
36+
37+
private Ruby::AstNode getChild(int i) { result = this.getImpl().getChildNode(i) }
38+
39+
/** Gets the `i`th element in this destructured parameter. */
40+
final AstNode getElement(int i) {
41+
exists(Ruby::AstNode c | c = this.getChild(i) | toGenerated(result) = c)
42+
}
43+
44+
/** Gets an element in this destructured parameter. */
45+
final AstNode getAnElement() { result = this.getElement(_) }
46+
47+
override LocalVariable getAVariable() {
48+
result = this.getAnElement().(LocalVariableWriteAccess).getVariable()
49+
or
50+
result = this.getAnElement().(DestructuredParameter).getAVariable()
51+
}
52+
53+
override string toString() { result = "(..., ...)" }
54+
55+
override AstNode getAChild(string pred) { pred = "getElement" and result = this.getElement(_) }
56+
57+
final override string getAPrimaryQlClass() { result = "DestructuredParameter" }
58+
}
59+
60+
/**
61+
* DEPRECATED
62+
*
2663
* A parameter defined using a pattern.
2764
*
2865
* This includes both simple parameters and tuple parameters.
2966
*/
30-
class PatternParameter extends Parameter, Pattern, TPatternParameter {
67+
deprecated class PatternParameter extends Parameter, Pattern, TPatternParameter {
3168
override LocalVariable getAVariable() { result = Pattern.super.getAVariable() }
3269
}
3370

34-
/** A parameter defined using a tuple pattern. */
35-
class TuplePatternParameter extends PatternParameter, TuplePattern, TTuplePatternParameter {
71+
/**
72+
* DEPRECATED
73+
*
74+
* A parameter defined using a tuple pattern.
75+
*/
76+
deprecated class TuplePatternParameter extends PatternParameter, TuplePattern,
77+
TDestructuredParameter {
3678
final override LocalVariable getAVariable() { result = TuplePattern.super.getAVariable() }
37-
38-
final override string getAPrimaryQlClass() { result = "TuplePatternParameter" }
39-
40-
override AstNode getAChild(string pred) { result = TuplePattern.super.getAChild(pred) }
4179
}
4280

4381
/** A named parameter. */
@@ -72,7 +110,7 @@ class NamedParameter extends Parameter, TNamedParameter {
72110
}
73111

74112
/** A simple (normal) parameter. */
75-
class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern, TSimpleParameter instanceof SimpleParameterImpl {
113+
class SimpleParameter extends NamedParameter, TSimpleParameter instanceof SimpleParameterImpl {
76114
final override string getName() { result = SimpleParameterImpl.super.getNameImpl() }
77115

78116
final override LocalVariable getVariable() {

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

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ private import internal.TreeSitter
66
private import internal.Variable
77
private import internal.Parameter
88

9-
/** A pattern. */
10-
class Pattern extends AstNode {
9+
/**
10+
* DEPRECATED
11+
*
12+
* A pattern.
13+
*/
14+
deprecated class Pattern extends AstNode {
1115
Pattern() {
1216
explicitAssignmentNode(toGenerated(this), _)
1317
or
@@ -24,36 +28,20 @@ class Pattern extends AstNode {
2428
Variable getAVariable() { none() }
2529
}
2630

27-
private class LhsExpr_ =
28-
TVariableAccess or TTokenConstantAccess or TScopeResolutionConstantAccess or TMethodCall or
29-
TSimpleParameter;
31+
deprecated private class TVariablePattern = TVariableAccess or TSimpleParameter;
3032

3133
/**
32-
* A "left-hand-side" expression. An `LhsExpr` can occur on the left-hand side of
33-
* operator assignments (`AssignOperation`), in patterns (`Pattern`) on the left-hand side of
34-
* an assignment (`AssignExpr`) or for loop (`ForExpr`), and as the exception
35-
* variable of a `rescue` clause (`RescueClause`).
34+
* DEPRECATED
3635
*
37-
* An `LhsExpr` can be a simple variable, a constant, a call, or an element reference:
38-
* ```rb
39-
* var = 1
40-
* var += 1
41-
* E = 1
42-
* foo.bar = 1
43-
* foo[0] = 1
44-
* rescue E => var
45-
* ```
36+
* A simple variable pattern.
4637
*/
47-
class LhsExpr extends Pattern, LhsExpr_, Expr {
38+
deprecated class VariablePattern extends Pattern, LhsExpr, TVariablePattern {
4839
override Variable getAVariable() { result = this.(VariableAccess).getVariable() }
4940
}
5041

51-
private class TVariablePattern = TVariableAccess or TSimpleParameter;
52-
53-
/** A simple variable pattern. */
54-
class VariablePattern extends Pattern, LhsExpr, TVariablePattern { }
55-
5642
/**
43+
* DEPRECATED
44+
*
5745
* A tuple pattern.
5846
*
5947
* This includes both tuple patterns in parameters and assignments. Example patterns:
@@ -63,9 +51,7 @@ class VariablePattern extends Pattern, LhsExpr, TVariablePattern { }
6351
* a, b, *rest, c, d = value
6452
* ```
6553
*/
66-
class TuplePattern extends Pattern, TTuplePattern {
67-
override string getAPrimaryQlClass() { result = "TuplePattern" }
68-
54+
deprecated class TuplePattern extends Pattern, TTuplePattern {
6955
private TuplePatternImpl getImpl() { result = toGenerated(this) }
7056

7157
private Ruby::AstNode getChild(int i) { result = this.getImpl().getChildNode(i) }
@@ -92,10 +78,6 @@ class TuplePattern extends Pattern, TTuplePattern {
9278
final int getRestIndex() { result = this.getImpl().getRestIndex() }
9379

9480
override Variable getAVariable() { result = this.getElement(_).getAVariable() }
95-
96-
override string toString() { result = "(..., ...)" }
97-
98-
override AstNode getAChild(string pred) { pred = "getElement" and result = this.getElement(_) }
9981
}
10082

10183
private class TPatternNode =

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

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ private module Cached {
296296
TTokenSuperCall(Ruby::Super g) { vcall(g) } or
297297
TToplevel(Ruby::Program g) or
298298
TTrueLiteral(Ruby::True g) or
299-
TTuplePatternParameter(Ruby::DestructuredParameter g) or
299+
TDestructuredParameter(Ruby::DestructuredParameter g) or
300300
TUnaryMinusExpr(Ruby::Unary g) { g instanceof @ruby_unary_minus } or
301301
TUnaryPlusExpr(Ruby::Unary g) { g instanceof @ruby_unary_plus } or
302302
TUndefStmt(Ruby::Undef g) or
@@ -342,7 +342,7 @@ private module Cached {
342342
TStringConcatenation or TStringEscapeSequenceComponent or TStringInterpolationComponent or
343343
TStringTextComponent or TSubExprReal or TSubshellLiteral or TSymbolArrayLiteral or
344344
TTernaryIfExpr or TThen or TTokenConstantAccess or TTokenMethodName or TTokenSuperCall or
345-
TToplevel or TTrueLiteral or TTuplePatternParameter or TUnaryMinusExpr or TUnaryPlusExpr or
345+
TToplevel or TTrueLiteral or TDestructuredParameter or TUnaryMinusExpr or TUnaryPlusExpr or
346346
TUndefStmt or TUnlessExpr or TUnlessModifierExpr or TUntilExpr or TUntilModifierExpr or
347347
TVariableReferencePattern or TWhenExpr or TWhileExpr or TWhileModifierExpr or TYieldCall;
348348

@@ -502,7 +502,7 @@ private module Cached {
502502
n = TTokenSuperCall(result) or
503503
n = TToplevel(result) or
504504
n = TTrueLiteral(result) or
505-
n = TTuplePatternParameter(result) or
505+
n = TDestructuredParameter(result) or
506506
n = TUnaryMinusExpr(result) or
507507
n = TUnaryPlusExpr(result) or
508508
n = TUndefStmt(result) or
@@ -613,6 +613,15 @@ private module Cached {
613613
or
614614
result = toGenerated(n).getLocation()
615615
}
616+
617+
cached
618+
predicate lhsExpr(AST::Expr e) {
619+
explicitAssignmentNode(toGenerated(e), _)
620+
or
621+
implicitAssignmentNode(toGenerated(e))
622+
or
623+
e = getSynthChild(any(AST::AssignExpr ae), 0)
624+
}
616625
}
617626

618627
import Cached
@@ -645,11 +654,13 @@ class TLoop = TConditionalLoop or TForExpr;
645654

646655
class TSelf = TSelfReal or TSelfSynth;
647656

657+
class TDestructuredLhsExpr = TDestructuredLeftAssignment or TLeftAssignmentList;
658+
648659
class TExpr =
649660
TSelf or TArgumentList or TInClause or TRescueClause or TRescueModifierExpr or TPair or
650661
TStringConcatenation or TCall or TBlockArgument or TConstantAccess or TControlExpr or
651662
TWhenExpr or TLiteral or TCallable or TVariableAccess or TStmtSequence or TOperation or
652-
TSimpleParameter or TForwardArgument;
663+
TSimpleParameter or TForwardArgument or TDestructuredLhsExpr;
653664

654665
class TSplatExpr = TSplatExprReal or TSplatExprSynth;
655666

@@ -778,18 +789,20 @@ class TStmt =
778789
class TReturningStmt = TReturnStmt or TBreakStmt or TNextStmt;
779790

780791
class TParameter =
781-
TPatternParameter or TBlockParameter or THashSplatParameter or THashSplatNilParameter or
782-
TKeywordParameter or TOptionalParameter or TSplatParameter or TForwardParameter;
792+
TSimpleParameter or TDestructuredParameter or TBlockParameter or THashSplatParameter or
793+
THashSplatNilParameter or TKeywordParameter or TOptionalParameter or TSplatParameter or
794+
TForwardParameter;
783795

784796
class TSimpleParameter = TSimpleParameterReal or TSimpleParameterSynth;
785797

786-
class TPatternParameter = TSimpleParameter or TTuplePatternParameter;
798+
deprecated class TPatternParameter = TSimpleParameter or TDestructuredParameter;
787799

788800
class TNamedParameter =
789801
TSimpleParameter or TBlockParameter or THashSplatParameter or TKeywordParameter or
790802
TOptionalParameter or TSplatParameter;
791803

792-
class TTuplePattern = TTuplePatternParameter or TDestructuredLeftAssignment or TLeftAssignmentList;
804+
deprecated class TTuplePattern =
805+
TDestructuredParameter or TDestructuredLeftAssignment or TLeftAssignmentList;
793806

794807
class TVariableAccess =
795808
TLocalVariableAccess or TGlobalVariableAccess or TInstanceVariableAccess or

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,29 @@ Ruby::AstNode getBodyStmtChild(TBodyStmt b, int i) {
7373
or
7474
result = any(Ruby::Begin g | b = TBeginExpr(g)).getChild(i)
7575
}
76+
77+
abstract class DestructuredLhsExprImpl extends Ruby::AstNode {
78+
abstract Ruby::AstNode getChildNode(int i);
79+
80+
final int getRestIndex() {
81+
result = unique(int i | this.getChildNode(i) instanceof Ruby::RestAssignment)
82+
}
83+
}
84+
85+
class DestructuredLeftAssignmentImpl extends DestructuredLhsExprImpl,
86+
Ruby::DestructuredLeftAssignment {
87+
override Ruby::AstNode getChildNode(int i) { result = this.getChild(i) }
88+
}
89+
90+
class LeftAssignmentListImpl extends DestructuredLhsExprImpl, Ruby::LeftAssignmentList {
91+
override Ruby::AstNode getChildNode(int i) {
92+
this =
93+
any(Ruby::LeftAssignmentList lal |
94+
if
95+
strictcount(int j | exists(lal.getChild(j))) = 1 and
96+
lal.getChild(0) instanceof Ruby::DestructuredLeftAssignment
97+
then result = lal.getChild(0).(Ruby::DestructuredLeftAssignment).getChild(i)
98+
else result = lal.getChild(i)
99+
)
100+
}
101+
}

0 commit comments

Comments
 (0)