mirror of
https://github.com/github/codeql.git
synced 2026-04-20 22:44:52 +02:00
Merge pull request #12964 from hvitved/ruby/remove-synth-returns
Ruby: Remove canonical return nodes
This commit is contained in:
@@ -778,7 +778,7 @@ module API {
|
||||
or
|
||||
exists(TypeTracker t2 |
|
||||
result = trackUseNode(src, t2).track(t2, t) and
|
||||
not result instanceof DataFlowPrivate::SelfParameterNode
|
||||
not result instanceof DataFlow::SelfParameterNode
|
||||
)
|
||||
}
|
||||
|
||||
@@ -800,7 +800,7 @@ module API {
|
||||
or
|
||||
exists(TypeBackTracker t2, DataFlow::LocalSourceNode mid |
|
||||
mid = trackDefNode(rhs, t2) and
|
||||
not mid instanceof DataFlowPrivate::SelfParameterNode and
|
||||
not mid instanceof DataFlow::SelfParameterNode and
|
||||
result = mid.backtrack(t2, t)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,18 +8,21 @@ private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
|
||||
private import codeql.ruby.dataflow.FlowSummary
|
||||
private import codeql.ruby.dataflow.SSA
|
||||
private import codeql.util.Boolean
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A `LocalSourceNode` for a `self` variable. This is either an implicit `self`
|
||||
* parameter or an implicit SSA entry definition.
|
||||
* A `LocalSourceNode` for a `self` variable. This is the implicit `self`
|
||||
* parameter, when it exists, otherwise the implicit SSA entry definition.
|
||||
*/
|
||||
private class SelfLocalSourceNode extends DataFlow::LocalSourceNode {
|
||||
private SelfVariable self;
|
||||
|
||||
SelfLocalSourceNode() {
|
||||
self = this.(SelfParameterNode).getSelfVariable()
|
||||
self = this.(SelfParameterNodeImpl).getSelfVariable()
|
||||
or
|
||||
self = this.(SsaSelfDefinitionNode).getVariable()
|
||||
self = this.(SsaSelfDefinitionNode).getVariable() and
|
||||
not LocalFlow::localFlowSsaParamInput(_, this)
|
||||
}
|
||||
|
||||
/** Gets the `self` variable. */
|
||||
@@ -470,35 +473,28 @@ private module Cached {
|
||||
import Cached
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlow::LocalSourceNode trackModuleAccess(Module m, TypeTracker t) {
|
||||
t.start() and m = resolveConstantReadAccess(result.asExpr().getExpr())
|
||||
or
|
||||
exists(TypeTracker t2, StepSummary summary |
|
||||
result = trackModuleAccessRec(m, t2, summary) and t = t2.append(summary)
|
||||
)
|
||||
private predicate isNotSelf(DataFlow::Node n) { not n instanceof SelfParameterNodeImpl }
|
||||
|
||||
private module TrackModuleInput implements CallGraphConstruction::Simple::InputSig {
|
||||
class State = Module;
|
||||
|
||||
predicate start(DataFlow::Node start, Module m) {
|
||||
m = resolveConstantReadAccess(start.asExpr().getExpr())
|
||||
}
|
||||
|
||||
// We exclude steps into `self` parameters, and instead rely on the type of the
|
||||
// enclosing module
|
||||
predicate filter(DataFlow::Node n) { n instanceof SelfParameterNodeImpl }
|
||||
}
|
||||
|
||||
/**
|
||||
* We exclude steps into `self` parameters, and instead rely on the type of the
|
||||
* enclosing module.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlow::LocalSourceNode trackModuleAccessRec(Module m, TypeTracker t, StepSummary summary) {
|
||||
StepSummary::step(trackModuleAccess(m, t), result, summary) and
|
||||
not result instanceof SelfParameterNode
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlow::LocalSourceNode trackModuleAccess(Module m) {
|
||||
result = trackModuleAccess(m, TypeTracker::end())
|
||||
}
|
||||
predicate trackModuleAccess = CallGraphConstruction::Simple::Make<TrackModuleInput>::track/1;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasUserDefinedNew(Module m) {
|
||||
exists(DataFlow::MethodNode method |
|
||||
// not `getAnAncestor` because singleton methods cannot be included
|
||||
singletonMethodOnModule(method.asCallableAstNode(), "new", m.getSuperClass*()) and
|
||||
not method.getSelfParameter().getAMethodCall("allocate").flowsTo(method.getAReturningNode())
|
||||
not method.getSelfParameter().getAMethodCall("allocate").flowsTo(method.getAReturnNode())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -531,141 +527,162 @@ private predicate isStandardNewCall(RelevantCall new, Module m, boolean exact) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `n` is an instance of type `tp`. */
|
||||
private predicate isInstance(DataFlow::Node n, Module tp, boolean exact) {
|
||||
n.asExpr().getExpr() instanceof NilLiteral and
|
||||
tp = TResolved("NilClass") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr().(BooleanLiteral).isFalse() and
|
||||
tp = TResolved("FalseClass") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr().(BooleanLiteral).isTrue() and
|
||||
tp = TResolved("TrueClass") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr() instanceof IntegerLiteral and
|
||||
tp = TResolved("Integer") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr() instanceof FloatLiteral and
|
||||
tp = TResolved("Float") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr() instanceof RationalLiteral and
|
||||
tp = TResolved("Rational") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr() instanceof ComplexLiteral and
|
||||
tp = TResolved("Complex") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr() instanceof StringlikeLiteral and
|
||||
tp = TResolved("String") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr() instanceof CfgNodes::ExprNodes::ArrayLiteralCfgNode and
|
||||
tp = TResolved("Array") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr() instanceof CfgNodes::ExprNodes::HashLiteralCfgNode and
|
||||
tp = TResolved("Hash") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr() instanceof MethodBase and
|
||||
tp = TResolved("Symbol") and
|
||||
exact = true
|
||||
or
|
||||
n.asParameter() instanceof BlockParameter and
|
||||
tp = TResolved("Proc") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr() instanceof Lambda and
|
||||
tp = TResolved("Proc") and
|
||||
exact = true
|
||||
or
|
||||
isStandardNewCall(n.asExpr(), tp, exact)
|
||||
or
|
||||
// `self` reference in method or top-level (but not in module or singleton method,
|
||||
// where instance methods cannot be called; only singleton methods)
|
||||
n =
|
||||
any(SelfLocalSourceNode self |
|
||||
exists(MethodBase m |
|
||||
selfInMethod(self.getVariable(), m, tp) and
|
||||
not m instanceof SingletonMethod and
|
||||
if m.getEnclosingModule() instanceof Toplevel then exact = true else exact = false
|
||||
)
|
||||
or
|
||||
selfInToplevel(self.getVariable(), tp) and
|
||||
exact = true
|
||||
)
|
||||
or
|
||||
// `in C => c then c.foo`
|
||||
asModulePattern(n, tp) and
|
||||
exact = false
|
||||
or
|
||||
// `case object when C then object.foo`
|
||||
hasAdjacentTypeCheckedReads(_, _, n.asExpr(), tp) and
|
||||
exact = false
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlow::Node trackInstance(Module tp, boolean exact, TypeTracker t) {
|
||||
t.start() and
|
||||
(
|
||||
isInstance(result, tp, exact)
|
||||
or
|
||||
exists(Module m |
|
||||
(if m.isClass() then tp = TResolved("Class") else tp = TResolved("Module")) and
|
||||
exact = true
|
||||
|
|
||||
// needed for e.g. `C.new`
|
||||
m = resolveConstantReadAccess(result.asExpr().getExpr())
|
||||
or
|
||||
// needed for e.g. `self.include`
|
||||
selfInModule(result.(SelfLocalSourceNode).getVariable(), m)
|
||||
or
|
||||
// needed for e.g. `self.puts`
|
||||
selfInMethod(result.(SelfLocalSourceNode).getVariable(), any(SingletonMethod sm), m)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(TypeTracker t2, StepSummary summary |
|
||||
result = trackInstanceRec(tp, t2, exact, summary) and t = t2.append(summary)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
|
||||
localFlowStepTypeTracker(nodeFrom, nodeTo) and
|
||||
summary.toString() = "level"
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasAdjacentTypeCheckedReads(DataFlow::Node node) {
|
||||
hasAdjacentTypeCheckedReads(_, _, node.asExpr(), _)
|
||||
}
|
||||
|
||||
/**
|
||||
* We exclude steps into `self` parameters and type checked variables. For those,
|
||||
* we instead rely on the type of the enclosing module resp. the type being checked
|
||||
* against, and apply an open-world assumption when determining possible dispatch
|
||||
* targets.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlow::Node trackInstanceRec(Module tp, TypeTracker t, boolean exact, StepSummary summary) {
|
||||
exists(DataFlow::Node mid | mid = trackInstance(tp, exact, t) |
|
||||
StepSummary::smallstep(mid, result, summary) and
|
||||
not result instanceof SelfParameterNode
|
||||
private module TrackInstanceInput implements CallGraphConstruction::InputSig {
|
||||
pragma[nomagic]
|
||||
private predicate isInstanceNoCall(DataFlow::Node n, Module tp, boolean exact) {
|
||||
n.asExpr().getExpr() instanceof NilLiteral and
|
||||
tp = TResolved("NilClass") and
|
||||
exact = true
|
||||
or
|
||||
localFlowStep(mid, result, summary) and
|
||||
not hasAdjacentTypeCheckedReads(result)
|
||||
)
|
||||
n.asExpr().getExpr().(BooleanLiteral).isFalse() and
|
||||
tp = TResolved("FalseClass") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr().(BooleanLiteral).isTrue() and
|
||||
tp = TResolved("TrueClass") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr() instanceof IntegerLiteral and
|
||||
tp = TResolved("Integer") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr() instanceof FloatLiteral and
|
||||
tp = TResolved("Float") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr() instanceof RationalLiteral and
|
||||
tp = TResolved("Rational") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr() instanceof ComplexLiteral and
|
||||
tp = TResolved("Complex") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr() instanceof StringlikeLiteral and
|
||||
tp = TResolved("String") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr() instanceof CfgNodes::ExprNodes::ArrayLiteralCfgNode and
|
||||
tp = TResolved("Array") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr() instanceof CfgNodes::ExprNodes::HashLiteralCfgNode and
|
||||
tp = TResolved("Hash") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr() instanceof MethodBase and
|
||||
tp = TResolved("Symbol") and
|
||||
exact = true
|
||||
or
|
||||
n.asParameter() instanceof BlockParameter and
|
||||
tp = TResolved("Proc") and
|
||||
exact = true
|
||||
or
|
||||
n.asExpr().getExpr() instanceof Lambda and
|
||||
tp = TResolved("Proc") and
|
||||
exact = true
|
||||
or
|
||||
// `self` reference in method or top-level (but not in module or singleton method,
|
||||
// where instance methods cannot be called; only singleton methods)
|
||||
n =
|
||||
any(SelfLocalSourceNode self |
|
||||
exists(MethodBase m |
|
||||
selfInMethod(self.getVariable(), m, tp) and
|
||||
not m instanceof SingletonMethod and
|
||||
if m.getEnclosingModule() instanceof Toplevel then exact = true else exact = false
|
||||
)
|
||||
or
|
||||
selfInToplevel(self.getVariable(), tp) and
|
||||
exact = true
|
||||
)
|
||||
or
|
||||
// `in C => c then c.foo`
|
||||
asModulePattern(n, tp) and
|
||||
exact = false
|
||||
or
|
||||
// `case object when C then object.foo`
|
||||
hasAdjacentTypeCheckedReads(_, _, n.asExpr(), tp) and
|
||||
exact = false
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isInstanceCall(DataFlow::Node n, Module tp, boolean exact) {
|
||||
isStandardNewCall(n.asExpr(), tp, exact)
|
||||
}
|
||||
|
||||
/** Holds if `n` is an instance of type `tp`. */
|
||||
pragma[inline]
|
||||
private predicate isInstance(DataFlow::Node n, Module tp, boolean exact) {
|
||||
isInstanceNoCall(n, tp, exact)
|
||||
or
|
||||
isInstanceCall(n, tp, exact)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasAdjacentTypeCheckedReads(DataFlow::Node node) {
|
||||
hasAdjacentTypeCheckedReads(_, _, node.asExpr(), _)
|
||||
}
|
||||
|
||||
newtype State = additional MkState(Module m, Boolean exact)
|
||||
|
||||
predicate start(DataFlow::Node start, State state) {
|
||||
exists(Module tp, boolean exact | state = MkState(tp, exact) |
|
||||
isInstance(start, tp, exact)
|
||||
or
|
||||
exists(Module m |
|
||||
(if m.isClass() then tp = TResolved("Class") else tp = TResolved("Module")) and
|
||||
exact = true
|
||||
|
|
||||
// needed for e.g. `C.new`
|
||||
m = resolveConstantReadAccess(start.asExpr().getExpr())
|
||||
or
|
||||
// needed for e.g. `self.include`
|
||||
selfInModule(start.(SelfLocalSourceNode).getVariable(), m)
|
||||
or
|
||||
// needed for e.g. `self.puts`
|
||||
selfInMethod(start.(SelfLocalSourceNode).getVariable(), any(SingletonMethod sm), m)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate stepNoCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
|
||||
// We exclude steps into `self` parameters. For those, we instead rely on the type of
|
||||
// the enclosing module
|
||||
StepSummary::smallstepNoCall(nodeFrom, nodeTo, summary) and
|
||||
isNotSelf(nodeTo)
|
||||
or
|
||||
// We exclude steps into type checked variables. For those, we instead rely on the
|
||||
// type being checked against
|
||||
localFlowStep(nodeFrom, nodeTo, summary) and
|
||||
not hasAdjacentTypeCheckedReads(nodeTo)
|
||||
}
|
||||
|
||||
predicate stepCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
|
||||
StepSummary::smallstepCall(nodeFrom, nodeTo, summary)
|
||||
}
|
||||
|
||||
class StateProj = Unit;
|
||||
|
||||
Unit stateProj(State state) { exists(state) and exists(result) }
|
||||
|
||||
// We exclude steps into `self` parameters, and instead rely on the type of the
|
||||
// enclosing module
|
||||
predicate filter(DataFlow::Node n, Unit u) {
|
||||
n instanceof SelfParameterNodeImpl and
|
||||
exists(u)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlow::Node trackInstance(Module tp, boolean exact) {
|
||||
result = trackInstance(tp, exact, TypeTracker::end())
|
||||
result =
|
||||
CallGraphConstruction::Make<TrackInstanceInput>::track(TrackInstanceInput::MkState(tp, exact))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -706,30 +723,17 @@ private CfgScope getTargetInstance(RelevantCall call, string method) {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlow::LocalSourceNode trackBlock(Block block, TypeTracker t) {
|
||||
t.start() and result.asExpr().getExpr() = block
|
||||
or
|
||||
exists(TypeTracker t2, StepSummary summary |
|
||||
result = trackBlockRec(block, t2, summary) and
|
||||
t = t2.append(summary)
|
||||
)
|
||||
private module TrackBlockInput implements CallGraphConstruction::Simple::InputSig {
|
||||
class State = Block;
|
||||
|
||||
predicate start(DataFlow::Node start, Block block) { start.asExpr().getExpr() = block }
|
||||
|
||||
// We exclude steps into `self` parameters, and instead rely on the type of the
|
||||
// enclosing module
|
||||
predicate filter(DataFlow::Node n) { n instanceof SelfParameterNodeImpl }
|
||||
}
|
||||
|
||||
/**
|
||||
* We exclude steps into `self` parameters, which may happen when the code
|
||||
* base contains implementations of `call`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlow::LocalSourceNode trackBlockRec(Block block, TypeTracker t, StepSummary summary) {
|
||||
StepSummary::step(trackBlock(block, t), result, summary) and
|
||||
not result instanceof SelfParameterNode
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlow::LocalSourceNode trackBlock(Block block) {
|
||||
result = trackBlock(block, TypeTracker::end())
|
||||
}
|
||||
private predicate trackBlock = CallGraphConstruction::Simple::Make<TrackBlockInput>::track/1;
|
||||
|
||||
/** Holds if `m` is a singleton method named `name`, defined on `object. */
|
||||
private predicate singletonMethod(MethodBase m, string name, Expr object) {
|
||||
@@ -896,92 +900,98 @@ predicate singletonMethodOnInstance(MethodBase method, string name, Expr object)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is reverse flow from `nodeFrom` to `nodeTo` via a parameter.
|
||||
*
|
||||
* This is only used for tracking singleton methods, where we want to be able
|
||||
* to handle cases like
|
||||
*
|
||||
* ```rb
|
||||
* def add_singleton x
|
||||
* def x.foo; end
|
||||
* end
|
||||
*
|
||||
* y = add_singleton C.new
|
||||
* y.foo
|
||||
* ```
|
||||
*
|
||||
* and
|
||||
*
|
||||
* ```rb
|
||||
* class C
|
||||
* def add_singleton_to_self
|
||||
* def self.foo; end
|
||||
* end
|
||||
* end
|
||||
*
|
||||
* y = C.new
|
||||
* y.add_singleton_to_self
|
||||
* y.foo
|
||||
* ```
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate paramReturnFlow(
|
||||
DataFlow::Node nodeFrom, DataFlow::PostUpdateNode nodeTo, StepSummary summary
|
||||
) {
|
||||
exists(RelevantCall call, DataFlow::Node arg, DataFlow::ParameterNode p, Expr nodeFromPreExpr |
|
||||
TypeTrackerSpecific::callStep(call, arg, p) and
|
||||
nodeTo.getPreUpdateNode() = arg and
|
||||
summary.toString() = "return" and
|
||||
(
|
||||
nodeFromPreExpr = nodeFrom.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr().getExpr()
|
||||
private module TrackSingletonMethodOnInstanceInput implements CallGraphConstruction::InputSig {
|
||||
/**
|
||||
* Holds if there is reverse flow from `nodeFrom` to `nodeTo` via a parameter.
|
||||
*
|
||||
* This is only used for tracking singleton methods, where we want to be able
|
||||
* to handle cases like
|
||||
*
|
||||
* ```rb
|
||||
* def add_singleton x
|
||||
* def x.foo; end
|
||||
* end
|
||||
*
|
||||
* y = add_singleton C.new
|
||||
* y.foo
|
||||
* ```
|
||||
*
|
||||
* and
|
||||
*
|
||||
* ```rb
|
||||
* class C
|
||||
* def add_singleton_to_self
|
||||
* def self.foo; end
|
||||
* end
|
||||
* end
|
||||
*
|
||||
* y = C.new
|
||||
* y.add_singleton_to_self
|
||||
* y.foo
|
||||
* ```
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate paramReturnFlow(
|
||||
DataFlow::Node nodeFrom, DataFlow::PostUpdateNode nodeTo, StepSummary summary
|
||||
) {
|
||||
exists(RelevantCall call, DataFlow::Node arg, DataFlow::ParameterNode p, Expr nodeFromPreExpr |
|
||||
TypeTrackerSpecific::callStep(call, arg, p) and
|
||||
nodeTo.getPreUpdateNode() = arg and
|
||||
summary.toString() = "return" and
|
||||
(
|
||||
nodeFromPreExpr = nodeFrom.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr().getExpr()
|
||||
or
|
||||
nodeFromPreExpr = nodeFrom.asExpr().getExpr() and
|
||||
singletonMethodOnInstance(_, _, nodeFromPreExpr)
|
||||
)
|
||||
|
|
||||
nodeFromPreExpr = p.getParameter().(NamedParameter).getVariable().getAnAccess()
|
||||
or
|
||||
nodeFromPreExpr = nodeFrom.asExpr().getExpr() and
|
||||
singletonMethodOnInstance(_, _, nodeFromPreExpr)
|
||||
nodeFromPreExpr = p.(SelfParameterNodeImpl).getSelfVariable().getAnAccess()
|
||||
)
|
||||
|
|
||||
nodeFromPreExpr = p.getParameter().(NamedParameter).getVariable().getAnAccess()
|
||||
or
|
||||
nodeFromPreExpr = p.(SelfParameterNode).getSelfVariable().getAnAccess()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlow::Node trackSingletonMethodOnInstance(MethodBase method, string name, TypeTracker t) {
|
||||
t.start() and
|
||||
singletonMethodOnInstance(method, name, result.asExpr().getExpr())
|
||||
or
|
||||
exists(TypeTracker t2, StepSummary summary |
|
||||
result = trackSingletonMethodOnInstanceRec(method, name, t2, summary) and
|
||||
t = t2.append(summary) and
|
||||
// Stop flow at redefinitions.
|
||||
//
|
||||
// Example:
|
||||
// ```rb
|
||||
// def x.foo; end
|
||||
// def x.foo; end
|
||||
// x.foo # <- we want to resolve this call to the second definition only
|
||||
// ```
|
||||
not singletonMethodOnInstance(_, name, result.asExpr().getExpr())
|
||||
)
|
||||
}
|
||||
class State = MethodBase;
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlow::Node trackSingletonMethodOnInstanceRec(
|
||||
MethodBase method, string name, TypeTracker t, StepSummary summary
|
||||
) {
|
||||
exists(DataFlow::Node mid | mid = trackSingletonMethodOnInstance(method, name, t) |
|
||||
StepSummary::smallstep(mid, result, summary)
|
||||
predicate start(DataFlow::Node start, MethodBase method) {
|
||||
singletonMethodOnInstance(method, _, start.asExpr().getExpr())
|
||||
}
|
||||
|
||||
predicate stepNoCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
|
||||
StepSummary::smallstepNoCall(nodeFrom, nodeTo, summary)
|
||||
or
|
||||
paramReturnFlow(mid, result, summary)
|
||||
localFlowStep(nodeFrom, nodeTo, summary)
|
||||
}
|
||||
|
||||
predicate stepCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
|
||||
StepSummary::smallstepCall(nodeFrom, nodeTo, summary)
|
||||
or
|
||||
localFlowStep(mid, result, summary)
|
||||
)
|
||||
paramReturnFlow(nodeFrom, nodeTo, summary)
|
||||
}
|
||||
|
||||
class StateProj extends string {
|
||||
StateProj() { singletonMethodOnInstance(_, this, _) }
|
||||
}
|
||||
|
||||
StateProj stateProj(MethodBase method) { singletonMethodOnInstance(method, result, _) }
|
||||
|
||||
// Stop flow at redefinitions.
|
||||
//
|
||||
// Example:
|
||||
// ```rb
|
||||
// def x.foo; end
|
||||
// def x.foo; end
|
||||
// x.foo # <- we want to resolve this call to the second definition only
|
||||
// ```
|
||||
predicate filter(DataFlow::Node n, StateProj name) {
|
||||
singletonMethodOnInstance(_, name, n.asExpr().getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DataFlow::Node trackSingletonMethodOnInstance(MethodBase method, string name) {
|
||||
result = trackSingletonMethodOnInstance(method, name, TypeTracker::end())
|
||||
result = CallGraphConstruction::Make<TrackSingletonMethodOnInstanceInput>::track(method) and
|
||||
singletonMethodOnInstance(method, name, _)
|
||||
}
|
||||
|
||||
/** Holds if a `self` access may be the receiver of `call` directly inside module `m`. */
|
||||
|
||||
@@ -131,10 +131,10 @@ module LocalFlow {
|
||||
/**
|
||||
* Holds if `nodeFrom` is a parameter node, and `nodeTo` is a corresponding SSA node.
|
||||
*/
|
||||
predicate localFlowSsaParamInput(Node nodeFrom, Node nodeTo) {
|
||||
predicate localFlowSsaParamInput(Node nodeFrom, SsaDefinitionExtNode nodeTo) {
|
||||
nodeTo = getParameterDefNode(nodeFrom.(ParameterNodeImpl).getParameter())
|
||||
or
|
||||
nodeTo = getSelfParameterDefNode(nodeFrom.(SelfParameterNode).getMethod())
|
||||
nodeTo = getSelfParameterDefNode(nodeFrom.(SelfParameterNodeImpl).getMethod())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,14 +143,13 @@ module LocalFlow {
|
||||
*
|
||||
* This is intended to recover from flow not currently recognised by ordinary capture flow.
|
||||
*/
|
||||
predicate localFlowSsaParamCaptureInput(Node nodeFrom, Node nodeTo) {
|
||||
exists(Ssa::CapturedEntryDefinition def, ParameterNodeImpl p |
|
||||
(nodeFrom = p or LocalFlow::localFlowSsaParamInput(p, nodeFrom)) and
|
||||
predicate localFlowSsaParamCaptureInput(ParameterNodeImpl nodeFrom, Node nodeTo) {
|
||||
exists(Ssa::CapturedEntryDefinition def |
|
||||
nodeTo.(SsaDefinitionExtNode).getDefinitionExt() = def
|
||||
|
|
||||
p.getParameter().(NamedParameter).getVariable() = def.getSourceVariable()
|
||||
nodeFrom.getParameter().(NamedParameter).getVariable() = def.getSourceVariable()
|
||||
or
|
||||
p.(SelfParameterNode).getSelfVariable() = def.getSourceVariable()
|
||||
nodeFrom.(SelfParameterNode).getSelfVariable() = def.getSourceVariable()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -164,7 +163,7 @@ module LocalFlow {
|
||||
|
||||
/**
|
||||
* Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
|
||||
* SSA definition `def`.
|
||||
* some SSA definition.
|
||||
*/
|
||||
private predicate localSsaFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
exists(SsaImpl::DefinitionExt def |
|
||||
@@ -182,6 +181,8 @@ module LocalFlow {
|
||||
// Flow into phi (read) SSA definition node from def
|
||||
localFlowSsaInputFromDef(nodeFrom, def, nodeTo)
|
||||
)
|
||||
or
|
||||
localFlowSsaParamInput(nodeFrom, nodeTo)
|
||||
// TODO
|
||||
// or
|
||||
// // Flow into uncertain SSA definition
|
||||
@@ -223,6 +224,13 @@ module LocalFlow {
|
||||
op.getExpr() instanceof BinaryLogicalOperation and
|
||||
nodeFrom.asExpr() = op.getAnOperand()
|
||||
)
|
||||
or
|
||||
nodeTo.(ParameterNodeImpl).getParameter() =
|
||||
any(NamedParameter p |
|
||||
p.(OptionalParameter).getDefaultValue() = nodeFrom.asExpr().getExpr()
|
||||
or
|
||||
p.(KeywordParameter).getDefaultValue() = nodeFrom.asExpr().getExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,12 +287,6 @@ private module Cached {
|
||||
newtype TNode =
|
||||
TExprNode(CfgNodes::ExprCfgNode n) { TaintTrackingPrivate::forceCachingInSameStage() } or
|
||||
TReturningNode(CfgNodes::ReturningCfgNode n) or
|
||||
TSynthReturnNode(CfgScope scope, ReturnKind kind) {
|
||||
exists(ReturningNode ret |
|
||||
ret.(NodeImpl).getCfgScope() = scope and
|
||||
ret.getKind() = kind
|
||||
)
|
||||
} or
|
||||
TSsaDefinitionExtNode(SsaImpl::DefinitionExt def) or
|
||||
TNormalParameterNode(Parameter p) {
|
||||
p instanceof SimpleParameter or
|
||||
@@ -326,12 +328,6 @@ private module Cached {
|
||||
TNormalParameterNode or TBlockParameterNode or TSelfParameterNode or
|
||||
TSynthHashSplatParameterNode or TSummaryParameterNode;
|
||||
|
||||
private predicate defaultValueFlow(NamedParameter p, ExprNode e) {
|
||||
p.(OptionalParameter).getDefaultValue() = e.getExprNode().getExpr()
|
||||
or
|
||||
p.(KeywordParameter).getDefaultValue() = e.getExprNode().getExpr()
|
||||
}
|
||||
|
||||
cached
|
||||
Location getLocation(NodeImpl n) { result = n.getLocationImpl() }
|
||||
|
||||
@@ -346,12 +342,6 @@ private module Cached {
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
defaultValueFlow(nodeTo.(ParameterNodeImpl).getParameter(), nodeFrom)
|
||||
or
|
||||
LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
|
||||
or
|
||||
nodeTo.(SynthReturnNode).getAnInput() = nodeFrom
|
||||
or
|
||||
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo) and
|
||||
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
|
||||
or
|
||||
@@ -373,10 +363,6 @@ private module Cached {
|
||||
predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) {
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
defaultValueFlow(nodeTo.(ParameterNodeImpl).getParameter(), nodeFrom)
|
||||
or
|
||||
LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
|
||||
or
|
||||
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
|
||||
or
|
||||
// Simple flow through library code is included in the exposed local
|
||||
@@ -386,19 +372,11 @@ private module Cached {
|
||||
|
||||
/**
|
||||
* This is the local flow predicate that is used in type tracking.
|
||||
*
|
||||
* This needs to exclude `localFlowSsaParamInput` due to a performance trick
|
||||
* in type tracking, where such steps are treated as call steps.
|
||||
*/
|
||||
cached
|
||||
predicate localFlowStepTypeTracker(Node nodeFrom, Node nodeTo) {
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
exists(NamedParameter p |
|
||||
defaultValueFlow(p, nodeFrom) and
|
||||
nodeTo = LocalFlow::getParameterDefNode(p)
|
||||
)
|
||||
or
|
||||
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
|
||||
or
|
||||
// Flow into phi node from read
|
||||
@@ -440,12 +418,10 @@ private module Cached {
|
||||
n instanceof ExprNode and
|
||||
not reachedFromExprOrEntrySsaDef(n)
|
||||
or
|
||||
// Ensure all entry SSA definitions are local sources -- for parameters, this
|
||||
// is needed by type tracking
|
||||
entrySsaDefinition(n)
|
||||
or
|
||||
// Needed for flow out in type tracking
|
||||
n instanceof SynthReturnNode
|
||||
// Ensure all entry SSA definitions are local sources, except those that correspond
|
||||
// to parameters (which are themselves local sources)
|
||||
entrySsaDefinition(n) and
|
||||
not LocalFlow::localFlowSsaParamInput(_, n)
|
||||
or
|
||||
// Needed for stores in type tracking
|
||||
TypeTrackerSpecific::storeStepIntoSourceNode(_, n, _)
|
||||
@@ -507,7 +483,7 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate exprNodeReturnedFromCached(ExprNode e, Callable c) {
|
||||
exists(ReturningNode r |
|
||||
exists(ReturnNode r |
|
||||
nodeGetEnclosingCallable(r).asCallable() = c and
|
||||
(
|
||||
r.(ExplicitReturnNode).getReturningNode().getReturnedValueNode() = e.asExpr() or
|
||||
@@ -542,8 +518,6 @@ predicate nodeIsHidden(Node n) {
|
||||
or
|
||||
n instanceof SummaryParameterNode
|
||||
or
|
||||
n instanceof SynthReturnNode
|
||||
or
|
||||
n instanceof SynthHashSplatParameterNode
|
||||
or
|
||||
n instanceof SynthHashSplatArgumentNode
|
||||
@@ -658,10 +632,10 @@ private module ParameterNodes {
|
||||
* The value of the `self` parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
class SelfParameterNode extends ParameterNodeImpl, TSelfParameterNode {
|
||||
class SelfParameterNodeImpl extends ParameterNodeImpl, TSelfParameterNode {
|
||||
private MethodBase method;
|
||||
|
||||
SelfParameterNode() { this = TSelfParameterNode(method) }
|
||||
SelfParameterNodeImpl() { this = TSelfParameterNode(method) }
|
||||
|
||||
final MethodBase getMethod() { result = method }
|
||||
|
||||
@@ -937,24 +911,26 @@ private class NewCall extends DataFlowCall {
|
||||
NewCall() { this.asCall().getExpr().(MethodCall).getMethodName() = "new" }
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a value syntactically returned by a callable. */
|
||||
abstract class ReturningNode extends Node {
|
||||
/** Gets the kind of this return node. */
|
||||
abstract ReturnKind getKind();
|
||||
|
||||
pragma[nomagic]
|
||||
predicate hasKind(ReturnKind kind, CfgScope scope) {
|
||||
kind = this.getKind() and
|
||||
scope = this.(NodeImpl).getCfgScope()
|
||||
}
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a value returned by a callable. */
|
||||
abstract class ReturnNode extends Node {
|
||||
/** Gets the kind of this return node. */
|
||||
abstract ReturnKind getKind();
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a value returned by a callable. */
|
||||
abstract class SourceReturnNode extends ReturnNode {
|
||||
/** Gets the kind of this return node. */
|
||||
abstract ReturnKind getKindSource(); // only exists to avoid spurious negative recursion
|
||||
|
||||
final override ReturnKind getKind() { result = this.getKindSource() }
|
||||
|
||||
pragma[nomagic]
|
||||
predicate hasKind(ReturnKind kind, CfgScope scope) {
|
||||
kind = this.getKindSource() and
|
||||
scope = this.(NodeImpl).getCfgScope()
|
||||
}
|
||||
}
|
||||
|
||||
private module ReturnNodes {
|
||||
private predicate isValid(CfgNodes::ReturningCfgNode node) {
|
||||
exists(ReturningStmt stmt, Callable scope |
|
||||
@@ -976,14 +952,14 @@ private module ReturnNodes {
|
||||
* A data-flow node that represents an expression explicitly returned by
|
||||
* a callable.
|
||||
*/
|
||||
class ExplicitReturnNode extends ReturningNode, ReturningStatementNode {
|
||||
class ExplicitReturnNode extends SourceReturnNode, ReturningStatementNode {
|
||||
ExplicitReturnNode() {
|
||||
isValid(n) and
|
||||
n.getASuccessor().(CfgNodes::AnnotatedExitNode).isNormal() and
|
||||
n.getScope() instanceof Callable
|
||||
}
|
||||
|
||||
override ReturnKind getKind() {
|
||||
override ReturnKind getKindSource() {
|
||||
if n.getNode() instanceof BreakStmt
|
||||
then result instanceof BreakReturnKind
|
||||
else
|
||||
@@ -1012,10 +988,10 @@ private module ReturnNodes {
|
||||
* a callable. An implicit return happens when an expression can be the
|
||||
* last thing that is evaluated in the body of the callable.
|
||||
*/
|
||||
class ExprReturnNode extends ReturningNode, ExprNode {
|
||||
class ExprReturnNode extends SourceReturnNode, ExprNode {
|
||||
ExprReturnNode() { exists(Callable c | implicitReturn(c, this) = c.getAStmt()) }
|
||||
|
||||
override ReturnKind getKind() {
|
||||
override ReturnKind getKindSource() {
|
||||
exists(CfgScope scope | scope = this.(NodeImpl).getCfgScope() |
|
||||
if isUserDefinedNew(scope)
|
||||
then result instanceof NewReturnKind
|
||||
@@ -1040,7 +1016,7 @@ private module ReturnNodes {
|
||||
* the implicit `self` reference in `@x` will return data stored in the field
|
||||
* `x` out to the call `C.new`.
|
||||
*/
|
||||
class InitializeReturnNode extends ExprPostUpdateNode, ReturningNode {
|
||||
class InitializeReturnNode extends ExprPostUpdateNode, ReturnNode {
|
||||
InitializeReturnNode() {
|
||||
exists(Method initialize |
|
||||
this.getCfgScope() = initialize and
|
||||
@@ -1053,32 +1029,6 @@ private module ReturnNodes {
|
||||
override ReturnKind getKind() { result instanceof NewReturnKind }
|
||||
}
|
||||
|
||||
/**
|
||||
* A synthetic data-flow node for joining flow from different syntactic
|
||||
* returns into a single node.
|
||||
*
|
||||
* This node only exists to avoid computing the product of a large fan-in
|
||||
* with a large fan-out.
|
||||
*/
|
||||
class SynthReturnNode extends NodeImpl, ReturnNode, TSynthReturnNode {
|
||||
private CfgScope scope;
|
||||
private ReturnKind kind;
|
||||
|
||||
SynthReturnNode() { this = TSynthReturnNode(scope, kind) }
|
||||
|
||||
/** Gets a syntactic return node that flows into this synthetic node. */
|
||||
pragma[nomagic]
|
||||
ReturningNode getAnInput() { result.hasKind(kind, scope) }
|
||||
|
||||
override ReturnKind getKind() { result = kind }
|
||||
|
||||
override CfgScope getCfgScope() { result = scope }
|
||||
|
||||
override Location getLocationImpl() { result = scope.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = "return " + kind + " in " + scope }
|
||||
}
|
||||
|
||||
private class SummaryReturnNode extends SummaryNode, ReturnNode {
|
||||
private ReturnKind rk;
|
||||
|
||||
@@ -1339,9 +1289,6 @@ private import PostUpdateNodes
|
||||
/** A node that performs a type cast. */
|
||||
class CastNode extends Node {
|
||||
CastNode() {
|
||||
// ensure that actual return nodes are included in the path graph
|
||||
this instanceof ReturningNode
|
||||
or
|
||||
// ensure that all variable assignments are included in the path graph
|
||||
this.(SsaDefinitionExtNode).getDefinitionExt() instanceof Ssa::WriteDefinition
|
||||
}
|
||||
|
||||
@@ -195,10 +195,22 @@ class ParameterNode extends LocalSourceNode, TParameterNode instanceof Parameter
|
||||
/** Gets the parameter corresponding to this node, if any. */
|
||||
final Parameter getParameter() { result = super.getParameter() }
|
||||
|
||||
/** Gets the callable that this parameter belongs to. */
|
||||
final Callable getCallable() { result = super.getCfgScope() }
|
||||
|
||||
/** Gets the name of the parameter, if any. */
|
||||
final string getName() { result = this.getParameter().(NamedParameter).getName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of an implicit `self` parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
class SelfParameterNode extends ParameterNode instanceof SelfParameterNodeImpl {
|
||||
/** Gets the underlying `self` variable. */
|
||||
final SelfVariable getSelfVariable() { result = super.getSelfVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node that is a source of local flow.
|
||||
*/
|
||||
@@ -328,9 +340,6 @@ private module Cached {
|
||||
exists(Node mid | hasLocalSource(mid, source) |
|
||||
localFlowStepTypeTracker(mid, sink)
|
||||
or
|
||||
// Explicitly include the SSA param input step as type-tracking omits this step.
|
||||
LocalFlow::localFlowSsaParamInput(mid, sink)
|
||||
or
|
||||
LocalFlow::localFlowSsaParamCaptureInput(mid, sink)
|
||||
)
|
||||
}
|
||||
@@ -1176,19 +1185,15 @@ class CallableNode extends StmtSequenceNode {
|
||||
result = this.getBlockParameter().getAMethodCall("call")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the canonical return node from this callable.
|
||||
*
|
||||
* Each callable has exactly one such node, and its location may not correspond
|
||||
* to any particular return site - consider using `getAReturningNode` to get nodes
|
||||
* whose locations correspond to return sites.
|
||||
*/
|
||||
Node getReturn() { result.(SynthReturnNode).getCfgScope() = callable }
|
||||
|
||||
/**
|
||||
* Gets a data flow node whose value is about to be returned by this callable.
|
||||
*/
|
||||
Node getAReturningNode() { result = this.getReturn().(SynthReturnNode).getAnInput() }
|
||||
Node getAReturnNode() { result.(ReturnNode).(NodeImpl).getCfgScope() = callable }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Use `getAReturnNode` instead.
|
||||
*/
|
||||
deprecated Node getAReturningNode() { result = this.getAReturnNode() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,6 @@ private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.controlflow.CfgNodes
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.dataflow.internal.DataFlowDispatch
|
||||
private import codeql.ruby.dataflow.internal.DataFlowPrivate
|
||||
private import codeql.ruby.ApiGraphs
|
||||
private import codeql.ruby.frameworks.Stdlib
|
||||
private import codeql.ruby.frameworks.Core
|
||||
@@ -319,19 +318,19 @@ private class ActiveRecordModelFinderCall extends ActiveRecordModelInstantiation
|
||||
|
||||
// A `self` reference that may resolve to an active record model object
|
||||
private class ActiveRecordModelClassSelfReference extends ActiveRecordModelInstantiation,
|
||||
SsaSelfDefinitionNode
|
||||
DataFlow::SelfParameterNode
|
||||
{
|
||||
private ActiveRecordModelClass cls;
|
||||
|
||||
ActiveRecordModelClassSelfReference() {
|
||||
exists(MethodBase m |
|
||||
m = this.getCfgScope() and
|
||||
m = this.getCallable() and
|
||||
m.getEnclosingModule() = cls and
|
||||
m = cls.getAMethod()
|
||||
) and
|
||||
// In a singleton method, `self` refers to the class itself rather than an
|
||||
// instance of that class
|
||||
not this.getSelfScope() instanceof SingletonMethod
|
||||
not this.getSelfVariable().getDeclaringScope() instanceof SingletonMethod
|
||||
}
|
||||
|
||||
final override ActiveRecordModelClass getClass() { result = cls }
|
||||
|
||||
@@ -21,7 +21,7 @@ module Rack {
|
||||
AppCandidate() {
|
||||
call = this.getInstanceMethod("call") and
|
||||
call.getNumberOfParameters() = 1 and
|
||||
call.getReturn() = trackRackResponse()
|
||||
call.getAReturnNode() = trackRackResponse()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -412,9 +412,7 @@ module Filters {
|
||||
/**
|
||||
* Holds if `n` is the self parameter of method `m`.
|
||||
*/
|
||||
private predicate selfParameter(DataFlowPrivate::SelfParameterNode n, Method m) {
|
||||
m = n.getMethod()
|
||||
}
|
||||
private predicate selfParameter(DataFlow::SelfParameterNode n, Method m) { m = n.getCallable() }
|
||||
|
||||
/**
|
||||
* A class defining additional jump steps arising from filters.
|
||||
|
||||
@@ -224,6 +224,50 @@ private module Cached {
|
||||
|
||||
private import Cached
|
||||
|
||||
private predicate step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
|
||||
stepNoCall(nodeFrom, nodeTo, summary)
|
||||
or
|
||||
stepCall(nodeFrom, nodeTo, summary)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate stepProj(TypeTrackingNode nodeFrom, StepSummary summary) {
|
||||
step(nodeFrom, _, summary)
|
||||
}
|
||||
|
||||
bindingset[nodeFrom, t]
|
||||
pragma[inline_late]
|
||||
pragma[noopt]
|
||||
private TypeTracker stepInlineLate(TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) {
|
||||
exists(StepSummary summary |
|
||||
stepProj(nodeFrom, summary) and
|
||||
result = t.append(summary) and
|
||||
step(nodeFrom, nodeTo, summary)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate smallstep(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
|
||||
smallstepNoCall(nodeFrom, nodeTo, summary)
|
||||
or
|
||||
smallstepCall(nodeFrom, nodeTo, summary)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate smallstepProj(Node nodeFrom, StepSummary summary) {
|
||||
smallstep(nodeFrom, _, summary)
|
||||
}
|
||||
|
||||
bindingset[nodeFrom, t]
|
||||
pragma[inline_late]
|
||||
pragma[noopt]
|
||||
private TypeTracker smallstepInlineLate(TypeTracker t, Node nodeFrom, Node nodeTo) {
|
||||
exists(StepSummary summary |
|
||||
smallstepProj(nodeFrom, summary) and
|
||||
result = t.append(summary) and
|
||||
smallstep(nodeFrom, nodeTo, summary)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nodeFrom` is being written to the `content` of the object in `nodeTo`.
|
||||
*
|
||||
@@ -298,21 +342,50 @@ class StepSummary extends TStepSummary {
|
||||
module StepSummary {
|
||||
/**
|
||||
* Gets the summary that corresponds to having taken a forwards
|
||||
* heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
|
||||
* inter-procedural step from `nodeFrom` to `nodeTo`.
|
||||
*
|
||||
* This predicate is inlined, which enables better join-orders when
|
||||
* the call graph construction and type tracking are mutually recursive.
|
||||
* In such cases, non-linear recursion involving `step` will be limited
|
||||
* to non-linear recursion for the parts of `step` that involve the
|
||||
* call graph.
|
||||
* This predicate should normally not be used; consider using `step`
|
||||
* instead.
|
||||
*/
|
||||
predicate stepCall = Cached::stepCall/3;
|
||||
|
||||
/**
|
||||
* Gets the summary that corresponds to having taken a forwards
|
||||
* intra-procedural step from `nodeFrom` to `nodeTo`.
|
||||
*
|
||||
* This predicate should normally not be used; consider using `step`
|
||||
* instead.
|
||||
*/
|
||||
predicate stepNoCall = Cached::stepNoCall/3;
|
||||
|
||||
/**
|
||||
* Gets the summary that corresponds to having taken a forwards
|
||||
* heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
|
||||
stepNoCall(nodeFrom, nodeTo, summary)
|
||||
or
|
||||
stepCall(nodeFrom, nodeTo, summary)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summary that corresponds to having taken a forwards
|
||||
* inter-procedural step from `nodeFrom` to `nodeTo`.
|
||||
*
|
||||
* This predicate should normally not be used; consider using `step`
|
||||
* instead.
|
||||
*/
|
||||
predicate smallstepNoCall = Cached::smallstepNoCall/3;
|
||||
|
||||
/**
|
||||
* Gets the summary that corresponds to having taken a forwards
|
||||
* intra-procedural step from `nodeFrom` to `nodeTo`.
|
||||
*
|
||||
* This predicate should normally not be used; consider using `step`
|
||||
* instead.
|
||||
*/
|
||||
predicate smallstepCall = Cached::smallstepCall/3;
|
||||
|
||||
/**
|
||||
* Gets the summary that corresponds to having taken a forwards
|
||||
* local, heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
|
||||
@@ -320,7 +393,6 @@ module StepSummary {
|
||||
* Unlike `StepSummary::step`, this predicate does not compress
|
||||
* type-preserving steps.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate smallstep(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
|
||||
smallstepNoCall(nodeFrom, nodeTo, summary)
|
||||
or
|
||||
@@ -431,10 +503,7 @@ class TypeTracker extends TTypeTracker {
|
||||
*/
|
||||
pragma[inline]
|
||||
TypeTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) {
|
||||
exists(StepSummary summary |
|
||||
StepSummary::step(nodeFrom, pragma[only_bind_out](nodeTo), pragma[only_bind_into](summary)) and
|
||||
result = this.append(pragma[only_bind_into](summary))
|
||||
)
|
||||
result = stepInlineLate(this, nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -463,10 +532,7 @@ class TypeTracker extends TTypeTracker {
|
||||
*/
|
||||
pragma[inline]
|
||||
TypeTracker smallstep(Node nodeFrom, Node nodeTo) {
|
||||
exists(StepSummary summary |
|
||||
StepSummary::smallstep(nodeFrom, nodeTo, summary) and
|
||||
result = this.append(summary)
|
||||
)
|
||||
result = smallstepInlineLate(this, nodeFrom, nodeTo)
|
||||
or
|
||||
simpleLocalFlowStep(nodeFrom, nodeTo) and
|
||||
result = this
|
||||
@@ -481,6 +547,39 @@ module TypeTracker {
|
||||
TypeTracker end() { result.end() }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate backStepProj(TypeTrackingNode nodeTo, StepSummary summary) {
|
||||
step(_, nodeTo, summary)
|
||||
}
|
||||
|
||||
bindingset[nodeTo, t]
|
||||
pragma[inline_late]
|
||||
pragma[noopt]
|
||||
private TypeBackTracker backStepInlineLate(
|
||||
TypeBackTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo
|
||||
) {
|
||||
exists(StepSummary summary |
|
||||
backStepProj(nodeTo, summary) and
|
||||
result = t.prepend(summary) and
|
||||
step(nodeFrom, nodeTo, summary)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate backSmallstepProj(TypeTrackingNode nodeTo, StepSummary summary) {
|
||||
smallstep(_, nodeTo, summary)
|
||||
}
|
||||
|
||||
bindingset[nodeTo, t]
|
||||
pragma[inline_late]
|
||||
pragma[noopt]
|
||||
private TypeBackTracker backSmallstepInlineLate(TypeBackTracker t, Node nodeFrom, Node nodeTo) {
|
||||
exists(StepSummary summary |
|
||||
backSmallstepProj(nodeTo, summary) and
|
||||
result = t.prepend(summary) and
|
||||
smallstep(nodeFrom, nodeTo, summary)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A summary of the steps needed to back-track a use of a value to a given dataflow node.
|
||||
*
|
||||
@@ -564,10 +663,7 @@ class TypeBackTracker extends TTypeBackTracker {
|
||||
*/
|
||||
pragma[inline]
|
||||
TypeBackTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) {
|
||||
exists(StepSummary summary |
|
||||
StepSummary::step(pragma[only_bind_out](nodeFrom), nodeTo, pragma[only_bind_into](summary)) and
|
||||
this = result.prepend(pragma[only_bind_into](summary))
|
||||
)
|
||||
this = backStepInlineLate(result, nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -596,10 +692,7 @@ class TypeBackTracker extends TTypeBackTracker {
|
||||
*/
|
||||
pragma[inline]
|
||||
TypeBackTracker smallstep(Node nodeFrom, Node nodeTo) {
|
||||
exists(StepSummary summary |
|
||||
StepSummary::smallstep(nodeFrom, nodeTo, summary) and
|
||||
this = result.prepend(summary)
|
||||
)
|
||||
this = backSmallstepInlineLate(result, nodeFrom, nodeTo)
|
||||
or
|
||||
simpleLocalFlowStep(nodeFrom, nodeTo) and
|
||||
this = result
|
||||
@@ -635,3 +728,169 @@ module TypeBackTracker {
|
||||
*/
|
||||
TypeBackTracker end() { result.end() }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Provides logic for constructing a call graph in mutual recursion with type tracking.
|
||||
*
|
||||
* When type tracking is used to construct a call graph, we cannot use the join-order
|
||||
* from `stepInlineLate`, because `step` becomes a recursive call, which means that we
|
||||
* will have a conjunct with 3 recursive calls: the call to `step`, the call to `stepProj`,
|
||||
* and the recursive type tracking call itself. The solution is to split the three-way
|
||||
* non-linear recursion into two non-linear predicates: one that first joins with the
|
||||
* projected `stepCall` relation, followed by a predicate that joins with the full
|
||||
* `stepCall` relation (`stepNoCall` not being recursive, can be join-ordered in the
|
||||
* same way as in `stepInlineLate`).
|
||||
*/
|
||||
module CallGraphConstruction {
|
||||
/** The input to call graph construction. */
|
||||
signature module InputSig {
|
||||
/** A state to track during type tracking. */
|
||||
class State;
|
||||
|
||||
/** Holds if type tracking should start at `start` in state `state`. */
|
||||
predicate start(Node start, State state);
|
||||
|
||||
/**
|
||||
* Holds if type tracking should use the step from `nodeFrom` to `nodeTo`,
|
||||
* which _does not_ depend on the call graph.
|
||||
*
|
||||
* Implementing this predicate using `StepSummary::[small]stepNoCall` yields
|
||||
* standard type tracking.
|
||||
*/
|
||||
predicate stepNoCall(Node nodeFrom, Node nodeTo, StepSummary summary);
|
||||
|
||||
/**
|
||||
* Holds if type tracking should use the step from `nodeFrom` to `nodeTo`,
|
||||
* which _does_ depend on the call graph.
|
||||
*
|
||||
* Implementing this predicate using `StepSummary::[small]stepCall` yields
|
||||
* standard type tracking.
|
||||
*/
|
||||
predicate stepCall(Node nodeFrom, Node nodeTo, StepSummary summary);
|
||||
|
||||
/** A projection of an element from the state space. */
|
||||
class StateProj;
|
||||
|
||||
/** Gets the projection of `state`. */
|
||||
StateProj stateProj(State state);
|
||||
|
||||
/** Holds if type tracking should stop at `n` when we are tracking projected state `stateProj`. */
|
||||
predicate filter(Node n, StateProj stateProj);
|
||||
}
|
||||
|
||||
/** Provides the `track` predicate for use in call graph construction. */
|
||||
module Make<InputSig Input> {
|
||||
pragma[nomagic]
|
||||
private predicate stepNoCallProj(Node nodeFrom, StepSummary summary) {
|
||||
Input::stepNoCall(nodeFrom, _, summary)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate stepCallProj(Node nodeFrom, StepSummary summary) {
|
||||
Input::stepCall(nodeFrom, _, summary)
|
||||
}
|
||||
|
||||
bindingset[nodeFrom, t]
|
||||
pragma[inline_late]
|
||||
pragma[noopt]
|
||||
private TypeTracker stepNoCallInlineLate(
|
||||
TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo
|
||||
) {
|
||||
exists(StepSummary summary |
|
||||
stepNoCallProj(nodeFrom, summary) and
|
||||
result = t.append(summary) and
|
||||
Input::stepNoCall(nodeFrom, nodeTo, summary)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[state]
|
||||
pragma[inline_late]
|
||||
private Input::StateProj stateProjInlineLate(Input::State state) {
|
||||
result = Input::stateProj(state)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Node track(Input::State state, TypeTracker t) {
|
||||
t.start() and Input::start(result, state)
|
||||
or
|
||||
exists(Input::StateProj stateProj |
|
||||
stateProj = stateProjInlineLate(state) and
|
||||
not Input::filter(result, stateProj)
|
||||
|
|
||||
exists(TypeTracker t2 | t = stepNoCallInlineLate(t2, track(state, t2), result))
|
||||
or
|
||||
exists(StepSummary summary |
|
||||
// non-linear recursion
|
||||
Input::stepCall(trackCall(state, t, summary), result, summary)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[t, summary]
|
||||
pragma[inline_late]
|
||||
private TypeTracker appendInlineLate(TypeTracker t, StepSummary summary) {
|
||||
result = t.append(summary)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Node trackCall(Input::State state, TypeTracker t, StepSummary summary) {
|
||||
exists(TypeTracker t2 |
|
||||
// non-linear recursion
|
||||
result = track(state, t2) and
|
||||
stepCallProj(result, summary) and
|
||||
t = appendInlineLate(t2, summary)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a node that can be reached from _some_ start node in state `state`. */
|
||||
pragma[nomagic]
|
||||
Node track(Input::State state) { result = track(state, TypeTracker::end()) }
|
||||
}
|
||||
|
||||
/** A simple version of `CallGraphConstruction` that uses standard type tracking. */
|
||||
module Simple {
|
||||
/** The input to call graph construction. */
|
||||
signature module InputSig {
|
||||
/** A state to track during type tracking. */
|
||||
class State;
|
||||
|
||||
/** Holds if type tracking should start at `start` in state `state`. */
|
||||
predicate start(Node start, State state);
|
||||
|
||||
/** Holds if type tracking should stop at `n`. */
|
||||
predicate filter(Node n);
|
||||
}
|
||||
|
||||
/** Provides the `track` predicate for use in call graph construction. */
|
||||
module Make<InputSig Input> {
|
||||
private module I implements CallGraphConstruction::InputSig {
|
||||
private import codeql.util.Unit
|
||||
|
||||
class State = Input::State;
|
||||
|
||||
predicate start(Node start, State state) { Input::start(start, state) }
|
||||
|
||||
predicate stepNoCall(Node nodeFrom, Node nodeTo, StepSummary summary) {
|
||||
StepSummary::stepNoCall(nodeFrom, nodeTo, summary)
|
||||
}
|
||||
|
||||
predicate stepCall(Node nodeFrom, Node nodeTo, StepSummary summary) {
|
||||
StepSummary::stepCall(nodeFrom, nodeTo, summary)
|
||||
}
|
||||
|
||||
class StateProj = Unit;
|
||||
|
||||
Unit stateProj(State state) { exists(state) and exists(result) }
|
||||
|
||||
predicate filter(Node n, Unit u) {
|
||||
Input::filter(n) and
|
||||
exists(u)
|
||||
}
|
||||
}
|
||||
|
||||
import CallGraphConstruction::Make<I>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ predicate jumpStep = DataFlowPrivate::jumpStep/2;
|
||||
/** Holds if there is direct flow from `param` to a return. */
|
||||
pragma[nomagic]
|
||||
private predicate flowThrough(DataFlowPublic::ParameterNode param) {
|
||||
exists(DataFlowPrivate::ReturningNode returnNode, DataFlowDispatch::ReturnKind rk |
|
||||
exists(DataFlowPrivate::SourceReturnNode returnNode, DataFlowDispatch::ReturnKind rk |
|
||||
param.flowsTo(returnNode) and
|
||||
returnNode.hasKind(rk, param.(DataFlowPrivate::NodeImpl).getCfgScope())
|
||||
|
|
||||
@@ -221,15 +221,7 @@ predicate callStep(ExprNodes::CallCfgNode call, Node arg, DataFlowPrivate::Param
|
||||
* recursion (or, at best, terrible performance), since identifying calls to library
|
||||
* methods is done using API graphs (which uses type tracking).
|
||||
*/
|
||||
predicate callStep(Node nodeFrom, Node nodeTo) {
|
||||
callStep(_, nodeFrom, nodeTo)
|
||||
or
|
||||
// In normal data-flow, this will be a local flow step. But for type tracking
|
||||
// we model it as a call step, in order to avoid computing a potential
|
||||
// self-cross product of all calls to a function that returns one of its parameters
|
||||
// (only to later filter that flow out using `TypeTracker::append`).
|
||||
DataFlowPrivate::LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
|
||||
}
|
||||
predicate callStep(Node nodeFrom, Node nodeTo) { callStep(_, nodeFrom, nodeTo) }
|
||||
|
||||
/**
|
||||
* Holds if `nodeFrom` steps to `nodeTo` by being returned from a call.
|
||||
@@ -241,19 +233,13 @@ predicate callStep(Node nodeFrom, Node nodeTo) {
|
||||
predicate returnStep(Node nodeFrom, Node nodeTo) {
|
||||
exists(ExprNodes::CallCfgNode call |
|
||||
nodeFrom instanceof DataFlowPrivate::ReturnNode and
|
||||
not nodeFrom instanceof DataFlowPrivate::InitializeReturnNode and
|
||||
nodeFrom.(DataFlowPrivate::NodeImpl).getCfgScope() = DataFlowDispatch::getTarget(call) and
|
||||
// deliberately do not include `getInitializeTarget`, since calls to `new` should not
|
||||
// get the return value from `initialize`. Any fields being set in the initializer
|
||||
// will reach all reads via `callStep` and `localFieldStep`.
|
||||
nodeTo.asExpr().getNode() = call.getNode()
|
||||
)
|
||||
or
|
||||
// In normal data-flow, this will be a local flow step. But for type tracking
|
||||
// we model it as a returning flow step, in order to avoid computing a potential
|
||||
// self-cross product of all calls to a function that returns one of its parameters
|
||||
// (only to later filter that flow out using `TypeTracker::append`).
|
||||
nodeTo.(DataFlowPrivate::SynthReturnNode).getAnInput() = nodeFrom and
|
||||
not nodeFrom instanceof DataFlowPrivate::InitializeReturnNode
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -609,26 +595,15 @@ private DataFlow::Node evaluateSummaryComponentStackLocal(
|
||||
pragma[only_bind_out](tail)) and
|
||||
stack = SCS::push(pragma[only_bind_out](head), pragma[only_bind_out](tail))
|
||||
|
|
||||
exists(
|
||||
DataFlowDispatch::ArgumentPosition apos, DataFlowDispatch::ParameterPosition ppos,
|
||||
DataFlowPrivate::ParameterNodeImpl p
|
||||
|
|
||||
exists(DataFlowDispatch::ArgumentPosition apos, DataFlowDispatch::ParameterPosition ppos |
|
||||
head = SummaryComponent::parameter(apos) and
|
||||
DataFlowDispatch::parameterMatch(ppos, apos) and
|
||||
p.isSourceParameterOf(prev.asExpr().getExpr(), ppos) and
|
||||
// We need to include both `p` and the SSA definition for `p`, since in type-tracking
|
||||
// the step from `p` to the SSA definition is considered a call step.
|
||||
result =
|
||||
[p.(DataFlow::Node), DataFlowPrivate::LocalFlow::getParameterDefNode(p.getParameter())]
|
||||
result.(DataFlowPrivate::ParameterNodeImpl).isSourceParameterOf(prev.asExpr().getExpr(), ppos)
|
||||
)
|
||||
or
|
||||
exists(DataFlowPrivate::SynthReturnNode ret |
|
||||
head = SummaryComponent::return() and
|
||||
ret.getCfgScope() = prev.asExpr().getExpr() and
|
||||
// We need to include both `ret` and `ret.getAnInput()`, since in type-tracking
|
||||
// the step from `ret.getAnInput()` to `ret` is considered a return step.
|
||||
result = [ret.(DataFlow::Node), ret.getAnInput()]
|
||||
)
|
||||
head = SummaryComponent::return() and
|
||||
result.(DataFlowPrivate::ReturnNode).(DataFlowPrivate::NodeImpl).getCfgScope() =
|
||||
prev.asExpr().getExpr()
|
||||
or
|
||||
exists(DataFlow::ContentSet content |
|
||||
head = SummaryComponent::withoutContent(content) and
|
||||
|
||||
@@ -2,7 +2,7 @@ import codeql.ruby.AST
|
||||
import codeql.ruby.dataflow.internal.DataFlowPrivate
|
||||
import codeql.ruby.dataflow.internal.DataFlowDispatch
|
||||
|
||||
query predicate ret(ReturningNode node) { any() }
|
||||
query predicate ret(SourceReturnNode node) { any() }
|
||||
|
||||
query predicate arg(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) {
|
||||
n.argumentOf(call, pos) and
|
||||
|
||||
@@ -1,129 +1,72 @@
|
||||
track
|
||||
| type_tracker.rb:1:1:10:3 | self (Container) | type tracker without call steps | type_tracker.rb:1:1:10:3 | self (Container) |
|
||||
| type_tracker.rb:1:1:53:4 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:18:1:21:3 | self (positional) |
|
||||
| type_tracker.rb:1:1:53:4 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:18:1:21:3 | self in positional |
|
||||
| type_tracker.rb:1:1:53:4 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:25:1:28:3 | self (keyword) |
|
||||
| type_tracker.rb:1:1:53:4 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:25:1:28:3 | self in keyword |
|
||||
| type_tracker.rb:1:1:53:4 | self (type_tracker.rb) | type tracker without call steps | type_tracker.rb:1:1:53:4 | self (type_tracker.rb) |
|
||||
| type_tracker.rb:2:5:5:7 | &block | type tracker without call steps | type_tracker.rb:2:5:5:7 | &block |
|
||||
| type_tracker.rb:2:5:5:7 | field= | type tracker without call steps | type_tracker.rb:2:5:5:7 | field= |
|
||||
| type_tracker.rb:2:5:5:7 | return return in field= | type tracker without call steps | type_tracker.rb:2:5:5:7 | return return in field= |
|
||||
| type_tracker.rb:2:5:5:7 | return return in field= | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type tracker without call steps | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type tracker without call steps | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker with call steps | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker with call steps | type_tracker.rb:8:9:8:14 | @field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:5:5:7 | return return in field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:5:5:7 | return return in field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:7:5:9:7 | return return in field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:7:5:9:7 | return return in field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:8:9:8:14 | @field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:8:9:8:14 | @field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:3:9:3:23 | call to puts | type tracker without call steps | type_tracker.rb:3:9:3:23 | call to puts |
|
||||
| type_tracker.rb:3:14:3:23 | call to field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:4:9:4:14 | @field | type tracker without call steps | type_tracker.rb:4:9:4:14 | @field |
|
||||
| type_tracker.rb:7:5:9:7 | &block | type tracker without call steps | type_tracker.rb:7:5:9:7 | &block |
|
||||
| type_tracker.rb:7:5:9:7 | field | type tracker without call steps | type_tracker.rb:7:5:9:7 | field |
|
||||
| type_tracker.rb:7:5:9:7 | return return in field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:7:5:9:7 | return return in field | type tracker without call steps | type_tracker.rb:7:5:9:7 | return return in field |
|
||||
| type_tracker.rb:7:5:9:7 | return return in field | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:7:5:9:7 | self (field) | type tracker without call steps | type_tracker.rb:7:5:9:7 | self (field) |
|
||||
| type_tracker.rb:7:5:9:7 | self in field | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) |
|
||||
| type_tracker.rb:7:5:9:7 | self in field | type tracker without call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:8:9:8:14 | @field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:8:9:8:14 | @field | type tracker without call steps | type_tracker.rb:7:5:9:7 | return return in field |
|
||||
| type_tracker.rb:8:9:8:14 | @field | type tracker without call steps | type_tracker.rb:8:9:8:14 | @field |
|
||||
| type_tracker.rb:8:9:8:14 | @field | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:12:1:16:3 | &block | type tracker without call steps | type_tracker.rb:12:1:16:3 | &block |
|
||||
| type_tracker.rb:12:1:16:3 | m | type tracker without call steps | type_tracker.rb:12:1:16:3 | m |
|
||||
| type_tracker.rb:12:1:16:3 | return return in m | type tracker without call steps | type_tracker.rb:12:1:16:3 | return return in m |
|
||||
| type_tracker.rb:12:1:16:3 | self (m) | type tracker without call steps | type_tracker.rb:12:1:16:3 | self (m) |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type tracker with call steps | type_tracker.rb:12:1:16:3 | self (m) |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type tracker without call steps | type_tracker.rb:12:1:16:3 | self in m |
|
||||
| type_tracker.rb:13:5:13:7 | var | type tracker without call steps | type_tracker.rb:13:5:13:7 | var |
|
||||
| type_tracker.rb:13:11:13:19 | Container | type tracker without call steps | type_tracker.rb:13:11:13:19 | Container |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type tracker without call steps | type_tracker.rb:13:11:13:23 | call to new |
|
||||
| type_tracker.rb:14:5:14:7 | [post] var | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) |
|
||||
| type_tracker.rb:14:5:14:7 | [post] var | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:14:5:14:7 | [post] var | type tracker without call steps | type_tracker.rb:14:5:14:7 | [post] var |
|
||||
| type_tracker.rb:14:5:14:13 | call to field= | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps | type_tracker.rb:8:9:8:14 | @field |
|
||||
| type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps with content attribute field | type_tracker.rb:7:5:9:7 | self (field) |
|
||||
| type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps with content attribute field | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:14:17:14:23 | "hello" |
|
||||
| type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps with content attribute field | type_tracker.rb:14:5:14:7 | [post] var |
|
||||
| type_tracker.rb:14:17:14:23 | __synth__0 | type tracker without call steps | type_tracker.rb:14:17:14:23 | __synth__0 |
|
||||
| type_tracker.rb:15:5:15:18 | call to puts | type tracker without call steps | type_tracker.rb:12:1:16:3 | return return in m |
|
||||
| type_tracker.rb:15:5:15:18 | call to puts | type tracker without call steps | type_tracker.rb:15:5:15:18 | call to puts |
|
||||
| type_tracker.rb:15:10:15:18 | call to field | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:18:1:21:3 | &block | type tracker without call steps | type_tracker.rb:18:1:21:3 | &block |
|
||||
| type_tracker.rb:18:1:21:3 | positional | type tracker without call steps | type_tracker.rb:18:1:21:3 | positional |
|
||||
| type_tracker.rb:18:1:21:3 | return return in positional | type tracker without call steps | type_tracker.rb:18:1:21:3 | return return in positional |
|
||||
| type_tracker.rb:18:1:21:3 | return return in positional | type tracker without call steps | type_tracker.rb:23:1:23:16 | call to positional |
|
||||
| type_tracker.rb:18:1:21:3 | self (positional) | type tracker without call steps | type_tracker.rb:18:1:21:3 | self (positional) |
|
||||
| type_tracker.rb:18:1:21:3 | self in positional | type tracker with call steps | type_tracker.rb:18:1:21:3 | self (positional) |
|
||||
| type_tracker.rb:18:1:21:3 | self in positional | type tracker without call steps | type_tracker.rb:18:1:21:3 | self in positional |
|
||||
| type_tracker.rb:18:16:18:17 | p1 | type tracker with call steps | type_tracker.rb:18:16:18:17 | p1 |
|
||||
| type_tracker.rb:18:16:18:17 | p1 | type tracker without call steps | type_tracker.rb:18:16:18:17 | p1 |
|
||||
| type_tracker.rb:18:16:18:17 | p1 | type tracker without call steps | type_tracker.rb:18:16:18:17 | p1 |
|
||||
| type_tracker.rb:18:16:18:17 | p1 | type tracker without call steps | type_tracker.rb:18:16:18:17 | p1 |
|
||||
| type_tracker.rb:18:20:18:21 | p2 | type tracker with call steps | type_tracker.rb:18:20:18:21 | p2 |
|
||||
| type_tracker.rb:18:20:18:21 | p2 | type tracker without call steps | type_tracker.rb:18:20:18:21 | p2 |
|
||||
| type_tracker.rb:18:20:18:21 | p2 | type tracker without call steps | type_tracker.rb:18:20:18:21 | p2 |
|
||||
| type_tracker.rb:18:20:18:21 | p2 | type tracker without call steps | type_tracker.rb:18:20:18:21 | p2 |
|
||||
| type_tracker.rb:19:5:19:11 | call to puts | type tracker without call steps | type_tracker.rb:19:5:19:11 | call to puts |
|
||||
| type_tracker.rb:20:5:20:11 | call to puts | type tracker without call steps | type_tracker.rb:18:1:21:3 | return return in positional |
|
||||
| type_tracker.rb:20:5:20:11 | call to puts | type tracker without call steps | type_tracker.rb:20:5:20:11 | call to puts |
|
||||
| type_tracker.rb:20:5:20:11 | call to puts | type tracker without call steps | type_tracker.rb:23:1:23:16 | call to positional |
|
||||
| type_tracker.rb:23:1:23:16 | call to positional | type tracker without call steps | type_tracker.rb:23:1:23:16 | call to positional |
|
||||
| type_tracker.rb:23:12:23:12 | 1 | type tracker with call steps | type_tracker.rb:18:16:18:17 | p1 |
|
||||
| type_tracker.rb:23:12:23:12 | 1 | type tracker with call steps | type_tracker.rb:18:16:18:17 | p1 |
|
||||
| type_tracker.rb:23:12:23:12 | 1 | type tracker without call steps | type_tracker.rb:23:12:23:12 | 1 |
|
||||
| type_tracker.rb:23:15:23:15 | 2 | type tracker with call steps | type_tracker.rb:18:20:18:21 | p2 |
|
||||
| type_tracker.rb:23:15:23:15 | 2 | type tracker with call steps | type_tracker.rb:18:20:18:21 | p2 |
|
||||
| type_tracker.rb:23:15:23:15 | 2 | type tracker without call steps | type_tracker.rb:23:15:23:15 | 2 |
|
||||
| type_tracker.rb:25:1:28:3 | &block | type tracker without call steps | type_tracker.rb:25:1:28:3 | &block |
|
||||
| type_tracker.rb:25:1:28:3 | **kwargs | type tracker without call steps | type_tracker.rb:25:1:28:3 | **kwargs |
|
||||
| type_tracker.rb:25:1:28:3 | keyword | type tracker without call steps | type_tracker.rb:25:1:28:3 | keyword |
|
||||
| type_tracker.rb:25:1:28:3 | return return in keyword | type tracker without call steps | type_tracker.rb:25:1:28:3 | return return in keyword |
|
||||
| type_tracker.rb:25:1:28:3 | return return in keyword | type tracker without call steps | type_tracker.rb:30:1:30:21 | call to keyword |
|
||||
| type_tracker.rb:25:1:28:3 | return return in keyword | type tracker without call steps | type_tracker.rb:31:1:31:21 | call to keyword |
|
||||
| type_tracker.rb:25:1:28:3 | return return in keyword | type tracker without call steps | type_tracker.rb:32:1:32:27 | call to keyword |
|
||||
| type_tracker.rb:25:1:28:3 | self (keyword) | type tracker without call steps | type_tracker.rb:25:1:28:3 | self (keyword) |
|
||||
| type_tracker.rb:25:1:28:3 | self in keyword | type tracker with call steps | type_tracker.rb:25:1:28:3 | self (keyword) |
|
||||
| type_tracker.rb:25:1:28:3 | self in keyword | type tracker without call steps | type_tracker.rb:25:1:28:3 | self in keyword |
|
||||
| type_tracker.rb:25:13:25:14 | p1 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 |
|
||||
| type_tracker.rb:25:13:25:14 | p1 | type tracker without call steps | type_tracker.rb:25:13:25:14 | p1 |
|
||||
| type_tracker.rb:25:13:25:14 | p1 | type tracker without call steps | type_tracker.rb:25:13:25:14 | p1 |
|
||||
| type_tracker.rb:25:13:25:14 | p1 | type tracker without call steps | type_tracker.rb:25:13:25:14 | p1 |
|
||||
| type_tracker.rb:25:18:25:19 | p2 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 |
|
||||
| type_tracker.rb:25:18:25:19 | p2 | type tracker without call steps | type_tracker.rb:25:18:25:19 | p2 |
|
||||
| type_tracker.rb:25:18:25:19 | p2 | type tracker without call steps | type_tracker.rb:25:18:25:19 | p2 |
|
||||
| type_tracker.rb:25:18:25:19 | p2 | type tracker without call steps | type_tracker.rb:25:18:25:19 | p2 |
|
||||
| type_tracker.rb:26:5:26:11 | call to puts | type tracker without call steps | type_tracker.rb:26:5:26:11 | call to puts |
|
||||
| type_tracker.rb:27:5:27:11 | call to puts | type tracker without call steps | type_tracker.rb:25:1:28:3 | return return in keyword |
|
||||
| type_tracker.rb:27:5:27:11 | call to puts | type tracker without call steps | type_tracker.rb:27:5:27:11 | call to puts |
|
||||
| type_tracker.rb:27:5:27:11 | call to puts | type tracker without call steps | type_tracker.rb:30:1:30:21 | call to keyword |
|
||||
| type_tracker.rb:27:5:27:11 | call to puts | type tracker without call steps | type_tracker.rb:31:1:31:21 | call to keyword |
|
||||
@@ -134,14 +77,12 @@ track
|
||||
| type_tracker.rb:30:9:30:10 | :p1 | type tracker without call steps | type_tracker.rb:30:9:30:10 | :p1 |
|
||||
| type_tracker.rb:30:9:30:13 | Pair | type tracker without call steps | type_tracker.rb:30:9:30:13 | Pair |
|
||||
| type_tracker.rb:30:13:30:13 | 3 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 |
|
||||
| type_tracker.rb:30:13:30:13 | 3 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 |
|
||||
| type_tracker.rb:30:13:30:13 | 3 | type tracker with call steps with content element :p1 | type_tracker.rb:25:1:28:3 | **kwargs |
|
||||
| type_tracker.rb:30:13:30:13 | 3 | type tracker without call steps | type_tracker.rb:30:13:30:13 | 3 |
|
||||
| type_tracker.rb:30:13:30:13 | 3 | type tracker without call steps with content element :p1 | type_tracker.rb:30:1:30:21 | ** |
|
||||
| type_tracker.rb:30:16:30:17 | :p2 | type tracker without call steps | type_tracker.rb:30:16:30:17 | :p2 |
|
||||
| type_tracker.rb:30:16:30:20 | Pair | type tracker without call steps | type_tracker.rb:30:16:30:20 | Pair |
|
||||
| type_tracker.rb:30:20:30:20 | 4 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 |
|
||||
| type_tracker.rb:30:20:30:20 | 4 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 |
|
||||
| type_tracker.rb:30:20:30:20 | 4 | type tracker with call steps with content element :p2 | type_tracker.rb:25:1:28:3 | **kwargs |
|
||||
| type_tracker.rb:30:20:30:20 | 4 | type tracker without call steps | type_tracker.rb:30:20:30:20 | 4 |
|
||||
| type_tracker.rb:30:20:30:20 | 4 | type tracker without call steps with content element :p2 | type_tracker.rb:30:1:30:21 | ** |
|
||||
@@ -151,14 +92,12 @@ track
|
||||
| type_tracker.rb:31:9:31:10 | :p2 | type tracker without call steps | type_tracker.rb:31:9:31:10 | :p2 |
|
||||
| type_tracker.rb:31:9:31:13 | Pair | type tracker without call steps | type_tracker.rb:31:9:31:13 | Pair |
|
||||
| type_tracker.rb:31:13:31:13 | 5 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 |
|
||||
| type_tracker.rb:31:13:31:13 | 5 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 |
|
||||
| type_tracker.rb:31:13:31:13 | 5 | type tracker with call steps with content element :p2 | type_tracker.rb:25:1:28:3 | **kwargs |
|
||||
| type_tracker.rb:31:13:31:13 | 5 | type tracker without call steps | type_tracker.rb:31:13:31:13 | 5 |
|
||||
| type_tracker.rb:31:13:31:13 | 5 | type tracker without call steps with content element :p2 | type_tracker.rb:31:1:31:21 | ** |
|
||||
| type_tracker.rb:31:16:31:17 | :p1 | type tracker without call steps | type_tracker.rb:31:16:31:17 | :p1 |
|
||||
| type_tracker.rb:31:16:31:20 | Pair | type tracker without call steps | type_tracker.rb:31:16:31:20 | Pair |
|
||||
| type_tracker.rb:31:20:31:20 | 6 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 |
|
||||
| type_tracker.rb:31:20:31:20 | 6 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 |
|
||||
| type_tracker.rb:31:20:31:20 | 6 | type tracker with call steps with content element :p1 | type_tracker.rb:25:1:28:3 | **kwargs |
|
||||
| type_tracker.rb:31:20:31:20 | 6 | type tracker without call steps | type_tracker.rb:31:20:31:20 | 6 |
|
||||
| type_tracker.rb:31:20:31:20 | 6 | type tracker without call steps with content element :p1 | type_tracker.rb:31:1:31:21 | ** |
|
||||
@@ -168,68 +107,33 @@ track
|
||||
| type_tracker.rb:32:9:32:11 | :p2 | type tracker without call steps | type_tracker.rb:32:9:32:11 | :p2 |
|
||||
| type_tracker.rb:32:9:32:16 | Pair | type tracker without call steps | type_tracker.rb:32:9:32:16 | Pair |
|
||||
| type_tracker.rb:32:16:32:16 | 7 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 |
|
||||
| type_tracker.rb:32:16:32:16 | 7 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 |
|
||||
| type_tracker.rb:32:16:32:16 | 7 | type tracker with call steps with content element :p2 | type_tracker.rb:25:1:28:3 | **kwargs |
|
||||
| type_tracker.rb:32:16:32:16 | 7 | type tracker without call steps | type_tracker.rb:32:16:32:16 | 7 |
|
||||
| type_tracker.rb:32:16:32:16 | 7 | type tracker without call steps with content element :p2 | type_tracker.rb:32:1:32:27 | ** |
|
||||
| type_tracker.rb:32:19:32:21 | :p1 | type tracker without call steps | type_tracker.rb:32:19:32:21 | :p1 |
|
||||
| type_tracker.rb:32:19:32:26 | Pair | type tracker without call steps | type_tracker.rb:32:19:32:26 | Pair |
|
||||
| type_tracker.rb:32:26:32:26 | 8 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 |
|
||||
| type_tracker.rb:32:26:32:26 | 8 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 |
|
||||
| type_tracker.rb:32:26:32:26 | 8 | type tracker with call steps with content element :p1 | type_tracker.rb:25:1:28:3 | **kwargs |
|
||||
| type_tracker.rb:32:26:32:26 | 8 | type tracker without call steps | type_tracker.rb:32:26:32:26 | 8 |
|
||||
| type_tracker.rb:32:26:32:26 | 8 | type tracker without call steps with content element :p1 | type_tracker.rb:32:1:32:27 | ** |
|
||||
| type_tracker.rb:34:1:53:3 | &block | type tracker without call steps | type_tracker.rb:34:1:53:3 | &block |
|
||||
| type_tracker.rb:34:1:53:3 | return return in throughArray | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:34:1:53:3 | self in throughArray | type tracker without call steps | type_tracker.rb:34:1:53:3 | self in throughArray |
|
||||
| type_tracker.rb:34:1:53:3 | throughArray | type tracker without call steps | type_tracker.rb:34:1:53:3 | throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps | type_tracker.rb:34:18:34:20 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps | type_tracker.rb:36:5:36:10 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps | type_tracker.rb:40:5:40:12 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps | type_tracker.rb:44:5:44:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element | type_tracker.rb:38:13:38:25 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element | type_tracker.rb:44:5:44:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element | type_tracker.rb:50:14:50:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element 0 or unknown | type_tracker.rb:35:11:35:15 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element 0 or unknown | type_tracker.rb:42:14:42:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker with call steps with content element 0 or unknown | type_tracker.rb:46:14:46:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:18:34:20 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:18:34:20 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:18:34:20 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:36:5:36:10 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:36:5:36:10 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:40:5:40:12 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:40:5:40:12 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:44:5:44:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:44:5:44:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:38:13:38:25 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:38:13:38:25 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:44:5:44:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:44:5:44:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:50:14:50:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:50:14:50:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:35:11:35:15 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:35:11:35:15 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:42:14:42:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:42:14:42:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:46:14:46:26 | call to [] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps with content element 0 or unknown | type_tracker.rb:46:14:46:26 | call to [] |
|
||||
| type_tracker.rb:34:23:34:23 | y | type tracker with call steps | type_tracker.rb:34:23:34:23 | y |
|
||||
| type_tracker.rb:34:23:34:23 | y | type tracker without call steps | type_tracker.rb:34:23:34:23 | y |
|
||||
| type_tracker.rb:34:23:34:23 | y | type tracker without call steps | type_tracker.rb:34:23:34:23 | y |
|
||||
| type_tracker.rb:34:23:34:23 | y | type tracker without call steps | type_tracker.rb:34:23:34:23 | y |
|
||||
| type_tracker.rb:34:26:34:26 | z | type tracker with call steps | type_tracker.rb:34:26:34:26 | z |
|
||||
| type_tracker.rb:34:26:34:26 | z | type tracker without call steps | type_tracker.rb:34:26:34:26 | z |
|
||||
| type_tracker.rb:34:26:34:26 | z | type tracker without call steps | type_tracker.rb:34:26:34:26 | z |
|
||||
| type_tracker.rb:34:26:34:26 | z | type tracker without call steps | type_tracker.rb:34:26:34:26 | z |
|
||||
| type_tracker.rb:35:5:35:7 | tmp | type tracker without call steps | type_tracker.rb:35:5:35:7 | tmp |
|
||||
@@ -315,46 +219,33 @@ track
|
||||
| type_tracker.rb:50:5:50:10 | array4 | type tracker without call steps | type_tracker.rb:50:5:50:10 | array4 |
|
||||
| type_tracker.rb:50:14:50:26 | Array | type tracker without call steps | type_tracker.rb:50:14:50:26 | Array |
|
||||
| type_tracker.rb:50:14:50:26 | call to [] | type tracker without call steps | type_tracker.rb:50:14:50:26 | call to [] |
|
||||
| type_tracker.rb:50:15:50:15 | 1 | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:15:50:15 | 1 | type tracker without call steps | type_tracker.rb:50:15:50:15 | 1 |
|
||||
| type_tracker.rb:50:15:50:15 | 1 | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:15:50:15 | 1 | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:15:50:15 | 1 | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:15:50:15 | 1 | type tracker without call steps with content element 0 or unknown | type_tracker.rb:50:14:50:26 | call to [] |
|
||||
| type_tracker.rb:50:17:50:17 | 2 | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:17:50:17 | 2 | type tracker without call steps | type_tracker.rb:50:17:50:17 | 2 |
|
||||
| type_tracker.rb:50:17:50:17 | 2 | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:17:50:17 | 2 | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:17:50:17 | 2 | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:17:50:17 | 2 | type tracker without call steps with content element 1 or unknown | type_tracker.rb:50:14:50:26 | call to [] |
|
||||
| type_tracker.rb:50:19:50:19 | 3 | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:19:50:19 | 3 | type tracker without call steps | type_tracker.rb:50:19:50:19 | 3 |
|
||||
| type_tracker.rb:50:19:50:19 | 3 | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:19:50:19 | 3 | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:19:50:19 | 3 | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:19:50:19 | 3 | type tracker without call steps with content element 2 or unknown | type_tracker.rb:50:14:50:26 | call to [] |
|
||||
| type_tracker.rb:50:21:50:21 | 4 | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:21:50:21 | 4 | type tracker without call steps | type_tracker.rb:50:21:50:21 | 4 |
|
||||
| type_tracker.rb:50:21:50:21 | 4 | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:21:50:21 | 4 | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:21:50:21 | 4 | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:21:50:21 | 4 | type tracker without call steps with content element 3 or unknown | type_tracker.rb:50:14:50:26 | call to [] |
|
||||
| type_tracker.rb:50:23:50:23 | 5 | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:23:50:23 | 5 | type tracker without call steps | type_tracker.rb:50:23:50:23 | 5 |
|
||||
| type_tracker.rb:50:23:50:23 | 5 | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:23:50:23 | 5 | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:23:50:23 | 5 | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:23:50:23 | 5 | type tracker without call steps with content element 4 or unknown | type_tracker.rb:50:14:50:26 | call to [] |
|
||||
| type_tracker.rb:50:25:50:25 | 6 | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:25:50:25 | 6 | type tracker without call steps | type_tracker.rb:50:25:50:25 | 6 |
|
||||
| type_tracker.rb:50:25:50:25 | 6 | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:25:50:25 | 6 | type tracker without call steps with content element | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:25:50:25 | 6 | type tracker without call steps with content element | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:25:50:25 | 6 | type tracker without call steps with content element 5 or unknown | type_tracker.rb:50:14:50:26 | call to [] |
|
||||
| type_tracker.rb:51:5:51:10 | [post] array4 | type tracker without call steps | type_tracker.rb:51:5:51:10 | [post] array4 |
|
||||
| type_tracker.rb:51:5:51:13 | call to []= | type tracker without call steps | type_tracker.rb:51:5:51:13 | call to []= |
|
||||
| type_tracker.rb:51:17:51:19 | __synth__0 | type tracker without call steps | type_tracker.rb:51:17:51:19 | __synth__0 |
|
||||
| type_tracker.rb:52:5:52:13 | ...[...] | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:52:5:52:13 | ...[...] | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
trackEnd
|
||||
| type_tracker.rb:1:1:10:3 | self (Container) | type_tracker.rb:1:1:10:3 | self (Container) |
|
||||
@@ -373,15 +264,6 @@ trackEnd
|
||||
| type_tracker.rb:1:1:53:4 | self (type_tracker.rb) | type_tracker.rb:32:1:32:27 | self |
|
||||
| type_tracker.rb:2:5:5:7 | &block | type_tracker.rb:2:5:5:7 | &block |
|
||||
| type_tracker.rb:2:5:5:7 | field= | type_tracker.rb:2:5:5:7 | field= |
|
||||
| type_tracker.rb:2:5:5:7 | return return in field= | type_tracker.rb:2:5:5:7 | return return in field= |
|
||||
| type_tracker.rb:2:5:5:7 | return return in field= | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:9:3:23 | self |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:14:3:17 | self |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:4:9:4:14 | self |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:7:5:9:7 | self (field) |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:8:9:8:14 | self |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:3:9:3:23 | self |
|
||||
@@ -390,25 +272,14 @@ trackEnd
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:7:5:9:7 | self (field) |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:8:9:8:14 | self |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:5:5:7 | return return in field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:5:5:7 | return return in field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:9:4:20 | ... = ... |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:9:4:20 | ... = ... |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:18:4:20 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:4:18:4:20 | val |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:7:5:9:7 | return return in field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:7:5:9:7 | return return in field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:8:9:8:14 | @field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:8:9:8:14 | @field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:3:9:3:23 | call to puts | type_tracker.rb:3:9:3:23 | call to puts |
|
||||
| type_tracker.rb:3:14:3:23 | call to field | type_tracker.rb:3:14:3:23 | call to field |
|
||||
@@ -416,23 +287,14 @@ trackEnd
|
||||
| type_tracker.rb:7:5:9:7 | &block | type_tracker.rb:7:5:9:7 | &block |
|
||||
| type_tracker.rb:7:5:9:7 | field | type_tracker.rb:1:1:10:3 | Container |
|
||||
| type_tracker.rb:7:5:9:7 | field | type_tracker.rb:7:5:9:7 | field |
|
||||
| type_tracker.rb:7:5:9:7 | return return in field | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:7:5:9:7 | return return in field | type_tracker.rb:7:5:9:7 | return return in field |
|
||||
| type_tracker.rb:7:5:9:7 | return return in field | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:7:5:9:7 | self (field) | type_tracker.rb:7:5:9:7 | self (field) |
|
||||
| type_tracker.rb:7:5:9:7 | self (field) | type_tracker.rb:8:9:8:14 | self |
|
||||
| type_tracker.rb:7:5:9:7 | self in field | type_tracker.rb:7:5:9:7 | self (field) |
|
||||
| type_tracker.rb:7:5:9:7 | self in field | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:7:5:9:7 | self in field | type_tracker.rb:8:9:8:14 | self |
|
||||
| type_tracker.rb:8:9:8:14 | @field | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:8:9:8:14 | @field | type_tracker.rb:7:5:9:7 | return return in field |
|
||||
| type_tracker.rb:8:9:8:14 | @field | type_tracker.rb:8:9:8:14 | @field |
|
||||
| type_tracker.rb:8:9:8:14 | @field | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:12:1:16:3 | &block | type_tracker.rb:12:1:16:3 | &block |
|
||||
| type_tracker.rb:12:1:16:3 | m | type_tracker.rb:12:1:16:3 | m |
|
||||
| type_tracker.rb:12:1:16:3 | return return in m | type_tracker.rb:12:1:16:3 | return return in m |
|
||||
| type_tracker.rb:12:1:16:3 | self (m) | type_tracker.rb:12:1:16:3 | self (m) |
|
||||
| type_tracker.rb:12:1:16:3 | self (m) | type_tracker.rb:15:5:15:18 | self |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:12:1:16:3 | self (m) |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:12:1:16:3 | self in m |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:15:5:15:18 | self |
|
||||
@@ -470,16 +332,10 @@ trackEnd
|
||||
| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:14:17:14:23 | __synth__0 |
|
||||
| type_tracker.rb:14:17:14:23 | "hello" | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:14:17:14:23 | __synth__0 | type_tracker.rb:14:17:14:23 | __synth__0 |
|
||||
| type_tracker.rb:15:5:15:18 | call to puts | type_tracker.rb:12:1:16:3 | return return in m |
|
||||
| type_tracker.rb:15:5:15:18 | call to puts | type_tracker.rb:15:5:15:18 | call to puts |
|
||||
| type_tracker.rb:15:10:15:18 | call to field | type_tracker.rb:15:10:15:18 | call to field |
|
||||
| type_tracker.rb:18:1:21:3 | &block | type_tracker.rb:18:1:21:3 | &block |
|
||||
| type_tracker.rb:18:1:21:3 | positional | type_tracker.rb:18:1:21:3 | positional |
|
||||
| type_tracker.rb:18:1:21:3 | return return in positional | type_tracker.rb:18:1:21:3 | return return in positional |
|
||||
| type_tracker.rb:18:1:21:3 | return return in positional | type_tracker.rb:23:1:23:16 | call to positional |
|
||||
| type_tracker.rb:18:1:21:3 | self (positional) | type_tracker.rb:18:1:21:3 | self (positional) |
|
||||
| type_tracker.rb:18:1:21:3 | self (positional) | type_tracker.rb:19:5:19:11 | self |
|
||||
| type_tracker.rb:18:1:21:3 | self (positional) | type_tracker.rb:20:5:20:11 | self |
|
||||
| type_tracker.rb:18:1:21:3 | self in positional | type_tracker.rb:18:1:21:3 | self (positional) |
|
||||
| type_tracker.rb:18:1:21:3 | self in positional | type_tracker.rb:18:1:21:3 | self in positional |
|
||||
| type_tracker.rb:18:1:21:3 | self in positional | type_tracker.rb:19:5:19:11 | self |
|
||||
@@ -487,17 +343,12 @@ trackEnd
|
||||
| type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:18:16:18:17 | p1 |
|
||||
| type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:18:16:18:17 | p1 |
|
||||
| type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:18:16:18:17 | p1 |
|
||||
| type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:18:16:18:17 | p1 |
|
||||
| type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:19:10:19:11 | p1 |
|
||||
| type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:19:10:19:11 | p1 |
|
||||
| type_tracker.rb:18:20:18:21 | p2 | type_tracker.rb:18:20:18:21 | p2 |
|
||||
| type_tracker.rb:18:20:18:21 | p2 | type_tracker.rb:18:20:18:21 | p2 |
|
||||
| type_tracker.rb:18:20:18:21 | p2 | type_tracker.rb:18:20:18:21 | p2 |
|
||||
| type_tracker.rb:18:20:18:21 | p2 | type_tracker.rb:18:20:18:21 | p2 |
|
||||
| type_tracker.rb:18:20:18:21 | p2 | type_tracker.rb:20:10:20:11 | p2 |
|
||||
| type_tracker.rb:18:20:18:21 | p2 | type_tracker.rb:20:10:20:11 | p2 |
|
||||
| type_tracker.rb:19:5:19:11 | call to puts | type_tracker.rb:19:5:19:11 | call to puts |
|
||||
| type_tracker.rb:20:5:20:11 | call to puts | type_tracker.rb:18:1:21:3 | return return in positional |
|
||||
| type_tracker.rb:20:5:20:11 | call to puts | type_tracker.rb:20:5:20:11 | call to puts |
|
||||
| type_tracker.rb:20:5:20:11 | call to puts | type_tracker.rb:23:1:23:16 | call to positional |
|
||||
| type_tracker.rb:23:1:23:16 | call to positional | type_tracker.rb:23:1:23:16 | call to positional |
|
||||
@@ -512,13 +363,6 @@ trackEnd
|
||||
| type_tracker.rb:25:1:28:3 | &block | type_tracker.rb:25:1:28:3 | &block |
|
||||
| type_tracker.rb:25:1:28:3 | **kwargs | type_tracker.rb:25:1:28:3 | **kwargs |
|
||||
| type_tracker.rb:25:1:28:3 | keyword | type_tracker.rb:25:1:28:3 | keyword |
|
||||
| type_tracker.rb:25:1:28:3 | return return in keyword | type_tracker.rb:25:1:28:3 | return return in keyword |
|
||||
| type_tracker.rb:25:1:28:3 | return return in keyword | type_tracker.rb:30:1:30:21 | call to keyword |
|
||||
| type_tracker.rb:25:1:28:3 | return return in keyword | type_tracker.rb:31:1:31:21 | call to keyword |
|
||||
| type_tracker.rb:25:1:28:3 | return return in keyword | type_tracker.rb:32:1:32:27 | call to keyword |
|
||||
| type_tracker.rb:25:1:28:3 | self (keyword) | type_tracker.rb:25:1:28:3 | self (keyword) |
|
||||
| type_tracker.rb:25:1:28:3 | self (keyword) | type_tracker.rb:26:5:26:11 | self |
|
||||
| type_tracker.rb:25:1:28:3 | self (keyword) | type_tracker.rb:27:5:27:11 | self |
|
||||
| type_tracker.rb:25:1:28:3 | self in keyword | type_tracker.rb:25:1:28:3 | self (keyword) |
|
||||
| type_tracker.rb:25:1:28:3 | self in keyword | type_tracker.rb:25:1:28:3 | self in keyword |
|
||||
| type_tracker.rb:25:1:28:3 | self in keyword | type_tracker.rb:26:5:26:11 | self |
|
||||
@@ -526,17 +370,12 @@ trackEnd
|
||||
| type_tracker.rb:25:13:25:14 | p1 | type_tracker.rb:25:13:25:14 | p1 |
|
||||
| type_tracker.rb:25:13:25:14 | p1 | type_tracker.rb:25:13:25:14 | p1 |
|
||||
| type_tracker.rb:25:13:25:14 | p1 | type_tracker.rb:25:13:25:14 | p1 |
|
||||
| type_tracker.rb:25:13:25:14 | p1 | type_tracker.rb:25:13:25:14 | p1 |
|
||||
| type_tracker.rb:25:13:25:14 | p1 | type_tracker.rb:26:10:26:11 | p1 |
|
||||
| type_tracker.rb:25:13:25:14 | p1 | type_tracker.rb:26:10:26:11 | p1 |
|
||||
| type_tracker.rb:25:18:25:19 | p2 | type_tracker.rb:25:18:25:19 | p2 |
|
||||
| type_tracker.rb:25:18:25:19 | p2 | type_tracker.rb:25:18:25:19 | p2 |
|
||||
| type_tracker.rb:25:18:25:19 | p2 | type_tracker.rb:25:18:25:19 | p2 |
|
||||
| type_tracker.rb:25:18:25:19 | p2 | type_tracker.rb:25:18:25:19 | p2 |
|
||||
| type_tracker.rb:25:18:25:19 | p2 | type_tracker.rb:27:10:27:11 | p2 |
|
||||
| type_tracker.rb:25:18:25:19 | p2 | type_tracker.rb:27:10:27:11 | p2 |
|
||||
| type_tracker.rb:26:5:26:11 | call to puts | type_tracker.rb:26:5:26:11 | call to puts |
|
||||
| type_tracker.rb:27:5:27:11 | call to puts | type_tracker.rb:25:1:28:3 | return return in keyword |
|
||||
| type_tracker.rb:27:5:27:11 | call to puts | type_tracker.rb:27:5:27:11 | call to puts |
|
||||
| type_tracker.rb:27:5:27:11 | call to puts | type_tracker.rb:30:1:30:21 | call to keyword |
|
||||
| type_tracker.rb:27:5:27:11 | call to puts | type_tracker.rb:31:1:31:21 | call to keyword |
|
||||
@@ -587,80 +426,45 @@ trackEnd
|
||||
| type_tracker.rb:32:26:32:26 | 8 | type_tracker.rb:26:10:26:11 | p1 |
|
||||
| type_tracker.rb:32:26:32:26 | 8 | type_tracker.rb:32:26:32:26 | 8 |
|
||||
| type_tracker.rb:34:1:53:3 | &block | type_tracker.rb:34:1:53:3 | &block |
|
||||
| type_tracker.rb:34:1:53:3 | return return in throughArray | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:34:1:53:3 | self in throughArray | type_tracker.rb:34:1:53:3 | self in throughArray |
|
||||
| type_tracker.rb:34:1:53:3 | throughArray | type_tracker.rb:34:1:53:3 | throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:18:34:20 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:18:34:20 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:18:34:20 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:18:34:20 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:35:12:35:14 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:35:12:35:14 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:36:5:36:10 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:36:5:36:10 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:5:39:12 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:5:39:12 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:5:39:18 | ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:5:39:18 | ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:16:39:18 | ... = ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:16:39:18 | ... = ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:16:39:18 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:16:39:18 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:16:39:18 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:39:16:39:18 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:40:5:40:12 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:40:5:40:12 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:5:43:13 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:5:43:13 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:5:43:19 | ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:5:43:19 | ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:17:43:19 | ... = ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:17:43:19 | ... = ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:17:43:19 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:17:43:19 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:17:43:19 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:43:17:43:19 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:44:5:44:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:44:5:44:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:5:47:13 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:5:47:13 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:5:47:19 | ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:5:47:19 | ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:17:47:19 | ... = ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:17:47:19 | ... = ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:17:47:19 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:17:47:19 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:17:47:19 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:47:17:47:19 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:5:51:13 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:5:51:13 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:5:51:19 | ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:5:51:19 | ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:17:51:19 | ... = ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:17:51:19 | ... = ... |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:17:51:19 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:17:51:19 | __synth__0 |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:17:51:19 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:51:17:51:19 | obj |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:34:23:34:23 | y | type_tracker.rb:34:23:34:23 | y |
|
||||
| type_tracker.rb:34:23:34:23 | y | type_tracker.rb:34:23:34:23 | y |
|
||||
| type_tracker.rb:34:23:34:23 | y | type_tracker.rb:34:23:34:23 | y |
|
||||
| type_tracker.rb:34:23:34:23 | y | type_tracker.rb:34:23:34:23 | y |
|
||||
| type_tracker.rb:34:23:34:23 | y | type_tracker.rb:39:11:39:11 | y |
|
||||
| type_tracker.rb:34:23:34:23 | y | type_tracker.rb:39:11:39:11 | y |
|
||||
| type_tracker.rb:34:23:34:23 | y | type_tracker.rb:44:12:44:12 | y |
|
||||
| type_tracker.rb:34:23:34:23 | y | type_tracker.rb:44:12:44:12 | y |
|
||||
| type_tracker.rb:34:23:34:23 | y | type_tracker.rb:51:12:51:12 | y |
|
||||
| type_tracker.rb:34:23:34:23 | y | type_tracker.rb:51:12:51:12 | y |
|
||||
| type_tracker.rb:34:26:34:26 | z | type_tracker.rb:34:26:34:26 | z |
|
||||
| type_tracker.rb:34:26:34:26 | z | type_tracker.rb:34:26:34:26 | z |
|
||||
| type_tracker.rb:34:26:34:26 | z | type_tracker.rb:34:26:34:26 | z |
|
||||
| type_tracker.rb:34:26:34:26 | z | type_tracker.rb:34:26:34:26 | z |
|
||||
| type_tracker.rb:34:26:34:26 | z | type_tracker.rb:52:12:52:12 | z |
|
||||
| type_tracker.rb:34:26:34:26 | z | type_tracker.rb:52:12:52:12 | z |
|
||||
| type_tracker.rb:35:5:35:7 | tmp | type_tracker.rb:35:5:35:7 | tmp |
|
||||
| type_tracker.rb:35:11:35:15 | Array | type_tracker.rb:35:11:35:15 | Array |
|
||||
@@ -743,29 +547,22 @@ trackEnd
|
||||
| type_tracker.rb:50:14:50:26 | call to [] | type_tracker.rb:50:14:50:26 | call to [] |
|
||||
| type_tracker.rb:50:14:50:26 | call to [] | type_tracker.rb:51:5:51:10 | array4 |
|
||||
| type_tracker.rb:50:14:50:26 | call to [] | type_tracker.rb:52:5:52:10 | array4 |
|
||||
| type_tracker.rb:50:15:50:15 | 1 | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:15:50:15 | 1 | type_tracker.rb:50:15:50:15 | 1 |
|
||||
| type_tracker.rb:50:15:50:15 | 1 | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:17:50:17 | 2 | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:17:50:17 | 2 | type_tracker.rb:50:17:50:17 | 2 |
|
||||
| type_tracker.rb:50:17:50:17 | 2 | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:19:50:19 | 3 | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:19:50:19 | 3 | type_tracker.rb:50:19:50:19 | 3 |
|
||||
| type_tracker.rb:50:19:50:19 | 3 | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:21:50:21 | 4 | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:21:50:21 | 4 | type_tracker.rb:50:21:50:21 | 4 |
|
||||
| type_tracker.rb:50:21:50:21 | 4 | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:23:50:23 | 5 | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:23:50:23 | 5 | type_tracker.rb:50:23:50:23 | 5 |
|
||||
| type_tracker.rb:50:23:50:23 | 5 | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:50:25:50:25 | 6 | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:50:25:50:25 | 6 | type_tracker.rb:50:25:50:25 | 6 |
|
||||
| type_tracker.rb:50:25:50:25 | 6 | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
| type_tracker.rb:51:5:51:10 | [post] array4 | type_tracker.rb:51:5:51:10 | [post] array4 |
|
||||
| type_tracker.rb:51:5:51:10 | [post] array4 | type_tracker.rb:52:5:52:10 | array4 |
|
||||
| type_tracker.rb:51:5:51:13 | call to []= | type_tracker.rb:51:5:51:13 | call to []= |
|
||||
| type_tracker.rb:51:17:51:19 | __synth__0 | type_tracker.rb:51:17:51:19 | __synth__0 |
|
||||
| type_tracker.rb:52:5:52:13 | ...[...] | type_tracker.rb:34:1:53:3 | return return in throughArray |
|
||||
| type_tracker.rb:52:5:52:13 | ...[...] | type_tracker.rb:52:5:52:13 | ...[...] |
|
||||
forwardButNoBackwardFlow
|
||||
backwardButNoForwardFlow
|
||||
|
||||
Reference in New Issue
Block a user