@@ -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. */
70151class 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 ( _)
0 commit comments