mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Improve performance of desugaring transformations
This commit is contained in:
@@ -13,7 +13,7 @@ predicate isScopeResolutionMethodCall(Generated::ScopeResolution g, Generated::I
|
||||
}
|
||||
|
||||
abstract class CallImpl extends Call {
|
||||
abstract Expr getArgumentImpl(int n);
|
||||
abstract AstNode getArgumentImpl(int n);
|
||||
|
||||
/**
|
||||
* It is not possible to define this predicate as
|
||||
@@ -28,7 +28,7 @@ abstract class CallImpl extends Call {
|
||||
}
|
||||
|
||||
abstract class MethodCallImpl extends CallImpl, MethodCall {
|
||||
abstract Expr getReceiverImpl();
|
||||
abstract AstNode getReceiverImpl();
|
||||
|
||||
abstract string getMethodNameImpl();
|
||||
}
|
||||
@@ -42,9 +42,9 @@ class MethodCallSynth extends MethodCallImpl, TMethodCallSynth {
|
||||
)
|
||||
}
|
||||
|
||||
final override Expr getReceiverImpl() { synthChild(this, 0, result) }
|
||||
final override AstNode getReceiverImpl() { synthChild(this, 0, result) }
|
||||
|
||||
final override Expr getArgumentImpl(int n) { synthChild(this, n + 1, result) and n >= 0 }
|
||||
final override AstNode getArgumentImpl(int n) { synthChild(this, n + 1, result) and n >= 0 }
|
||||
|
||||
final override int getNumberOfArgumentsImpl() { this = TMethodCallSynth(_, _, _, _, result) }
|
||||
}
|
||||
@@ -56,7 +56,7 @@ class IdentifierMethodCall extends MethodCallImpl, TIdentifierMethodCall {
|
||||
|
||||
final override string getMethodNameImpl() { result = g.getValue() }
|
||||
|
||||
final override Self getReceiverImpl() { result = TSelfSynth(this, 0) }
|
||||
final override AstNode getReceiverImpl() { result = TSelfSynth(this, 0) }
|
||||
|
||||
final override Expr getArgumentImpl(int n) { none() }
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ private import AST
|
||||
private import TreeSitter
|
||||
|
||||
class AssignmentImpl extends Operation, TAssignment {
|
||||
abstract Pattern getLeftOperandImpl();
|
||||
abstract AstNode getLeftOperandImpl();
|
||||
|
||||
abstract Expr getRightOperandImpl();
|
||||
abstract AstNode getRightOperandImpl();
|
||||
}
|
||||
|
||||
class AssignExprReal extends AssignmentImpl, AssignExpr, TAssignExprReal {
|
||||
@@ -13,19 +13,19 @@ class AssignExprReal extends AssignmentImpl, AssignExpr, TAssignExprReal {
|
||||
|
||||
AssignExprReal() { this = TAssignExprReal(g) }
|
||||
|
||||
final override Pattern getLeftOperandImpl() { toGenerated(result) = g.getLeft() }
|
||||
final override AstNode getLeftOperandImpl() { toGenerated(result) = g.getLeft() }
|
||||
|
||||
final override Expr getRightOperandImpl() { toGenerated(result) = g.getRight() }
|
||||
final override AstNode getRightOperandImpl() { toGenerated(result) = g.getRight() }
|
||||
}
|
||||
|
||||
class AssignExprSynth extends AssignmentImpl, AssignExpr, TAssignExprSynth {
|
||||
final override Pattern getLeftOperandImpl() { synthChild(this, 0, result) }
|
||||
final override AstNode getLeftOperandImpl() { synthChild(this, 0, result) }
|
||||
|
||||
final override Expr getRightOperandImpl() { synthChild(this, 1, result) }
|
||||
final override AstNode getRightOperandImpl() { synthChild(this, 1, result) }
|
||||
}
|
||||
|
||||
class AssignOperationImpl extends AssignmentImpl, AssignOperation {
|
||||
final override LhsExpr getLeftOperandImpl() { toGenerated(result) = g.getLeft() }
|
||||
final override AstNode getLeftOperandImpl() { toGenerated(result) = g.getLeft() }
|
||||
|
||||
final override Expr getRightOperandImpl() { toGenerated(result) = g.getRight() }
|
||||
final override AstNode getRightOperandImpl() { toGenerated(result) = g.getRight() }
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
private import AST
|
||||
private import TreeSitter
|
||||
private import codeql_ruby.ast.internal.Call
|
||||
private import codeql_ruby.ast.internal.Operation
|
||||
private import codeql_ruby.ast.internal.Parameter
|
||||
private import codeql_ruby.ast.internal.Variable
|
||||
private import codeql_ruby.AST
|
||||
|
||||
@@ -31,8 +29,8 @@ newtype SynthKind =
|
||||
} or
|
||||
ModuloExprKind() or
|
||||
MulExprKind() or
|
||||
StmtSequenceKind() or
|
||||
RShiftExprKind() or
|
||||
StmtSequenceKind() or
|
||||
SelfKind() or
|
||||
SubExprKind()
|
||||
|
||||
@@ -110,7 +108,7 @@ private predicate assign(
|
||||
i = assignIndex and
|
||||
child = SynthChild(AssignExprKind())
|
||||
or
|
||||
parent = getSynthChild(assignParent, assignIndex) and
|
||||
parent = TAssignExprSynth(assignParent, assignIndex) and
|
||||
(
|
||||
i = 0 and
|
||||
child = SynthChild(LocalVariableAccessSynthKind(v))
|
||||
@@ -120,43 +118,128 @@ private predicate assign(
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[arity, setter]
|
||||
private SynthKind getCallKind(MethodCall mc, boolean setter, int arity) {
|
||||
result = MethodCallKind(mc.getMethodName(), setter, arity)
|
||||
}
|
||||
|
||||
private SomeLocation getSomeLocation(AstNode n) {
|
||||
result = SomeLocation(toGenerated(n).getLocation())
|
||||
}
|
||||
|
||||
private module ImplicitSelfSynthesis {
|
||||
pragma[nomagic]
|
||||
private predicate identifierMethodCallSelfSynthesis(
|
||||
AstNode mc, int i, Child child, LocationOption l
|
||||
) {
|
||||
child = SynthChild(SelfKind()) and
|
||||
mc = TIdentifierMethodCall(_) and
|
||||
i = 0 and
|
||||
l = NoneLocation()
|
||||
}
|
||||
|
||||
private class IdentifierMethodCallSelfSynthesis extends Synthesis {
|
||||
final override predicate child(AstNode parent, int i, Child child, LocationOption l) {
|
||||
child = SynthChild(SelfKind()) and
|
||||
parent = TIdentifierMethodCall(_) and
|
||||
i = 0 and
|
||||
l = NoneLocation()
|
||||
identifierMethodCallSelfSynthesis(parent, i, child, l)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate regularMethodCallSelfSynthesis(
|
||||
TRegularMethodCall mc, int i, Child child, LocationOption l
|
||||
) {
|
||||
exists(Generated::AstNode g |
|
||||
mc = TRegularMethodCall(g) and
|
||||
// If there's no explicit receiver (or scope resolution that acts like a
|
||||
// receiver), then the receiver is implicitly `self`. N.B. `::Foo()` is
|
||||
// not valid Ruby.
|
||||
not exists(g.(Generated::Call).getReceiver()) and
|
||||
not exists(g.(Generated::Call).getMethod().(Generated::ScopeResolution).getScope())
|
||||
) and
|
||||
child = SynthChild(SelfKind()) and
|
||||
i = 0 and
|
||||
l = NoneLocation()
|
||||
}
|
||||
|
||||
private class RegularMethodCallSelfSynthesis extends Synthesis {
|
||||
final override predicate child(AstNode parent, int i, Child child, LocationOption l) {
|
||||
child = SynthChild(SelfKind()) and
|
||||
i = 0 and
|
||||
exists(Generated::AstNode g |
|
||||
parent = TRegularMethodCall(g) and
|
||||
// If there's no explicit receiver (or scope resolution that acts like a
|
||||
// receiver), then the receiver is implicitly `self`. N.B. `::Foo()` is
|
||||
// not valid Ruby.
|
||||
not exists(g.(Generated::Call).getReceiver()) and
|
||||
not exists(g.(Generated::Call).getMethod().(Generated::ScopeResolution).getScope())
|
||||
) and
|
||||
l = NoneLocation()
|
||||
regularMethodCallSelfSynthesis(parent, i, child, l)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private module SetterDesugar {
|
||||
/** An assignment where the left-hand side is a method call. */
|
||||
private class SetterAssignExpr extends AssignExpr {
|
||||
private MethodCall mc;
|
||||
|
||||
pragma[nomagic]
|
||||
SetterAssignExpr() { mc = this.getLeftOperand() }
|
||||
|
||||
MethodCall getMethodCall() { result = mc }
|
||||
|
||||
pragma[nomagic]
|
||||
MethodCallKind getCallKind(boolean setter, int arity) {
|
||||
result = MethodCallKind(mc.getMethodName(), setter, arity)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
Expr getReceiver() { result = mc.getReceiver() }
|
||||
|
||||
pragma[nomagic]
|
||||
Expr getArgument(int i) { result = mc.getArgument(i) }
|
||||
|
||||
pragma[nomagic]
|
||||
int getNumberOfArguments() { result = mc.getNumberOfArguments() }
|
||||
|
||||
pragma[nomagic]
|
||||
LocationOption getMethodCallLocation() { result = getSomeLocation(mc) }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate setterMethodCallSynthesis(AstNode parent, int i, Child child, LocationOption l) {
|
||||
exists(SetterAssignExpr sae |
|
||||
parent = sae and
|
||||
i = -1 and
|
||||
child = SynthChild(StmtSequenceKind()) and
|
||||
l = NoneLocation()
|
||||
or
|
||||
exists(AstNode seq | seq = TStmtSequenceSynth(sae, -1) |
|
||||
parent = seq and
|
||||
i = 0 and
|
||||
child = SynthChild(sae.getCallKind(true, sae.getNumberOfArguments() + 1)) and
|
||||
l = sae.getMethodCallLocation()
|
||||
or
|
||||
exists(AstNode call | call = TMethodCallSynth(seq, 0, _, _, _) |
|
||||
parent = call and
|
||||
i = 0 and
|
||||
child = RealChild(sae.getReceiver()) and
|
||||
l = NoneLocation()
|
||||
or
|
||||
parent = call and
|
||||
child = RealChild(sae.getArgument(i - 1)) and
|
||||
l = NoneLocation()
|
||||
or
|
||||
l = sae.getMethodCallLocation() and
|
||||
exists(int valueIndex | valueIndex = sae.getNumberOfArguments() + 1 |
|
||||
parent = call and
|
||||
i = valueIndex and
|
||||
child = SynthChild(AssignExprKind())
|
||||
or
|
||||
parent = TAssignExprSynth(call, valueIndex) and
|
||||
(
|
||||
i = 0 and
|
||||
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(sae, 0)))
|
||||
or
|
||||
i = 1 and
|
||||
child = RealChild(sae.getRightOperand())
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
parent = seq and
|
||||
i = 1 and
|
||||
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(sae, 0))) and
|
||||
l = sae.getMethodCallLocation()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* ```rb
|
||||
* x.foo = y
|
||||
@@ -171,68 +254,23 @@ private module SetterDesugar {
|
||||
*/
|
||||
private class SetterMethodCallSynthesis extends Synthesis {
|
||||
final override predicate child(AstNode parent, int i, Child child, LocationOption l) {
|
||||
exists(AssignExpr ae, MethodCall mc | mc = ae.getLeftOperand() |
|
||||
parent = ae and
|
||||
i = -1 and
|
||||
child = SynthChild(StmtSequenceKind()) and
|
||||
l = NoneLocation()
|
||||
or
|
||||
exists(AstNode seq | seq = getSynthChild(ae, -1) |
|
||||
parent = seq and
|
||||
i = 0 and
|
||||
child = SynthChild(getCallKind(mc, true, mc.getNumberOfArguments() + 1)) and
|
||||
l = getSomeLocation(mc)
|
||||
or
|
||||
exists(AstNode call | call = getSynthChild(seq, 0) |
|
||||
parent = call and
|
||||
i = 0 and
|
||||
child = RealChild(mc.getReceiver()) and
|
||||
l = NoneLocation()
|
||||
or
|
||||
parent = call and
|
||||
child = RealChild(mc.getArgument(i - 1)) and
|
||||
l = NoneLocation()
|
||||
or
|
||||
l = getSomeLocation(mc) and
|
||||
exists(int valueIndex | valueIndex = mc.getNumberOfArguments() + 1 |
|
||||
parent = call and
|
||||
i = valueIndex and
|
||||
child = SynthChild(AssignExprKind())
|
||||
or
|
||||
parent = getSynthChild(call, valueIndex) and
|
||||
(
|
||||
i = 0 and
|
||||
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(ae, 0)))
|
||||
or
|
||||
i = 1 and
|
||||
child = RealChild(ae.getRightOperand())
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
parent = seq and
|
||||
i = 1 and
|
||||
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(ae, 0))) and
|
||||
l = getSomeLocation(mc)
|
||||
)
|
||||
)
|
||||
setterMethodCallSynthesis(parent, i, child, l)
|
||||
}
|
||||
|
||||
final override predicate excludeFromControlFlowTree(AstNode n) {
|
||||
n.(MethodCall) = any(AssignExpr ae).getLeftOperand()
|
||||
n = any(SetterAssignExpr sae).getMethodCall()
|
||||
}
|
||||
|
||||
final override predicate localVariable(AstNode n, int i) {
|
||||
n.(AssignExpr).getLeftOperand() instanceof MethodCall and
|
||||
n instanceof SetterAssignExpr and
|
||||
i = 0
|
||||
}
|
||||
|
||||
final override predicate methodCall(string name, boolean setter, int arity) {
|
||||
exists(AssignExpr ae, MethodCall mc |
|
||||
mc = ae.getLeftOperand() and
|
||||
name = mc.getMethodName() and
|
||||
exists(SetterAssignExpr sae |
|
||||
name = sae.getMethodCall().getMethodName() and
|
||||
setter = true and
|
||||
arity = mc.getNumberOfArguments() + 1
|
||||
arity = sae.getNumberOfArguments() + 1
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -279,6 +317,57 @@ private module AssignOperationDesugar {
|
||||
)
|
||||
}
|
||||
|
||||
/** An assignment operation where the left-hand side is a variable. */
|
||||
private class VariableAssignOperation extends AssignOperation {
|
||||
private Variable v;
|
||||
|
||||
pragma[nomagic]
|
||||
VariableAssignOperation() { v = this.getLeftOperand().(VariableAccess).getVariable() }
|
||||
|
||||
pragma[nomagic]
|
||||
SynthKind getVariableAccessKind() {
|
||||
result in [
|
||||
LocalVariableAccessRealKind(v).(SynthKind), InstanceVariableAccessKind(v),
|
||||
ClassVariableAccessKind(v), GlobalVariableAccessKind(v)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate variableAssignOperationSynthesis(
|
||||
AstNode parent, int i, Child child, LocationOption l
|
||||
) {
|
||||
exists(VariableAssignOperation vao |
|
||||
parent = vao and
|
||||
i = -1 and
|
||||
child = SynthChild(AssignExprKind()) and
|
||||
l = NoneLocation()
|
||||
or
|
||||
exists(AstNode assign | assign = TAssignExprSynth(vao, -1) |
|
||||
parent = assign and
|
||||
i = 0 and
|
||||
child = RealChild(vao.getLeftOperand()) and
|
||||
l = NoneLocation()
|
||||
or
|
||||
parent = assign and
|
||||
i = 1 and
|
||||
child = SynthChild(getKind(vao)) and
|
||||
l = SomeLocation(getAssignOperationLocation(vao))
|
||||
or
|
||||
parent = getSynthChild(assign, 1) and
|
||||
(
|
||||
i = 0 and
|
||||
child = SynthChild(vao.getVariableAccessKind()) and
|
||||
l = getSomeLocation(vao.getLeftOperand())
|
||||
or
|
||||
i = 1 and
|
||||
child = RealChild(vao.getRightOperand()) and
|
||||
l = NoneLocation()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* ```rb
|
||||
* x += y
|
||||
@@ -294,46 +383,133 @@ private module AssignOperationDesugar {
|
||||
*/
|
||||
private class VariableAssignOperationSynthesis extends Synthesis {
|
||||
final override predicate child(AstNode parent, int i, Child child, LocationOption l) {
|
||||
exists(AssignOperation ao, VariableReal v |
|
||||
v = ao.getLeftOperand().(VariableAccess).getVariable()
|
||||
|
|
||||
parent = ao and
|
||||
i = -1 and
|
||||
child = SynthChild(AssignExprKind()) and
|
||||
l = NoneLocation()
|
||||
or
|
||||
exists(AstNode assign | assign = getSynthChild(ao, -1) |
|
||||
parent = assign and
|
||||
i = 0 and
|
||||
child = RealChild(ao.getLeftOperand()) and
|
||||
l = NoneLocation()
|
||||
or
|
||||
parent = assign and
|
||||
i = 1 and
|
||||
child = SynthChild(getKind(ao)) and
|
||||
l = SomeLocation(getAssignOperationLocation(ao))
|
||||
or
|
||||
parent = getSynthChild(assign, 1) and
|
||||
(
|
||||
i = 0 and
|
||||
child =
|
||||
SynthChild([
|
||||
LocalVariableAccessRealKind(v).(SynthKind), InstanceVariableAccessKind(v),
|
||||
ClassVariableAccessKind(v), GlobalVariableAccessKind(v)
|
||||
]) and
|
||||
l = getSomeLocation(ao.getLeftOperand())
|
||||
or
|
||||
i = 1 and
|
||||
child = RealChild(ao.getRightOperand()) and
|
||||
l = NoneLocation()
|
||||
)
|
||||
)
|
||||
)
|
||||
variableAssignOperationSynthesis(parent, i, child, l)
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets an assignment operation where the LHS is method call `mc`. */
|
||||
private AssignOperation assignOperationMethodCall(MethodCall mc) { result.getLeftOperand() = mc }
|
||||
/** An assignment operation where the left-hand side is a method call. */
|
||||
private class SetterAssignOperation extends AssignOperation {
|
||||
private MethodCall mc;
|
||||
|
||||
pragma[nomagic]
|
||||
SetterAssignOperation() { mc = this.getLeftOperand() }
|
||||
|
||||
MethodCall getMethodCall() { result = mc }
|
||||
|
||||
pragma[nomagic]
|
||||
MethodCallKind getCallKind(boolean setter, int arity) {
|
||||
result = MethodCallKind(mc.getMethodName(), setter, arity)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
Expr getReceiver() { result = mc.getReceiver() }
|
||||
|
||||
pragma[nomagic]
|
||||
Expr getArgument(int i) { result = mc.getArgument(i) }
|
||||
|
||||
pragma[nomagic]
|
||||
int getNumberOfArguments() { result = mc.getNumberOfArguments() }
|
||||
|
||||
pragma[nomagic]
|
||||
LocationOption getMethodCallLocation() { result = getSomeLocation(mc) }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate methodCallAssignOperationSynthesis(
|
||||
AstNode parent, int i, Child child, LocationOption l
|
||||
) {
|
||||
exists(SetterAssignOperation sao |
|
||||
parent = sao and
|
||||
i = -1 and
|
||||
child = SynthChild(StmtSequenceKind()) and
|
||||
l = NoneLocation()
|
||||
or
|
||||
exists(AstNode seq, AstNode receiver |
|
||||
seq = TStmtSequenceSynth(sao, -1) and receiver = sao.getReceiver()
|
||||
|
|
||||
// `__synth__0 = foo`
|
||||
assign(parent, i, child, TLocalVariableSynth(sao, 0), seq, 0, receiver) and
|
||||
l = getSomeLocation(receiver)
|
||||
or
|
||||
// `__synth__1 = bar`
|
||||
exists(Expr arg, int j | arg = sao.getArgument(j - 1) |
|
||||
assign(parent, i, child, TLocalVariableSynth(sao, j), seq, j, arg) and
|
||||
l = getSomeLocation(arg)
|
||||
)
|
||||
or
|
||||
// `__synth__2 = __synth__0.[](__synth__1) + y`
|
||||
exists(int opAssignIndex | opAssignIndex = sao.getNumberOfArguments() + 1 |
|
||||
parent = seq and
|
||||
i = opAssignIndex and
|
||||
child = SynthChild(AssignExprKind()) and
|
||||
l = SomeLocation(getAssignOperationLocation(sao))
|
||||
or
|
||||
exists(AstNode assign | assign = TAssignExprSynth(seq, opAssignIndex) |
|
||||
parent = assign and
|
||||
i = 0 and
|
||||
child =
|
||||
SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(sao, opAssignIndex))) and
|
||||
l = SomeLocation(getAssignOperationLocation(sao))
|
||||
or
|
||||
parent = assign and
|
||||
i = 1 and
|
||||
child = SynthChild(getKind(sao)) and
|
||||
l = SomeLocation(getAssignOperationLocation(sao))
|
||||
or
|
||||
// `__synth__0.[](__synth__1) + y`
|
||||
exists(AstNode op | op = getSynthChild(assign, 1) |
|
||||
parent = op and
|
||||
i = 0 and
|
||||
child = SynthChild(sao.getCallKind(false, sao.getNumberOfArguments())) and
|
||||
l = sao.getMethodCallLocation()
|
||||
or
|
||||
parent = TMethodCallSynth(op, 0, _, _, _) and
|
||||
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(sao, i))) and
|
||||
(
|
||||
i = 0 and
|
||||
l = getSomeLocation(receiver)
|
||||
or
|
||||
l = getSomeLocation(sao.getArgument(i - 1))
|
||||
)
|
||||
or
|
||||
parent = op and
|
||||
i = 1 and
|
||||
child = RealChild(sao.getRightOperand()) and
|
||||
l = NoneLocation()
|
||||
)
|
||||
)
|
||||
or
|
||||
// `__synth__0.[]=(__synth__1, __synth__2);`
|
||||
parent = seq and
|
||||
i = opAssignIndex + 1 and
|
||||
child = SynthChild(sao.getCallKind(true, opAssignIndex)) and
|
||||
l = sao.getMethodCallLocation()
|
||||
or
|
||||
exists(AstNode setter | setter = TMethodCallSynth(seq, opAssignIndex + 1, _, _, _) |
|
||||
parent = setter and
|
||||
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(sao, i))) and
|
||||
(
|
||||
i = 0 and
|
||||
l = getSomeLocation(receiver)
|
||||
or
|
||||
l = getSomeLocation(sao.getArgument(i - 1))
|
||||
)
|
||||
or
|
||||
parent = setter and
|
||||
i = opAssignIndex + 1 and
|
||||
child =
|
||||
SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(sao, opAssignIndex))) and
|
||||
l = SomeLocation(getAssignOperationLocation(sao))
|
||||
)
|
||||
or
|
||||
parent = seq and
|
||||
i = opAssignIndex + 2 and
|
||||
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(sao, opAssignIndex))) and
|
||||
l = SomeLocation(getAssignOperationLocation(sao))
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* ```rb
|
||||
@@ -352,119 +528,25 @@ private module AssignOperationDesugar {
|
||||
*/
|
||||
private class MethodCallAssignOperationSynthesis extends Synthesis {
|
||||
final override predicate child(AstNode parent, int i, Child child, LocationOption l) {
|
||||
exists(AssignOperation ao, MethodCall mc | ao = assignOperationMethodCall(mc) |
|
||||
parent = ao and
|
||||
i = -1 and
|
||||
child = SynthChild(StmtSequenceKind()) and
|
||||
l = NoneLocation()
|
||||
or
|
||||
exists(AstNode seq, AstNode receiver |
|
||||
seq = getSynthChild(ao, -1) and receiver = mc.getReceiver()
|
||||
|
|
||||
// `__synth__0 = foo`
|
||||
assign(parent, i, child, TLocalVariableSynth(ao, 0), seq, 0, receiver) and
|
||||
l = getSomeLocation(receiver)
|
||||
or
|
||||
// `__synth__1 = bar`
|
||||
exists(Expr arg, int j | arg = mc.getArgument(j - 1) |
|
||||
assign(parent, i, child, TLocalVariableSynth(ao, j), seq, j, arg) and
|
||||
l = getSomeLocation(arg)
|
||||
)
|
||||
or
|
||||
// `__synth__2 = __synth__0.[](__synth__1) + y`
|
||||
exists(int opAssignIndex | opAssignIndex = mc.getNumberOfArguments() + 1 |
|
||||
parent = seq and
|
||||
i = opAssignIndex and
|
||||
child = SynthChild(AssignExprKind()) and
|
||||
l = SomeLocation(getAssignOperationLocation(ao))
|
||||
or
|
||||
exists(AstNode assign | assign = getSynthChild(seq, opAssignIndex) |
|
||||
parent = assign and
|
||||
i = 0 and
|
||||
child =
|
||||
SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(ao, opAssignIndex))) and
|
||||
l = SomeLocation(getAssignOperationLocation(ao))
|
||||
or
|
||||
parent = assign and
|
||||
i = 1 and
|
||||
child = SynthChild(getKind(ao)) and
|
||||
l = SomeLocation(getAssignOperationLocation(ao))
|
||||
or
|
||||
// `__synth__0.[](__synth__1) + y`
|
||||
exists(AstNode op | op = getSynthChild(assign, 1) |
|
||||
parent = op and
|
||||
i = 0 and
|
||||
child = SynthChild(getCallKind(mc, false, mc.getNumberOfArguments())) and
|
||||
l = getSomeLocation(mc)
|
||||
or
|
||||
parent = getSynthChild(op, 0) and
|
||||
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(ao, i))) and
|
||||
(
|
||||
i = 0 and
|
||||
l = getSomeLocation(receiver)
|
||||
or
|
||||
l = getSomeLocation(mc.getArgument(i - 1))
|
||||
)
|
||||
or
|
||||
parent = op and
|
||||
i = 1 and
|
||||
child = RealChild(ao.getRightOperand()) and
|
||||
l = NoneLocation()
|
||||
)
|
||||
)
|
||||
or
|
||||
// `__synth__0.[]=(__synth__1, __synth__2);`
|
||||
parent = seq and
|
||||
i = opAssignIndex + 1 and
|
||||
child = SynthChild(getCallKind(mc, true, opAssignIndex)) and
|
||||
l = getSomeLocation(mc)
|
||||
or
|
||||
exists(AstNode setter | setter = getSynthChild(seq, opAssignIndex + 1) |
|
||||
parent = setter and
|
||||
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(ao, i))) and
|
||||
(
|
||||
i = 0 and
|
||||
l = getSomeLocation(receiver)
|
||||
or
|
||||
l = getSomeLocation(mc.getArgument(i - 1))
|
||||
)
|
||||
or
|
||||
parent = setter and
|
||||
i = opAssignIndex + 1 and
|
||||
child =
|
||||
SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(ao, opAssignIndex))) and
|
||||
l = SomeLocation(getAssignOperationLocation(ao))
|
||||
)
|
||||
or
|
||||
parent = seq and
|
||||
i = opAssignIndex + 2 and
|
||||
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(ao, opAssignIndex))) and
|
||||
l = SomeLocation(getAssignOperationLocation(ao))
|
||||
)
|
||||
)
|
||||
)
|
||||
methodCallAssignOperationSynthesis(parent, i, child, l)
|
||||
}
|
||||
|
||||
final override predicate localVariable(AstNode n, int i) {
|
||||
exists(MethodCall mc | n = assignOperationMethodCall(mc) |
|
||||
i in [0 .. mc.getNumberOfArguments() + 1]
|
||||
)
|
||||
n = any(SetterAssignOperation sao | i in [0 .. sao.getNumberOfArguments() + 1])
|
||||
}
|
||||
|
||||
final override predicate methodCall(string name, boolean setter, int arity) {
|
||||
exists(MethodCall mc | exists(assignOperationMethodCall(mc)) |
|
||||
name = mc.getMethodName() and
|
||||
exists(SetterAssignOperation sao | name = sao.getMethodCall().getMethodName() |
|
||||
setter = false and
|
||||
arity = mc.getNumberOfArguments()
|
||||
arity = sao.getNumberOfArguments()
|
||||
or
|
||||
name = mc.getMethodName() and
|
||||
setter = true and
|
||||
arity = mc.getNumberOfArguments() + 1
|
||||
arity = sao.getNumberOfArguments() + 1
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate excludeFromControlFlowTree(AstNode n) {
|
||||
exists(assignOperationMethodCall(n))
|
||||
n = any(SetterAssignOperation sao).getMethodCall()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,12 +33,12 @@ calls/calls.rb:
|
||||
# 315| getStmt: [LocalVariableAccess] __synth__0
|
||||
# 318| [AssignAddExpr] ... += ...
|
||||
# 318| getDesugared: [StmtSequence] ...
|
||||
# 318| getStmt: [SetterMethodCall] call to count=
|
||||
# 318| getReceiver: [LocalVariableAccess] __synth__0
|
||||
# 318| getArgument: [LocalVariableAccess] __synth__1
|
||||
# 318| getStmt: [AssignExpr] ... = ...
|
||||
# 318| getAnOperand/getRightOperand: [Self] self
|
||||
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 318| getStmt: [SetterMethodCall] call to count=
|
||||
# 318| getReceiver: [LocalVariableAccess] __synth__0
|
||||
# 318| getArgument: [LocalVariableAccess] __synth__1
|
||||
# 318| getStmt: [AssignExpr] ... = ...
|
||||
# 318| getAnOperand/getRightOperand: [AddExpr] ... + ...
|
||||
# 318| getAnOperand/getLeftOperand: [MethodCall] call to count
|
||||
@@ -48,14 +48,14 @@ calls/calls.rb:
|
||||
# 318| getStmt: [LocalVariableAccess] __synth__1
|
||||
# 319| [AssignAddExpr] ... += ...
|
||||
# 319| getDesugared: [StmtSequence] ...
|
||||
# 319| getStmt: [SetterMethodCall] call to []=
|
||||
# 319| getReceiver: [LocalVariableAccess] __synth__0
|
||||
# 319| getArgument: [LocalVariableAccess] __synth__1
|
||||
# 319| getArgument: [LocalVariableAccess] __synth__2
|
||||
# 319| getStmt: [AssignExpr] ... = ...
|
||||
# 319| getAnOperand/getRightOperand: [MethodCall] call to foo
|
||||
# 319| getReceiver: [Self] self
|
||||
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 319| getStmt: [SetterMethodCall] call to []=
|
||||
# 319| getReceiver: [LocalVariableAccess] __synth__0
|
||||
# 319| getArgument: [LocalVariableAccess] __synth__1
|
||||
# 319| getArgument: [LocalVariableAccess] __synth__2
|
||||
# 319| getStmt: [AssignExpr] ... = ...
|
||||
# 319| getAnOperand/getRightOperand: [IntegerLiteral] 0
|
||||
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1
|
||||
@@ -69,6 +69,11 @@ calls/calls.rb:
|
||||
# 319| getStmt: [LocalVariableAccess] __synth__2
|
||||
# 320| [AssignMulExpr] ... *= ...
|
||||
# 320| getDesugared: [StmtSequence] ...
|
||||
# 320| getStmt: [AssignExpr] ... = ...
|
||||
# 320| getAnOperand/getRightOperand: [MethodCall] call to bar
|
||||
# 320| getReceiver: [MethodCall] call to foo
|
||||
# 320| getReceiver: [Self] self
|
||||
# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 320| getStmt: [SetterMethodCall] call to []=
|
||||
# 320| getReceiver: [LocalVariableAccess] __synth__0
|
||||
# 320| getArgument: [LocalVariableAccess] __synth__1
|
||||
@@ -76,11 +81,6 @@ calls/calls.rb:
|
||||
# 320| getArgument: [LocalVariableAccess] __synth__3
|
||||
# 320| getArgument: [LocalVariableAccess] __synth__4
|
||||
# 320| getStmt: [AssignExpr] ... = ...
|
||||
# 320| getAnOperand/getRightOperand: [MethodCall] call to bar
|
||||
# 320| getReceiver: [MethodCall] call to foo
|
||||
# 320| getReceiver: [Self] self
|
||||
# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 320| getStmt: [AssignExpr] ... = ...
|
||||
# 320| getAnOperand/getRightOperand: [IntegerLiteral] 0
|
||||
# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__1
|
||||
# 320| getStmt: [AssignExpr] ... = ...
|
||||
|
||||
@@ -2214,18 +2214,18 @@ desugar.rb:
|
||||
# 14| ...
|
||||
#-----| -> exit m4 (normal)
|
||||
|
||||
# 14| call to count=
|
||||
#-----| -> __synth__1
|
||||
|
||||
# 14| ... = ...
|
||||
#-----| -> __synth__1
|
||||
|
||||
# 14| __synth__0
|
||||
# 14| call to count=
|
||||
#-----| -> __synth__1
|
||||
|
||||
# 14| __synth__0
|
||||
#-----| -> x
|
||||
|
||||
# 14| __synth__0
|
||||
#-----| -> __synth__1
|
||||
|
||||
# 14| call to count
|
||||
#-----| -> 1
|
||||
|
||||
@@ -2242,10 +2242,10 @@ desugar.rb:
|
||||
#-----| -> ... = ...
|
||||
|
||||
# 14| __synth__1
|
||||
#-----| -> call to count=
|
||||
#-----| -> __synth__0
|
||||
|
||||
# 14| __synth__1
|
||||
#-----| -> __synth__0
|
||||
#-----| -> call to count=
|
||||
|
||||
# 14| 1
|
||||
#-----| -> ... + ...
|
||||
@@ -2276,18 +2276,18 @@ desugar.rb:
|
||||
# 18| ...
|
||||
#-----| -> exit m5 (normal)
|
||||
|
||||
# 18| call to []=
|
||||
#-----| -> __synth__4
|
||||
|
||||
# 18| ... = ...
|
||||
#-----| -> __synth__1
|
||||
|
||||
# 18| __synth__0
|
||||
#-----| -> __synth__1
|
||||
# 18| call to []=
|
||||
#-----| -> __synth__4
|
||||
|
||||
# 18| __synth__0
|
||||
#-----| -> x
|
||||
|
||||
# 18| __synth__0
|
||||
#-----| -> __synth__1
|
||||
|
||||
# 18| call to []
|
||||
#-----| -> 1
|
||||
|
||||
@@ -2301,10 +2301,10 @@ desugar.rb:
|
||||
#-----| -> __synth__2
|
||||
|
||||
# 18| __synth__1
|
||||
#-----| -> __synth__2
|
||||
#-----| -> 0
|
||||
|
||||
# 18| __synth__1
|
||||
#-----| -> 0
|
||||
#-----| -> __synth__2
|
||||
|
||||
# 18| __synth__1
|
||||
#-----| -> __synth__2
|
||||
@@ -2319,10 +2319,10 @@ desugar.rb:
|
||||
#-----| -> __synth__3
|
||||
|
||||
# 18| __synth__2
|
||||
#-----| -> __synth__3
|
||||
#-----| -> y
|
||||
|
||||
# 18| __synth__2
|
||||
#-----| -> y
|
||||
#-----| -> __synth__3
|
||||
|
||||
# 18| __synth__2
|
||||
#-----| -> __synth__3
|
||||
@@ -2340,10 +2340,10 @@ desugar.rb:
|
||||
#-----| -> __synth__4
|
||||
|
||||
# 18| __synth__3
|
||||
#-----| -> __synth__4
|
||||
#-----| -> x
|
||||
|
||||
# 18| __synth__3
|
||||
#-----| -> x
|
||||
#-----| -> __synth__4
|
||||
|
||||
# 18| __synth__3
|
||||
#-----| -> call to []
|
||||
@@ -2361,10 +2361,10 @@ desugar.rb:
|
||||
#-----| -> ... = ...
|
||||
|
||||
# 18| __synth__4
|
||||
#-----| -> call to []=
|
||||
#-----| -> __synth__0
|
||||
|
||||
# 18| __synth__4
|
||||
#-----| -> __synth__0
|
||||
#-----| -> call to []=
|
||||
|
||||
# 18| 1
|
||||
#-----| -> ... + ...
|
||||
|
||||
Reference in New Issue
Block a user