Skip to content

Commit 9a8e138

Browse files
committed
Ruby: also change evaluation order for scoped constants
1 parent a819797 commit 9a8e138

File tree

4 files changed

+62
-11
lines changed

4 files changed

+62
-11
lines changed

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

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,40 @@ private module DestructuredAssignDesugar {
950950
}
951951
}
952952

953+
abstract private class LhsWithReceiver extends Expr {
954+
abstract Expr getReceiver();
955+
956+
abstract SynthKind getSynthKind();
957+
}
958+
959+
private class LhsCall extends LhsWithReceiver instanceof MethodCall {
960+
final override Expr getReceiver() { result = MethodCall.super.getReceiver() }
961+
962+
final override SynthKind getSynthKind() {
963+
result = MethodCallKind(super.getMethodName(), false, super.getNumberOfArguments())
964+
}
965+
}
966+
967+
private class LhsScopedConstant extends LhsWithReceiver, TScopeResolutionConstantAccess {
968+
private Ruby::AstNode receiver;
969+
private string name;
970+
971+
LhsScopedConstant() {
972+
exists(Ruby::ScopeResolution e, Ruby::Constant c |
973+
this = TScopeResolutionConstantAccess(e, c)
974+
|
975+
receiver = e.getScope() and
976+
name = c.getValue()
977+
)
978+
}
979+
980+
final string getName() { result = name }
981+
982+
final override Expr getReceiver() { toGenerated(result) = receiver }
983+
984+
final override SynthKind getSynthKind() { result = ConstantWriteAccessKind(name) }
985+
}
986+
953987
pragma[nomagic]
954988
private predicate destructuredAssignSynthesis(AstNode parent, int i, Child child) {
955989
exists(DestructuredAssignExpr tae |
@@ -958,7 +992,7 @@ private module DestructuredAssignDesugar {
958992
child = SynthChild(StmtSequenceKind())
959993
or
960994
exists(AstNode seq | seq = TStmtSequenceSynth(tae, -1) |
961-
exists(MethodCall mc, int j | mc = tae.getElement(j) |
995+
exists(LhsWithReceiver mc, int j | mc = tae.getElement(j) |
962996
parent = seq and
963997
i = j and
964998
child = SynthChild(AssignExprKind())
@@ -1005,25 +1039,29 @@ private module DestructuredAssignDesugar {
10051039
exists(AstNode assign |
10061040
assign = TAssignExprSynth(seq, j + 1 + tae.getNumberOfElements())
10071041
|
1008-
exists(MethodCall mc | mc = elem |
1042+
exists(LhsWithReceiver mc | mc = elem |
10091043
parent = assign and
10101044
i = 0 and
1011-
child =
1012-
SynthChild(MethodCallKind(mc.getMethodName(), false, mc.getNumberOfArguments()))
1045+
child = SynthChild(mc.getSynthKind())
10131046
or
1014-
exists(AstNode call | call = TMethodCallSynth(assign, 0, _, _, _) |
1047+
exists(AstNode call | synthChild(assign, 0, call) |
10151048
parent = call and
10161049
i = 0 and
10171050
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(tae, j)))
10181051
or
10191052
parent = call and
1020-
child = childRef(mc.getArgument(i - 1))
1053+
child = childRef(mc.(MethodCall).getArgument(i - 1))
10211054
)
10221055
)
10231056
or
10241057
(
1025-
elem instanceof VariableAccess or
1026-
elem instanceof ConstantAccess or
1058+
elem instanceof VariableAccess
1059+
or
1060+
elem instanceof ConstantAccess and
1061+
not exists(Ruby::ScopeResolution g |
1062+
elem = TScopeResolutionConstantAccess(g, _) and exists(g.getScope())
1063+
)
1064+
or
10271065
elem instanceof DestructuredLhsExpr
10281066
) and
10291067
parent = assign and
@@ -1096,7 +1134,7 @@ private module DestructuredAssignDesugar {
10961134
synthChild(seq, tae.getNumberOfElements(), n) and
10971135
hasLocation(tae.getRightOperand(), l)
10981136
or
1099-
exists(MethodCall elem, int j |
1137+
exists(LhsWithReceiver elem, int j |
11001138
elem = tae.getElement(j) and
11011139
synthChild(seq, j, n) and
11021140
hasLocation(elem.getReceiver(), l)
@@ -1113,6 +1151,13 @@ private module DestructuredAssignDesugar {
11131151
i = [0 .. n.(DestructuredAssignExpr).getNumberOfElements()]
11141152
}
11151153

1154+
final override predicate constantWriteAccess(string name) {
1155+
exists(DestructuredAssignExpr tae, LhsScopedConstant ca |
1156+
ca = tae.getElement(_) and
1157+
name = ca.getName()
1158+
)
1159+
}
1160+
11161161
final override predicate methodCall(string name, boolean setter, int arity) {
11171162
name = "[]" and
11181163
setter = false and
@@ -1127,7 +1172,7 @@ private module DestructuredAssignDesugar {
11271172
}
11281173

11291174
final override predicate excludeFromControlFlowTree(AstNode n) {
1130-
n = any(DestructuredAssignExpr tae).getElement(_).(MethodCall)
1175+
n = any(DestructuredAssignExpr tae).getElement(_).(LhsWithReceiver)
11311176
}
11321177
}
11331178
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,8 +959,11 @@ operations/operations.rb:
959959
# 104| getReceiver: [LocalVariableAccess] __synth__3
960960
# 104| getArgument: [IntegerLiteral] 1
961961
# 104| getStmt: [AssignExpr] ... = ...
962+
# 104| getAnOperand/getRightOperand: [LocalVariableAccess] foo
963+
# 104| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2
964+
# 104| getStmt: [AssignExpr] ... = ...
962965
# 104| getAnOperand/getLeftOperand: [ConstantAssignment] FOO
963-
# 104| getScopeExpr: [LocalVariableAccess] foo
966+
# 104| getScopeExpr: [LocalVariableAccess] __synth__2
964967
# 104| getAnOperand/getRightOperand: [MethodCall] call to []
965968
# 104| getReceiver: [LocalVariableAccess] __synth__3
966969
# 104| getArgument: [IntegerLiteral] 2

ruby/ql/test/library-tests/ast/operations/assignment.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ assignments
6868
| operations.rb:104:1:104:3 | ... = ... | = | operations.rb:104:1:104:3 | FOO | operations.rb:104:1:104:3 | call to [] | AssignExpr |
6969
| operations.rb:104:1:104:32 | ... = ... | = | operations.rb:104:1:104:20 | (..., ...) | operations.rb:104:24:104:32 | [...] | AssignExpr |
7070
| operations.rb:104:6:104:10 | ... = ... | = | operations.rb:104:6:104:10 | BAR | operations.rb:104:6:104:10 | call to [] | AssignExpr |
71+
| operations.rb:104:13:104:15 | ... = ... | = | operations.rb:104:13:104:15 | __synth__2 | operations.rb:104:13:104:15 | foo | AssignExpr |
7172
| operations.rb:104:13:104:20 | ... = ... | = | operations.rb:104:13:104:20 | FOO | operations.rb:104:13:104:20 | call to [] | AssignExpr |
7273
| operations.rb:104:24:104:32 | ... = ... | = | operations.rb:104:24:104:32 | __synth__3 | operations.rb:104:24:104:32 | * ... | AssignExpr |
7374
assignOperations

ruby/ql/test/library-tests/ast/operations/operation.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@
236236
| operations.rb:104:1:104:32 | ... = ... | = | operations.rb:104:24:104:32 | [...] | AssignExpr |
237237
| operations.rb:104:6:104:10 | ... = ... | = | operations.rb:104:6:104:10 | BAR | AssignExpr |
238238
| operations.rb:104:6:104:10 | ... = ... | = | operations.rb:104:6:104:10 | call to [] | AssignExpr |
239+
| operations.rb:104:13:104:15 | ... = ... | = | operations.rb:104:13:104:15 | __synth__2 | AssignExpr |
240+
| operations.rb:104:13:104:15 | ... = ... | = | operations.rb:104:13:104:15 | foo | AssignExpr |
239241
| operations.rb:104:13:104:20 | ... = ... | = | operations.rb:104:13:104:20 | FOO | AssignExpr |
240242
| operations.rb:104:13:104:20 | ... = ... | = | operations.rb:104:13:104:20 | call to [] | AssignExpr |
241243
| operations.rb:104:24:104:32 | * ... | * | operations.rb:104:24:104:32 | [...] | SplatExpr |

0 commit comments

Comments
 (0)