Skip to content

Commit e9ef53c

Browse files
authored
Merge pull request #7390 from hvitved/ruby/deprecate-pattern-classes
Ruby: Deprecate `Pattern` classes
2 parents 95d175e + 4ccf9bf commit e9ef53c

24 files changed

+374
-187
lines changed

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

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class IfExpr extends ConditionalExpr, TIfExpr {
102102
cond = false and result = this.getElse()
103103
}
104104

105-
override AstNode getAChild(string pred) {
105+
final override AstNode getAChild(string pred) {
106106
result = super.getAChild(pred)
107107
or
108108
pred = "getThen" and result = this.getThen()
@@ -192,8 +192,8 @@ class UnlessExpr extends ConditionalExpr, TUnlessExpr {
192192

193193
final override string toString() { result = "unless ..." }
194194

195-
override AstNode getAChild(string pred) {
196-
result = ConditionalExpr.super.getAChild(pred)
195+
final override AstNode getAChild(string pred) {
196+
result = super.getAChild(pred)
197197
or
198198
pred = "getThen" and result = this.getThen()
199199
or
@@ -229,8 +229,8 @@ class IfModifierExpr extends ConditionalExpr, TIfModifierExpr {
229229

230230
final override string toString() { result = "... if ..." }
231231

232-
override AstNode getAChild(string pred) {
233-
result = ConditionalExpr.super.getAChild(pred)
232+
final override AstNode getAChild(string pred) {
233+
result = super.getAChild(pred)
234234
or
235235
pred = "getBody" and result = this.getBody()
236236
}
@@ -264,8 +264,8 @@ class UnlessModifierExpr extends ConditionalExpr, TUnlessModifierExpr {
264264

265265
final override string toString() { result = "... unless ..." }
266266

267-
override AstNode getAChild(string pred) {
268-
result = ConditionalExpr.super.getAChild(pred)
267+
final override AstNode getAChild(string pred) {
268+
result = super.getAChild(pred)
269269
or
270270
pred = "getBody" and result = this.getBody()
271271
}
@@ -300,8 +300,8 @@ class TernaryIfExpr extends ConditionalExpr, TTernaryIfExpr {
300300

301301
final override string toString() { result = "... ? ... : ..." }
302302

303-
override AstNode getAChild(string pred) {
304-
result = ConditionalExpr.super.getAChild(pred)
303+
final override AstNode getAChild(string pred) {
304+
result = super.getAChild(pred)
305305
or
306306
pred = "getThen" and result = this.getThen()
307307
or
@@ -390,7 +390,7 @@ class CaseExpr extends ControlExpr instanceof CaseExprImpl {
390390

391391
final override string toString() { result = "case ..." }
392392

393-
override AstNode getAChild(string pred) {
393+
final override AstNode getAChild(string pred) {
394394
result = ControlExpr.super.getAChild(pred)
395395
or
396396
pred = "getValue" and result = this.getValue()
@@ -444,7 +444,7 @@ class WhenExpr extends Expr, TWhenExpr {
444444

445445
final override string toString() { result = "when ..." }
446446

447-
override AstNode getAChild(string pred) {
447+
final override AstNode getAChild(string pred) {
448448
result = super.getAChild(pred)
449449
or
450450
pred = "getBody" and result = this.getBody()
@@ -517,7 +517,7 @@ class InClause extends Expr, TInClause {
517517

518518
final override string toString() { result = "in ... then ..." }
519519

520-
override AstNode getAChild(string pred) {
520+
final override AstNode getAChild(string pred) {
521521
result = super.getAChild(pred)
522522
or
523523
pred = "getBody" and result = this.getBody()
@@ -552,7 +552,7 @@ class ConditionalLoop extends Loop, TConditionalLoop {
552552
Expr getCondition() { none() }
553553

554554
override AstNode getAChild(string pred) {
555-
result = Loop.super.getAChild(pred)
555+
result = super.getAChild(pred)
556556
or
557557
pred = "getCondition" and result = this.getCondition()
558558
}
@@ -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
@@ -707,8 +707,8 @@ class ForExpr extends Loop, TForExpr {
707707

708708
final override string toString() { result = "for ... in ..." }
709709

710-
override AstNode getAChild(string pred) {
711-
result = Loop.super.getAChild(pred)
710+
final override AstNode getAChild(string pred) {
711+
result = super.getAChild(pred)
712712
or
713713
pred = "getPattern" and result = this.getPattern()
714714
or

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

Lines changed: 86 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,87 @@ 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+
final override AstNode getAChild(string pred) {
144+
result = super.getAChild(pred)
145+
or
146+
pred = "getElement" and result = this.getElement(_)
147+
}
148+
}
149+
69150
/** A sequence of expressions. */
70151
class StmtSequence extends Expr, TStmtSequence {
71152
override string getAPrimaryQlClass() { result = "StmtSequence" }
@@ -136,7 +217,7 @@ class BodyStmt extends StmtSequence, TBodyStmt {
136217
final predicate hasEnsure() { exists(this.getEnsure()) }
137218

138219
override AstNode getAChild(string pred) {
139-
result = StmtSequence.super.getAChild(pred)
220+
result = super.getAChild(pred)
140221
or
141222
pred = "getRescue" and result = this.getRescue(_)
142223
or
@@ -214,7 +295,7 @@ class Pair extends Expr, TPair {
214295

215296
final override string toString() { result = "Pair" }
216297

217-
override AstNode getAChild(string pred) {
298+
final override AstNode getAChild(string pred) {
218299
result = super.getAChild(pred)
219300
or
220301
pred = "getKey" and result = this.getKey()
@@ -283,7 +364,7 @@ class RescueClause extends Expr, TRescueClause {
283364

284365
final override string toString() { result = "rescue ..." }
285366

286-
override AstNode getAChild(string pred) {
367+
final override AstNode getAChild(string pred) {
287368
result = super.getAChild(pred)
288369
or
289370
pred = "getException" and result = this.getException(_)
@@ -325,7 +406,7 @@ class RescueModifierExpr extends Expr, TRescueModifierExpr {
325406

326407
final override string toString() { result = "... rescue ..." }
327408

328-
override AstNode getAChild(string pred) {
409+
final override AstNode getAChild(string pred) {
329410
result = super.getAChild(pred)
330411
or
331412
pred = "getBody" and result = this.getBody()
@@ -386,7 +467,7 @@ class StringConcatenation extends Expr, TStringConcatenation {
386467

387468
final override string toString() { result = "\"...\" \"...\"" }
388469

389-
override AstNode getAChild(string pred) {
470+
final override AstNode getAChild(string pred) {
390471
result = super.getAChild(pred)
391472
or
392473
pred = "getString" and result = this.getString(_)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,14 +443,14 @@ 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() }
450450

451451
final override string toString() { result = "... " + this.getOperator() + " ..." }
452452

453-
override AstNode getAChild(string pred) {
453+
final override AstNode getAChild(string pred) {
454454
result = Operation.super.getAChild(pred)
455455
or
456456
pred = "getLeftOperand" and result = this.getLeftOperand()

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

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ private import internal.TreeSitter
77
/** A parameter. */
88
class Parameter extends AstNode, TParameter {
99
/** Gets the callable that this parameter belongs to. */
10-
final Callable getCallable() { result.getAParameter() = this }
10+
final Callable getCallable() {
11+
result.getAParameter() = this
12+
or
13+
exists(DestructuredParameter parent |
14+
this = parent.getAnElement() and
15+
result = parent.getCallable()
16+
)
17+
}
1118

1219
/** Gets the zero-based position of this parameter. */
1320
final int getPosition() { this = any(Callable c).getParameter(result) }
@@ -23,21 +30,63 @@ class Parameter extends AstNode, TParameter {
2330
}
2431

2532
/**
33+
* A parameter defined using destructuring. For example
34+
*
35+
* ```rb
36+
* def tuples((a,b))
37+
* puts "#{a} #{b}"
38+
* end
39+
* ```
40+
*/
41+
class DestructuredParameter extends Parameter, TDestructuredParameter {
42+
private DestructuredParameterImpl getImpl() { result = toGenerated(this) }
43+
44+
private Ruby::AstNode getChild(int i) { result = this.getImpl().getChildNode(i) }
45+
46+
/** Gets the `i`th element in this destructured parameter. */
47+
final AstNode getElement(int i) {
48+
exists(Ruby::AstNode c | c = this.getChild(i) | toGenerated(result) = c)
49+
}
50+
51+
/** Gets an element in this destructured parameter. */
52+
final AstNode getAnElement() { result = this.getElement(_) }
53+
54+
override LocalVariable getAVariable() {
55+
result = this.getAnElement().(LocalVariableWriteAccess).getVariable()
56+
or
57+
result = this.getAnElement().(DestructuredParameter).getAVariable()
58+
}
59+
60+
override string toString() { result = "(..., ...)" }
61+
62+
final override AstNode getAChild(string pred) {
63+
result = super.getAChild(pred)
64+
or
65+
pred = "getElement" and result = this.getElement(_)
66+
}
67+
68+
final override string getAPrimaryQlClass() { result = "DestructuredParameter" }
69+
}
70+
71+
/**
72+
* DEPRECATED
73+
*
2674
* A parameter defined using a pattern.
2775
*
2876
* This includes both simple parameters and tuple parameters.
2977
*/
30-
class PatternParameter extends Parameter, Pattern, TPatternParameter {
78+
deprecated class PatternParameter extends Parameter, Pattern, TPatternParameter {
3179
override LocalVariable getAVariable() { result = Pattern.super.getAVariable() }
3280
}
3381

34-
/** A parameter defined using a tuple pattern. */
35-
class TuplePatternParameter extends PatternParameter, TuplePattern, TTuplePatternParameter {
82+
/**
83+
* DEPRECATED
84+
*
85+
* A parameter defined using a tuple pattern.
86+
*/
87+
deprecated class TuplePatternParameter extends PatternParameter, TuplePattern,
88+
TDestructuredParameter {
3689
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) }
4190
}
4291

4392
/** A named parameter. */
@@ -72,7 +121,7 @@ class NamedParameter extends Parameter, TNamedParameter {
72121
}
73122

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

78127
final override LocalVariable getVariable() {

0 commit comments

Comments
 (0)