Skip to content

Commit 8b90d02

Browse files
committed
Ruby: change evaluation order of destructured assignments
1 parent 559f6a5 commit 8b90d02

File tree

9 files changed

+212
-120
lines changed

9 files changed

+212
-120
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ private import AST
44
private import TreeSitter
55

66
class StmtSequenceSynth extends StmtSequence, TStmtSequenceSynth {
7-
final override Stmt getStmt(int n) { synthChild(this, n, result) }
7+
final override Stmt getStmt(int n) {
8+
result = rank[n + 1](int i, Stmt s | synthChild(this, i, s) | s order by i)
9+
}
810

911
final override string toString() { result = "..." }
1012
}

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

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -958,14 +958,32 @@ private module DestructuredAssignDesugar {
958958
child = SynthChild(StmtSequenceKind())
959959
or
960960
exists(AstNode seq | seq = TStmtSequenceSynth(tae, -1) |
961+
exists(MethodCall mc, int j | mc = tae.getElement(j) |
962+
parent = seq and
963+
i = j and
964+
child = SynthChild(AssignExprKind())
965+
or
966+
exists(AstNode assign | assign = TAssignExprSynth(seq, j) |
967+
parent = assign and
968+
i = 0 and
969+
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(tae, j)))
970+
or
971+
parent = assign and
972+
i = 1 and
973+
child = childRef(mc.getReceiver())
974+
)
975+
)
976+
or
961977
parent = seq and
962-
i = 0 and
978+
i = tae.getNumberOfElements() and
963979
child = SynthChild(AssignExprKind())
964980
or
965-
exists(AstNode assign | assign = TAssignExprSynth(seq, 0) |
981+
exists(AstNode assign | assign = TAssignExprSynth(seq, tae.getNumberOfElements()) |
966982
parent = assign and
967983
i = 0 and
968-
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(tae, 0)))
984+
child =
985+
SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(tae,
986+
tae.getNumberOfElements())))
969987
or
970988
parent = assign and
971989
i = 1 and
@@ -981,10 +999,33 @@ private module DestructuredAssignDesugar {
981999
restIndex = tae.getRestIndexOrNumberOfElements()
9821000
|
9831001
parent = seq and
984-
i = j + 1 and
1002+
i = j + 1 + tae.getNumberOfElements() and
9851003
child = SynthChild(AssignExprKind())
9861004
or
987-
exists(AstNode assign | assign = TAssignExprSynth(seq, j + 1) |
1005+
exists(AstNode assign |
1006+
assign = TAssignExprSynth(seq, j + 1 + tae.getNumberOfElements())
1007+
|
1008+
exists(MethodCall mc | mc = elem |
1009+
parent = assign and
1010+
i = 0 and
1011+
child =
1012+
SynthChild(MethodCallKind(mc.getMethodName(), false, mc.getNumberOfArguments()))
1013+
or
1014+
exists(AstNode call | call = TMethodCallSynth(assign, 0, _, _, _) |
1015+
parent = call and
1016+
i = 0 and
1017+
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(tae, j)))
1018+
or
1019+
parent = call and
1020+
child = childRef(mc.getArgument(i - 1))
1021+
)
1022+
)
1023+
or
1024+
(
1025+
elem instanceof VariableAccess or
1026+
elem instanceof ConstantAccess or
1027+
elem instanceof DestructuredLhsExpr
1028+
) and
9881029
parent = assign and
9891030
i = 0 and
9901031
child = childRef(elem)
@@ -995,7 +1036,9 @@ private module DestructuredAssignDesugar {
9951036
or
9961037
parent = TMethodCallSynth(assign, 1, _, _, _) and
9971038
i = 0 and
998-
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(tae, 0)))
1039+
child =
1040+
SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(tae,
1041+
tae.getNumberOfElements())))
9991042
or
10001043
j < restIndex and
10011044
parent = TMethodCallSynth(assign, 1, _, _, _) and
@@ -1050,26 +1093,41 @@ private module DestructuredAssignDesugar {
10501093

10511094
final override predicate location(AstNode n, Location l) {
10521095
exists(DestructuredAssignExpr tae, StmtSequence seq | seq = tae.getDesugared() |
1053-
n = seq.getStmt(0) and
1096+
synthChild(seq, tae.getNumberOfElements(), n) and
10541097
hasLocation(tae.getRightOperand(), l)
10551098
or
1056-
exists(AstNode elem, int j |
1099+
exists(MethodCall elem, int j |
10571100
elem = tae.getElement(j) and
1058-
n = seq.getStmt(j + 1) and
1101+
synthChild(seq, j, n) and
1102+
hasLocation(elem.getReceiver(), l)
1103+
)
1104+
or
1105+
exists(AstNode elem, int j | elem = tae.getElement(j) |
1106+
synthChild(seq, j + 1 + tae.getNumberOfElements(), n) and
10591107
hasLocation(elem, l)
10601108
)
10611109
)
10621110
}
10631111

10641112
final override predicate localVariable(AstNode n, int i) {
1065-
n instanceof DestructuredAssignExpr and
1066-
i = 0
1113+
i = [0 .. n.(DestructuredAssignExpr).getNumberOfElements()]
10671114
}
10681115

10691116
final override predicate methodCall(string name, boolean setter, int arity) {
10701117
name = "[]" and
10711118
setter = false and
10721119
arity = 1
1120+
or
1121+
exists(DestructuredAssignExpr tae, MethodCall mc |
1122+
mc = tae.getElement(_) and
1123+
name = mc.getMethodName() and
1124+
setter = false and
1125+
arity = mc.getNumberOfArguments()
1126+
)
1127+
}
1128+
1129+
final override predicate excludeFromControlFlowTree(AstNode n) {
1130+
n = any(DestructuredAssignExpr tae).getElement(_).(MethodCall)
10731131
}
10741132
}
10751133
}

ruby/ql/test/library-tests/ast/AstDesugar.expected

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -81,44 +81,53 @@ calls/calls.rb:
8181
# 318| [AssignExpr] ... = ...
8282
# 318| getDesugared: [StmtSequence] ...
8383
# 318| getStmt: [AssignExpr] ... = ...
84-
# 318| getAnOperand/getLeftOperand: [MethodCall] call to foo
84+
# 318| getAnOperand/getRightOperand: [SelfVariableAccess] self
85+
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
86+
# 318| getStmt: [AssignExpr] ... = ...
8587
# 318| getDesugared: [StmtSequence] ...
8688
# 318| getStmt: [SetterMethodCall] call to foo=
87-
# 318| getReceiver: [SelfVariableAccess] self
89+
# 318| getReceiver: [LocalVariableAccess] __synth__0
8890
# 318| getArgument: [AssignExpr] ... = ...
8991
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1
9092
# 318| getAnOperand/getRightOperand: [MethodCall] call to []
91-
# 318| getReceiver: [LocalVariableAccess] __synth__0
93+
# 318| getReceiver: [LocalVariableAccess] __synth__3
9294
# 318| getArgument: [IntegerLiteral] 0
9395
# 318| getStmt: [LocalVariableAccess] __synth__0__1
96+
# 318| getAnOperand/getLeftOperand: [MethodCall] call to foo
97+
# 318| getStmt: [AssignExpr] ... = ...
98+
# 318| getAnOperand/getRightOperand: [SelfVariableAccess] self
99+
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1
94100
# 318| getStmt: [AssignExpr] ... = ...
95-
# 318| getAnOperand/getLeftOperand: [MethodCall] call to bar
96101
# 318| getDesugared: [StmtSequence] ...
97102
# 318| getStmt: [SetterMethodCall] call to bar=
98-
# 318| getReceiver: [SelfVariableAccess] self
103+
# 318| getReceiver: [LocalVariableAccess] __synth__1
99104
# 318| getArgument: [AssignExpr] ... = ...
100105
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1
101106
# 318| getAnOperand/getRightOperand: [MethodCall] call to []
102-
# 318| getReceiver: [LocalVariableAccess] __synth__0
107+
# 318| getReceiver: [LocalVariableAccess] __synth__3
103108
# 318| getArgument: [RangeLiteral] _ .. _
104109
# 318| getBegin: [IntegerLiteral] 1
105110
# 318| getEnd: [IntegerLiteral] -2
106111
# 318| getStmt: [LocalVariableAccess] __synth__0__1
112+
# 318| getAnOperand/getLeftOperand: [MethodCall] call to bar
113+
# 318| getStmt: [AssignExpr] ... = ...
114+
# 318| getAnOperand/getRightOperand: [MethodCall] call to foo
115+
# 318| getReceiver: [SelfVariableAccess] self
116+
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2
107117
# 318| getStmt: [AssignExpr] ... = ...
108-
# 318| getAnOperand/getLeftOperand: [ElementReference] ...[...]
109118
# 318| getDesugared: [StmtSequence] ...
110119
# 318| getStmt: [SetterMethodCall] call to []=
111-
# 318| getReceiver: [MethodCall] call to foo
112-
# 318| getReceiver: [SelfVariableAccess] self
120+
# 318| getReceiver: [LocalVariableAccess] __synth__2
113121
# 318| getArgument: [AssignExpr] ... = ...
114122
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1
115123
# 318| getAnOperand/getRightOperand: [MethodCall] call to []
116-
# 318| getReceiver: [LocalVariableAccess] __synth__0
124+
# 318| getReceiver: [LocalVariableAccess] __synth__3
117125
# 318| getArgument: [IntegerLiteral] -1
118126
# 318| getArgument: [IntegerLiteral] 4
119127
# 318| getStmt: [LocalVariableAccess] __synth__0__1
128+
# 318| getAnOperand/getLeftOperand: [MethodCall] call to []
120129
# 318| getStmt: [AssignExpr] ... = ...
121-
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
130+
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3
122131
# 318| getAnOperand/getRightOperand: [SplatExpr] * ...
123132
# 318| getAnOperand/getOperand/getReceiver: [ArrayLiteral] [...]
124133
# 318| getDesugared: [MethodCall] call to []
@@ -132,25 +141,28 @@ calls/calls.rb:
132141
# 319| getStmt: [AssignExpr] ... = ...
133142
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] a
134143
# 319| getAnOperand/getRightOperand: [MethodCall] call to []
135-
# 319| getReceiver: [LocalVariableAccess] __synth__0
144+
# 319| getReceiver: [LocalVariableAccess] __synth__2
136145
# 319| getArgument: [IntegerLiteral] 0
137146
# 319| getStmt: [AssignExpr] ... = ...
138-
# 319| getAnOperand/getLeftOperand: [ElementReference] ...[...]
147+
# 319| getAnOperand/getRightOperand: [MethodCall] call to foo
148+
# 319| getReceiver: [SelfVariableAccess] self
149+
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1
150+
# 319| getStmt: [AssignExpr] ... = ...
139151
# 319| getDesugared: [StmtSequence] ...
140152
# 319| getStmt: [SetterMethodCall] call to []=
141-
# 319| getReceiver: [MethodCall] call to foo
142-
# 319| getReceiver: [SelfVariableAccess] self
153+
# 319| getReceiver: [LocalVariableAccess] __synth__1
143154
# 319| getArgument: [AssignExpr] ... = ...
144155
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1
145156
# 319| getAnOperand/getRightOperand: [MethodCall] call to []
146-
# 319| getReceiver: [LocalVariableAccess] __synth__0
157+
# 319| getReceiver: [LocalVariableAccess] __synth__2
147158
# 319| getArgument: [RangeLiteral] _ .. _
148159
# 319| getBegin: [IntegerLiteral] 1
149160
# 319| getEnd: [IntegerLiteral] -1
150161
# 319| getArgument: [IntegerLiteral] 5
151162
# 319| getStmt: [LocalVariableAccess] __synth__0__1
163+
# 319| getAnOperand/getLeftOperand: [MethodCall] call to []
152164
# 319| getStmt: [AssignExpr] ... = ...
153-
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
165+
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2
154166
# 319| getAnOperand/getRightOperand: [SplatExpr] * ...
155167
# 319| getAnOperand/getOperand/getReceiver: [ArrayLiteral] [...]
156168
# 319| getDesugared: [MethodCall] call to []
@@ -240,23 +252,23 @@ calls/calls.rb:
240252
# 342| getStmt: [AssignExpr] ... = ...
241253
# 342| getDesugared: [StmtSequence] ...
242254
# 342| getStmt: [AssignExpr] ... = ...
243-
# 342| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1
255+
# 342| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3__1
244256
# 342| getAnOperand/getRightOperand: [SplatExpr] * ...
245257
# 342| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] __synth__0__1
246258
# 342| getStmt: [AssignExpr] ... = ...
247259
# 342| getAnOperand/getLeftOperand: [LocalVariableAccess] x
248260
# 342| getAnOperand/getRightOperand: [MethodCall] call to []
249-
# 342| getReceiver: [LocalVariableAccess] __synth__0__1
261+
# 342| getReceiver: [LocalVariableAccess] __synth__3__1
250262
# 342| getArgument: [IntegerLiteral] 0
251263
# 342| getStmt: [AssignExpr] ... = ...
252264
# 342| getAnOperand/getLeftOperand: [LocalVariableAccess] y
253265
# 342| getAnOperand/getRightOperand: [MethodCall] call to []
254-
# 342| getReceiver: [LocalVariableAccess] __synth__0__1
266+
# 342| getReceiver: [LocalVariableAccess] __synth__3__1
255267
# 342| getArgument: [IntegerLiteral] 1
256268
# 342| getStmt: [AssignExpr] ... = ...
257269
# 342| getAnOperand/getLeftOperand: [LocalVariableAccess] z
258270
# 342| getAnOperand/getRightOperand: [MethodCall] call to []
259-
# 342| getReceiver: [LocalVariableAccess] __synth__0__1
271+
# 342| getReceiver: [LocalVariableAccess] __synth__3__1
260272
# 342| getArgument: [IntegerLiteral] 2
261273
# 342| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
262274
# 343| getStmt: [MethodCall] call to foo
@@ -632,18 +644,18 @@ control/loops.rb:
632644
# 22| getStmt: [AssignExpr] ... = ...
633645
# 22| getDesugared: [StmtSequence] ...
634646
# 22| getStmt: [AssignExpr] ... = ...
635-
# 22| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1
647+
# 22| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2__1
636648
# 22| getAnOperand/getRightOperand: [SplatExpr] * ...
637649
# 22| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] __synth__0__1
638650
# 22| getStmt: [AssignExpr] ... = ...
639651
# 22| getAnOperand/getLeftOperand: [LocalVariableAccess] key
640652
# 22| getAnOperand/getRightOperand: [MethodCall] call to []
641-
# 22| getReceiver: [LocalVariableAccess] __synth__0__1
653+
# 22| getReceiver: [LocalVariableAccess] __synth__2__1
642654
# 22| getArgument: [IntegerLiteral] 0
643655
# 22| getStmt: [AssignExpr] ... = ...
644656
# 22| getAnOperand/getLeftOperand: [LocalVariableAccess] value
645657
# 22| getAnOperand/getRightOperand: [MethodCall] call to []
646-
# 22| getReceiver: [LocalVariableAccess] __synth__0__1
658+
# 22| getReceiver: [LocalVariableAccess] __synth__2__1
647659
# 22| getArgument: [IntegerLiteral] 1
648660
# 22| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
649661
# 23| getStmt: [AssignAddExpr] ... += ...
@@ -677,18 +689,18 @@ control/loops.rb:
677689
# 28| getStmt: [AssignExpr] ... = ...
678690
# 28| getDesugared: [StmtSequence] ...
679691
# 28| getStmt: [AssignExpr] ... = ...
680-
# 28| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1
692+
# 28| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2__1
681693
# 28| getAnOperand/getRightOperand: [SplatExpr] * ...
682694
# 28| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] __synth__0__1
683695
# 28| getStmt: [AssignExpr] ... = ...
684696
# 28| getAnOperand/getLeftOperand: [LocalVariableAccess] key
685697
# 28| getAnOperand/getRightOperand: [MethodCall] call to []
686-
# 28| getReceiver: [LocalVariableAccess] __synth__0__1
698+
# 28| getReceiver: [LocalVariableAccess] __synth__2__1
687699
# 28| getArgument: [IntegerLiteral] 0
688700
# 28| getStmt: [AssignExpr] ... = ...
689701
# 28| getAnOperand/getLeftOperand: [LocalVariableAccess] value
690702
# 28| getAnOperand/getRightOperand: [MethodCall] call to []
691-
# 28| getReceiver: [LocalVariableAccess] __synth__0__1
703+
# 28| getReceiver: [LocalVariableAccess] __synth__2__1
692704
# 28| getArgument: [IntegerLiteral] 1
693705
# 28| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
694706
# 29| getStmt: [AssignAddExpr] ... += ...

0 commit comments

Comments
 (0)