Merge pull request #14787 from hvitved/ruby/prune-dataflow-nodes

Ruby: Prune irrelevant data flow nodes and edges
This commit is contained in:
Tom Hvitved
2023-11-20 16:03:00 +01:00
committed by GitHub
3 changed files with 119 additions and 116 deletions

View File

@@ -398,25 +398,29 @@ module VariableCapture {
CapturedSsaDefinitionExt() { this.getSourceVariable() instanceof CapturedVariable }
}
/**
* Holds if there is control-flow insensitive data-flow from `node1` to `node2`
* involving a captured variable. Only used in type tracking.
*/
predicate flowInsensitiveStep(Node node1, Node node2) {
exists(CapturedSsaDefinitionExt def, CapturedVariable v |
// From an assignment or implicit initialization of a captured variable to its flow-insensitive node
def = node1.(SsaDefinitionExtNode).getDefinitionExt() and
// From an assignment or implicit initialization of a captured variable to its flow-insensitive node
private predicate flowInsensitiveWriteStep(
SsaDefinitionExtNode node1, CapturedVariableNode node2, CapturedVariable v
) {
exists(CapturedSsaDefinitionExt def |
def = node1.getDefinitionExt() and
def.getSourceVariable() = v and
(
def instanceof Ssa::WriteDefinition
or
def instanceof Ssa::SelfDefinition
) and
node2.(CapturedVariableNode).getVariable() = v
or
// From a captured variable node to its flow-sensitive capture nodes
node1.(CapturedVariableNode).getVariable() = v and
def = node2.(SsaDefinitionExtNode).getDefinitionExt() and
node2.getVariable() = v
)
}
// From a captured variable node to its flow-sensitive capture nodes
private predicate flowInsensitiveReadStep(
CapturedVariableNode node1, SsaDefinitionExtNode node2, CapturedVariable v
) {
exists(CapturedSsaDefinitionExt def |
node1.getVariable() = v and
def = node2.getDefinitionExt() and
def.getSourceVariable() = v and
(
def instanceof Ssa::CapturedCallDefinition
@@ -425,6 +429,20 @@ module VariableCapture {
)
)
}
/**
* Holds if there is control-flow insensitive data-flow from `node1` to `node2`
* involving a captured variable. Only used in type tracking.
*/
predicate flowInsensitiveStep(Node node1, Node node2) {
exists(CapturedVariable v |
flowInsensitiveWriteStep(node1, node2, v) and
flowInsensitiveReadStep(_, _, v)
or
flowInsensitiveReadStep(node1, node2, v) and
flowInsensitiveWriteStep(_, _, v)
)
}
}
private predicate splatParameterAt(Callable c, int pos) {
@@ -443,7 +461,7 @@ private module Cached {
cached
newtype TNode =
TExprNode(CfgNodes::ExprCfgNode n) or
TReturningNode(CfgNodes::ReturningCfgNode n) or
TReturningNode(CfgNodes::ReturningCfgNode n) { exists(n.getReturnedValueNode()) } or
TSsaDefinitionExtNode(SsaImpl::DefinitionExt def) or
TCapturedVariableNode(VariableCapture::CapturedVariable v) or
TNormalParameterNode(Parameter p) {
@@ -478,11 +496,11 @@ private module Cached {
} or
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
TSynthHashSplatArgumentNode(CfgNodes::ExprNodes::CallCfgNode c) {
exists(Argument arg | arg.isArgumentOf(c, any(ArgumentPosition pos | pos.isKeyword(_))))
or
c.getAnArgument() instanceof CfgNodes::ExprNodes::PairCfgNode
ArgumentNodes::synthHashSplatStore(c, _, _)
} or
TSynthSplatArgumentNode(CfgNodes::ExprNodes::CallCfgNode c) {
ArgumentNodes::synthSplatStore(c, _, _)
} or
TSynthSplatArgumentNode(CfgNodes::ExprNodes::CallCfgNode c) or
TSynthSplatArgumentShiftNode(CfgNodes::ExprNodes::CallCfgNode c, int splatPos, int n) {
// we use -1 to represent data at an unknown index
n in [-1 .. 10] and
@@ -652,7 +670,7 @@ private module Cached {
)
} or
TSplatContent(int i, Boolean shifted) { i in [0 .. 10] } or
THashSplatContent(ConstantValue cv) { not cv.isInt(_) } or
THashSplatContent(ConstantValue::ConstantSymbolValue cv) or
TCapturedVariableContent(VariableCapture::CapturedVariable v) or
// Only used by type-tracking
TAttributeName(string name) { name = any(SetterMethodCall c).getTargetName() }
@@ -1269,6 +1287,51 @@ module ArgumentNodes {
final override Location getLocationImpl() { result = call_.getLocation() }
}
/**
* Holds if a store-step should be added from keyword argument `arg`, belonging to
* `call`, into a synthetic hash splat argument.
*/
predicate synthHashSplatStore(
CfgNodes::ExprNodes::CallCfgNode call, CfgNodes::ExprCfgNode arg, ContentSet c
) {
exists(ConstantValue cv |
// symbol key
exists(ArgumentPosition keywordPos, string name |
arg.(Argument).isArgumentOf(call, keywordPos) and
keywordPos.isKeyword(name) and
cv.isSymbol(name)
)
or
// non-symbol key
exists(CfgNodes::ExprNodes::PairCfgNode pair, CfgNodes::ExprCfgNode key |
arg = pair.getValue() and
pair = call.getAnArgument() and
key = pair.getKey() and
cv = key.getConstantValue() and
not cv.isSymbol(_)
)
|
if call instanceof CfgNodes::ExprNodes::HashLiteralCfgNode
then
/*
* Needed for cases like
*
* ```rb
* hash = { a: taint, b: safe }
*
* def foo(a:, b:)
* sink(a)
* end
*
* foo(**hash)
* ```
*/
c.isSingleton(Content::getElementContent(cv))
else c.isSingleton(THashSplatContent(cv))
)
}
/**
* A data-flow node that represents all keyword arguments wrapped in a hash.
*
@@ -1285,44 +1348,7 @@ module ArgumentNodes {
* Holds if a store-step should be added from argument `arg` into this synthetic
* hash-splat argument.
*/
predicate storeFrom(Node arg, ContentSet c) {
exists(ConstantValue cv |
if call_ instanceof CfgNodes::ExprNodes::HashLiteralCfgNode
then
/*
* Needed for cases like
*
* ```rb
* hash = { a: taint, b: safe }
*
* def foo(a:, b:)
* sink(a)
* end
*
* foo(**hash)
* ```
*/
c.isSingleton(TKnownElementContent(cv))
else c.isSingleton(THashSplatContent(cv))
|
// symbol key
exists(ArgumentPosition keywordPos, string name |
arg.asExpr().(Argument).isArgumentOf(call_, keywordPos) and
keywordPos.isKeyword(name) and
cv.isSymbol(name)
)
or
// non-symbol key
exists(CfgNodes::ExprNodes::PairCfgNode pair, CfgNodes::ExprCfgNode key |
arg.asExpr() = pair.getValue() and
pair = call_.getAnArgument() and
key = pair.getKey() and
cv = key.getConstantValue() and
not cv.isSymbol(_)
)
)
}
predicate storeFrom(Node arg, ContentSet c) { synthHashSplatStore(call_, arg.asExpr(), c) }
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) {
call = call_ and
@@ -1332,6 +1358,39 @@ module ArgumentNodes {
override string toStringImpl() { result = "synthetic hash-splat argument" }
}
/**
* Holds if a store-step should be added from positional argument `arg`, belonging to
* `call`, into a synthetic splat argument.
*/
predicate synthSplatStore(CfgNodes::ExprNodes::CallCfgNode call, Argument arg, ContentSet c) {
exists(int n |
exists(ArgumentPosition pos |
arg.isArgumentOf(call, pos) and
pos.isPositional(n) and
not exists(int i | splatArgumentAt(call, i) and i < n)
)
|
if call instanceof CfgNodes::ExprNodes::ArrayLiteralCfgNode
then
/*
* Needed for cases like
*
* ```rb
* arr = [taint, safe]
*
* def foo(a, b)
* sink(a)
* end
*
* foo(*arr)
* ```
*/
c = getArrayContent(n)
else c = getSplatContent(n, false)
)
}
/**
* A data-flow node that represents all positional arguments wrapped in an array.
*
@@ -1346,31 +1405,7 @@ module ArgumentNodes {
* Holds if a store-step should be added from argument `arg` into this synthetic
* splat argument.
*/
predicate storeFrom(Node arg, ContentSet c) {
exists(ArgumentPosition pos, int n |
arg.asExpr().(Argument).isArgumentOf(call_, pos) and
pos.isPositional(n) and
not exists(int i | splatArgumentAt(call_, i) and i < n) and
if call_ instanceof CfgNodes::ExprNodes::ArrayLiteralCfgNode
then
/*
* Needed for cases like
*
* ```rb
* arr = [taint, safe]
*
* def foo(a, b)
* sink(a)
* end
*
* foo(*arr)
* ```
*/
c = getArrayContent(n)
else c = getSplatContent(n, false)
)
}
predicate storeFrom(Node arg, ContentSet c) { synthSplatStore(call_, arg.asExpr(), c) }
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) {
call = call_ and

View File

@@ -606,12 +606,12 @@ module Content {
* we have an implicit hash-splat argument containing `{:a => 1, :b => 2, :c => 3}`.
*/
class HashSplatContent extends ElementContent, THashSplatContent {
private ConstantValue cv;
private ConstantValue::ConstantSymbolValue cv;
HashSplatContent() { this = THashSplatContent(cv) }
/** Gets the hash key. */
ConstantValue getKey() { result = cv }
ConstantValue::ConstantSymbolValue getKey() { result = cv }
override string toString() { result = "hash-splat position " + cv }
}

View File

@@ -4,7 +4,6 @@ ret
| local_dataflow.rb:12:3:12:5 | call to p |
| local_dataflow.rb:16:3:16:10 | break |
| 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 |
| local_dataflow.rb:38:3:38:13 | "reachable" |
@@ -1234,36 +1233,23 @@ arg
| local_dataflow.rb:9:10:9:10 | 1 | local_dataflow.rb:9:9:9:15 | call to [] | position 0 |
| local_dataflow.rb:9:12:9:12 | 2 | local_dataflow.rb:9:9:9:15 | call to [] | position 1 |
| local_dataflow.rb:9:14:9:14 | 3 | local_dataflow.rb:9:9:9:15 | call to [] | position 2 |
| local_dataflow.rb:10:5:13:3 | synthetic splat argument | local_dataflow.rb:10:5:13:3 | call to each | synthetic * |
| local_dataflow.rb:10:5:13:3 | { ... } | local_dataflow.rb:10:5:13:3 | call to each | block |
| local_dataflow.rb:10:9:10:9 | defined? ... | local_dataflow.rb:10:9:10:9 | [false] ! ... | self |
| local_dataflow.rb:10:9:10:9 | defined? ... | local_dataflow.rb:10:9:10:9 | [true] ! ... | self |
| local_dataflow.rb:10:9:10:9 | synthetic splat argument | local_dataflow.rb:10:9:10:9 | [false] ! ... | synthetic * |
| local_dataflow.rb:10:9:10:9 | synthetic splat argument | local_dataflow.rb:10:9:10:9 | [true] ! ... | synthetic * |
| local_dataflow.rb:10:9:10:9 | synthetic splat argument | local_dataflow.rb:10:9:10:9 | defined? ... | synthetic * |
| local_dataflow.rb:10:9:10:9 | x | local_dataflow.rb:10:9:10:9 | defined? ... | self |
| local_dataflow.rb:10:14:10:18 | array | local_dataflow.rb:10:5:13:3 | call to each | self |
| local_dataflow.rb:11:1:11:2 | self | local_dataflow.rb:11:1:11:2 | call to do | self |
| local_dataflow.rb:11:1:11:2 | synthetic splat argument | local_dataflow.rb:11:1:11:2 | call to do | synthetic * |
| local_dataflow.rb:12:3:12:5 | self | local_dataflow.rb:12:3:12:5 | call to p | self |
| local_dataflow.rb:12:3:12:5 | synthetic splat argument | local_dataflow.rb:12:3:12:5 | call to p | synthetic * |
| local_dataflow.rb:12:5:12:5 | x | local_dataflow.rb:12:3:12:5 | call to p | position 0 |
| local_dataflow.rb:15:1:17:3 | synthetic splat argument | local_dataflow.rb:15:1:17:3 | call to each | synthetic * |
| local_dataflow.rb:15:1:17:3 | { ... } | local_dataflow.rb:15:1:17:3 | call to each | block |
| local_dataflow.rb:15:5:15:5 | defined? ... | local_dataflow.rb:15:5:15:5 | [false] ! ... | self |
| local_dataflow.rb:15:5:15:5 | defined? ... | local_dataflow.rb:15:5:15:5 | [true] ! ... | self |
| local_dataflow.rb:15:5:15:5 | synthetic splat argument | local_dataflow.rb:15:5:15:5 | [false] ! ... | synthetic * |
| local_dataflow.rb:15:5:15:5 | synthetic splat argument | local_dataflow.rb:15:5:15:5 | [true] ! ... | synthetic * |
| local_dataflow.rb:15:5:15:5 | synthetic splat argument | local_dataflow.rb:15:5:15:5 | defined? ... | synthetic * |
| local_dataflow.rb:15:5:15:5 | x | local_dataflow.rb:15:5:15:5 | defined? ... | self |
| local_dataflow.rb:15:10:15:14 | array | local_dataflow.rb:15:1:17:3 | call to each | self |
| local_dataflow.rb:19:1:21:3 | synthetic splat argument | local_dataflow.rb:19:1:21:3 | call to each | synthetic * |
| local_dataflow.rb:19:1:21:3 | { ... } | local_dataflow.rb:19:1:21:3 | call to each | block |
| local_dataflow.rb:19:5:19:5 | defined? ... | local_dataflow.rb:19:5:19:5 | [false] ! ... | self |
| local_dataflow.rb:19:5:19:5 | defined? ... | local_dataflow.rb:19:5:19:5 | [true] ! ... | self |
| local_dataflow.rb:19:5:19:5 | synthetic splat argument | local_dataflow.rb:19:5:19:5 | [false] ! ... | synthetic * |
| local_dataflow.rb:19:5:19:5 | synthetic splat argument | local_dataflow.rb:19:5:19:5 | [true] ! ... | synthetic * |
| local_dataflow.rb:19:5:19:5 | synthetic splat argument | local_dataflow.rb:19:5:19:5 | defined? ... | synthetic * |
| local_dataflow.rb:19:5:19:5 | x | local_dataflow.rb:19:5:19:5 | defined? ... | self |
| local_dataflow.rb:19:10:19:14 | array | local_dataflow.rb:19:1:21:3 | call to each | self |
| local_dataflow.rb:20:6:20:6 | x | local_dataflow.rb:20:6:20:10 | ... > ... | self |
@@ -1276,7 +1262,6 @@ arg
| local_dataflow.rb:42:6:42:11 | synthetic splat argument | local_dataflow.rb:42:6:42:11 | ... == ... | synthetic * |
| local_dataflow.rb:42:11:42:11 | 4 | local_dataflow.rb:42:6:42:11 | ... == ... | position 0 |
| local_dataflow.rb:49:1:53:3 | self | local_dataflow.rb:49:1:53:3 | call to m | self |
| local_dataflow.rb:49:1:53:3 | synthetic splat argument | local_dataflow.rb:49:1:53:3 | call to m | synthetic * |
| local_dataflow.rb:49:3:53:3 | do ... end | local_dataflow.rb:49:1:53:3 | call to m | block |
| local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:50:18:50:22 | ... < ... | self |
| local_dataflow.rb:50:18:50:22 | synthetic splat argument | local_dataflow.rb:50:18:50:22 | ... < ... | synthetic * |
@@ -1408,7 +1393,6 @@ arg
| local_dataflow.rb:112:8:112:16 | self | local_dataflow.rb:112:8:112:16 | call to source | self |
| local_dataflow.rb:112:8:112:16 | synthetic splat argument | local_dataflow.rb:112:8:112:16 | call to source | synthetic * |
| local_dataflow.rb:112:8:112:20 | call to dup | local_dataflow.rb:112:3:112:21 | call to sink | position 0 |
| local_dataflow.rb:112:8:112:20 | synthetic splat argument | local_dataflow.rb:112:8:112:20 | call to dup | synthetic * |
| local_dataflow.rb:112:15:112:15 | 1 | local_dataflow.rb:112:8:112:16 | call to source | position 0 |
| local_dataflow.rb:113:3:113:25 | self | local_dataflow.rb:113:3:113:25 | call to sink | self |
| local_dataflow.rb:113:3:113:25 | synthetic splat argument | local_dataflow.rb:113:3:113:25 | call to sink | synthetic * |
@@ -1416,9 +1400,7 @@ arg
| local_dataflow.rb:113:8:113:16 | self | local_dataflow.rb:113:8:113:16 | call to source | self |
| local_dataflow.rb:113:8:113:16 | synthetic splat argument | local_dataflow.rb:113:8:113:16 | call to source | synthetic * |
| local_dataflow.rb:113:8:113:20 | call to dup | local_dataflow.rb:113:8:113:24 | call to dup | self |
| local_dataflow.rb:113:8:113:20 | synthetic splat argument | local_dataflow.rb:113:8:113:20 | call to dup | synthetic * |
| local_dataflow.rb:113:8:113:24 | call to dup | local_dataflow.rb:113:3:113:25 | call to sink | position 0 |
| local_dataflow.rb:113:8:113:24 | synthetic splat argument | local_dataflow.rb:113:8:113:24 | call to dup | synthetic * |
| local_dataflow.rb:113:15:113:15 | 1 | local_dataflow.rb:113:8:113:16 | call to source | position 0 |
| local_dataflow.rb:117:3:117:24 | self | local_dataflow.rb:117:3:117:24 | call to sink | self |
| local_dataflow.rb:117:3:117:24 | synthetic splat argument | local_dataflow.rb:117:3:117:24 | call to sink | synthetic * |
@@ -1426,13 +1408,11 @@ arg
| local_dataflow.rb:117:8:117:16 | self | local_dataflow.rb:117:8:117:16 | call to source | self |
| local_dataflow.rb:117:8:117:16 | synthetic splat argument | local_dataflow.rb:117:8:117:16 | call to source | synthetic * |
| local_dataflow.rb:117:8:117:23 | call to tap | local_dataflow.rb:117:3:117:24 | call to sink | position 0 |
| local_dataflow.rb:117:8:117:23 | synthetic splat argument | local_dataflow.rb:117:8:117:23 | call to tap | synthetic * |
| local_dataflow.rb:117:15:117:15 | 1 | local_dataflow.rb:117:8:117:16 | call to source | position 0 |
| local_dataflow.rb:117:22:117:23 | { ... } | local_dataflow.rb:117:8:117:23 | call to tap | block |
| local_dataflow.rb:118:3:118:11 | call to source | local_dataflow.rb:118:3:118:31 | call to tap | self |
| local_dataflow.rb:118:3:118:11 | self | local_dataflow.rb:118:3:118:11 | call to source | self |
| local_dataflow.rb:118:3:118:11 | synthetic splat argument | local_dataflow.rb:118:3:118:11 | call to source | synthetic * |
| local_dataflow.rb:118:3:118:31 | synthetic splat argument | local_dataflow.rb:118:3:118:31 | call to tap | synthetic * |
| local_dataflow.rb:118:10:118:10 | 1 | local_dataflow.rb:118:3:118:11 | call to source | position 0 |
| local_dataflow.rb:118:17:118:31 | { ... } | local_dataflow.rb:118:3:118:31 | call to tap | block |
| local_dataflow.rb:118:23:118:29 | self | local_dataflow.rb:118:23:118:29 | call to sink | self |
@@ -1444,9 +1424,7 @@ arg
| local_dataflow.rb:119:8:119:16 | self | local_dataflow.rb:119:8:119:16 | call to source | self |
| local_dataflow.rb:119:8:119:16 | synthetic splat argument | local_dataflow.rb:119:8:119:16 | call to source | synthetic * |
| local_dataflow.rb:119:8:119:23 | call to tap | local_dataflow.rb:119:8:119:30 | call to tap | self |
| local_dataflow.rb:119:8:119:23 | synthetic splat argument | local_dataflow.rb:119:8:119:23 | call to tap | synthetic * |
| local_dataflow.rb:119:8:119:30 | call to tap | local_dataflow.rb:119:3:119:31 | call to sink | position 0 |
| local_dataflow.rb:119:8:119:30 | synthetic splat argument | local_dataflow.rb:119:8:119:30 | call to tap | synthetic * |
| local_dataflow.rb:119:15:119:15 | 1 | local_dataflow.rb:119:8:119:16 | call to source | position 0 |
| local_dataflow.rb:119:22:119:23 | { ... } | local_dataflow.rb:119:8:119:23 | call to tap | block |
| local_dataflow.rb:119:29:119:30 | { ... } | local_dataflow.rb:119:8:119:30 | call to tap | block |
@@ -1456,18 +1434,14 @@ arg
| local_dataflow.rb:123:8:123:16 | self | local_dataflow.rb:123:8:123:16 | call to source | self |
| local_dataflow.rb:123:8:123:16 | synthetic splat argument | local_dataflow.rb:123:8:123:16 | call to source | synthetic * |
| local_dataflow.rb:123:8:123:20 | call to dup | local_dataflow.rb:123:8:123:45 | call to tap | self |
| local_dataflow.rb:123:8:123:20 | synthetic splat argument | local_dataflow.rb:123:8:123:20 | call to dup | synthetic * |
| local_dataflow.rb:123:8:123:45 | call to tap | local_dataflow.rb:123:8:123:49 | call to dup | self |
| local_dataflow.rb:123:8:123:45 | synthetic splat argument | local_dataflow.rb:123:8:123:45 | call to tap | synthetic * |
| local_dataflow.rb:123:8:123:49 | call to dup | local_dataflow.rb:123:3:123:50 | call to sink | position 0 |
| local_dataflow.rb:123:8:123:49 | synthetic splat argument | local_dataflow.rb:123:8:123:49 | call to dup | synthetic * |
| local_dataflow.rb:123:15:123:15 | 1 | local_dataflow.rb:123:8:123:16 | call to source | position 0 |
| local_dataflow.rb:123:26:123:45 | { ... } | local_dataflow.rb:123:8:123:45 | call to tap | block |
| local_dataflow.rb:123:32:123:43 | self | local_dataflow.rb:123:32:123:43 | call to puts | self |
| local_dataflow.rb:123:32:123:43 | synthetic splat argument | local_dataflow.rb:123:32:123:43 | call to puts | synthetic * |
| local_dataflow.rb:123:37:123:43 | "hello" | local_dataflow.rb:123:32:123:43 | call to puts | position 0 |
| local_dataflow.rb:127:3:127:8 | self | local_dataflow.rb:127:3:127:8 | call to rand | self |
| local_dataflow.rb:127:3:127:8 | synthetic splat argument | local_dataflow.rb:127:3:127:8 | call to rand | synthetic * |
| local_dataflow.rb:132:6:132:11 | self | local_dataflow.rb:132:6:132:11 | call to use | self |
| local_dataflow.rb:132:6:132:11 | synthetic splat argument | local_dataflow.rb:132:6:132:11 | call to use | synthetic * |
| local_dataflow.rb:132:10:132:10 | x | local_dataflow.rb:132:6:132:11 | call to use | position 0 |
@@ -1498,8 +1472,6 @@ arg
| local_dataflow.rb:137:14:137:14 | x | local_dataflow.rb:137:10:137:15 | call to use | position 0 |
| local_dataflow.rb:137:20:137:26 | [false] ! ... | local_dataflow.rb:137:10:137:26 | [false] ... && ... | position 0 |
| local_dataflow.rb:137:20:137:26 | [true] ! ... | local_dataflow.rb:137:10:137:26 | [true] ... && ... | position 0 |
| local_dataflow.rb:137:20:137:26 | synthetic splat argument | local_dataflow.rb:137:20:137:26 | [false] ! ... | synthetic * |
| local_dataflow.rb:137:20:137:26 | synthetic splat argument | local_dataflow.rb:137:20:137:26 | [true] ! ... | synthetic * |
| local_dataflow.rb:137:21:137:26 | call to use | local_dataflow.rb:137:20:137:26 | [false] ! ... | self |
| local_dataflow.rb:137:21:137:26 | call to use | local_dataflow.rb:137:20:137:26 | [true] ! ... | self |
| local_dataflow.rb:137:21:137:26 | self | local_dataflow.rb:137:21:137:26 | call to use | self |
@@ -1508,8 +1480,6 @@ arg
| local_dataflow.rb:141:8:141:14 | [false] ! ... | local_dataflow.rb:141:8:141:37 | [false] ... \|\| ... | self |
| local_dataflow.rb:141:8:141:14 | [false] ! ... | local_dataflow.rb:141:8:141:37 | [true] ... \|\| ... | self |
| local_dataflow.rb:141:8:141:14 | [true] ! ... | local_dataflow.rb:141:8:141:37 | [true] ... \|\| ... | self |
| local_dataflow.rb:141:8:141:14 | synthetic splat argument | local_dataflow.rb:141:8:141:14 | [false] ! ... | synthetic * |
| local_dataflow.rb:141:8:141:14 | synthetic splat argument | local_dataflow.rb:141:8:141:14 | [true] ! ... | synthetic * |
| local_dataflow.rb:141:8:141:37 | synthetic splat argument | local_dataflow.rb:141:8:141:37 | [false] ... \|\| ... | synthetic * |
| local_dataflow.rb:141:8:141:37 | synthetic splat argument | local_dataflow.rb:141:8:141:37 | [true] ... \|\| ... | synthetic * |
| local_dataflow.rb:141:9:141:14 | call to use | local_dataflow.rb:141:8:141:14 | [false] ! ... | self |
@@ -1528,8 +1498,6 @@ arg
| local_dataflow.rb:141:24:141:24 | x | local_dataflow.rb:141:20:141:25 | call to use | position 0 |
| local_dataflow.rb:141:30:141:36 | [false] ! ... | local_dataflow.rb:141:20:141:36 | [false] ... && ... | position 0 |
| local_dataflow.rb:141:30:141:36 | [true] ! ... | local_dataflow.rb:141:20:141:36 | [true] ... && ... | position 0 |
| local_dataflow.rb:141:30:141:36 | synthetic splat argument | local_dataflow.rb:141:30:141:36 | [false] ! ... | synthetic * |
| local_dataflow.rb:141:30:141:36 | synthetic splat argument | local_dataflow.rb:141:30:141:36 | [true] ! ... | synthetic * |
| local_dataflow.rb:141:31:141:36 | call to use | local_dataflow.rb:141:30:141:36 | [false] ! ... | self |
| local_dataflow.rb:141:31:141:36 | call to use | local_dataflow.rb:141:30:141:36 | [true] ! ... | self |
| local_dataflow.rb:141:31:141:36 | self | local_dataflow.rb:141:31:141:36 | call to use | self |