Ruby: Flatten nested statements inside desugared for loops

This commit is contained in:
Tom Hvitved
2021-11-11 15:12:16 +01:00
parent 9125b85ff0
commit 413375992d
9 changed files with 171 additions and 161 deletions

View File

@@ -583,7 +583,7 @@ class ForExpr extends Loop, TForExpr {
final override string getAPrimaryQlClass() { result = "ForExpr" }
/** Gets the body of this `for` loop. */
final override Stmt getBody() { toGenerated(result) = g.getBody() }
final override StmtSequence getBody() { toGenerated(result) = g.getBody() }
/** Gets the pattern representing the iteration argument. */
final Pattern getPattern() { toGenerated(result) = g.getPattern() }

View File

@@ -1,6 +1,7 @@
private import codeql.ruby.AST
private import codeql.ruby.CFG
private import internal.AST
private import internal.Expr
private import internal.TreeSitter
/**
@@ -91,90 +92,19 @@ class StmtSequence extends Expr, TStmtSequence {
}
}
private class StmtSequenceSynth extends StmtSequence, TStmtSequenceSynth {
final override Stmt getStmt(int n) { synthChild(this, n, result) }
final override string toString() { result = "..." }
}
private class Then extends StmtSequence, TThen {
private Ruby::Then g;
Then() { this = TThen(g) }
override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
final override string toString() { result = "then ..." }
}
private class Else extends StmtSequence, TElse {
private Ruby::Else g;
Else() { this = TElse(g) }
override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
final override string toString() { result = "else ..." }
}
private class Do extends StmtSequence, TDo {
private Ruby::Do g;
Do() { this = TDo(g) }
override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
final override string toString() { result = "do ..." }
}
private class Ensure extends StmtSequence, TEnsure {
private Ruby::Ensure g;
Ensure() { this = TEnsure(g) }
override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
final override string toString() { result = "ensure ..." }
}
/**
* A sequence of statements representing the body of a method, class, module,
* or do-block. That is, any body that may also include rescue/ensure/else
* statements.
*/
class BodyStmt extends StmtSequence, TBodyStmt {
// Not defined by dispatch, as it should not be exposed
private Ruby::AstNode getChild(int i) {
result = any(Ruby::Method g | this = TMethod(g)).getChild(i)
or
result = any(Ruby::SingletonMethod g | this = TSingletonMethod(g)).getChild(i)
or
exists(Ruby::Lambda g | this = TLambda(g) |
result = g.getBody().(Ruby::DoBlock).getChild(i) or
result = g.getBody().(Ruby::Block).getChild(i)
)
or
result = any(Ruby::DoBlock g | this = TDoBlock(g)).getChild(i)
or
result = any(Ruby::Program g | this = TToplevel(g)).getChild(i) and
not result instanceof Ruby::BeginBlock
or
result = any(Ruby::Class g | this = TClassDeclaration(g)).getChild(i)
or
result = any(Ruby::SingletonClass g | this = TSingletonClass(g)).getChild(i)
or
result = any(Ruby::Module g | this = TModuleDeclaration(g)).getChild(i)
or
result = any(Ruby::Begin g | this = TBeginExpr(g)).getChild(i)
}
final override Stmt getStmt(int n) {
result =
rank[n + 1](AstNode node, int i |
toGenerated(node) = this.getChild(i) and
not node instanceof Else and
not node instanceof RescueClause and
not node instanceof Ensure
toGenerated(result) =
rank[n + 1](Ruby::AstNode node, int i |
node = getBodyStmtChild(this, i) and
not node instanceof Ruby::Else and
not node instanceof Ruby::Rescue and
not node instanceof Ruby::Ensure
|
node order by i
)
@@ -183,17 +113,25 @@ class BodyStmt extends StmtSequence, TBodyStmt {
/** Gets the `n`th rescue clause in this block. */
final RescueClause getRescue(int n) {
result =
rank[n + 1](RescueClause node, int i | toGenerated(node) = this.getChild(i) | node order by i)
rank[n + 1](RescueClause node, int i |
toGenerated(node) = getBodyStmtChild(this, i)
|
node order by i
)
}
/** Gets a rescue clause in this block. */
final RescueClause getARescue() { result = this.getRescue(_) }
/** Gets the `else` clause in this block, if any. */
final StmtSequence getElse() { result = unique(Else s | toGenerated(s) = getChild(_)) }
final StmtSequence getElse() {
result = unique(Else s | toGenerated(s) = getBodyStmtChild(this, _))
}
/** Gets the `ensure` clause in this block, if any. */
final StmtSequence getEnsure() { result = unique(Ensure s | toGenerated(s) = getChild(_)) }
final StmtSequence getEnsure() {
result = unique(Ensure s | toGenerated(s) = getBodyStmtChild(this, _))
}
final predicate hasEnsure() { exists(this.getEnsure()) }

View File

@@ -0,0 +1,75 @@
private import codeql.ruby.AST
private import codeql.ruby.CFG
private import AST
private import TreeSitter
class StmtSequenceSynth extends StmtSequence, TStmtSequenceSynth {
final override Stmt getStmt(int n) { synthChild(this, n, result) }
final override string toString() { result = "..." }
}
class Then extends StmtSequence, TThen {
private Ruby::Then g;
Then() { this = TThen(g) }
override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
final override string toString() { result = "then ..." }
}
class Else extends StmtSequence, TElse {
private Ruby::Else g;
Else() { this = TElse(g) }
override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
final override string toString() { result = "else ..." }
}
class Do extends StmtSequence, TDo {
private Ruby::Do g;
Do() { this = TDo(g) }
override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
final override string toString() { result = "do ..." }
}
class Ensure extends StmtSequence, TEnsure {
private Ruby::Ensure g;
Ensure() { this = TEnsure(g) }
override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
final override string toString() { result = "ensure ..." }
}
// Not defined by dispatch, as it should not be exposed
Ruby::AstNode getBodyStmtChild(TBodyStmt b, int i) {
result = any(Ruby::Method g | b = TMethod(g)).getChild(i)
or
result = any(Ruby::SingletonMethod g | b = TSingletonMethod(g)).getChild(i)
or
exists(Ruby::Lambda g | b = TLambda(g) |
result = g.getBody().(Ruby::DoBlock).getChild(i) or
result = g.getBody().(Ruby::Block).getChild(i)
)
or
result = any(Ruby::DoBlock g | b = TDoBlock(g)).getChild(i)
or
result = any(Ruby::Program g | b = TToplevel(g)).getChild(i) and
not result instanceof Ruby::BeginBlock
or
result = any(Ruby::Class g | b = TClassDeclaration(g)).getChild(i)
or
result = any(Ruby::SingletonClass g | b = TSingletonClass(g)).getChild(i)
or
result = any(Ruby::Module g | b = TModuleDeclaration(g)).getChild(i)
or
result = any(Ruby::Begin g | b = TBeginExpr(g)).getChild(i)
}

View File

@@ -3,6 +3,7 @@
private import AST
private import TreeSitter
private import codeql.ruby.ast.internal.Call
private import codeql.ruby.ast.internal.Expr
private import codeql.ruby.ast.internal.Variable
private import codeql.ruby.ast.internal.Pattern
private import codeql.ruby.ast.internal.Scope
@@ -880,8 +881,7 @@ private module ForLoopDesugar {
or
// rest of block body
parent = block and
i = 2 and
child = RealChild(for.getBody())
child = RealChild(for.getBody().(Do).getStmt(i - 2))
)
)
)
@@ -902,5 +902,9 @@ private module ForLoopDesugar {
n instanceof TSimpleParameterSynth and
i = 0
}
final override predicate excludeFromControlFlowTree(AstNode n) {
n = any(ForExpr for).getBody()
}
}
}

View File

@@ -61,6 +61,9 @@ module CfgScope {
final override predicate exit(AstNode last, Completion c) {
last(this.(Trees::EndBlockTree).getLastBodyChild(), last, c)
or
last(this.(Trees::EndBlockTree).getBodyChild(_, _), last, c) and
not c instanceof NormalCompletion
}
}
@@ -79,6 +82,9 @@ module CfgScope {
final override predicate exit(AstNode last, Completion c) {
last(this.(Trees::BraceBlockTree).getLastBodyChild(), last, c)
or
last(this.(Trees::BraceBlockTree).getBodyChild(_, _), last, c) and
not c instanceof NormalCompletion
}
}
}

View File

@@ -31,9 +31,8 @@ calls/calls.rb:
# 226| getStmt: [AssignExpr] ... = ...
# 226| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
# 226| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 226| getStmt: [StmtSequence] do ...
# 227| getStmt: [MethodCall] call to baz
# 227| getReceiver: [Self, SelfVariableAccess] self
# 227| getStmt: [MethodCall] call to baz
# 227| getReceiver: [Self, SelfVariableAccess] self
# 226| getReceiver: [MethodCall] call to bar
# 226| getReceiver: [Self, SelfVariableAccess] self
# 229| [ForExpr] for ... in ...
@@ -44,9 +43,8 @@ calls/calls.rb:
# 229| getStmt: [AssignExpr] ... = ...
# 229| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
# 229| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 229| getStmt: [StmtSequence] do ...
# 230| getStmt: [MethodCall] call to baz
# 230| getReceiver: [ConstantReadAccess] X
# 230| getStmt: [MethodCall] call to baz
# 230| getReceiver: [ConstantReadAccess] X
# 229| getReceiver: [MethodCall] call to bar
# 229| getReceiver: [ConstantReadAccess] X
# 314| [AssignExpr] ... = ...
@@ -248,12 +246,11 @@ calls/calls.rb:
# 340| getArgument: [IntegerLiteral] 2
# 340| getReceiver: [LocalVariableAccess] __synth__0__1
# 340| getLeftOperand: [TuplePattern] (..., ...)
# 340| getStmt: [StmtSequence] do ...
# 341| getStmt: [MethodCall] call to foo
# 341| getReceiver: [Self, SelfVariableAccess] self
# 341| getArgument: [LocalVariableAccess] x
# 341| getArgument: [LocalVariableAccess] y
# 341| getArgument: [LocalVariableAccess] z
# 341| getStmt: [MethodCall] call to foo
# 341| getReceiver: [Self, SelfVariableAccess] self
# 341| getArgument: [LocalVariableAccess] x
# 341| getArgument: [LocalVariableAccess] y
# 341| getArgument: [LocalVariableAccess] z
# 340| getReceiver: [ArrayLiteral] [...]
# 340| getDesugared: [MethodCall] call to []
# 340| getReceiver: [ConstantReadAccess] Array
@@ -409,16 +406,15 @@ control/loops.rb:
# 9| getStmt: [AssignExpr] ... = ...
# 9| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
# 9| getAnOperand/getLeftOperand: [LocalVariableAccess] n
# 9| getStmt: [StmtSequence] do ...
# 10| getStmt: [AssignAddExpr] ... += ...
# 10| getDesugared: [AssignExpr] ... = ...
# 10| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 10| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 10| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum
# 10| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] n
# 11| getStmt: [AssignExpr] ... = ...
# 11| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 11| getAnOperand/getRightOperand: [LocalVariableAccess] n
# 10| getStmt: [AssignAddExpr] ... += ...
# 10| getDesugared: [AssignExpr] ... = ...
# 10| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 10| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 10| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum
# 10| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] n
# 11| getStmt: [AssignExpr] ... = ...
# 11| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 11| getAnOperand/getRightOperand: [LocalVariableAccess] n
# 9| getReceiver: [RangeLiteral] _ .. _
# 9| getBegin: [IntegerLiteral] 1
# 9| getEnd: [IntegerLiteral] 10
@@ -430,19 +426,18 @@ control/loops.rb:
# 16| getStmt: [AssignExpr] ... = ...
# 16| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
# 16| getAnOperand/getLeftOperand: [LocalVariableAccess] n
# 16| getStmt: [StmtSequence] do ...
# 17| getStmt: [AssignAddExpr] ... += ...
# 17| getDesugared: [AssignExpr] ... = ...
# 17| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 17| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 17| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum
# 17| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] n
# 18| getStmt: [AssignSubExpr] ... -= ...
# 18| getDesugared: [AssignExpr] ... = ...
# 18| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 18| getAnOperand/getRightOperand: [SubExpr] ... - ...
# 18| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo
# 18| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] n
# 17| getStmt: [AssignAddExpr] ... += ...
# 17| getDesugared: [AssignExpr] ... = ...
# 17| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 17| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 17| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum
# 17| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] n
# 18| getStmt: [AssignSubExpr] ... -= ...
# 18| getDesugared: [AssignExpr] ... = ...
# 18| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 18| getAnOperand/getRightOperand: [SubExpr] ... - ...
# 18| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo
# 18| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] n
# 16| getReceiver: [RangeLiteral] _ .. _
# 16| getBegin: [IntegerLiteral] 1
# 16| getEnd: [IntegerLiteral] 10
@@ -468,19 +463,18 @@ control/loops.rb:
# 22| getArgument: [IntegerLiteral] 1
# 22| getReceiver: [LocalVariableAccess] __synth__0__1
# 22| getLeftOperand: [TuplePattern] (..., ...)
# 22| getStmt: [StmtSequence] do ...
# 23| getStmt: [AssignAddExpr] ... += ...
# 23| getDesugared: [AssignExpr] ... = ...
# 23| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 23| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 23| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum
# 23| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value
# 24| getStmt: [AssignMulExpr] ... *= ...
# 24| getDesugared: [AssignExpr] ... = ...
# 24| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 24| getAnOperand/getRightOperand: [MulExpr] ... * ...
# 24| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo
# 24| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value
# 23| getStmt: [AssignAddExpr] ... += ...
# 23| getDesugared: [AssignExpr] ... = ...
# 23| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 23| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 23| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum
# 23| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value
# 24| getStmt: [AssignMulExpr] ... *= ...
# 24| getDesugared: [AssignExpr] ... = ...
# 24| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 24| getAnOperand/getRightOperand: [MulExpr] ... * ...
# 24| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo
# 24| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value
# 22| getReceiver: [HashLiteral] {...}
# 22| getElement: [Pair] Pair
# 22| getKey: [SymbolLiteral] :foo
@@ -510,20 +504,19 @@ control/loops.rb:
# 28| getArgument: [IntegerLiteral] 1
# 28| getReceiver: [LocalVariableAccess] __synth__0__1
# 28| getLeftOperand: [TuplePattern] (..., ...)
# 28| getStmt: [StmtSequence] do ...
# 29| getStmt: [AssignAddExpr] ... += ...
# 29| getDesugared: [AssignExpr] ... = ...
# 29| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 29| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 29| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum
# 29| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value
# 30| getStmt: [AssignDivExpr] ... /= ...
# 30| getDesugared: [AssignExpr] ... = ...
# 30| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 30| getAnOperand/getRightOperand: [DivExpr] ... / ...
# 30| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo
# 30| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value
# 31| getStmt: [BreakStmt] break
# 29| getStmt: [AssignAddExpr] ... += ...
# 29| getDesugared: [AssignExpr] ... = ...
# 29| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 29| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 29| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum
# 29| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value
# 30| getStmt: [AssignDivExpr] ... /= ...
# 30| getDesugared: [AssignExpr] ... = ...
# 30| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 30| getAnOperand/getRightOperand: [DivExpr] ... / ...
# 30| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo
# 30| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value
# 31| getStmt: [BreakStmt] break
# 28| getReceiver: [HashLiteral] {...}
# 28| getElement: [Pair] Pair
# 28| getKey: [SymbolLiteral] :foo
@@ -705,14 +698,13 @@ erb/template.html.erb:
# 27| getStmt: [AssignExpr] ... = ...
# 27| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
# 27| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 27| getStmt: [StmtSequence] do ...
# 28| getStmt: [AssignAddExpr] ... += ...
# 28| getDesugared: [AssignExpr] ... = ...
# 28| getAnOperand/getLeftOperand: [LocalVariableAccess] xs
# 28| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 28| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] xs
# 28| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] x
# 29| getStmt: [LocalVariableAccess] xs
# 28| getStmt: [AssignAddExpr] ... += ...
# 28| getDesugared: [AssignExpr] ... = ...
# 28| getAnOperand/getLeftOperand: [LocalVariableAccess] xs
# 28| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 28| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] xs
# 28| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] x
# 29| getStmt: [LocalVariableAccess] xs
# 27| getReceiver: [ArrayLiteral] [...]
# 27| getDesugared: [MethodCall] call to []
# 27| getReceiver: [ConstantReadAccess] Array

View File

@@ -1458,9 +1458,6 @@ cfg.rb:
# 90| 3.4e5
#-----| -> call to []
# 90| do ...
#-----| -> exit { ... } (normal)
# 91| if ...
#-----| -> self
@@ -1478,7 +1475,7 @@ cfg.rb:
#-----| next -> exit { ... } (normal)
# 92| call to puts
#-----| -> do ...
#-----| -> exit { ... } (normal)
# 92| self
#-----| -> x

View File

@@ -36,7 +36,6 @@
| local_dataflow.rb:10:14:10:18 | array | local_dataflow.rb:15:10:15:14 | array |
| local_dataflow.rb:11:1:11:2 | [post] self | local_dataflow.rb:12:3:12:5 | self |
| local_dataflow.rb:11:1:11:2 | self | local_dataflow.rb:12:3:12:5 | self |
| local_dataflow.rb:12:3:12:5 | call to p | local_dataflow.rb:10:19:13:3 | do ... |
| local_dataflow.rb:15:1:17:3 | __synth__0__1 | local_dataflow.rb:15:1:17:3 | ... = ... |
| local_dataflow.rb:15:1:17:3 | __synth__0__1 | local_dataflow.rb:15:1:17:3 | ... = ... |
| local_dataflow.rb:15:1:17:3 | __synth__0__1 | local_dataflow.rb:15:1:17:3 | __synth__0__1 |
@@ -49,7 +48,6 @@
| local_dataflow.rb:19:1:21:3 | __synth__0__1 | local_dataflow.rb:19:1:21:3 | ... = ... |
| local_dataflow.rb:19:1:21:3 | __synth__0__1 | local_dataflow.rb:19:1:21:3 | __synth__0__1 |
| local_dataflow.rb:19:1:21:3 | __synth__0__1 | local_dataflow.rb:19:1:21:3 | __synth__0__1 |
| local_dataflow.rb:20:3:20:25 | if ... | local_dataflow.rb:19:16:21:3 | do ... |
| local_dataflow.rb:24:2:24:8 | break | local_dataflow.rb:23:1:25:3 | while ... |
| local_dataflow.rb:24:8:24:8 | 5 | local_dataflow.rb:24:2:24:8 | break |
| local_dataflow.rb:28:5:28:26 | M | local_dataflow.rb:28:1:28:26 | ... = ... |

View File

@@ -1,8 +1,8 @@
ret
| local_dataflow.rb:6:3:6:14 | ... = ... |
| local_dataflow.rb:10:19:13:3 | do ... |
| local_dataflow.rb:12:3:12:5 | call to p |
| local_dataflow.rb:16:3:16:10 | break |
| local_dataflow.rb:19:16:21:3 | do ... |
| local_dataflow.rb:20:3:20:25 | if ... |
| local_dataflow.rb:20:17:20:21 | break |
| local_dataflow.rb:32:14:32:21 | "method" |
| local_dataflow.rb:36:6:36:13 | return |