Merge pull request #11024 from asgerf/rb/data-flow-layer-capture2

Ruby: expand DataFlow API
This commit is contained in:
Asger F
2022-11-09 15:06:03 +01:00
committed by GitHub
35 changed files with 1865 additions and 416 deletions

View File

@@ -36,6 +36,13 @@ private module Cached {
not s instanceof ModuleBase and
result = getEnclosingMethod(s.getOuterScope())
}
cached
Toplevel getEnclosingToplevel(Scope s) {
result = s
or
result = getEnclosingToplevel(s.getOuterScope())
}
}
private import Cached
@@ -66,6 +73,9 @@ class AstNode extends TAstNode {
/** Gets the enclosing method, if any. */
final MethodBase getEnclosingMethod() { result = getEnclosingMethod(scopeOfInclSynth(this)) }
/** Gets the enclosing top-level. */
final Toplevel getEnclosingToplevel() { result = getEnclosingToplevel(scopeOfInclSynth(this)) }
/** Gets a textual representation of this node. */
cached
string toString() { none() }

View File

@@ -271,10 +271,7 @@ module Http {
/** Gets the URL pattern for this route, if it can be statically determined. */
string getUrlPattern() {
exists(CfgNodes::ExprNodes::StringlikeLiteralCfgNode strNode |
this.getUrlPatternArg().getALocalSource() = DataFlow::exprNode(strNode) and
result = strNode.getExpr().getConstantValue().getStringlikeValue()
)
result = this.getUrlPatternArg().getALocalSource().getConstantValue().getStringlikeValue()
}
/**
@@ -538,10 +535,12 @@ module Http {
/** Gets the mimetype of this HTTP response, if it can be statically determined. */
string getMimetype() {
exists(CfgNodes::ExprNodes::StringlikeLiteralCfgNode strNode |
this.getMimetypeOrContentTypeArg().getALocalSource() = DataFlow::exprNode(strNode) and
result = strNode.getExpr().getConstantValue().getStringlikeValue().splitAt(";", 0)
)
result =
this.getMimetypeOrContentTypeArg()
.getALocalSource()
.getConstantValue()
.getStringlikeValue()
.splitAt(";", 0)
or
not exists(this.getMimetypeOrContentTypeArg()) and
result = this.getMimetypeDefault()

View File

@@ -170,6 +170,24 @@ module ConstantValue {
/** A constant `nil` value. */
class ConstantNilValue extends ConstantValue, TNil { }
/** Gets the integer constant `x`. */
ConstantValue fromInt(int x) { result.getInt() = x }
/** Gets the float constant `x`. */
ConstantValue fromFloat(float x) { result.getFloat() = x }
/** Gets the string constant `x`. */
ConstantValue fromString(string x) { result.getString() = x }
/** Gets the symbol constant `x`. */
ConstantValue fromSymbol(string x) { result.getSymbol() = x }
/** Gets the regexp constant `x`. */
ConstantValue fromRegExp(string x) { result.getRegExp() = x }
/** Gets the string, symbol, or regexp constant `x`. */
ConstantValue fromStringlikeValue(string x) { result.getStringlikeValue() = x }
}
/** An access to a constant. */

View File

@@ -3,6 +3,7 @@ private import codeql.ruby.CFG
private import internal.AST
private import internal.Module
private import internal.TreeSitter
private import internal.Scope
/**
* A representation of a run-time `module` or `class` value.
@@ -23,6 +24,22 @@ class Module extends TModule {
/** Gets an `include`d module. */
Module getAnIncludedModule() { result = getAnIncludedModule(this) }
/** Gets the super class or an included or prepended module. */
Module getAnImmediateAncestor() {
result = [this.getSuperClass(), this.getAPrependedModule(), this.getAnIncludedModule()]
}
/** Gets a direct subclass or module including or prepending this one. */
Module getAnImmediateDescendent() { this = result.getAnImmediateAncestor() }
/** Gets a module that is transitively subclassed, included, or prepended by this module. */
pragma[inline]
Module getAnAncestor() { result = this.getAnImmediateAncestor*() }
/** Gets a module that transitively subclasses, includes, or prepends this module. */
pragma[inline]
Module getADescendent() { result = this.getAnImmediateDescendent*() }
/** Holds if this module is a class. */
pragma[noinline]
predicate isClass() {
@@ -63,6 +80,99 @@ class Module extends TModule {
loc.getStartColumn()
)
}
/** Gets a constant or `self` access that refers to this module. */
private Expr getAnImmediateReferenceBase() {
resolveConstantReadAccess(result) = this
or
result.(SelfVariableAccess).getVariable() = this.getADeclaration().getModuleSelfVariable()
}
/** Gets a singleton class that augments this module object. */
SingletonClass getASingletonClass() { result.getValue() = this.getAnImmediateReferenceBase() }
/**
* Gets a singleton method on this module, either declared as a singleton method
* or an instance method on a singleton class.
*
* Does not take inheritance into account.
*/
MethodBase getAnOwnSingletonMethod() {
result.(SingletonMethod).getObject() = this.getAnImmediateReferenceBase()
or
result = this.getASingletonClass().getAMethod().(Method)
}
/**
* Gets an instance method named `name` declared in this module.
*
* Does not take inheritance into account.
*/
Method getOwnInstanceMethod(string name) { result = this.getADeclaration().getMethod(name) }
/**
* Gets an instance method declared in this module.
*
* Does not take inheritance into account.
*/
Method getAnOwnInstanceMethod() { result = this.getADeclaration().getMethod(_) }
/**
* Gets the instance method named `name` available in this module, including methods inherited
* from ancestors.
*/
Method getInstanceMethod(string name) { result = lookupMethod(this, name) }
/**
* Gets an instance method available in this module, including methods inherited
* from ancestors.
*/
Method getAnInstanceMethod() { result = lookupMethod(this, _) }
/** Gets a constant or `self` access that refers to this module. */
Expr getAnImmediateReference() {
result = this.getAnImmediateReferenceBase()
or
result.(SelfVariableAccess).getVariable().getDeclaringScope() = this.getAnOwnSingletonMethod()
}
pragma[nomagic]
private string getEnclosingModuleName() {
exists(string qname |
qname = this.getQualifiedName() and
result = qname.regexpReplaceAll("::[^:]*$", "") and
qname != result
)
}
pragma[nomagic]
private string getOwnModuleName() {
result = this.getQualifiedName().regexpReplaceAll("^.*::", "")
}
/**
* Gets the enclosing module, as it appears in the qualified name of this module.
*
* For example, the parent module of `A::B` is `A`, and `A` itself has no parent module.
*/
pragma[nomagic]
Module getParentModule() { result.getQualifiedName() = this.getEnclosingModuleName() }
/**
* Gets a module named `name` declared inside this one (not aliased), provided
* that such a module is defined or reopened in the current codebase.
*
* For example, for `A::B` the nested module named `C` would be `A::B::C`.
*
* Note that this is not the same as constant lookup. If `A::B::C` would resolve to a
* module whose qualified name is not `A::B::C`, then it will not be found by
* this predicate.
*/
pragma[nomagic]
Module getNestedModule(string name) {
result.getParentModule() = this and
result.getOwnModuleName() = name
}
}
/**
@@ -141,6 +251,46 @@ class ModuleBase extends BodyStmt, Scope, TModuleBase {
/** Gets the representation of the run-time value of this module or class. */
Module getModule() { none() }
/**
* Gets the `self` variable in the module-level scope.
*
* Does not include the `self` variable from any of the methods in the module.
*/
SelfVariable getModuleSelfVariable() { result.getDeclaringScope() = this }
/** Gets the nearest enclosing `Namespace` or `Toplevel`, possibly this module itself. */
Namespace getNamespaceOrToplevel() {
result = this
or
not this instanceof Namespace and
result = this.getEnclosingModule().getNamespaceOrToplevel()
}
/**
* Gets an expression denoting the super class or an included or prepended module.
*
* For example, `C` is an ancestor expression of `M` in each of the following examples:
* ```rb
* class M < C
* end
*
* module M
* include C
* prepend C
* end
* ```
*/
Expr getAnAncestorExpr() {
exists(MethodCall call |
call.getReceiver().(SelfVariableAccess).getVariable() = this.getModuleSelfVariable() and
call.getMethodName() = ["include", "prepend"] and
result = call.getArgument(0) and
scopeOfInclSynth(call) = this // only permit calls directly in the module scope, not in a block
)
or
result = this.(ClassDeclaration).getSuperclassExpr()
}
}
/**

View File

@@ -289,7 +289,7 @@ module Ssa {
)
}
final override string toString() { result = "<captured>" }
final override string toString() { result = "<captured> " + this.getSourceVariable() }
override Location getLocation() { result = this.getBasicBlock().getLocation() }
}

View File

@@ -119,11 +119,27 @@ module LocalFlow {
* Holds if `nodeFrom` is a parameter node, and `nodeTo` is a corresponding SSA node.
*/
predicate localFlowSsaParamInput(Node nodeFrom, Node nodeTo) {
nodeTo = getParameterDefNode(nodeFrom.(ParameterNode).getParameter())
nodeTo = getParameterDefNode(nodeFrom.(ParameterNodeImpl).getParameter())
or
nodeTo = getSelfParameterDefNode(nodeFrom.(SelfParameterNode).getMethod())
}
/**
* Holds if `nodeFrom -> nodeTo` is a step from a parameter to a capture entry node for
* that parameter.
*
* This is intended to recover from flow not currently recognised by ordinary capture flow.
*/
predicate localFlowSsaParamCaptureInput(Node nodeFrom, Node nodeTo) {
exists(Ssa::CapturedEntryDefinition def |
nodeFrom.asParameter().(NamedParameter).getVariable() = def.getSourceVariable()
or
nodeFrom.(SelfParameterNode).getSelfVariable() = def.getSourceVariable()
|
nodeTo.(SsaDefinitionNode).getDefinition() = def
)
}
/**
* Holds if there is a local use-use flow step from `nodeFrom` to `nodeTo`
* involving SSA definition `def`.
@@ -309,7 +325,7 @@ private module Cached {
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
or
defaultValueFlow(nodeTo.(ParameterNode).getParameter(), nodeFrom)
defaultValueFlow(nodeTo.(ParameterNodeImpl).getParameter(), nodeFrom)
or
LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
or
@@ -338,7 +354,7 @@ private module Cached {
predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) {
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
or
defaultValueFlow(nodeTo.(ParameterNode).getParameter(), nodeFrom)
defaultValueFlow(nodeTo.(ParameterNodeImpl).getParameter(), nodeFrom)
or
LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
or
@@ -349,7 +365,12 @@ private module Cached {
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(nodeFrom, nodeTo, _)
}
/** This is the local flow predicate that is used in type tracking. */
/**
* 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)
@@ -396,7 +417,7 @@ private module Cached {
cached
predicate isLocalSourceNode(Node n) {
n instanceof ParameterNode
n instanceof TParameterNode
or
// Expressions that can't be reached from another entry definition or expression
n instanceof ExprNode and
@@ -1272,7 +1293,7 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)
creation.asExpr() =
any(CfgNodes::ExprNodes::MethodCallCfgNode mc |
c.asCallable() = mc.getBlock().getExpr() and
mc.getExpr().getMethodName() = "lambda"
mc.getExpr().getMethodName() = ["lambda", "proc"]
)
)
}

View File

@@ -54,6 +54,30 @@ class Node extends TNode {
* Gets a data flow node to which data may flow from this node in one local step.
*/
Node getASuccessor() { localFlowStep(this, result) }
/** Gets the constant value of this expression, if any. */
ConstantValue getConstantValue() { result = this.asExpr().getConstantValue() }
/**
* Gets the callable corresponding to this block, lambda expression, or call to `proc` or `lambda`.
*
* For example, gets the callable in each of the following cases:
* ```rb
* { |x| x } # block expression
* ->(x) { x } # lambda expression
* proc { |x| x } # call to 'proc'
* lambda { |x| x } # call to 'lambda'
* ```
*/
pragma[noinline]
CallableNode asCallable() {
result = this
or
exists(DataFlowCallable c |
lambdaCreation(this, _, c) and
result.asCallableAstNode() = c.asCallable()
)
}
}
/** A data-flow node corresponding to a call in the control-flow graph. */
@@ -124,6 +148,31 @@ class CallNode extends LocalSourceNode, ExprNode {
}
}
/**
* A call to a setter method.
*
* For example,
* ```rb
* self.foo = 10
* a[0] = 10
* ```
*/
class SetterCallNode extends CallNode {
SetterCallNode() { this.getExprNode().getExpr() instanceof SetterMethodCall }
/**
* Gets the name of the method being called without the trailing `=`. For example, in the following
* two statements the target name is `value`:
* ```rb
* foo.value=(1)
* foo.value = 1
* ```
*/
final string getTargetName() {
result = this.getExprNode().getExpr().(SetterMethodCall).getTargetName()
}
}
/**
* An expression, viewed as a node in a data flow graph.
*
@@ -144,7 +193,7 @@ class ExprNode extends Node, TExprNode {
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
class ParameterNode extends Node, TParameterNode instanceof ParameterNodeImpl {
class ParameterNode extends LocalSourceNode, TParameterNode instanceof ParameterNodeImpl {
/** Gets the parameter corresponding to this node, if any. */
final Parameter getParameter() { result = super.getParameter() }
@@ -177,6 +226,80 @@ class LocalSourceNode extends Node {
*/
pragma[inline]
LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t2 = t.step(result, this) }
/**
* Gets a node to which data may flow from this node in zero or
* more local data-flow steps.
*/
pragma[inline]
Node getALocalUse() { hasLocalSource(result, this) }
/** Gets a method call where this node flows to the receiver. */
CallNode getAMethodCall() { Cached::hasMethodCall(this, result, _) }
/** Gets a call to a method named `name`, where this node flows to the receiver. */
CallNode getAMethodCall(string name) { Cached::hasMethodCall(this, result, name) }
/** Gets a call `obj.name` with no arguments, where this node flows to `obj`. */
CallNode getAnAttributeRead(string name) {
result = this.getAMethodCall(name) and
result.getNumberOfArguments() = 0
}
/**
* Gets a value assigned to `name` on this object, such as the `x` in `obj.name = x`.
*
* Concretely, this gets the argument of any call to `name=` where this node flows to the receiver.
*/
Node getAnAttributeWriteValue(string name) {
result = this.getAMethodCall(name + "=").getArgument(0)
}
/**
* Gets an access to an element on this node, such as `obj[key]`.
*
* Concretely this gets a call to `[]` with 1 argument, where this node flows to the receiver.
*/
CallNode getAnElementRead() {
result = this.getAMethodCall("[]") and result.getNumberOfArguments() = 1
}
/**
* Gets an access to the element `key` on this node, such as `obj[:key]`.
*
* Concretely this gets a call to `[]` where this node flows to the receiver
* and the first and only argument has the constant value `key`.
*/
CallNode getAnElementRead(ConstantValue key) {
result = this.getAnElementRead() and
key = result.getArgument(0).getConstantValue()
}
private CallNode getAnElementWriteCall() {
result = this.getAMethodCall("[]=") and
result.getNumberOfArguments() = 2
}
/**
* Gets a value stored as an element on this node, such as the `x` in `obj[key] = x`.
*
* Concretely, this gets the second argument from any call to `[]=` where this node flows to the receiver.
*/
Node getAnElementWriteValue() { result = this.getAnElementWriteCall().getArgument(1) }
/**
* Gets the `x` in `obj[key] = x`, where this node flows to `obj`.
*
* Concretely, this gets the second argument from any call to `[]=` where this node flows to the receiver
* and the first argument has constant value `key`.
*/
Node getAnElementWriteValue(ConstantValue key) {
exists(CallNode call |
call = this.getAnElementWriteCall() and
call.getArgument(0).getConstantValue() = key and
result = call.getArgument(1)
)
}
}
/**
@@ -196,18 +319,76 @@ class PostUpdateNode extends Node instanceof PostUpdateNodeImpl {
}
cached
private predicate hasLocalSource(Node sink, Node source) {
// Declaring `source` to be a `SourceNode` currently causes a redundant check in the
// recursive case, so instead we check it explicitly here.
source = sink and
source instanceof LocalSourceNode
or
exists(Node mid |
hasLocalSource(mid, source) and
localFlowStepTypeTracker(mid, sink)
)
private module Cached {
cached
predicate hasLocalSource(Node sink, Node source) {
// Declaring `source` to be a `SourceNode` currently causes a redundant check in the
// recursive case, so instead we check it explicitly here.
source = sink and
source instanceof LocalSourceNode
or
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)
)
}
cached
predicate hasMethodCall(LocalSourceNode source, CallNode call, string name) {
source.flowsTo(call.getReceiver()) and
call.getMethodName() = name
}
cached
predicate hasYieldCall(BlockParameterNode block, CallNode yield) {
exists(MethodBase method, YieldCall call |
block.getMethod() = method and
call.getEnclosingMethod() = method and
yield.asExpr().getExpr() = call
)
}
/**
* A place in which a named constant can be looked up during constant lookup.
*/
cached
newtype TConstLookupScope =
/** Look up in a qualified constant name `base::`. */
MkQualifiedLookup(ConstantAccess base) or
/** Look up in the ancestors of `mod`. */
MkAncestorLookup(Module mod) or
/** Look up in a module syntactically nested in a declaration of `mod`. */
MkNestedLookup(Module mod) or
/** Pseudo-scope for accesses that are known to resolve to `mod`. */
MkExactLookup(Module mod)
/**
* Gets a `LocalSourceNode` to represent the constant read or written by `access`.
*/
cached
LocalSourceNode getConstantAccessNode(ConstantAccess access) {
// Namespaces don't evaluate to the constant being accessed, they return the value of their last statement.
// Use the definition of 'self' in the namespace as the representative in this case.
result.(SsaDefinitionNode).getDefinition().(Ssa::SelfDefinition).getSourceVariable() =
access.(Namespace).getModuleSelfVariable()
or
not access instanceof Namespace and
result.asExpr().getExpr() = access
}
cached
predicate forceCachingInSameStage() { any() }
cached
predicate forceCachingBackref() { exists(any(ConstRef const).getConstant(_)) }
}
private import Cached
/** Gets a node corresponding to expression `e`. */
ExprNode exprNode(CfgNodes::ExprCfgNode e) { result.getExprNode() = e }
@@ -562,3 +743,591 @@ abstract deprecated class BarrierGuard extends CfgNodes::ExprCfgNode {
result.asExpr() = this.getAMaybeGuardedCapturedDef().getARead()
}
}
/**
* A representation of a run-time module or class.
*
* This is equivalent to the type `Ast::Module` but provides data-flow specific methods.
*/
class ModuleNode instanceof Module {
/** Gets a declaration of this module, if any. */
final ModuleBase getADeclaration() { result = super.getADeclaration() }
/** Gets the super class of this module, if any. */
final ModuleNode getSuperClass() { result = super.getSuperClass() }
/** Gets an immediate sub class of this module, if any. */
final ModuleNode getASubClass() { result = super.getASubClass() }
/** Gets a `prepend`ed module. */
final ModuleNode getAPrependedModule() { result = super.getAPrependedModule() }
/** Gets an `include`d module. */
final ModuleNode getAnIncludedModule() { result = super.getAnIncludedModule() }
/** Gets the super class or an included or prepended module. */
final ModuleNode getAnImmediateAncestor() { result = super.getAnImmediateAncestor() }
/** Gets a direct subclass or module including or prepending this one. */
final ModuleNode getAnImmediateDescendent() { result = super.getAnImmediateDescendent() }
/** Gets a module that is transitively subclassed, included, or prepended by this module. */
pragma[inline]
final ModuleNode getAnAncestor() { result = super.getAnAncestor() }
/** Gets a module that transitively subclasses, includes, or prepends this module. */
pragma[inline]
final ModuleNode getADescendent() { result = super.getADescendent() }
/**
* Gets the expression node denoting the super class or an included or prepended module.
*
* For example, `C` is an ancestor expression of `M` in each of the following examples:
* ```rb
* class M < C
* end
*
* module M
* include C
* prepend C
* end
* ```
*/
final ExprNode getAnAncestorExpr() {
result.asExpr().getExpr() = super.getADeclaration().getAnAncestorExpr()
}
/** Holds if this module is a class. */
predicate isClass() { super.isClass() }
/** Gets a textual representation of this module. */
final string toString() { result = super.toString() }
/**
* Gets the qualified name of this module, if any.
*
* Only modules that can be resolved will have a qualified name.
*/
final string getQualifiedName() { result = super.getQualifiedName() }
/** Gets the location of this module. */
final Location getLocation() { result = super.getLocation() }
/**
* Gets `self` in a declaration of this module.
*
* This only gets `self` at the module level, not inside any (singleton) method.
*/
LocalSourceNode getModuleLevelSelf() {
result.(SsaDefinitionNode).getVariable() = super.getADeclaration().getModuleSelfVariable()
}
/**
* Gets `self` in the module declaration or in one of its singleton methods.
*
* Does not take inheritance into account.
*/
LocalSourceNode getAnOwnModuleSelf() {
result = this.getModuleLevelSelf()
or
result = this.getAnOwnSingletonMethod().getSelfParameter()
}
/**
* Gets a call to method `name` on `self` in the module-level scope of this module.
*
* For example,
* ```rb
* module M
* include A # getAModuleLevelCall("include")
* foo :bar # getAModuleLevelCall("foo")
* end
* ```
*/
CallNode getAModuleLevelCall(string name) {
result = this.getModuleLevelSelf().getAMethodCall(name)
}
/** Gets a constant or `self` variable that refers to this module. */
LocalSourceNode getAnImmediateReference() {
result.asExpr().getExpr() = super.getAnImmediateReference()
}
/**
* Gets a singleton method declared in this module (or in a singleton class
* augmenting this module).
*
* Does not take inheritance into account.
*/
MethodNode getAnOwnSingletonMethod() {
result.asCallableAstNode() = super.getAnOwnSingletonMethod()
}
/**
* Gets the singleton method named `name` declared in this module (or in a singleton class
* augmenting this module).
*
* Does not take inheritance into account.
*/
MethodNode getOwnSingletonMethod(string name) {
result = this.getAnOwnSingletonMethod() and
result.getMethodName() = name
}
/**
* Gets an instance method declared in this module.
*
* Does not take inheritance into account.
*/
MethodNode getAnOwnInstanceMethod() {
result.asCallableAstNode() = this.getADeclaration().getAMethod().(Method)
}
/**
* Gets an instance method named `name` declared in this module.
*
* Does not take inheritance into account.
*/
MethodNode getOwnInstanceMethod(string name) {
result = this.getAnOwnInstanceMethod() and
result.getMethodName() = name
}
/**
* Gets the `self` parameter of an instance method declared in this module.
*
* Does not take inheritance into account.
*/
ParameterNode getAnOwnInstanceSelf() {
result = TSelfParameterNode(this.getAnOwnInstanceMethod().asCallableAstNode())
}
/**
* Gets the `self` parameter of an instance method available in this module,
* including those inherited from ancestors.
*/
ParameterNode getAnInstanceSelf() {
// Make sure to include the 'self' in overridden instance methods
result = this.getAnAncestor().getAnOwnInstanceSelf()
}
private InstanceVariableAccess getAnOwnInstanceVariableAccess(string name) {
exists(InstanceVariable v |
v.getDeclaringScope() = this.getADeclaration() and
v.getName() = name and
result.getVariable() = v
)
}
/**
* Gets an access to the instance variable `name` in this module.
*
* Does not take inheritance into account.
*/
LocalSourceNode getAnOwnInstanceVariableRead(string name) {
result.asExpr().getExpr() =
this.getAnOwnInstanceVariableAccess(name).(InstanceVariableReadAccess)
}
/**
* Gets the right-hand side of an assignment to the instance variable `name` in this module.
*
* Does not take inheritance into account.
*/
Node getAnOwnInstanceVariableWriteValue(string name) {
exists(AssignExpr assignment |
assignment.getLeftOperand() = this.getAnOwnInstanceVariableAccess(name) and
result.asExpr().getExpr() = assignment.getRightOperand()
)
}
/**
* Gets the instance method named `name` available in this module, including methods inherited
* from ancestors.
*
* Overridden methods are not included.
*/
MethodNode getInstanceMethod(string name) {
result.asCallableAstNode() = super.getInstanceMethod(name)
}
/**
* Gets an instance method available in this module, including methods inherited
* from ancestors.
*
* Overridden methods are not included.
*/
MethodNode getAnInstanceMethod() { result = this.getInstanceMethod(_) }
/**
* Gets the enclosing module, as it appears in the qualified name of this module.
*
* For example, the parent module of `A::B` is `A`, and `A` itself has no parent module.
*/
ModuleNode getParentModule() { result = super.getParentModule() }
/**
* Gets a module named `name` declared inside this one (not aliased), provided
* that such a module is defined or reopened in the current codebase.
*
* For example, for `A::B` the nested module named `C` would be `A::B::C`.
*
* Note that this is not the same as constant lookup. If `A::B::C` would resolve to a
* module whose qualified name is not `A::B::C`, then it will not be found by
* this predicate.
*/
ModuleNode getNestedModule(string name) { result = super.getNestedModule(name) }
}
/**
* A representation of a run-time class.
*/
class ClassNode extends ModuleNode {
ClassNode() { this.isClass() }
}
/**
* A data flow node corresponding to a method, block, or lambda expression.
*/
class CallableNode extends ExprNode {
private Callable callable;
CallableNode() { this.asExpr().getExpr() = callable }
/** Gets the underlying AST node as a `Callable`. */
Callable asCallableAstNode() { result = callable }
private ParameterPosition getParameterPosition(ParameterNodeImpl node) {
node.isSourceParameterOf(callable, result)
}
/** Gets the `n`th positional parameter. */
ParameterNode getParameter(int n) { this.getParameterPosition(result).isPositional(n) }
/** Gets the keyword parameter of the given name. */
ParameterNode getKeywordParameter(string name) {
this.getParameterPosition(result).isKeyword(name)
}
/** Gets the `self` parameter of this callable, if any. */
ParameterNode getSelfParameter() { this.getParameterPosition(result).isSelf() }
/**
* Gets the `hash-splat` parameter. This is a synthetic parameter holding
* a hash object with entries for each keyword argument passed to the function.
*/
ParameterNode getHashSplatParameter() { this.getParameterPosition(result).isHashSplat() }
/**
* Gets the block parameter of this method, if any.
*/
ParameterNode getBlockParameter() { this.getParameterPosition(result).isBlock() }
/**
* Gets a `yield` in this method or `.call` on the block parameter.
*/
CallNode getABlockCall() {
hasYieldCall(this.getBlockParameter(), result)
or
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() }
}
/**
* A data flow node corresponding to a method (possibly a singleton method).
*/
class MethodNode extends CallableNode {
MethodNode() { super.asCallableAstNode() instanceof MethodBase }
/** Gets the underlying AST node for this method. */
override MethodBase asCallableAstNode() { result = super.asCallableAstNode() }
/** Gets the name of this method. */
string getMethodName() { result = this.asCallableAstNode().getName() }
}
/**
* A data flow node corresponding to a block argument.
*/
class BlockNode extends CallableNode {
BlockNode() { super.asCallableAstNode() instanceof Block }
/** Gets the underlying AST node for this block. */
override Block asCallableAstNode() { result = super.asCallableAstNode() }
}
/**
* A representation of a pair such as `K => V` or `K: V`.
*
* Unlike most expressions, pairs do not evaluate to actual objects at runtime and their nodes
* cannot generally be expected to have meaningful data flow edges.
* This node simply provides convenient access to the key and value as data flow nodes.
*/
class PairNode extends ExprNode {
PairNode() { this.getExprNode() instanceof CfgNodes::ExprNodes::PairCfgNode }
/**
* Holds if this pair is of form `key => value` or `key: value`.
*/
predicate hasKeyAndValue(Node key, Node value) {
exists(CfgNodes::ExprNodes::PairCfgNode n |
this.getExprNode() = n and
key = TExprNode(n.getKey()) and
value = TExprNode(n.getValue())
)
}
/** Gets the key expression of this pair, such as the `K` in `K => V` or `K: V`. */
Node getKey() { this.hasKeyAndValue(result, _) }
/** Gets the value expression of this pair, such as the `V` in `K => V` or `K: V`. */
Node getValue() { this.hasKeyAndValue(_, result) }
}
/**
* A data-flow node that corresponds to a hash literal. Hash literals are desugared
* into calls to `Hash.[]`, so this includes both desugared calls as well as
* explicit calls.
*/
class HashLiteralNode extends LocalSourceNode, ExprNode {
HashLiteralNode() { super.getExprNode() instanceof CfgNodes::ExprNodes::HashLiteralCfgNode }
/** Gets a pair in this hash literal. */
PairNode getAKeyValuePair() {
result.getExprNode() =
super.getExprNode().(CfgNodes::ExprNodes::HashLiteralCfgNode).getAKeyValuePair()
}
/** Gets the value associated with the constant `key`, if known. */
Node getElementFromKey(ConstantValue key) {
exists(ExprNode keyNode |
this.getAKeyValuePair().hasKeyAndValue(keyNode, result) and
keyNode.getConstantValue() = key
)
}
}
/**
* A data-flow node corresponding to an array literal. Array literals are desugared
* into calls to `Array.[]`, so this includes both desugared calls as well as
* explicit calls.
*/
class ArrayLiteralNode extends LocalSourceNode, ExprNode {
ArrayLiteralNode() { super.getExprNode() instanceof CfgNodes::ExprNodes::ArrayLiteralCfgNode }
/**
* Gets an element of the array.
*/
Node getAnElement() { result = this.(CallNode).getPositionalArgument(_) }
}
/**
* An access to a constant, such as `C`, `C::D`, or a class or module declaration.
*
* See `DataFlow::getConstant` for usage example.
*/
class ConstRef extends LocalSourceNode {
private ConstantAccess access;
ConstRef() { this = getConstantAccessNode(access) }
/** Gets the underlying constant access AST node. */
ConstantAccess asConstantAccess() { result = access }
/** Gets the underlying module declaration, if any. */
Namespace asNamespaceDeclaration() { result = access }
/** Gets the module defined or re-opened by this constant access, if any. */
ModuleNode asModule() { result.getADeclaration() = access }
/**
* Gets the simple name of the constant being referenced, such as
* the `B` in `A::B`.
*/
string getName() { result = access.getName() }
/**
* Holds if this might refer to a top-level constant.
*/
predicate isPossiblyGlobal() {
exists(Module mod |
not exists(mod.getParentModule()) and
mod.getAnImmediateReference() = access
)
or
not exists(Module mod | mod.getAnImmediateReference() = access) and
not exists(access.getScopeExpr())
}
/**
* Gets a module for which this constant is the reference to an ancestor module.
*
* For example, `M` is the ancestry target of `C` in the following examples:
* ```rb
* class M < C {}
*
* module M
* include C
* end
*
* module M
* prepend C
* end
* ```
*/
private ModuleNode getAncestryTarget() { result.getAnAncestorExpr() = this }
/**
* Gets the known target module.
*
* We resolve these differently to prune out infeasible constant lookups.
*/
private Module getExactTarget() { result.getAnImmediateReference() = access }
/**
* Gets a scope in which a constant lookup may access the contents of the module referenced by this constant.
*/
cached
private TConstLookupScope getATargetScope() {
forceCachingInSameStage() and
result = MkAncestorLookup(this.getAncestryTarget().getAnImmediateDescendent*())
or
access = any(ConstantAccess ac).getScopeExpr() and
result = MkQualifiedLookup(access)
or
result = MkNestedLookup(this.getAncestryTarget())
or
result = MkExactLookup(access.(Namespace).getModule())
}
/**
* Gets the scope expression, or the immediately enclosing `Namespace` (skipping over singleton classes).
*
* Top-levels are not included, since this is only needed for nested constant lookup, and unqualified constants
* at the top-level are handled by `DataFlow::getConstant`, never `ConstRef.getConstant`.
*/
private TConstLookupScope getLookupScope() {
result = MkQualifiedLookup(access.getScopeExpr())
or
not exists(this.getExactTarget()) and
not exists(access.getScopeExpr()) and
not access.hasGlobalScope() and
(
result = MkAncestorLookup(access.getEnclosingModule().getNamespaceOrToplevel().getModule())
or
result = MkNestedLookup(access.getEnclosingModule().getEnclosingModule*().getModule())
)
}
/**
* Holds if this can reference a constant named `name` from `scope`.
*/
cached
private predicate accesses(TConstLookupScope scope, string name) {
forceCachingInSameStage() and
scope = this.getLookupScope() and
name = this.getName()
or
exists(Module mod |
this.getExactTarget() = mod.getNestedModule(name) and
scope = MkExactLookup(mod)
)
}
/**
* Gets a constant reference that may resolve to a member of this node.
*
* For example `DataFlow::getConstant("A").getConstant("B")` finds the following:
* ```rb
* A::B # simple reference
*
* module A
* B # in scope
* module X
* B # in nested scope
* end
* end
*
* module X
* include A
* B # via inclusion
* end
*
* class X < A
* B # via subclassing
* end
* ```
*/
pragma[inline]
ConstRef getConstant(string name) {
exists(TConstLookupScope scope |
pragma[only_bind_into](scope) = pragma[only_bind_out](this).getATargetScope() and
result.accesses(pragma[only_bind_out](scope), name)
)
}
/**
* Gets a module that transitively subclasses, includes, or prepends the module referred to by
* this constant.
*
* For example, `DataFlow::getConstant("A").getADescendentModule()` finds `B`, `C`, and `E`:
* ```rb
* class B < A
* end
*
* class C < B
* end
*
* module E
* include C
* end
* ```
*/
ModuleNode getADescendentModule() { MkAncestorLookup(result) = this.getATargetScope() }
}
/**
* Gets a constant reference that may resolve to the top-level constant `name`.
*
* To get nested constants, call `getConstant()` one or more times on the result.
*
* For example `DataFlow::getConstant("A").getConstant("B")` finds the following:
* ```rb
* A::B # simple reference
*
* module A
* B # in scope
* module X
* B # in nested scope
* end
* end
*
* module X
* include A
* B # via inclusion
* end
*
* class X < A
* B # via subclassing
* end
* ```
*/
pragma[nomagic]
ConstRef getConstant(string name) {
result.getName() = name and
result.isPossiblyGlobal()
}

View File

@@ -1,6 +1,7 @@
private import codeql.ssa.Ssa as SsaImplCommon
private import codeql.ruby.AST
private import codeql.ruby.CFG as Cfg
private import codeql.ruby.controlflow.internal.ControlFlowGraphImplShared as ControlFlowGraphImplShared
private import codeql.ruby.ast.Variable
private import Cfg::CfgNodes::ExprNodes
@@ -53,6 +54,9 @@ private module SsaInput implements SsaImplCommon::InputSig {
or
capturedExitRead(bb, i, v) and
certain = false
or
namespaceSelfExitRead(bb, i, v) and
certain = false
}
}
@@ -94,6 +98,21 @@ private predicate capturedExitRead(Cfg::AnnotatedExitBasicBlock bb, int i, Local
i = bb.length()
}
/**
* Holds if a pseudo read of namespace self-variable `v` should be inserted
* at index `i` in basic block `bb`. We do this to ensure that namespace
* self-variables always get an SSA definition.
*/
private predicate namespaceSelfExitRead(Cfg::AnnotatedExitBasicBlock bb, int i, SelfVariable v) {
exists(Namespace ns, AstNode last |
v.getDeclaringScope() = ns and
last = ControlFlowGraphImplShared::getAControlFlowExitNode(ns) and
if last = ns
then bb.getNode(i).getAPredecessor().getNode() = last
else bb.getNode(i).getNode() = last
)
}
/**
* Holds if captured variable `v` is read directly inside `scope`,
* or inside a (transitively) nested scope of `scope`.

View File

@@ -24,7 +24,7 @@ deprecated class ParamsCall = Rails::ParamsCall;
deprecated class CookiesCall = Rails::CookiesCall;
/**
* A `ClassDeclaration` for a class that extends `ActionController::Base`.
* A class that extends `ActionController::Base`.
* For example,
*
* ```rb
@@ -36,26 +36,61 @@ deprecated class CookiesCall = Rails::CookiesCall;
* end
* ```
*/
class ActionControllerControllerClass extends ClassDeclaration {
ActionControllerControllerClass() {
this.getSuperclassExpr() =
class ActionControllerClass extends DataFlow::ClassNode {
ActionControllerClass() {
this =
[
API::getTopLevelMember("ActionController").getMember("Base"),
DataFlow::getConstant("ActionController").getConstant("Base"),
// In Rails applications `ApplicationController` typically extends `ActionController::Base`, but we
// treat it separately in case the `ApplicationController` definition is not in the database.
API::getTopLevelMember("ApplicationController"),
DataFlow::getConstant("ApplicationController"),
// ActionController::Metal technically doesn't contain all of the
// methods available in Base, such as those for rendering views.
// However we prefer to be over-sensitive in this case in order to find
// more results.
API::getTopLevelMember("ActionController").getMember("Metal")
].getASubclass().getAValueReachableFromSource().asExpr().getExpr()
DataFlow::getConstant("ActionController").getConstant("Metal")
].getADescendentModule()
}
/**
* Gets an `ActionControllerActionMethod` defined in this class.
*/
ActionControllerActionMethod getAnAction() {
result = this.getAnInstanceMethod().asCallableAstNode()
}
/**
* Gets a `self` that possibly refers to an instance of this class.
*/
DataFlow::LocalSourceNode getSelf() {
result = this.getAnInstanceSelf()
or
// Include the module-level `self` to recover some cases where a block at the module level
// is invoked with an instance as the `self`, which we currently can't model directly.
// Concretely this happens in the block passed to `rescue_from`.
// TODO: revisit when we have better infrastructure for handling self in a block
result = this.getModuleLevelSelf()
}
}
private DataFlow::LocalSourceNode actionControllerInstance() {
result = any(ActionControllerClass cls).getSelf()
}
/**
* DEPRECATED. Use `ActionControllerClass` instead.
*
* A `ClassDeclaration` corresponding to an `ActionControllerClass`.
*/
deprecated class ActionControllerControllerClass extends ClassDeclaration {
ActionControllerControllerClass() { this = any(ActionControllerClass cls).getADeclaration() }
/**
* Gets a `ActionControllerActionMethod` defined in this class.
*/
ActionControllerActionMethod getAnAction() { result = this.getAMethod() }
ActionControllerActionMethod getAnAction() {
result = this.getAMethod().(Method) and result.isPrivate()
}
}
/**
@@ -63,9 +98,11 @@ class ActionControllerControllerClass extends ClassDeclaration {
* This may be the target of a route handler, if such a route is defined.
*/
class ActionControllerActionMethod extends Method, Http::Server::RequestHandler::Range {
private ActionControllerControllerClass controllerClass;
private ActionControllerClass controllerClass;
ActionControllerActionMethod() { this = controllerClass.getAMethod() and not this.isPrivate() }
ActionControllerActionMethod() {
this = controllerClass.getAnInstanceMethod().asCallableAstNode() and not this.isPrivate()
}
/**
* Establishes a mapping between a method within the file
@@ -91,7 +128,7 @@ class ActionControllerActionMethod extends Method, Http::Server::RequestHandler:
/**
* Gets the controller class containing this method.
*/
ActionControllerControllerClass getControllerClass() {
ActionControllerClass getControllerClass() {
// TODO: model the implicit render call when a path through the method does
// not end at an explicit render or redirect
result = controllerClass
@@ -102,37 +139,23 @@ class ActionControllerActionMethod extends Method, Http::Server::RequestHandler:
* May return multiple results.
*/
ActionDispatch::Routing::Route getARoute() {
exists(string name |
exists(string name, DataFlow::MethodNode m |
isRoute(result, name, controllerClass) and
isActionControllerMethod(this, name, controllerClass)
m = controllerClass.getInstanceMethod(name) and
this = m.asCallableAstNode()
)
}
}
pragma[nomagic]
private predicate isRoute(
ActionDispatch::Routing::Route route, string name, ActionControllerControllerClass controllerClass
ActionDispatch::Routing::Route route, string name, ActionControllerClass controllerClass
) {
route.getController() + "_controller" =
ActionDispatch::Routing::underscore(controllerClass.getAQualifiedName()) and
ActionDispatch::Routing::underscore(controllerClass.getQualifiedName()) and
name = route.getAction()
}
// A method call with a `self` receiver from within a controller class
private class ActionControllerContextCall extends MethodCall {
private ActionControllerControllerClass controllerClass;
ActionControllerContextCall() {
this.getReceiver() instanceof SelfVariableAccess and
this.getEnclosingModule() = controllerClass
}
/**
* Gets the controller class containing this method.
*/
ActionControllerControllerClass getControllerClass() { result = controllerClass }
}
/**
* A `RemoteFlowSource::Range` to represent accessing the
* ActionController parameters available via the `params` method.
@@ -158,13 +181,17 @@ class CookiesSource extends Http::Server::RequestInputAccess::Range {
}
/** A call to `cookies` from within a controller. */
private class ActionControllerCookiesCall extends ActionControllerContextCall, CookiesCallImpl {
ActionControllerCookiesCall() { this.getMethodName() = "cookies" }
private class ActionControllerCookiesCall extends CookiesCallImpl {
ActionControllerCookiesCall() {
this = actionControllerInstance().getAMethodCall("cookies").asExpr().getExpr()
}
}
/** A call to `params` from within a controller. */
private class ActionControllerParamsCall extends ActionControllerContextCall, ParamsCallImpl {
ActionControllerParamsCall() { this.getMethodName() = "params" }
private class ActionControllerParamsCall extends ParamsCallImpl {
ActionControllerParamsCall() {
this = actionControllerInstance().getAMethodCall("params").asExpr().getExpr()
}
}
/** Modeling for `ActionDispatch::Request`. */
@@ -174,10 +201,7 @@ private module Request {
* `ActionDispatch::Request`.
*/
private class RequestNode extends DataFlow::CallNode {
RequestNode() {
this.asExpr().getExpr() instanceof ActionControllerContextCall and
this.getMethodName() = "request"
}
RequestNode() { this = actionControllerInstance().getAMethodCall("request") }
}
/**
@@ -234,7 +258,7 @@ private module Request {
// Request headers are prefixed with `HTTP_` to distinguish them from
// "headers" supplied by Rack middleware.
this.getMethodName() = ["get_header", "fetch_header"] and
this.getArgument(0).asExpr().getExpr().getConstantValue().getString().regexpMatch("^HTTP_.+")
this.getArgument(0).getConstantValue().getString().regexpMatch("^HTTP_.+")
}
override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() }
@@ -290,9 +314,8 @@ private module Request {
*/
private class EnvHttpAccess extends DataFlow::CallNode, Http::Server::RequestInputAccess::Range {
EnvHttpAccess() {
any(EnvCall c).(DataFlow::LocalSourceNode).flowsTo(this.getReceiver()) and
this.getMethodName() = "[]" and
this.getArgument(0).asExpr().getExpr().getConstantValue().getString().regexpMatch("^HTTP_.+")
this = any(EnvCall c).getAMethodCall("[]") and
this.getArgument(0).getConstantValue().getString().regexpMatch("^HTTP_.+")
}
override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() }
@@ -302,21 +325,32 @@ private module Request {
}
/** A call to `render` from within a controller. */
private class ActionControllerRenderCall extends ActionControllerContextCall, RenderCallImpl {
ActionControllerRenderCall() { this.getMethodName() = "render" }
private class ActionControllerRenderCall extends RenderCallImpl {
ActionControllerRenderCall() {
this = actionControllerInstance().getAMethodCall("render").asExpr().getExpr()
}
}
/** A call to `render_to` from within a controller. */
private class ActionControllerRenderToCall extends ActionControllerContextCall, RenderToCallImpl {
ActionControllerRenderToCall() { this.getMethodName() = ["render_to_body", "render_to_string"] }
private class ActionControllerRenderToCall extends RenderToCallImpl {
ActionControllerRenderToCall() {
this =
actionControllerInstance()
.getAMethodCall(["render_to_body", "render_to_string"])
.asExpr()
.getExpr()
}
}
/** A call to `html_escape` from within a controller. */
private class ActionControllerHtmlEscapeCall extends HtmlEscapeCallImpl {
ActionControllerHtmlEscapeCall() {
// "h" is aliased to "html_escape" in ActiveSupport
this.getMethodName() = ["html_escape", "html_escape_once", "h", "sanitize"] and
this.getEnclosingModule() instanceof ActionControllerControllerClass
this =
actionControllerInstance()
.getAMethodCall(["html_escape", "html_escape_once", "h", "sanitize"])
.asExpr()
.getExpr()
}
}
@@ -324,9 +358,16 @@ private class ActionControllerHtmlEscapeCall extends HtmlEscapeCallImpl {
* A call to the `redirect_to` method, used in an action to redirect to a
* specific URL/path or to a different action in this controller.
*/
class RedirectToCall extends ActionControllerContextCall {
class RedirectToCall extends MethodCall {
private ActionControllerClass controller;
RedirectToCall() {
this.getMethodName() = ["redirect_to", "redirect_back", "redirect_back_or_to"]
this =
controller
.getSelf()
.getAMethodCall(["redirect_to", "redirect_back", "redirect_back_or_to"])
.asExpr()
.getExpr()
}
/** Gets the `Expr` representing the URL to redirect to, if any */
@@ -338,8 +379,10 @@ class RedirectToCall extends ActionControllerContextCall {
/** Gets the `ActionControllerActionMethod` to redirect to, if any */
ActionControllerActionMethod getRedirectActionMethod() {
this.getKeywordArgument("action").getConstantValue().isStringlikeValue(result.getName()) and
result.getEnclosingModule() = this.getControllerClass()
exists(string name |
this.getKeywordArgument("action").getConstantValue().isStringlikeValue(name) and
result = controller.getInstanceMethod(name).asCallableAstNode()
)
}
/**
@@ -373,18 +416,8 @@ class ActionControllerRedirectResponse extends Http::Server::HttpRedirectRespons
}
pragma[nomagic]
private predicate isActionControllerMethod(Method m, string name, ActionControllerControllerClass c) {
m.getName() = name and
m.getEnclosingModule() = c
}
pragma[nomagic]
private predicate actionControllerHasHelperMethodCall(ActionControllerControllerClass c, string name) {
exists(MethodCall mc |
mc.getMethodName() = "helper_method" and
mc.getAnArgument().getConstantValue().isStringlikeValue(name) and
mc.getEnclosingModule() = c
)
private predicate actionControllerHasHelperMethodCall(ActionControllerClass c, string name) {
c.getAModuleLevelCall("helper_method").getArgument(_).getConstantValue().isStringlikeValue(name)
}
/**
@@ -404,27 +437,28 @@ private predicate actionControllerHasHelperMethodCall(ActionControllerController
* See also https://api.rubyonrails.org/classes/AbstractController/Helpers/ClassMethods.html#method-i-helper_method
*/
class ActionControllerHelperMethod extends Method {
private ActionControllerControllerClass controllerClass;
private ActionControllerClass controllerClass;
ActionControllerHelperMethod() {
exists(string name |
isActionControllerMethod(this, name, controllerClass) and
actionControllerHasHelperMethodCall(controllerClass, name)
exists(DataFlow::MethodNode m, string name |
m = controllerClass.getInstanceMethod(name) and
actionControllerHasHelperMethodCall(controllerClass, name) and
this = m.asCallableAstNode()
)
}
/** Gets the class containing this helper method. */
ActionControllerControllerClass getControllerClass() { result = controllerClass }
ActionControllerClass getControllerClass() { result = controllerClass }
}
/**
* Gets an `ActionControllerControllerClass` associated with the given `ErbFile`
* Gets an `ActionControllerClass` associated with the given `ErbFile`
* according to Rails path conventions.
* For instance, a template file at `app/views/foo/bar/baz.html.erb` will be
* mapped to a controller class in `app/controllers/foo/bar/baz_controller.rb`,
* if such a controller class exists.
*/
ActionControllerControllerClass getAssociatedControllerClass(ErbFile f) {
ActionControllerClass getAssociatedControllerClass(ErbFile f) {
// There is a direct mapping from template file to controller class
controllerTemplateFile(result, f)
or
@@ -442,13 +476,13 @@ ActionControllerControllerClass getAssociatedControllerClass(ErbFile f) {
// TODO: improve layout support, e.g. for `layout` method
// https://guides.rubyonrails.org/layouts_and_rendering.html
/**
* Holds if `templatesFile` is a viable file "belonging" to the given
* Holds if `templateFile` is a viable file "belonging" to the given
* `ActionControllerControllerClass`, according to Rails conventions.
*
* This handles mappings between controllers in `app/controllers/`, and
* templates in `app/views/` and `app/views/layouts/`.
*/
predicate controllerTemplateFile(ActionControllerControllerClass cls, ErbFile templateFile) {
predicate controllerTemplateFile(ActionControllerClass cls, ErbFile templateFile) {
exists(string templatesPath, string sourcePrefix, string subPath, string controllerPath |
controllerPath = cls.getLocation().getFile().getRelativePath() and
templatesPath = templateFile.getParentContainer().getRelativePath() and
@@ -484,16 +518,14 @@ class ActionControllerSkipForgeryProtectionCall extends CsrfProtectionSetting::R
/**
* A call to `protect_from_forgery`.
*/
private class ActionControllerProtectFromForgeryCall extends CsrfProtectionSetting::Range {
private ActionControllerContextCall callExpr;
private class ActionControllerProtectFromForgeryCall extends CsrfProtectionSetting::Range,
DataFlow::CallNode {
ActionControllerProtectFromForgeryCall() {
callExpr = this.asExpr().getExpr() and
callExpr.getMethodName() = "protect_from_forgery"
this = actionControllerInstance().getAMethodCall("protect_from_forgery")
}
private string getWithValueText() {
result = callExpr.getKeywordArgument("with").getConstantValue().getSymbol()
result = this.getKeywordArgument("with").getConstantValue().getSymbol()
}
// Calls without `with: :exception` can allow for bypassing CSRF protection
@@ -508,11 +540,7 @@ private class ActionControllerProtectFromForgeryCall extends CsrfProtectionSetti
*/
private class SendFile extends FileSystemAccess::Range, DataFlow::CallNode {
SendFile() {
this.getMethodName() = "send_file" and
(
this.asExpr().getExpr() instanceof ActionControllerContextCall or
this.getReceiver().asExpr().getExpr() instanceof Response::ResponseCall
)
this = [actionControllerInstance(), Response::response()].getAMethodCall("send_file")
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
@@ -522,21 +550,13 @@ private module ParamsSummaries {
private import codeql.ruby.dataflow.FlowSummary
/**
* An instance of `ActionController::Parameters`, including those returned
* Gets an instance of `ActionController::Parameters`, including those returned
* from method calls on other instances.
*/
private class ParamsInstance extends DataFlow::Node {
ParamsInstance() {
this.asExpr().getExpr() instanceof Rails::ParamsCall
or
this =
any(DataFlow::CallNode call |
call.getReceiver() instanceof ParamsInstance and
call.getMethodName() = paramsMethodReturningParamsInstance()
)
or
exists(ParamsInstance prev | prev.(DataFlow::LocalSourceNode).flowsTo(this))
}
private DataFlow::LocalSourceNode paramsInstance() {
result.asExpr().getExpr() instanceof Rails::ParamsCall
or
result = paramsInstance().getAMethodCall(paramsMethodReturningParamsInstance())
}
/**
@@ -578,8 +598,7 @@ private module ParamsSummaries {
MethodsReturningParamsInstanceSummary() { this = "ActionController::Parameters#<various>" }
override MethodCall getACall() {
any(ParamsInstance i).asExpr().getExpr() = result.getReceiver() and
result.getMethodName() = methodReturnsTaintFromSelf()
result = paramsInstance().getAMethodCall(methodReturnsTaintFromSelf()).asExpr().getExpr()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
@@ -601,9 +620,8 @@ private module ParamsSummaries {
override MethodCall getACall() {
result.getMethodName() = ["merge", "reverse_merge", "with_defaults"] and
exists(ParamsInstance i |
i.asExpr().getExpr() = [result.getReceiver(), result.getArgument(0)]
)
paramsInstance().getALocalUse().asExpr().getExpr() =
[result.getReceiver(), result.getArgument(0)]
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
@@ -625,9 +643,8 @@ private module ParamsSummaries {
override MethodCall getACall() {
result.getMethodName() = ["merge!", "reverse_merge!", "with_defaults!"] and
exists(ParamsInstance i |
i.asExpr().getExpr() = [result.getReceiver(), result.getArgument(0)]
)
paramsInstance().getALocalUse().asExpr().getExpr() =
[result.getReceiver(), result.getArgument(0)]
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
@@ -643,15 +660,12 @@ private module ParamsSummaries {
* response.
*/
private module Response {
class ResponseCall extends ActionControllerContextCall {
ResponseCall() { this.getMethodName() = "response" }
DataFlow::LocalSourceNode response() {
result = actionControllerInstance().getAMethodCall("response")
}
class BodyWrite extends DataFlow::CallNode, Http::Server::HttpResponse::Range {
BodyWrite() {
this.getReceiver().asExpr().getExpr() instanceof ResponseCall and
this.getMethodName() = "body="
}
BodyWrite() { this = response().getAMethodCall("body=") }
override DataFlow::Node getBody() { result = this.getArgument(0) }
@@ -661,10 +675,7 @@ private module Response {
}
class SendFileCall extends DataFlow::CallNode, Http::Server::HttpResponse::Range {
SendFileCall() {
this.getReceiver().asExpr().getExpr() instanceof ResponseCall and
this.getMethodName() = "send_file"
}
SendFileCall() { this = response().getAMethodCall("send_file") }
override DataFlow::Node getBody() { result = this.getArgument(0) }
@@ -677,19 +688,12 @@ private module Response {
HeaderWrite() {
// response.header[key] = val
// response.headers[key] = val
exists(MethodCall headerCall |
headerCall.getMethodName() = ["header", "headers"] and
headerCall.getReceiver() instanceof ResponseCall
|
this.getReceiver().asExpr().getExpr() = headerCall and
this.getMethodName() = "[]="
)
this = response().getAMethodCall(["header", "headers"]).getAMethodCall("[]=")
or
// response.set_header(key) = val
// response[header] = val
// response.add_header(key, val)
this.getReceiver().asExpr().getExpr() instanceof ResponseCall and
this.getMethodName() = ["set_header", "[]=", "add_header"]
this = response().getAMethodCall(["set_header", "[]=", "add_header"])
}
override string getName() {
@@ -702,12 +706,12 @@ private module Response {
class SpecificHeaderWrite extends DataFlow::CallNode, Http::Server::HeaderWriteAccess::Range {
SpecificHeaderWrite() {
// response.<method> = val
this.getReceiver().asExpr().getExpr() instanceof ResponseCall and
this.getMethodName() =
[
"location=", "cache_control=", "_cache_control=", "etag=", "charset=", "content_type=",
"date=", "last_modified=", "weak_etag=", "strong_etag="
]
this =
response()
.getAMethodCall([
"location=", "cache_control=", "_cache_control=", "etag=", "charset=",
"content_type=", "date=", "last_modified=", "weak_etag=", "strong_etag="
])
}
override string getName() {

View File

@@ -571,9 +571,7 @@ class ActiveRecordAssociation extends DataFlow::CallNode {
* For example, in `has_many :posts`, this is `post`.
*/
string getTargetModelName() {
exists(string s |
s = this.getArgument(0).asExpr().getExpr().getConstantValue().getStringlikeValue()
|
exists(string s | s = this.getArgument(0).getConstantValue().getStringlikeValue() |
// has_one :profile
// belongs_to :user
this.isSingular() and

View File

@@ -92,102 +92,63 @@ module Rails {
}
/**
* A reference to either `Rails::Railtie`, `Rails::Engine`, or `Rails::Application`.
* Gets a reference to the `Rails` constant.
*/
private DataFlow::ConstRef rails() { result = DataFlow::getConstant("Rails") }
/**
* Gets a reference to either `Rails::Railtie`, `Rails::Engine`, or `Rails::Application`.
* `Engine` and `Application` extend `Railtie`, but may not have definitions present in the database.
*/
private class RailtieClassAccess extends ConstantReadAccess {
RailtieClassAccess() {
this.getScopeExpr().(ConstantAccess).getName() = "Rails" and
this.getName() = ["Railtie", "Engine", "Application"]
}
private DataFlow::ConstRef railtie() {
result = rails().getConstant(["Railtie", "Engine", "Application"])
}
// A `ClassDeclaration` that (transitively) extends `Rails::Railtie`
private class RailtieClass extends ClassDeclaration {
RailtieClass() {
this.getSuperclassExpr() instanceof RailtieClassAccess or
exists(RailtieClass other |
other.getModule() = this.getSuperclassExpr().(ConstantReadAccess).getModule()
)
}
}
/** Gets a class that transitively extends `Rails::Railtie` */
private DataFlow::ClassNode railtieClass() { result = railtie().getADescendentModule() }
private DataFlow::CallNode getAConfigureCallNode() {
// `Rails.application.configure`
result = API::getTopLevelMember("Rails").getReturn("application").getAMethodCall("configure")
/**
* Gets a reference to `Rails::Application` or `Rails.application`.
*/
private DataFlow::LocalSourceNode railsApp() {
result = rails().getAMethodCall("application")
or
// `Rails::Application.configure`
exists(ConstantReadAccess read, RailtieClass cls |
read = result.getReceiver().asExpr().getExpr() and
read.getModule() = cls.getModule() and
result.asExpr().getExpr().(MethodCall).getMethodName() = "configure"
)
result = rails().getConstant("Application")
}
/**
* Classes representing accesses to the Rails config object.
*/
private module Config {
/**
* An access to a Rails config object.
*/
private class SourceNode extends DataFlow::LocalSourceNode {
SourceNode() {
// `Foo < Rails::Application ... config ...`
exists(MethodCall configCall | this.asExpr().getExpr() = configCall |
configCall.getMethodName() = "config" and
configCall.getEnclosingModule() instanceof RailtieClass
)
or
// `Rails.application.config`
this = API::getTopLevelMember("Rails").getReturn("application").getReturn("config").asSource()
or
// `Rails.application.configure { ... config ... }`
// `Rails::Application.configure { ... config ... }`
exists(DataFlow::CallNode configureCallNode, Block block, MethodCall configCall |
configCall = this.asExpr().getExpr()
|
configureCallNode = getAConfigureCallNode() and
block = configureCallNode.asExpr().getExpr().(MethodCall).getBlock() and
configCall.getParent+() = block and
configCall.getMethodName() = "config"
)
}
DataFlow::LocalSourceNode configSource() {
// `Foo < Rails::Application ... config ...`
result = railtieClass().getAnOwnModuleSelf().getAMethodCall("config")
or
// `Rails.application.config`
result = railsApp().getAMethodCall("config")
or
// TODO: move away from getParent+() when have better infrastructure for overridden 'self' in blocks
// `Rails.application.configure { ... config ... }`
// `Rails::Application.configure { ... config ... }`
exists(Block block, MethodCall configCall | configCall = result.asExpr().getExpr() |
block = railsApp().getAMethodCall("configure").getBlock().asExpr().getExpr() and
configCall.getParent+() = block and
configCall.getMethodName() = "config"
)
}
/**
* A reference to the Rails config object.
* Gets a reference to the ActionController config object.
*/
class Node extends DataFlow::Node {
Node() { exists(SourceNode src | src.flowsTo(this)) }
DataFlow::LocalSourceNode actionController() {
result = configSource().getAMethodCall("action_controller")
}
/**
* A reference to the ActionController config object.
* Gets a reference to the ActionDispatch config object.
*/
class ActionControllerNode extends DataFlow::Node {
ActionControllerNode() {
exists(DataFlow::CallNode source |
source.getReceiver() instanceof Node and
source.getMethodName() = "action_controller"
|
source.flowsTo(this)
)
}
}
/**
* A reference to the ActionDispatch config object.
*/
class ActionDispatchNode extends DataFlow::Node {
ActionDispatchNode() {
exists(DataFlow::CallNode source |
source.getReceiver() instanceof Node and
source.getMethodName() = "action_dispatch"
|
source.flowsTo(this)
)
}
DataFlow::LocalSourceNode actionDispatch() {
result = configSource().getAMethodCall("action_dispatch")
}
}
@@ -200,24 +161,18 @@ private module Settings {
loc.getFile().getStem() = "test"
}
private class Setting extends DataFlow::CallNode {
private class Setting extends DataFlow::SetterCallNode {
Setting() {
// exclude some test configuration
not isInTestConfiguration(this.getLocation()) and
this.getReceiver+() instanceof Config::Node and
this.asExpr().getExpr() instanceof SetterMethodCall
this = Config::configSource().getAMethodCall+()
}
}
private class LiteralSetting extends Setting {
ConstantValue value;
LiteralSetting() {
exists(DataFlow::LocalSourceNode lsn |
lsn.asExpr().getConstantValue() = value and
lsn.flowsTo(this.getArgument(0))
)
}
LiteralSetting() { value = this.getArgument(0).getALocalSource().getConstantValue() }
string getValueText() { result = value.toString() }
@@ -262,8 +217,7 @@ private module Settings {
private class AllowForgeryProtectionSetting extends Settings::BooleanSetting,
CsrfProtectionSetting::Range {
AllowForgeryProtectionSetting() {
this.getReceiver() instanceof Config::ActionControllerNode and
this.getMethodName() = "allow_forgery_protection="
this = Config::actionController().getAMethodCall("allow_forgery_protection=")
}
override boolean getVerificationSetting() { result = this.getValue() }
@@ -277,8 +231,7 @@ private class AllowForgeryProtectionSetting extends Settings::BooleanSetting,
private class EncryptedCookieCipherSetting extends Settings::StringlikeSetting,
CookieSecurityConfigurationSetting::Range {
EncryptedCookieCipherSetting() {
this.getReceiver() instanceof Config::ActionDispatchNode and
this.getMethodName() = "encrypted_cookie_cipher="
this = Config::actionDispatch().getAMethodCall("encrypted_cookie_cipher=")
}
OpenSslCipher getCipher() { this.getValueText() = result.getName() }
@@ -298,8 +251,7 @@ private class EncryptedCookieCipherSetting extends Settings::StringlikeSetting,
private class UseAuthenticatedCookieEncryptionSetting extends Settings::BooleanSetting,
CookieSecurityConfigurationSetting::Range {
UseAuthenticatedCookieEncryptionSetting() {
this.getReceiver() instanceof Config::ActionDispatchNode and
this.getMethodName() = "use_authenticated_cookie_encryption="
this = Config::actionDispatch().getAMethodCall("use_authenticated_cookie_encryption=")
}
boolean getDefaultValue() { result = true }
@@ -321,8 +273,7 @@ private class UseAuthenticatedCookieEncryptionSetting extends Settings::BooleanS
private class CookiesSameSiteProtectionSetting extends Settings::NillableStringlikeSetting,
CookieSecurityConfigurationSetting::Range {
CookiesSameSiteProtectionSetting() {
this.getReceiver() instanceof Config::ActionDispatchNode and
this.getMethodName() = "cookies_same_site_protection="
this = Config::actionDispatch().getAMethodCall("cookies_same_site_protection=")
}
string getDefaultValue() { result = "lax" }

View File

@@ -12,26 +12,15 @@ private import codeql.ruby.DataFlow
* Modeling for `railties`.
*/
module Railties {
private class IncludeOrPrependCall extends MethodCall {
IncludeOrPrependCall() { this.getMethodName() = ["include", "prepend"] }
private DataFlow::ConstRef generatorsActionsConst() {
result = DataFlow::getConstant("Rails").getConstant("Generators").getConstant("Actions")
}
/**
* A class which `include`s `Rails::Generators::Actions`.
* Gets a class which is a descendent of `Rails::Generators::Actions`.
*/
private class GeneratorsActionsContext extends ClassDeclaration {
GeneratorsActionsContext() {
exists(IncludeOrPrependCall i |
i.getEnclosingModule() = this and
i.getArgument(0) =
API::getTopLevelMember("Rails")
.getMember("Generators")
.getMember("Actions")
.getAValueReachableFromSource()
.asExpr()
.getExpr()
)
}
private DataFlow::ClassNode generatorsActionsClass() {
result = generatorsActionsConst().getADescendentModule()
}
/**
@@ -40,8 +29,7 @@ module Railties {
*/
private class ExecuteCommandCall extends SystemCommandExecution::Range, DataFlow::CallNode {
ExecuteCommandCall() {
this.asExpr().getExpr().getEnclosingModule() instanceof GeneratorsActionsContext and
this.getMethodName() = "execute_command"
this = generatorsActionsClass().getAnInstanceSelf().getAMethodCall("execute_command")
}
override DataFlow::Node getAnArgument() { result = this.getArgument([0, 1]) }
@@ -54,8 +42,10 @@ module Railties {
*/
private class ExecuteCommandWrapperCall extends SystemCommandExecution::Range, DataFlow::CallNode {
ExecuteCommandWrapperCall() {
this.asExpr().getExpr().getEnclosingModule() instanceof GeneratorsActionsContext and
this.getMethodName() = ["rake", "rails_command", "git"]
this =
generatorsActionsClass()
.getAnInstanceSelf()
.getAMethodCall(["rake", "rails_command", "git"])
}
override DataFlow::Node getAnArgument() { result = this.getArgument(0) }

View File

@@ -88,11 +88,7 @@ module UnsafeDeserialization {
private predicate isOjModePair(CfgNodes::ExprNodes::PairCfgNode p, string modeValue) {
p.getKey().getConstantValue().isStringlikeValue("mode") and
exists(DataFlow::LocalSourceNode symbolLiteral, DataFlow::Node value |
symbolLiteral.asExpr().getExpr().getConstantValue().isSymbol(modeValue) and
symbolLiteral.flowsTo(value) and
value.asExpr() = p.getValue()
)
DataFlow::exprNode(p.getValue()).getALocalSource().getConstantValue().isSymbol(modeValue)
}
/**

View File

@@ -180,11 +180,10 @@ private module Shared {
private predicate isFlowFromLocals0(
CfgNodes::ExprNodes::ElementReferenceCfgNode refNode, string hashKey, ErbFile erb
) {
exists(DataFlow::Node argNode, CfgNodes::ExprNodes::StringlikeLiteralCfgNode strNode |
exists(DataFlow::Node argNode |
argNode.asExpr() = refNode.getArgument(0) and
refNode.getReceiver().getExpr().(MethodCall).getMethodName() = "local_assigns" and
argNode.getALocalSource() = DataFlow::exprNode(strNode) and
strNode.getExpr().getConstantValue().isStringlikeValue(hashKey) and
argNode.getALocalSource().getConstantValue().isStringlikeValue(hashKey) and
erb = refNode.getFile()
)
}

View File

@@ -17,18 +17,11 @@ import codeql.ruby.frameworks.ActionController
import DataFlow::PathGraph
/**
* A call to `request` in an ActionController controller class.
* Gets a call to `request` in an ActionController controller class.
* This probably refers to the incoming HTTP request object.
*/
class ActionControllerRequest extends DataFlow::Node {
ActionControllerRequest() {
exists(DataFlow::CallNode c |
c.asExpr().getExpr().getEnclosingModule() instanceof ActionControllerControllerClass and
c.getMethodName() = "request"
|
c.flowsTo(this)
)
}
DataFlow::LocalSourceNode request() {
result = any(ActionControllerClass cls).getSelf().getAMethodCall("request")
}
/**
@@ -36,9 +29,11 @@ class ActionControllerRequest extends DataFlow::Node {
*/
class WeakParams extends DataFlow::CallNode {
WeakParams() {
this.getReceiver() instanceof ActionControllerRequest and
this.getMethodName() =
["path_parameters", "query_parameters", "request_parameters", "GET", "POST"]
this =
request()
.getAMethodCall([
"path_parameters", "query_parameters", "request_parameters", "GET", "POST"
])
}
}

View File

@@ -20,7 +20,7 @@ import codeql.ruby.ast.Literal
from AmbiguousPathCall call
where
// there is not a constant string argument
not exists(call.getPathArgument().asExpr().getExpr().getConstantValue()) and
not exists(call.getPathArgument().getConstantValue()) and
// if it's a format string, then the first argument is not a constant string
not call.getPathArgument().getALocalSource().asExpr().getExpr().(StringLiteral).getComponent(0)
instanceof StringTextComponent

View File

@@ -3,7 +3,6 @@
| array_flow.rb:180:28:180:46 | # $ hasValueFlow=19 | Missing result:hasValueFlow=19 |
| array_flow.rb:226:10:226:13 | ...[...] | Unexpected result: hasValueFlow=25 |
| array_flow.rb:242:14:242:14 | x | Unexpected result: hasValueFlow=27.2 |
| array_flow.rb:255:16:255:56 | # $ hasValueFlow=28.1 $ hasValueFlow=28.2 | Missing result:hasValueFlow=28.1 |
| array_flow.rb:319:10:319:13 | ...[...] | Unexpected result: hasValueFlow=36.1 |
| array_flow.rb:320:10:320:13 | ...[...] | Unexpected result: hasValueFlow=36.1 |
| array_flow.rb:321:10:321:13 | ...[...] | Unexpected result: hasValueFlow=36.1 |
@@ -26,7 +25,6 @@
| array_flow.rb:490:10:490:13 | ...[...] | Unexpected result: hasValueFlow=54.5 |
| array_flow.rb:494:10:494:13 | ...[...] | Unexpected result: hasValueFlow=54.2 |
| array_flow.rb:494:10:494:13 | ...[...] | Unexpected result: hasValueFlow=54.3 |
| array_flow.rb:564:16:564:56 | # $ hasValueFlow=62.1 $ hasValueFlow=62.2 | Missing result:hasValueFlow=62.1 |
| array_flow.rb:575:16:575:34 | # $ hasValueFlow=63 | Missing result:hasValueFlow=63 |
| array_flow.rb:580:19:580:37 | # $ hasValueFlow=64 | Missing result:hasValueFlow=64 |
| array_flow.rb:582:16:582:34 | # $ hasValueFlow=64 | Missing result:hasValueFlow=64 |

View File

@@ -1,5 +1,17 @@
failures
edges
| captured_variables.rb:1:24:1:24 | x : | captured_variables.rb:2:20:2:20 | x |
| captured_variables.rb:1:24:1:24 | x : | captured_variables.rb:2:20:2:20 | x |
| captured_variables.rb:5:20:5:30 | call to source : | captured_variables.rb:1:24:1:24 | x : |
| captured_variables.rb:5:20:5:30 | call to source : | captured_variables.rb:1:24:1:24 | x : |
| captured_variables.rb:21:33:21:33 | x : | captured_variables.rb:23:14:23:14 | x |
| captured_variables.rb:21:33:21:33 | x : | captured_variables.rb:23:14:23:14 | x |
| captured_variables.rb:27:29:27:39 | call to source : | captured_variables.rb:21:33:21:33 | x : |
| captured_variables.rb:27:29:27:39 | call to source : | captured_variables.rb:21:33:21:33 | x : |
| captured_variables.rb:32:31:32:31 | x : | captured_variables.rb:34:14:34:14 | x |
| captured_variables.rb:32:31:32:31 | x : | captured_variables.rb:34:14:34:14 | x |
| captured_variables.rb:38:27:38:37 | call to source : | captured_variables.rb:32:31:32:31 | x : |
| captured_variables.rb:38:27:38:37 | call to source : | captured_variables.rb:32:31:32:31 | x : |
| instance_variables.rb:10:19:10:19 | x : | instance_variables.rb:11:18:11:18 | x : |
| instance_variables.rb:10:19:10:19 | x : | instance_variables.rb:11:18:11:18 | x : |
| instance_variables.rb:11:18:11:18 | x : | instance_variables.rb:11:9:11:14 | [post] self [@field] : |
@@ -152,6 +164,24 @@ edges
| instance_variables.rb:84:6:84:10 | foo13 [@field] : | instance_variables.rb:84:6:84:20 | call to get_field |
| instance_variables.rb:84:6:84:10 | foo13 [@field] : | instance_variables.rb:84:6:84:20 | call to get_field |
nodes
| captured_variables.rb:1:24:1:24 | x : | semmle.label | x : |
| captured_variables.rb:1:24:1:24 | x : | semmle.label | x : |
| captured_variables.rb:2:20:2:20 | x | semmle.label | x |
| captured_variables.rb:2:20:2:20 | x | semmle.label | x |
| captured_variables.rb:5:20:5:30 | call to source : | semmle.label | call to source : |
| captured_variables.rb:5:20:5:30 | call to source : | semmle.label | call to source : |
| captured_variables.rb:21:33:21:33 | x : | semmle.label | x : |
| captured_variables.rb:21:33:21:33 | x : | semmle.label | x : |
| captured_variables.rb:23:14:23:14 | x | semmle.label | x |
| captured_variables.rb:23:14:23:14 | x | semmle.label | x |
| captured_variables.rb:27:29:27:39 | call to source : | semmle.label | call to source : |
| captured_variables.rb:27:29:27:39 | call to source : | semmle.label | call to source : |
| captured_variables.rb:32:31:32:31 | x : | semmle.label | x : |
| captured_variables.rb:32:31:32:31 | x : | semmle.label | x : |
| captured_variables.rb:34:14:34:14 | x | semmle.label | x |
| captured_variables.rb:34:14:34:14 | x | semmle.label | x |
| captured_variables.rb:38:27:38:37 | call to source : | semmle.label | call to source : |
| captured_variables.rb:38:27:38:37 | call to source : | semmle.label | call to source : |
| instance_variables.rb:10:19:10:19 | x : | semmle.label | x : |
| instance_variables.rb:10:19:10:19 | x : | semmle.label | x : |
| instance_variables.rb:11:9:11:14 | [post] self [@field] : | semmle.label | [post] self [@field] : |
@@ -335,6 +365,9 @@ subpaths
| instance_variables.rb:84:6:84:10 | foo13 [@field] : | instance_variables.rb:13:5:15:7 | self in get_field [@field] : | instance_variables.rb:14:9:14:21 | return : | instance_variables.rb:84:6:84:20 | call to get_field |
| instance_variables.rb:84:6:84:10 | foo13 [@field] : | instance_variables.rb:13:5:15:7 | self in get_field [@field] : | instance_variables.rb:14:9:14:21 | return : | instance_variables.rb:84:6:84:20 | call to get_field |
#select
| captured_variables.rb:2:20:2:20 | x | captured_variables.rb:5:20:5:30 | call to source : | captured_variables.rb:2:20:2:20 | x | $@ | captured_variables.rb:5:20:5:30 | call to source : | call to source : |
| captured_variables.rb:23:14:23:14 | x | captured_variables.rb:27:29:27:39 | call to source : | captured_variables.rb:23:14:23:14 | x | $@ | captured_variables.rb:27:29:27:39 | call to source : | call to source : |
| captured_variables.rb:34:14:34:14 | x | captured_variables.rb:38:27:38:37 | call to source : | captured_variables.rb:34:14:34:14 | x | $@ | captured_variables.rb:38:27:38:37 | call to source : | call to source : |
| instance_variables.rb:20:10:20:13 | @foo | instance_variables.rb:19:12:19:21 | call to taint : | instance_variables.rb:20:10:20:13 | @foo | $@ | instance_variables.rb:19:12:19:21 | call to taint : | call to taint : |
| instance_variables.rb:25:6:25:18 | call to get_field | instance_variables.rb:24:15:24:23 | call to taint : | instance_variables.rb:25:6:25:18 | call to get_field | $@ | instance_variables.rb:24:15:24:23 | call to taint : | call to taint : |
| instance_variables.rb:29:6:29:18 | call to inc_field | instance_variables.rb:28:15:28:22 | call to taint : | instance_variables.rb:29:6:29:18 | call to inc_field | $@ | instance_variables.rb:28:15:28:22 | call to taint : | call to taint : |

View File

@@ -0,0 +1,17 @@
| captured_variables.rb:9:14:9:14 | x | Fixed missing result:hasValueFlow=1.2 |
| captured_variables.rb:16:14:16:14 | x | Fixed missing result:hasValueFlow=1.3 |
| instance_variables.rb:20:16:20:33 | # $ hasValueFlow=7 | Missing result:hasValueFlow=7 |
| instance_variables.rb:25:21:25:39 | # $ hasValueFlow=42 | Missing result:hasValueFlow=42 |
| instance_variables.rb:37:22:37:40 | # $ hasValueFlow=21 | Missing result:hasValueFlow=21 |
| instance_variables.rb:41:18:41:36 | # $ hasValueFlow=22 | Missing result:hasValueFlow=22 |
| instance_variables.rb:49:22:49:40 | # $ hasValueFlow=24 | Missing result:hasValueFlow=24 |
| instance_variables.rb:53:22:53:40 | # $ hasValueFlow=22 | Missing result:hasValueFlow=22 |
| instance_variables.rb:54:22:54:40 | # $ hasValueFlow=24 | Missing result:hasValueFlow=24 |
| instance_variables.rb:55:22:55:40 | # $ hasValueFlow=25 | Missing result:hasValueFlow=25 |
| instance_variables.rb:60:22:60:40 | # $ hasValueFlow=26 | Missing result:hasValueFlow=26 |
| instance_variables.rb:61:22:61:40 | # $ hasValueFlow=26 | Missing result:hasValueFlow=26 |
| instance_variables.rb:66:22:66:40 | # $ hasValueFlow=27 | Missing result:hasValueFlow=27 |
| instance_variables.rb:67:23:67:41 | # $ hasValueFlow=27 | Missing result:hasValueFlow=27 |
| instance_variables.rb:75:23:75:41 | # $ hasValueFlow=28 | Missing result:hasValueFlow=28 |
| instance_variables.rb:79:23:79:41 | # $ hasValueFlow=28 | Missing result:hasValueFlow=28 |
| instance_variables.rb:84:23:84:41 | # $ hasValueFlow=28 | Missing result:hasValueFlow=28 |

View File

@@ -0,0 +1 @@
import TestUtilities.InlineTypeTrackingFlowTest

View File

@@ -0,0 +1,38 @@
def capture_local_call x
fn = -> { sink(x) } # $ hasValueFlow=1.1
fn.call
end
capture_local_call source(1.1)
def capture_escape_return1 x
-> {
sink(x) # $ MISSING: hasValueFlow=1.2
}
end
(capture_escape_return1 source(1.2)).call
def capture_escape_return2 x
-> {
sink(x) # $ MISSING: hasValueFlow=1.3
}
end
Something.unknownMethod(capture_escape_return2 source(1.3))
def capture_escape_unknown_call x
fn = -> {
sink(x) # $ hasValueFlow=1.4
}
Something.unknownMethod(fn)
end
capture_escape_unknown_call source(1.4)
def call_it fn
fn.call
end
def capture_escape_known_call x
fn = -> {
sink(x) # $ hasValueFlow=1.5
}
call_it fn
end
capture_escape_known_call source(1.5)

View File

@@ -0,0 +1,234 @@
getAnAncestorExpr
| tst.rb:8:1:11:3 | C2 | tst.rb:8:12:8:13 | C1 |
| tst.rb:27:1:35:3 | C3 | tst.rb:27:12:27:13 | C2 |
| tst.rb:27:1:35:3 | C3 | tst.rb:28:13:28:17 | Mixin |
| tst.rb:27:1:35:3 | C3 | tst.rb:29:13:29:18 | Mixin2 |
| tst.rb:41:5:42:7 | N1::XY1 | tst.rb:41:17:41:20 | Y |
| tst.rb:44:9:45:11 | N1::N2::XY2 | tst.rb:44:21:44:24 | Y |
| tst.rb:49:1:51:3 | N2 | tst.rb:50:13:50:13 | X |
| tst.rb:53:5:54:7 | N2::XY3 | tst.rb:53:17:53:17 | Y |
getAnAncestor
| file://:0:0:0:0 | Array | file://:0:0:0:0 | Array |
| file://:0:0:0:0 | Array | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | Array | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | Array | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | BasicObject | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | Class | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | Class | file://:0:0:0:0 | Class |
| file://:0:0:0:0 | Class | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | Class | file://:0:0:0:0 | Module |
| file://:0:0:0:0 | Class | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | Complex | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | Complex | file://:0:0:0:0 | Complex |
| file://:0:0:0:0 | Complex | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | Complex | file://:0:0:0:0 | Numeric |
| file://:0:0:0:0 | Complex | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | FalseClass | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | FalseClass | file://:0:0:0:0 | FalseClass |
| file://:0:0:0:0 | FalseClass | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | FalseClass | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | Float | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | Float | file://:0:0:0:0 | Float |
| file://:0:0:0:0 | Float | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | Float | file://:0:0:0:0 | Numeric |
| file://:0:0:0:0 | Float | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | Hash | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | Hash | file://:0:0:0:0 | Hash |
| file://:0:0:0:0 | Hash | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | Hash | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | Integer | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | Integer | file://:0:0:0:0 | Integer |
| file://:0:0:0:0 | Integer | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | Integer | file://:0:0:0:0 | Numeric |
| file://:0:0:0:0 | Integer | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | Kernel | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | Module | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | Module | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | Module | file://:0:0:0:0 | Module |
| file://:0:0:0:0 | Module | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | NilClass | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | NilClass | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | NilClass | file://:0:0:0:0 | NilClass |
| file://:0:0:0:0 | NilClass | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | Numeric | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | Numeric | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | Numeric | file://:0:0:0:0 | Numeric |
| file://:0:0:0:0 | Numeric | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | Object | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | Object | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | Object | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | Proc | file://:0:0:0:0 | Proc |
| file://:0:0:0:0 | Rational | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | Rational | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | Rational | file://:0:0:0:0 | Numeric |
| file://:0:0:0:0 | Rational | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | Rational | file://:0:0:0:0 | Rational |
| file://:0:0:0:0 | String | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | String | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | String | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | String | file://:0:0:0:0 | String |
| file://:0:0:0:0 | Symbol | file://:0:0:0:0 | Symbol |
| file://:0:0:0:0 | TrueClass | file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | TrueClass | file://:0:0:0:0 | Kernel |
| file://:0:0:0:0 | TrueClass | file://:0:0:0:0 | Object |
| file://:0:0:0:0 | TrueClass | file://:0:0:0:0 | TrueClass |
| tst.rb:1:1:6:3 | C1 | file://:0:0:0:0 | BasicObject |
| tst.rb:1:1:6:3 | C1 | file://:0:0:0:0 | Kernel |
| tst.rb:1:1:6:3 | C1 | file://:0:0:0:0 | Object |
| tst.rb:1:1:6:3 | C1 | tst.rb:1:1:6:3 | C1 |
| tst.rb:8:1:11:3 | C2 | file://:0:0:0:0 | BasicObject |
| tst.rb:8:1:11:3 | C2 | file://:0:0:0:0 | Kernel |
| tst.rb:8:1:11:3 | C2 | file://:0:0:0:0 | Object |
| tst.rb:8:1:11:3 | C2 | tst.rb:1:1:6:3 | C1 |
| tst.rb:8:1:11:3 | C2 | tst.rb:8:1:11:3 | C2 |
| tst.rb:13:1:18:3 | Mixin | tst.rb:13:1:18:3 | Mixin |
| tst.rb:20:1:25:3 | Mixin2 | tst.rb:20:1:25:3 | Mixin2 |
| tst.rb:27:1:35:3 | C3 | file://:0:0:0:0 | BasicObject |
| tst.rb:27:1:35:3 | C3 | file://:0:0:0:0 | Kernel |
| tst.rb:27:1:35:3 | C3 | file://:0:0:0:0 | Object |
| tst.rb:27:1:35:3 | C3 | tst.rb:1:1:6:3 | C1 |
| tst.rb:27:1:35:3 | C3 | tst.rb:8:1:11:3 | C2 |
| tst.rb:27:1:35:3 | C3 | tst.rb:13:1:18:3 | Mixin |
| tst.rb:27:1:35:3 | C3 | tst.rb:20:1:25:3 | Mixin2 |
| tst.rb:27:1:35:3 | C3 | tst.rb:27:1:35:3 | C3 |
| tst.rb:40:1:47:3 | N1 | tst.rb:40:1:47:3 | N1 |
| tst.rb:41:5:42:7 | N1::XY1 | file://:0:0:0:0 | BasicObject |
| tst.rb:41:5:42:7 | N1::XY1 | file://:0:0:0:0 | Kernel |
| tst.rb:41:5:42:7 | N1::XY1 | file://:0:0:0:0 | Object |
| tst.rb:41:5:42:7 | N1::XY1 | tst.rb:41:5:42:7 | N1::XY1 |
| tst.rb:43:5:46:7 | N1::N2 | tst.rb:43:5:46:7 | N1::N2 |
| tst.rb:44:9:45:11 | N1::N2::XY2 | file://:0:0:0:0 | BasicObject |
| tst.rb:44:9:45:11 | N1::N2::XY2 | file://:0:0:0:0 | Kernel |
| tst.rb:44:9:45:11 | N1::N2::XY2 | file://:0:0:0:0 | Object |
| tst.rb:44:9:45:11 | N1::N2::XY2 | tst.rb:44:9:45:11 | N1::N2::XY2 |
| tst.rb:49:1:51:3 | N2 | tst.rb:49:1:51:3 | N2 |
| tst.rb:53:5:54:7 | N2::XY3 | file://:0:0:0:0 | BasicObject |
| tst.rb:53:5:54:7 | N2::XY3 | file://:0:0:0:0 | Kernel |
| tst.rb:53:5:54:7 | N2::XY3 | file://:0:0:0:0 | Object |
| tst.rb:53:5:54:7 | N2::XY3 | tst.rb:53:5:54:7 | N2::XY3 |
| tst.rb:57:1:62:3 | Nodes | file://:0:0:0:0 | BasicObject |
| tst.rb:57:1:62:3 | Nodes | file://:0:0:0:0 | Kernel |
| tst.rb:57:1:62:3 | Nodes | file://:0:0:0:0 | Object |
| tst.rb:57:1:62:3 | Nodes | tst.rb:57:1:62:3 | Nodes |
getModuleLevelSelf
| tst.rb:1:1:6:3 | C1 | tst.rb:1:1:6:3 | self (C1) |
| tst.rb:8:1:11:3 | C2 | tst.rb:8:1:11:3 | self (C2) |
| tst.rb:13:1:18:3 | Mixin | tst.rb:13:1:18:3 | self (Mixin) |
| tst.rb:20:1:25:3 | Mixin2 | tst.rb:20:1:25:3 | self (Mixin2) |
| tst.rb:27:1:35:3 | C3 | tst.rb:27:1:35:3 | self (C3) |
| tst.rb:40:1:47:3 | N1 | tst.rb:40:1:47:3 | self (N1) |
| tst.rb:41:5:42:7 | N1::XY1 | tst.rb:41:5:42:7 | self (XY1) |
| tst.rb:43:5:46:7 | N1::N2 | tst.rb:43:5:46:7 | self (N2) |
| tst.rb:44:9:45:11 | N1::N2::XY2 | tst.rb:44:9:45:11 | self (XY2) |
| tst.rb:49:1:51:3 | N2 | tst.rb:49:1:51:3 | self (N2) |
| tst.rb:49:1:51:3 | N2 | tst.rb:52:1:55:3 | self (N2) |
| tst.rb:53:5:54:7 | N2::XY3 | tst.rb:53:5:54:7 | self (XY3) |
| tst.rb:57:1:62:3 | Nodes | tst.rb:57:1:62:3 | self (Nodes) |
getAnImmediateReference
| file://:0:0:0:0 | Array | tst.rb:59:15:59:21 | Array |
| file://:0:0:0:0 | Hash | tst.rb:60:14:60:45 | Hash |
| tst.rb:1:1:6:3 | C1 | tst.rb:8:12:8:13 | C1 |
| tst.rb:8:1:11:3 | C2 | tst.rb:27:12:27:13 | C2 |
| tst.rb:13:1:18:3 | Mixin | tst.rb:28:13:28:17 | Mixin |
| tst.rb:20:1:25:3 | Mixin2 | tst.rb:29:13:29:18 | Mixin2 |
| tst.rb:27:1:35:3 | C3 | tst.rb:37:5:37:6 | C3 |
getOwnInstanceMethod
| tst.rb:1:1:6:3 | C1 | c1 | tst.rb:2:5:5:7 | c1 |
| tst.rb:8:1:11:3 | C2 | c2 | tst.rb:9:5:10:7 | c2 |
| tst.rb:13:1:18:3 | Mixin | m1 | tst.rb:14:5:15:7 | m1 |
| tst.rb:20:1:25:3 | Mixin2 | m2 | tst.rb:21:5:22:7 | m2 |
| tst.rb:57:1:62:3 | Nodes | m1 | tst.rb:58:5:61:7 | m1 |
getInstanceMethod
| tst.rb:1:1:6:3 | C1 | c1 | tst.rb:2:5:5:7 | c1 |
| tst.rb:8:1:11:3 | C2 | c1 | tst.rb:2:5:5:7 | c1 |
| tst.rb:8:1:11:3 | C2 | c2 | tst.rb:9:5:10:7 | c2 |
| tst.rb:13:1:18:3 | Mixin | m1 | tst.rb:14:5:15:7 | m1 |
| tst.rb:20:1:25:3 | Mixin2 | m2 | tst.rb:21:5:22:7 | m2 |
| tst.rb:27:1:35:3 | C3 | c1 | tst.rb:2:5:5:7 | c1 |
| tst.rb:27:1:35:3 | C3 | c2 | tst.rb:9:5:10:7 | c2 |
| tst.rb:27:1:35:3 | C3 | m1 | tst.rb:14:5:15:7 | m1 |
| tst.rb:27:1:35:3 | C3 | m2 | tst.rb:21:5:22:7 | m2 |
| tst.rb:57:1:62:3 | Nodes | m1 | tst.rb:58:5:61:7 | m1 |
getAnOwnInstanceSelf
| tst.rb:1:1:6:3 | C1 | tst.rb:2:5:5:7 | self in c1 |
| tst.rb:8:1:11:3 | C2 | tst.rb:9:5:10:7 | self in c2 |
| tst.rb:13:1:18:3 | Mixin | tst.rb:14:5:15:7 | self in m1 |
| tst.rb:20:1:25:3 | Mixin2 | tst.rb:21:5:22:7 | self in m2 |
| tst.rb:57:1:62:3 | Nodes | tst.rb:58:5:61:7 | self in m1 |
getAnInstanceSelf
| tst.rb:1:1:6:3 | C1 | tst.rb:2:5:5:7 | self in c1 |
| tst.rb:8:1:11:3 | C2 | tst.rb:2:5:5:7 | self in c1 |
| tst.rb:8:1:11:3 | C2 | tst.rb:9:5:10:7 | self in c2 |
| tst.rb:13:1:18:3 | Mixin | tst.rb:14:5:15:7 | self in m1 |
| tst.rb:20:1:25:3 | Mixin2 | tst.rb:21:5:22:7 | self in m2 |
| tst.rb:27:1:35:3 | C3 | tst.rb:2:5:5:7 | self in c1 |
| tst.rb:27:1:35:3 | C3 | tst.rb:9:5:10:7 | self in c2 |
| tst.rb:27:1:35:3 | C3 | tst.rb:14:5:15:7 | self in m1 |
| tst.rb:27:1:35:3 | C3 | tst.rb:21:5:22:7 | self in m2 |
| tst.rb:57:1:62:3 | Nodes | tst.rb:58:5:61:7 | self in m1 |
getOwnSingletonMethod
| tst.rb:13:1:18:3 | Mixin | m1s | tst.rb:16:5:17:7 | m1s |
| tst.rb:20:1:25:3 | Mixin2 | m2s | tst.rb:23:5:24:7 | m2s |
| tst.rb:27:1:35:3 | C3 | c3_self1 | tst.rb:32:9:33:11 | c3_self1 |
| tst.rb:27:1:35:3 | C3 | c3_self2 | tst.rb:37:1:38:3 | c3_self2 |
getAnOwnInstanceVariableRead
| tst.rb:1:1:6:3 | C1 | @field | tst.rb:4:9:4:14 | @field |
getAnOwnInstanceVariableWriteValue
| tst.rb:1:1:6:3 | C1 | @field | tst.rb:3:18:3:18 | 1 |
getParentModule
| tst.rb:41:5:42:7 | N1::XY1 | tst.rb:40:1:47:3 | N1 |
| tst.rb:43:5:46:7 | N1::N2 | tst.rb:40:1:47:3 | N1 |
| tst.rb:44:9:45:11 | N1::N2::XY2 | tst.rb:43:5:46:7 | N1::N2 |
| tst.rb:53:5:54:7 | N2::XY3 | tst.rb:49:1:51:3 | N2 |
getNestedModule
| tst.rb:40:1:47:3 | N1 | N2 | tst.rb:43:5:46:7 | N1::N2 |
| tst.rb:40:1:47:3 | N1 | XY1 | tst.rb:41:5:42:7 | N1::XY1 |
| tst.rb:43:5:46:7 | N1::N2 | XY2 | tst.rb:44:9:45:11 | N1::N2::XY2 |
| tst.rb:49:1:51:3 | N2 | XY3 | tst.rb:53:5:54:7 | N2::XY3 |
getTopLevelConst
| Array | tst.rb:59:15:59:21 | Array |
| C1 | tst.rb:1:1:6:3 | self (C1) |
| C1 | tst.rb:8:12:8:13 | C1 |
| C2 | tst.rb:8:1:11:3 | self (C2) |
| C2 | tst.rb:27:12:27:13 | C2 |
| C3 | tst.rb:27:1:35:3 | self (C3) |
| C3 | tst.rb:37:5:37:6 | C3 |
| Hash | tst.rb:60:14:60:45 | Hash |
| Mixin | tst.rb:13:1:18:3 | self (Mixin) |
| Mixin | tst.rb:28:13:28:17 | Mixin |
| Mixin2 | tst.rb:20:1:25:3 | self (Mixin2) |
| Mixin2 | tst.rb:29:13:29:18 | Mixin2 |
| N1 | tst.rb:40:1:47:3 | self (N1) |
| N2 | tst.rb:43:5:46:7 | self (N2) |
| N2 | tst.rb:49:1:51:3 | self (N2) |
| N2 | tst.rb:52:1:55:3 | self (N2) |
| Nodes | tst.rb:57:1:62:3 | self (Nodes) |
| X | tst.rb:41:17:41:17 | X |
| X | tst.rb:44:21:44:21 | X |
| X | tst.rb:50:13:50:13 | X |
| XY1 | tst.rb:41:5:42:7 | self (XY1) |
| XY2 | tst.rb:44:9:45:11 | self (XY2) |
| XY3 | tst.rb:53:5:54:7 | self (XY3) |
| Y | tst.rb:53:17:53:17 | Y |
getConstant
| tst.rb:41:17:41:17 | X | Y | tst.rb:41:17:41:20 | Y |
| tst.rb:44:21:44:21 | X | Y | tst.rb:44:21:44:24 | Y |
| tst.rb:50:13:50:13 | X | X | tst.rb:50:13:50:13 | X |
| tst.rb:50:13:50:13 | X | XY3 | tst.rb:53:5:54:7 | self (XY3) |
| tst.rb:50:13:50:13 | X | Y | tst.rb:53:17:53:17 | Y |
getXYClasses
| tst.rb:41:5:42:7 | N1::XY1 |
| tst.rb:44:9:45:11 | N1::N2::XY2 |
| tst.rb:53:5:54:7 | N2::XY3 |
hashLiteralNode
| tst.rb:60:14:60:45 | call to [] |
hashLiteralKey
| tst.rb:60:14:60:45 | call to [] | bar | tst.rb:60:36:60:36 | 2 |
| tst.rb:60:14:60:45 | call to [] | baz | tst.rb:60:44:60:44 | 3 |
| tst.rb:60:14:60:45 | call to [] | foo | tst.rb:60:24:60:24 | 1 |
arrayLiteralNode
| tst.rb:59:15:59:21 | call to [] |
arrayLiteralElement
| tst.rb:59:15:59:21 | call to [] | tst.rb:59:16:59:16 | 1 |
| tst.rb:59:15:59:21 | call to [] | tst.rb:59:18:59:18 | 2 |
| tst.rb:59:15:59:21 | call to [] | tst.rb:59:20:59:20 | 3 |

View File

@@ -0,0 +1,73 @@
import ruby
query DataFlow::Node getAnAncestorExpr(DataFlow::ModuleNode mod) {
result = mod.getAnAncestorExpr()
}
query DataFlow::ModuleNode getAnAncestor(DataFlow::ModuleNode mod) { result = mod.getAnAncestor() }
query DataFlow::Node getModuleLevelSelf(DataFlow::ModuleNode mod) {
result = mod.getModuleLevelSelf()
}
query DataFlow::Node getAnImmediateReference(DataFlow::ModuleNode mod) {
result = mod.getAnImmediateReference()
}
query DataFlow::MethodNode getOwnInstanceMethod(DataFlow::ModuleNode mod, string name) {
result = mod.getOwnInstanceMethod(name)
}
query DataFlow::MethodNode getInstanceMethod(DataFlow::ModuleNode mod, string name) {
result = mod.getInstanceMethod(name)
}
query DataFlow::Node getAnOwnInstanceSelf(DataFlow::ModuleNode mod) {
result = mod.getAnOwnInstanceSelf()
}
query DataFlow::Node getAnInstanceSelf(DataFlow::ModuleNode mod) {
result = mod.getAnInstanceSelf()
}
query DataFlow::Node getOwnSingletonMethod(DataFlow::ModuleNode mod, string name) {
result = mod.getOwnSingletonMethod(name)
}
query DataFlow::Node getAnOwnInstanceVariableRead(DataFlow::ModuleNode mod, string name) {
result = mod.getAnOwnInstanceVariableRead(name)
}
query DataFlow::Node getAnOwnInstanceVariableWriteValue(DataFlow::ModuleNode mod, string name) {
result = mod.getAnOwnInstanceVariableWriteValue(name)
}
query DataFlow::ModuleNode getParentModule(DataFlow::ModuleNode mod) {
result = mod.getParentModule()
}
query DataFlow::ModuleNode getNestedModule(DataFlow::ModuleNode mod, string name) {
result = mod.getNestedModule(name)
}
query DataFlow::Node getTopLevelConst(string name) { result = DataFlow::getConstant(name) }
query DataFlow::Node getConstant(DataFlow::ConstRef base, string name) {
result = base.getConstant(name)
}
query DataFlow::ModuleNode getXYClasses() {
result = DataFlow::getConstant("X").getConstant("Y").getADescendentModule()
}
query DataFlow::HashLiteralNode hashLiteralNode() { any() }
query DataFlow::Node hashLiteralKey(DataFlow::HashLiteralNode node, string key) {
result = node.getElementFromKey(Ast::ConstantValue::fromStringlikeValue(key))
}
query DataFlow::ArrayLiteralNode arrayLiteralNode() { any() }
query DataFlow::Node arrayLiteralElement(DataFlow::ArrayLiteralNode node) {
result = node.getAnElement()
}

View File

@@ -0,0 +1,62 @@
module C1
def c1
@field = 1
@field
end
end
class C2 < C1
def c2
end
end
module Mixin
def m1
end
def self.m1s
end
end
module Mixin2
def m2
end
def self.m2s
end
end
class C3 < C2
include Mixin
prepend Mixin2
class << self
def c3_self1
end
end
end
def C3.c3_self2
end
module N1
class XY1 < X::Y
end
module N2
class XY2 < X::Y
end
end
end
module N2
include X
end
module N2
class XY3 < Y
end
end
class Nodes
def m1
array=[1,2,3]
hash={'foo' => 1, 'bar' => 2, baz: 3}
end
end

View File

@@ -26,7 +26,7 @@
| local_dataflow.rb:9:9:9:15 | call to [] | local_dataflow.rb:9:1:9:15 | ... = ... |
| local_dataflow.rb:9:9:9:15 | call to [] | local_dataflow.rb:9:1:9:15 | ... = ... |
| local_dataflow.rb:10:5:13:3 | ... = ... | local_dataflow.rb:12:5:12:5 | x |
| local_dataflow.rb:10:5:13:3 | <captured> | local_dataflow.rb:11:1:11:2 | self |
| local_dataflow.rb:10:5:13:3 | <captured> self | local_dataflow.rb:11:1:11:2 | self |
| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | ... = ... |
| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | ... = ... |
| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | __synth__0__1 |
@@ -65,7 +65,7 @@
| local_dataflow.rb:45:10:45:10 | 6 | local_dataflow.rb:45:3:45:10 | return |
| local_dataflow.rb:49:1:53:3 | [post] self | local_dataflow.rb:55:1:55:14 | self |
| local_dataflow.rb:49:1:53:3 | self | local_dataflow.rb:55:1:55:14 | self |
| local_dataflow.rb:49:3:53:3 | <captured> | local_dataflow.rb:50:18:50:18 | x |
| local_dataflow.rb:49:3:53:3 | <captured> x | local_dataflow.rb:50:18:50:18 | x |
| local_dataflow.rb:50:8:50:13 | "next" | local_dataflow.rb:50:3:50:13 | next |
| local_dataflow.rb:50:18:50:18 | [post] x | local_dataflow.rb:51:20:51:20 | x |
| local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:51:20:51:20 | x |
@@ -264,7 +264,7 @@
| local_dataflow.rb:118:3:118:11 | [post] self | local_dataflow.rb:119:3:119:31 | self |
| local_dataflow.rb:118:3:118:11 | call to source | local_dataflow.rb:118:3:118:31 | call to tap |
| local_dataflow.rb:118:3:118:11 | self | local_dataflow.rb:119:3:119:31 | self |
| local_dataflow.rb:118:17:118:31 | <captured> | local_dataflow.rb:118:23:118:29 | self |
| local_dataflow.rb:118:17:118:31 | <captured> self | local_dataflow.rb:118:23:118:29 | self |
| local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:20:118:20 | x |
| local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:28:118:28 | x |
| local_dataflow.rb:119:3:119:31 | [post] self | local_dataflow.rb:119:8:119:16 | self |
@@ -278,4 +278,4 @@
| local_dataflow.rb:123:8:123:16 | call to source | local_dataflow.rb:123:8:123:20 | call to dup |
| local_dataflow.rb:123:8:123:20 | call to dup | local_dataflow.rb:123:8:123:45 | call to tap |
| local_dataflow.rb:123:8:123:45 | call to tap | local_dataflow.rb:123:8:123:49 | call to dup |
| local_dataflow.rb:123:26:123:45 | <captured> | local_dataflow.rb:123:32:123:43 | self |
| local_dataflow.rb:123:26:123:45 | <captured> self | local_dataflow.rb:123:32:123:43 | self |

View File

@@ -79,7 +79,7 @@
| local_dataflow.rb:9:9:9:15 | call to [] | local_dataflow.rb:9:1:9:15 | ... = ... |
| local_dataflow.rb:9:9:9:15 | call to [] | local_dataflow.rb:9:1:9:15 | ... = ... |
| local_dataflow.rb:10:5:13:3 | ... = ... | local_dataflow.rb:12:5:12:5 | x |
| local_dataflow.rb:10:5:13:3 | <captured> | local_dataflow.rb:11:1:11:2 | self |
| local_dataflow.rb:10:5:13:3 | <captured> self | local_dataflow.rb:11:1:11:2 | self |
| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | ... = ... |
| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | ... = ... |
| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | __synth__0__1 |
@@ -124,7 +124,7 @@
| local_dataflow.rb:45:10:45:10 | 6 | local_dataflow.rb:45:3:45:10 | return |
| local_dataflow.rb:49:1:53:3 | [post] self | local_dataflow.rb:55:1:55:14 | self |
| local_dataflow.rb:49:1:53:3 | self | local_dataflow.rb:55:1:55:14 | self |
| local_dataflow.rb:49:3:53:3 | <captured> | local_dataflow.rb:50:18:50:18 | x |
| local_dataflow.rb:49:3:53:3 | <captured> x | local_dataflow.rb:50:18:50:18 | x |
| local_dataflow.rb:50:8:50:13 | "next" | local_dataflow.rb:50:3:50:13 | next |
| local_dataflow.rb:50:18:50:18 | [post] x | local_dataflow.rb:51:20:51:20 | x |
| local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:50:18:50:22 | ... < ... |
@@ -339,7 +339,7 @@
| local_dataflow.rb:118:3:118:11 | [post] self | local_dataflow.rb:119:3:119:31 | self |
| local_dataflow.rb:118:3:118:11 | call to source | local_dataflow.rb:118:3:118:31 | call to tap |
| local_dataflow.rb:118:3:118:11 | self | local_dataflow.rb:119:3:119:31 | self |
| local_dataflow.rb:118:17:118:31 | <captured> | local_dataflow.rb:118:23:118:29 | self |
| local_dataflow.rb:118:17:118:31 | <captured> self | local_dataflow.rb:118:23:118:29 | self |
| local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:20:118:20 | x |
| local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:28:118:28 | x |
| local_dataflow.rb:119:3:119:31 | [post] self | local_dataflow.rb:119:8:119:16 | self |
@@ -353,4 +353,4 @@
| local_dataflow.rb:123:8:123:16 | call to source | local_dataflow.rb:123:8:123:20 | call to dup |
| local_dataflow.rb:123:8:123:20 | call to dup | local_dataflow.rb:123:8:123:45 | call to tap |
| local_dataflow.rb:123:8:123:45 | call to tap | local_dataflow.rb:123:8:123:49 | call to dup |
| local_dataflow.rb:123:26:123:45 | <captured> | local_dataflow.rb:123:32:123:43 | self |
| local_dataflow.rb:123:26:123:45 | <captured> self | local_dataflow.rb:123:32:123:43 | self |

View File

@@ -112,7 +112,7 @@ private class TypeFromCodeQL extends ModelInput::TypeModel {
override DataFlow::Node getASource(string package, string type) {
package = "test" and
type = "FooOrBar" and
result.asExpr().getExpr().getConstantValue().getString() = "magic_string"
result.getConstantValue().getString() = "magic_string"
}
override API::Node getAnApiNode(string package, string type) {

View File

@@ -1,4 +1,5 @@
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:10:3 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:18:1:21:3 | self (positional) |
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:18:1:21:3 | self in positional |
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:25:1:28:3 | self (keyword) |
@@ -18,13 +19,19 @@ track
| 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 |
@@ -189,20 +196,33 @@ track
| 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 |
@@ -337,6 +357,7 @@ track
| 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) |
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type_tracker.rb:1:1:10:3 | self (type_tracker.rb) |
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type_tracker.rb:18:1:21:3 | self (positional) |
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type_tracker.rb:18:1:21:3 | self in positional |
@@ -370,19 +391,24 @@ trackEnd
| 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 |
@@ -565,6 +591,7 @@ trackEnd
| 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 |

View File

@@ -22,7 +22,7 @@ query predicate trackEnd(LocalSourceNode src, DataFlow::Node dst) {
predicate backtrack(LocalSourceNode sink, TypeBackTracker t, LocalSourceNode src) {
t.start() and
sink = src
sink.getALocalSource() = src
or
exists(TypeBackTracker t2, LocalSourceNode mid |
backtrack(sink, t2, mid) and

View File

@@ -1,17 +1,18 @@
actionControllerControllerClasses
| action_controller/input_access.rb:1:1:50:3 | UsersController |
| action_controller/params_flow.rb:1:1:151:3 | MyController |
| action_controller/params_flow.rb:1:1:153:3 | MyController |
| action_controller/params_flow.rb:161:1:169:3 | Subclass |
| active_record/ActiveRecord.rb:23:1:39:3 | FooController |
| active_record/ActiveRecord.rb:41:1:64:3 | BarController |
| active_record/ActiveRecord.rb:66:1:98:3 | BazController |
| active_record/ActiveRecord.rb:100:1:108:3 | AnnotatedController |
| active_storage/active_storage.rb:39:1:45:3 | PostsController |
| active_storage/active_storage.rb:39:1:45:3 | PostsController2 |
| app/controllers/comments_controller.rb:1:1:40:3 | CommentsController |
| app/controllers/foo/bars_controller.rb:3:1:46:3 | BarsController |
| app/controllers/photos_controller.rb:1:1:4:3 | PhotosController |
| app/controllers/posts_controller.rb:1:1:10:3 | PostsController |
| app/controllers/tags_controller.rb:1:1:2:3 | TagsController |
| app/controllers/users/notifications_controller.rb:2:3:5:5 | NotificationsController |
| app/controllers/users/notifications_controller.rb:2:3:5:5 | Users::NotificationsController |
actionControllerActionMethods
| action_controller/input_access.rb:2:3:49:5 | index |
| action_controller/params_flow.rb:2:3:4:5 | m1 |
@@ -47,6 +48,8 @@ actionControllerActionMethods
| action_controller/params_flow.rb:125:3:132:5 | m30 |
| action_controller/params_flow.rb:134:3:141:5 | m31 |
| action_controller/params_flow.rb:143:3:150:5 | m32 |
| action_controller/params_flow.rb:156:3:158:5 | m33 |
| action_controller/params_flow.rb:162:3:164:5 | m34 |
| active_record/ActiveRecord.rb:27:3:38:5 | some_request_handler |
| active_record/ActiveRecord.rb:42:3:47:5 | some_other_request_handler |
| active_record/ActiveRecord.rb:49:3:63:5 | safe_paths |
@@ -117,6 +120,9 @@ paramsCalls
| action_controller/params_flow.rb:144:10:144:15 | call to params |
| action_controller/params_flow.rb:145:32:145:37 | call to params |
| action_controller/params_flow.rb:148:22:148:27 | call to params |
| action_controller/params_flow.rb:157:10:157:15 | call to params |
| action_controller/params_flow.rb:163:10:163:15 | call to params |
| action_controller/params_flow.rb:167:10:167:15 | call to params |
| action_mailer/mailer.rb:3:10:3:15 | call to params |
| active_record/ActiveRecord.rb:28:30:28:35 | call to params |
| active_record/ActiveRecord.rb:29:29:29:34 | call to params |
@@ -192,6 +198,9 @@ paramsSources
| action_controller/params_flow.rb:144:10:144:15 | call to params |
| action_controller/params_flow.rb:145:32:145:37 | call to params |
| action_controller/params_flow.rb:148:22:148:27 | call to params |
| action_controller/params_flow.rb:157:10:157:15 | call to params |
| action_controller/params_flow.rb:163:10:163:15 | call to params |
| action_controller/params_flow.rb:167:10:167:15 | call to params |
| action_mailer/mailer.rb:3:10:3:15 | call to params |
| active_record/ActiveRecord.rb:28:30:28:35 | call to params |
| active_record/ActiveRecord.rb:29:29:29:34 | call to params |
@@ -306,6 +315,9 @@ httpInputAccesses
| action_controller/params_flow.rb:144:10:144:15 | call to params | ActionController::Metal#params |
| action_controller/params_flow.rb:145:32:145:37 | call to params | ActionController::Metal#params |
| action_controller/params_flow.rb:148:22:148:27 | call to params | ActionController::Metal#params |
| action_controller/params_flow.rb:157:10:157:15 | call to params | ActionController::Metal#params |
| action_controller/params_flow.rb:163:10:163:15 | call to params | ActionController::Metal#params |
| action_controller/params_flow.rb:167:10:167:15 | call to params | ActionController::Metal#params |
| action_mailer/mailer.rb:3:10:3:15 | call to params | ActionController::Metal#params |
| active_record/ActiveRecord.rb:28:30:28:35 | call to params | ActionController::Metal#params |
| active_record/ActiveRecord.rb:29:29:29:34 | call to params | ActionController::Metal#params |

View File

@@ -5,7 +5,7 @@ private import codeql.ruby.frameworks.ActionView
private import codeql.ruby.Concepts
private import codeql.ruby.DataFlow
query predicate actionControllerControllerClasses(ActionControllerControllerClass cls) { any() }
query predicate actionControllerControllerClasses(ActionControllerClass cls) { any() }
query predicate actionControllerActionMethods(ActionControllerActionMethod m) { any() }
@@ -25,11 +25,11 @@ query predicate redirectToCalls(RedirectToCall c) { any() }
query predicate actionControllerHelperMethods(ActionControllerHelperMethod m) { any() }
query predicate getAssociatedControllerClasses(ActionControllerControllerClass cls, ErbFile f) {
query predicate getAssociatedControllerClasses(ActionControllerClass cls, ErbFile f) {
cls = getAssociatedControllerClass(f)
}
query predicate controllerTemplateFiles(ActionControllerControllerClass cls, ErbFile templateFile) {
query predicate controllerTemplateFiles(ActionControllerClass cls, ErbFile templateFile) {
controllerTemplateFile(cls, templateFile)
}

View File

@@ -44,6 +44,9 @@ edges
| params_flow.rb:145:32:145:37 | call to params : | params_flow.rb:145:10:145:38 | call to with_defaults! |
| params_flow.rb:148:5:148:5 | [post] p : | params_flow.rb:149:10:149:10 | p |
| params_flow.rb:148:22:148:27 | call to params : | params_flow.rb:148:5:148:5 | [post] p : |
| params_flow.rb:157:10:157:15 | call to params : | params_flow.rb:157:10:157:19 | ...[...] |
| params_flow.rb:163:10:163:15 | call to params : | params_flow.rb:163:10:163:19 | ...[...] |
| params_flow.rb:167:10:167:15 | call to params : | params_flow.rb:167:10:167:19 | ...[...] |
nodes
| params_flow.rb:3:10:3:15 | call to params : | semmle.label | call to params : |
| params_flow.rb:3:10:3:19 | ...[...] | semmle.label | ...[...] |
@@ -130,6 +133,12 @@ nodes
| params_flow.rb:148:5:148:5 | [post] p : | semmle.label | [post] p : |
| params_flow.rb:148:22:148:27 | call to params : | semmle.label | call to params : |
| params_flow.rb:149:10:149:10 | p | semmle.label | p |
| params_flow.rb:157:10:157:15 | call to params : | semmle.label | call to params : |
| params_flow.rb:157:10:157:19 | ...[...] | semmle.label | ...[...] |
| params_flow.rb:163:10:163:15 | call to params : | semmle.label | call to params : |
| params_flow.rb:163:10:163:19 | ...[...] | semmle.label | ...[...] |
| params_flow.rb:167:10:167:15 | call to params : | semmle.label | call to params : |
| params_flow.rb:167:10:167:19 | ...[...] | semmle.label | ...[...] |
subpaths
#select
| params_flow.rb:3:10:3:19 | ...[...] | params_flow.rb:3:10:3:15 | call to params : | params_flow.rb:3:10:3:19 | ...[...] | $@ | params_flow.rb:3:10:3:15 | call to params : | call to params : |
@@ -173,3 +182,6 @@ subpaths
| params_flow.rb:144:10:144:44 | call to with_defaults! | params_flow.rb:144:10:144:15 | call to params : | params_flow.rb:144:10:144:44 | call to with_defaults! | $@ | params_flow.rb:144:10:144:15 | call to params : | call to params : |
| params_flow.rb:145:10:145:38 | call to with_defaults! | params_flow.rb:145:32:145:37 | call to params : | params_flow.rb:145:10:145:38 | call to with_defaults! | $@ | params_flow.rb:145:32:145:37 | call to params : | call to params : |
| params_flow.rb:149:10:149:10 | p | params_flow.rb:148:22:148:27 | call to params : | params_flow.rb:149:10:149:10 | p | $@ | params_flow.rb:148:22:148:27 | call to params : | call to params : |
| params_flow.rb:157:10:157:19 | ...[...] | params_flow.rb:157:10:157:15 | call to params : | params_flow.rb:157:10:157:19 | ...[...] | $@ | params_flow.rb:157:10:157:15 | call to params : | call to params : |
| params_flow.rb:163:10:163:19 | ...[...] | params_flow.rb:163:10:163:15 | call to params : | params_flow.rb:163:10:163:19 | ...[...] | $@ | params_flow.rb:163:10:163:15 | call to params : | call to params : |
| params_flow.rb:167:10:167:19 | ...[...] | params_flow.rb:167:10:167:15 | call to params : | params_flow.rb:167:10:167:19 | ...[...] | $@ | params_flow.rb:167:10:167:15 | call to params : | call to params : |

View File

@@ -148,4 +148,22 @@ class MyController < ActionController::Base
p.with_defaults!(params)
sink p # $hasTaintFlow
end
include Mixin
end
module Mixin
def m33
sink params[:x] # $hasTaintFlow
end
end
class Subclass < MyController
def m34
sink params[:x] # $hasTaintFlow
end
rescue_from 'Foo::Bar' do |err|
sink params[:x] # $hasTaintFlow
end
end

View File

@@ -36,7 +36,7 @@ ActiveStorage.video_preview_arguments = custom_preview_args
ActiveStorage.variant_processor = custom_processor
class PostsController < ActionController::Base
class PostsController2 < ActionController::Base
def create
post = Post.new(params[:post])
post.images.attach(params[:images])

View File

@@ -4,6 +4,8 @@ definition
| class_variables.rb:9:1:16:3 | self (X) | class_variables.rb:9:1:16:3 | self |
| class_variables.rb:10:3:12:5 | self (b) | class_variables.rb:10:3:12:5 | self |
| class_variables.rb:13:3:15:5 | self (s) | class_variables.rb:13:3:15:5 | self |
| class_variables.rb:18:1:20:3 | self (Y) | class_variables.rb:18:1:20:3 | self |
| class_variables.rb:22:1:24:3 | self (M) | class_variables.rb:22:1:24:3 | self |
| class_variables.rb:26:1:29:3 | self (N) | class_variables.rb:26:1:29:3 | self |
| instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self |
| instance_variables.rb:1:1:44:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self |
@@ -13,9 +15,9 @@ definition
| instance_variables.rb:15:3:17:5 | self (m) | instance_variables.rb:15:3:17:5 | self |
| instance_variables.rb:20:1:25:3 | self (M) | instance_variables.rb:20:1:25:3 | self |
| instance_variables.rb:22:2:24:4 | self (n) | instance_variables.rb:22:2:24:4 | self |
| instance_variables.rb:27:6:29:1 | <captured> | instance_variables.rb:1:1:44:4 | self |
| instance_variables.rb:27:6:29:1 | <captured> self | instance_variables.rb:1:1:44:4 | self |
| instance_variables.rb:31:1:33:3 | self (bar) | instance_variables.rb:31:1:33:3 | self |
| instance_variables.rb:32:10:32:21 | <captured> | instance_variables.rb:31:1:33:3 | self |
| instance_variables.rb:32:10:32:21 | <captured> self | instance_variables.rb:31:1:33:3 | self |
| instance_variables.rb:35:1:44:4 | self (C) | instance_variables.rb:35:1:44:4 | self |
| instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self |
| instance_variables.rb:38:4:40:6 | self (y) | instance_variables.rb:38:4:40:6 | self |
@@ -32,8 +34,8 @@ definition
| nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a |
| nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a |
| nested_scopes.rb:17:15:17:19 | ... = ... | nested_scopes.rb:16:29:16:29 | a |
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:12:9:21:11 | self |
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:16:29:16:29 | a |
| nested_scopes.rb:18:23:18:36 | <captured> a | nested_scopes.rb:16:29:16:29 | a |
| nested_scopes.rb:18:23:18:36 | <captured> self | nested_scopes.rb:12:9:21:11 | self |
| nested_scopes.rb:22:9:24:11 | self (show_a2) | nested_scopes.rb:22:9:24:11 | self |
| nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a |
| nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self |
@@ -41,7 +43,7 @@ definition
| nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a |
| nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d |
| parameters.rb:1:1:1:1 | self (parameters.rb) | parameters.rb:1:1:62:1 | self |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self |
| parameters.rb:1:9:5:3 | <captured> self | parameters.rb:1:1:62:1 | self |
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x |
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y |
| parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self |
@@ -49,7 +51,7 @@ definition
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas |
| parameters.rb:15:1:19:3 | self (print_map) | parameters.rb:15:1:19:3 | self |
| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map |
| parameters.rb:16:12:18:5 | <captured> | parameters.rb:15:1:19:3 | self |
| parameters.rb:16:12:18:5 | <captured> self | parameters.rb:15:1:19:3 | self |
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key |
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value |
| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block |
@@ -76,8 +78,8 @@ definition
| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a |
| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b |
| parameters.rb:53:1:53:6 | ... = ... | parameters.rb:53:1:53:1 | x |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:53:1:53:1 | x |
| parameters.rb:54:9:57:3 | <captured> self | parameters.rb:1:1:62:1 | self |
| parameters.rb:54:9:57:3 | <captured> x | parameters.rb:53:1:53:1 | x |
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y |
| parameters.rb:54:19:54:23 | ... = ... | parameters.rb:53:1:53:1 | x |
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x |
@@ -86,11 +88,11 @@ definition
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b |
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c |
| scopes.rb:1:1:1:15 | self (scopes.rb) | scopes.rb:1:1:49:4 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self |
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self |
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a |
| scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a |
| scopes.rb:9:9:18:3 | <captured> a | scopes.rb:7:1:7:1 | a |
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self |
| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a |
| scopes.rb:13:4:13:4 | ... = ... | scopes.rb:7:1:7:1 | a |
| scopes.rb:13:7:13:7 | ... = ... | scopes.rb:13:7:13:7 | b |
@@ -98,9 +100,12 @@ definition
| scopes.rb:13:11:13:11 | ... = ... | scopes.rb:13:11:13:11 | c |
| scopes.rb:13:14:13:14 | ... = ... | scopes.rb:13:14:13:14 | d |
| scopes.rb:13:19:13:32 | ... = ... | scopes.rb:13:4:13:32 | __synth__0 |
| scopes.rb:26:1:26:12 | self (A) | scopes.rb:26:1:26:12 | self |
| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x |
| scopes.rb:28:1:30:3 | self (B) | scopes.rb:28:1:30:3 | self |
| scopes.rb:29:3:29:7 | ... = ... | scopes.rb:29:3:29:3 | x |
| scopes.rb:32:3:32:7 | ... = ... | scopes.rb:32:3:32:3 | x |
| scopes.rb:34:1:36:3 | self (C) | scopes.rb:34:1:36:3 | self |
| scopes.rb:35:3:35:7 | ... = ... | scopes.rb:35:3:35:3 | x |
| scopes.rb:41:1:49:3 | self (M) | scopes.rb:41:1:49:3 | self |
| scopes.rb:42:2:42:9 | ... = ... | scopes.rb:42:2:42:4 | var |
@@ -120,11 +125,11 @@ definition
| ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self |
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements |
| ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem |
| ssa.rb:26:3:28:5 | <captured> | ssa.rb:25:1:30:3 | self |
| ssa.rb:26:3:28:5 | <captured> self | ssa.rb:25:1:30:3 | self |
| ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 |
| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem |
| ssa.rb:32:1:36:3 | self (m3) | ssa.rb:32:1:36:3 | self |
| ssa.rb:33:16:35:5 | <captured> | ssa.rb:32:1:36:3 | self |
| ssa.rb:33:16:35:5 | <captured> self | ssa.rb:32:1:36:3 | self |
| ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x |
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self |
| ssa.rb:40:3:40:9 | ... = ... | ssa.rb:40:3:40:4 | m3 |
@@ -147,19 +152,19 @@ definition
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a |
| ssa.rb:65:3:65:15 | ... = ... | ssa.rb:65:3:65:10 | captured |
| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:64:1:72:3 | self |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured |
| ssa.rb:66:11:70:5 | <captured> captured | ssa.rb:65:3:65:10 | captured |
| ssa.rb:66:11:70:5 | <captured> self | ssa.rb:64:1:72:3 | self |
| ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a |
| ssa.rb:69:5:69:17 | ... = ... | ssa.rb:65:3:65:10 | captured |
| ssa.rb:74:1:79:3 | self (m10) | ssa.rb:74:1:79:3 | self |
| ssa.rb:75:3:75:14 | ... = ... | ssa.rb:75:3:75:10 | captured |
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:74:1:79:3 | self |
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:75:3:75:10 | captured |
| ssa.rb:76:7:78:5 | <captured> captured | ssa.rb:75:3:75:10 | captured |
| ssa.rb:76:7:78:5 | <captured> self | ssa.rb:74:1:79:3 | self |
| ssa.rb:81:1:88:3 | self (m11) | ssa.rb:81:1:88:3 | self |
| ssa.rb:82:3:82:14 | ... = ... | ssa.rb:82:3:82:10 | captured |
| ssa.rb:83:7:87:5 | <captured> | ssa.rb:81:1:88:3 | self |
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:81:1:88:3 | self |
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:82:3:82:10 | captured |
| ssa.rb:83:7:87:5 | <captured> self | ssa.rb:81:1:88:3 | self |
| ssa.rb:84:10:86:8 | <captured> captured | ssa.rb:82:3:82:10 | captured |
| ssa.rb:84:10:86:8 | <captured> self | ssa.rb:81:1:88:3 | self |
read
| class_variables.rb:1:1:1:3 | self (class_variables.rb) | class_variables.rb:1:1:29:4 | self | class_variables.rb:3:1:3:5 | self |
| class_variables.rb:5:1:7:3 | self (print) | class_variables.rb:5:1:7:3 | self | class_variables.rb:6:2:6:6 | self |
@@ -179,8 +184,8 @@ read
| instance_variables.rb:15:3:17:5 | self (m) | instance_variables.rb:15:3:17:5 | self | instance_variables.rb:16:5:16:6 | self |
| instance_variables.rb:20:1:25:3 | self (M) | instance_variables.rb:20:1:25:3 | self | instance_variables.rb:21:2:21:3 | self |
| instance_variables.rb:22:2:24:4 | self (n) | instance_variables.rb:22:2:24:4 | self | instance_variables.rb:23:4:23:5 | self |
| instance_variables.rb:27:6:29:1 | <captured> | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self |
| instance_variables.rb:32:10:32:21 | <captured> | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self |
| instance_variables.rb:27:6:29:1 | <captured> self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self |
| instance_variables.rb:32:10:32:21 | <captured> self | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self |
| instance_variables.rb:35:1:44:4 | self (C) | instance_variables.rb:35:1:44:4 | self | instance_variables.rb:36:3:36:4 | self |
| instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:41:4:41:4 | self |
| instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:42:4:42:7 | self |
@@ -202,8 +207,8 @@ read
| nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:15:11:15:11 | a |
| nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:16:13:16:13 | a |
| nested_scopes.rb:17:15:17:19 | ... = ... | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:15:18:15 | a |
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self |
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a |
| nested_scopes.rb:18:23:18:36 | <captured> a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a |
| nested_scopes.rb:18:23:18:36 | <captured> self | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self |
| nested_scopes.rb:22:9:24:11 | self (show_a2) | nested_scopes.rb:22:9:24:11 | self | nested_scopes.rb:23:11:23:16 | self |
| nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:23:16:23:16 | a |
| nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self | nested_scopes.rb:28:11:28:16 | self |
@@ -211,8 +216,8 @@ read
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:32:11:32:16 | self |
| nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:32:16:32:16 | a |
| nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:41:1:41:1 | d |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:4:4:4:9 | self |
| parameters.rb:1:9:5:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self |
| parameters.rb:1:9:5:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:4:4:4:9 | self |
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:3:9:3:9 | x |
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y |
| parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self | parameters.rb:9:5:9:33 | self |
@@ -222,7 +227,7 @@ read
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas |
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:11:14:11:19 | pizzas |
| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map |
| parameters.rb:16:12:18:5 | <captured> | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self |
| parameters.rb:16:12:18:5 | <captured> self | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self |
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key |
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value |
| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block |
@@ -246,8 +251,8 @@ read
| parameters.rb:49:1:51:3 | self (tuples) | parameters.rb:49:1:51:3 | self | parameters.rb:50:3:50:18 | self |
| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:50:11:50:11 | a |
| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:50:16:50:16 | b |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:56:4:56:9 | self |
| parameters.rb:54:9:57:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self |
| parameters.rb:54:9:57:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:56:4:56:9 | self |
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:56:9:56:9 | y |
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:55:9:55:9 | x |
| parameters.rb:59:1:61:3 | self (tuples_nested) | parameters.rb:59:1:61:3 | self | parameters.rb:60:3:60:23 | self |
@@ -255,19 +260,19 @@ read
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b |
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c |
| scopes.rb:1:1:1:15 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | scopes.rb:8:1:8:6 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:5:4:5:9 | self |
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self |
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self |
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:5:4:5:9 | self |
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
| scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:12:4:12:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:14:4:14:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:15:4:15:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:16:4:16:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:17:4:17:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a |
| scopes.rb:9:9:18:3 | <captured> a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a |
| scopes.rb:9:9:18:3 | <captured> a | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a |
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self |
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:12:4:12:9 | self |
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:14:4:14:9 | self |
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:15:4:15:9 | self |
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:16:4:16:9 | self |
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:17:4:17:9 | self |
| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a |
| scopes.rb:13:4:13:4 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a |
| scopes.rb:13:7:13:7 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b |
@@ -308,10 +313,10 @@ read
| ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:29:3:29:11 | self |
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements |
| ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem |
| ssa.rb:26:3:28:5 | <captured> | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self |
| ssa.rb:26:3:28:5 | <captured> self | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self |
| ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 |
| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem |
| ssa.rb:33:16:35:5 | <captured> | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self |
| ssa.rb:33:16:35:5 | <captured> self | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self |
| ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | ssa.rb:34:10:34:10 | x |
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:3:39:9 | self |
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:8:39:9 | self |
@@ -331,18 +336,18 @@ read
| ssa.rb:64:1:72:3 | self (m9) | ssa.rb:64:1:72:3 | self | ssa.rb:71:3:71:15 | self |
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a |
| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:64:1:72:3 | self | ssa.rb:68:5:68:17 | self |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured |
| ssa.rb:66:11:70:5 | <captured> captured | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured |
| ssa.rb:66:11:70:5 | <captured> captured | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured |
| ssa.rb:66:11:70:5 | <captured> self | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self |
| ssa.rb:66:11:70:5 | <captured> self | ssa.rb:64:1:72:3 | self | ssa.rb:68:5:68:17 | self |
| ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:67:10:67:10 | a |
| ssa.rb:74:1:79:3 | self (m10) | ssa.rb:74:1:79:3 | self | ssa.rb:76:3:78:5 | self |
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self |
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured |
| ssa.rb:76:7:78:5 | <captured> captured | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured |
| ssa.rb:76:7:78:5 | <captured> self | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self |
| ssa.rb:81:1:88:3 | self (m11) | ssa.rb:81:1:88:3 | self | ssa.rb:83:3:87:5 | self |
| ssa.rb:83:7:87:5 | <captured> | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self |
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self |
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
| ssa.rb:83:7:87:5 | <captured> self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self |
| ssa.rb:84:10:86:8 | <captured> captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
| ssa.rb:84:10:86:8 | <captured> self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self |
firstRead
| class_variables.rb:1:1:1:3 | self (class_variables.rb) | class_variables.rb:1:1:29:4 | self | class_variables.rb:3:1:3:5 | self |
| class_variables.rb:5:1:7:3 | self (print) | class_variables.rb:5:1:7:3 | self | class_variables.rb:6:2:6:6 | self |
@@ -358,8 +363,8 @@ firstRead
| instance_variables.rb:15:3:17:5 | self (m) | instance_variables.rb:15:3:17:5 | self | instance_variables.rb:16:5:16:6 | self |
| instance_variables.rb:20:1:25:3 | self (M) | instance_variables.rb:20:1:25:3 | self | instance_variables.rb:21:2:21:3 | self |
| instance_variables.rb:22:2:24:4 | self (n) | instance_variables.rb:22:2:24:4 | self | instance_variables.rb:23:4:23:5 | self |
| instance_variables.rb:27:6:29:1 | <captured> | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self |
| instance_variables.rb:32:10:32:21 | <captured> | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self |
| instance_variables.rb:27:6:29:1 | <captured> self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self |
| instance_variables.rb:32:10:32:21 | <captured> self | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self |
| instance_variables.rb:35:1:44:4 | self (C) | instance_variables.rb:35:1:44:4 | self | instance_variables.rb:36:3:36:4 | self |
| instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:41:4:41:4 | self |
| instance_variables.rb:38:4:40:6 | self (y) | instance_variables.rb:38:4:40:6 | self | instance_variables.rb:39:6:39:7 | self |
@@ -376,15 +381,15 @@ firstRead
| nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:14:16:14:16 | a |
| nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:16:13:16:13 | a |
| nested_scopes.rb:17:15:17:19 | ... = ... | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:15:18:15 | a |
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self |
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a |
| nested_scopes.rb:18:23:18:36 | <captured> a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a |
| nested_scopes.rb:18:23:18:36 | <captured> self | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self |
| nested_scopes.rb:22:9:24:11 | self (show_a2) | nested_scopes.rb:22:9:24:11 | self | nested_scopes.rb:23:11:23:16 | self |
| nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:23:16:23:16 | a |
| nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self | nested_scopes.rb:28:11:28:16 | self |
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:32:11:32:16 | self |
| nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:32:16:32:16 | a |
| nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:41:1:41:1 | d |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self |
| parameters.rb:1:9:5:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self |
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:3:9:3:9 | x |
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y |
| parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self | parameters.rb:9:5:9:33 | self |
@@ -393,7 +398,7 @@ firstRead
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:11:41:11:46 | client |
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas |
| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map |
| parameters.rb:16:12:18:5 | <captured> | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self |
| parameters.rb:16:12:18:5 | <captured> self | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self |
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key |
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value |
| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block |
@@ -416,7 +421,7 @@ firstRead
| parameters.rb:49:1:51:3 | self (tuples) | parameters.rb:49:1:51:3 | self | parameters.rb:50:3:50:18 | self |
| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:50:11:50:11 | a |
| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:50:16:50:16 | b |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self |
| parameters.rb:54:9:57:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self |
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:56:9:56:9 | y |
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:55:9:55:9 | x |
| parameters.rb:59:1:61:3 | self (tuples_nested) | parameters.rb:59:1:61:3 | self | parameters.rb:60:3:60:23 | self |
@@ -424,11 +429,11 @@ firstRead
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b |
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c |
| scopes.rb:1:1:1:15 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | scopes.rb:8:1:8:6 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self |
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self |
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
| scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a |
| scopes.rb:9:9:18:3 | <captured> a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a |
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self |
| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a |
| scopes.rb:13:4:13:4 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a |
| scopes.rb:13:7:13:7 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b |
@@ -451,10 +456,10 @@ firstRead
| ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:29:3:29:11 | self |
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements |
| ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem |
| ssa.rb:26:3:28:5 | <captured> | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self |
| ssa.rb:26:3:28:5 | <captured> self | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self |
| ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 |
| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem |
| ssa.rb:33:16:35:5 | <captured> | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self |
| ssa.rb:33:16:35:5 | <captured> self | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self |
| ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | ssa.rb:34:10:34:10 | x |
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:3:39:9 | self |
| ssa.rb:40:3:40:9 | ... = ... | ssa.rb:40:3:40:4 | m3 | ssa.rb:41:8:41:9 | m3 |
@@ -472,16 +477,16 @@ firstRead
| ssa.rb:64:1:72:3 | self (m9) | ssa.rb:64:1:72:3 | self | ssa.rb:71:3:71:15 | self |
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a |
| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured |
| ssa.rb:66:11:70:5 | <captured> captured | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured |
| ssa.rb:66:11:70:5 | <captured> self | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self |
| ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:67:10:67:10 | a |
| ssa.rb:74:1:79:3 | self (m10) | ssa.rb:74:1:79:3 | self | ssa.rb:76:3:78:5 | self |
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self |
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured |
| ssa.rb:76:7:78:5 | <captured> captured | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured |
| ssa.rb:76:7:78:5 | <captured> self | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self |
| ssa.rb:81:1:88:3 | self (m11) | ssa.rb:81:1:88:3 | self | ssa.rb:83:3:87:5 | self |
| ssa.rb:83:7:87:5 | <captured> | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self |
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self |
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
| ssa.rb:83:7:87:5 | <captured> self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self |
| ssa.rb:84:10:86:8 | <captured> captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
| ssa.rb:84:10:86:8 | <captured> self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self |
lastRead
| class_variables.rb:1:1:1:3 | self (class_variables.rb) | class_variables.rb:1:1:29:4 | self | class_variables.rb:3:1:3:5 | self |
| class_variables.rb:5:1:7:3 | self (print) | class_variables.rb:5:1:7:3 | self | class_variables.rb:6:2:6:6 | self |
@@ -498,8 +503,8 @@ lastRead
| instance_variables.rb:15:3:17:5 | self (m) | instance_variables.rb:15:3:17:5 | self | instance_variables.rb:16:5:16:6 | self |
| instance_variables.rb:20:1:25:3 | self (M) | instance_variables.rb:20:1:25:3 | self | instance_variables.rb:21:2:21:3 | self |
| instance_variables.rb:22:2:24:4 | self (n) | instance_variables.rb:22:2:24:4 | self | instance_variables.rb:23:4:23:5 | self |
| instance_variables.rb:27:6:29:1 | <captured> | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self |
| instance_variables.rb:32:10:32:21 | <captured> | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self |
| instance_variables.rb:27:6:29:1 | <captured> self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self |
| instance_variables.rb:32:10:32:21 | <captured> self | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self |
| instance_variables.rb:35:1:44:4 | self (C) | instance_variables.rb:35:1:44:4 | self | instance_variables.rb:36:3:36:4 | self |
| instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:42:6:42:7 | self |
| instance_variables.rb:38:4:40:6 | self (y) | instance_variables.rb:38:4:40:6 | self | instance_variables.rb:39:6:39:7 | self |
@@ -516,15 +521,15 @@ lastRead
| nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:15:11:15:11 | a |
| nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:16:13:16:13 | a |
| nested_scopes.rb:17:15:17:19 | ... = ... | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:15:18:15 | a |
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self |
| nested_scopes.rb:18:23:18:36 | <captured> | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a |
| nested_scopes.rb:18:23:18:36 | <captured> a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a |
| nested_scopes.rb:18:23:18:36 | <captured> self | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self |
| nested_scopes.rb:22:9:24:11 | self (show_a2) | nested_scopes.rb:22:9:24:11 | self | nested_scopes.rb:23:11:23:16 | self |
| nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:23:16:23:16 | a |
| nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self | nested_scopes.rb:28:16:28:16 | self |
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:32:11:32:16 | self |
| nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:32:16:32:16 | a |
| nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:41:1:41:1 | d |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:4:4:4:9 | self |
| parameters.rb:1:9:5:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:4:4:4:9 | self |
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:3:9:3:9 | x |
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y |
| parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self | parameters.rb:9:5:9:33 | self |
@@ -534,7 +539,7 @@ lastRead
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas |
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:11:14:11:19 | pizzas |
| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map |
| parameters.rb:16:12:18:5 | <captured> | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self |
| parameters.rb:16:12:18:5 | <captured> self | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self |
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key |
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value |
| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block |
@@ -556,7 +561,7 @@ lastRead
| parameters.rb:49:1:51:3 | self (tuples) | parameters.rb:49:1:51:3 | self | parameters.rb:50:3:50:18 | self |
| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:50:11:50:11 | a |
| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:50:16:50:16 | b |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:56:4:56:9 | self |
| parameters.rb:54:9:57:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:56:4:56:9 | self |
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:56:9:56:9 | y |
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:55:9:55:9 | x |
| parameters.rb:59:1:61:3 | self (tuples_nested) | parameters.rb:59:1:61:3 | self | parameters.rb:60:3:60:23 | self |
@@ -564,11 +569,11 @@ lastRead
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b |
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c |
| scopes.rb:1:1:1:15 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | scopes.rb:8:1:8:6 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:5:4:5:9 | self |
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:5:4:5:9 | self |
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
| scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:17:4:17:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a |
| scopes.rb:9:9:18:3 | <captured> a | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a |
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:17:4:17:9 | self |
| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a |
| scopes.rb:13:4:13:4 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a |
| scopes.rb:13:7:13:7 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b |
@@ -592,10 +597,10 @@ lastRead
| ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:29:3:29:11 | self |
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements |
| ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem |
| ssa.rb:26:3:28:5 | <captured> | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self |
| ssa.rb:26:3:28:5 | <captured> self | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self |
| ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 |
| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem |
| ssa.rb:33:16:35:5 | <captured> | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self |
| ssa.rb:33:16:35:5 | <captured> self | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self |
| ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | ssa.rb:34:10:34:10 | x |
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:41:3:41:13 | self |
| ssa.rb:40:3:40:9 | ... = ... | ssa.rb:40:3:40:4 | m3 | ssa.rb:41:8:41:9 | m3 |
@@ -613,16 +618,16 @@ lastRead
| ssa.rb:64:1:72:3 | self (m9) | ssa.rb:64:1:72:3 | self | ssa.rb:71:3:71:15 | self |
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a |
| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:64:1:72:3 | self | ssa.rb:68:5:68:17 | self |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured |
| ssa.rb:66:11:70:5 | <captured> captured | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured |
| ssa.rb:66:11:70:5 | <captured> self | ssa.rb:64:1:72:3 | self | ssa.rb:68:5:68:17 | self |
| ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:67:10:67:10 | a |
| ssa.rb:74:1:79:3 | self (m10) | ssa.rb:74:1:79:3 | self | ssa.rb:76:3:78:5 | self |
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self |
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured |
| ssa.rb:76:7:78:5 | <captured> captured | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured |
| ssa.rb:76:7:78:5 | <captured> self | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self |
| ssa.rb:81:1:88:3 | self (m11) | ssa.rb:81:1:88:3 | self | ssa.rb:83:3:87:5 | self |
| ssa.rb:83:7:87:5 | <captured> | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self |
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self |
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
| ssa.rb:83:7:87:5 | <captured> self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self |
| ssa.rb:84:10:86:8 | <captured> captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
| ssa.rb:84:10:86:8 | <captured> self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self |
adjacentReads
| class_variables.rb:26:1:29:3 | self (N) | class_variables.rb:26:1:29:3 | self | class_variables.rb:27:3:27:11 | self | class_variables.rb:28:3:28:7 | self |
| instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:1:1:1:4 | self | instance_variables.rb:11:1:11:9 | self |
@@ -636,19 +641,19 @@ adjacentReads
| nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:14:16:14:16 | a | nested_scopes.rb:15:11:15:11 | a |
| nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self | nested_scopes.rb:28:11:28:16 | self | nested_scopes.rb:28:16:28:16 | self |
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:30:16:30:19 | self | nested_scopes.rb:32:11:32:16 | self |
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self | parameters.rb:4:4:4:9 | self |
| parameters.rb:1:9:5:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self | parameters.rb:4:4:4:9 | self |
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | parameters.rb:11:14:11:19 | pizzas |
| parameters.rb:25:1:28:3 | self (opt_param) | parameters.rb:25:1:28:3 | self | parameters.rb:26:3:26:11 | self | parameters.rb:27:3:27:11 | self |
| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:40:25:43 | name | parameters.rb:26:8:26:11 | name |
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self | parameters.rb:56:4:56:9 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self | scopes.rb:3:9:3:9 | self |
| scopes.rb:2:9:6:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self | scopes.rb:5:4:5:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self | scopes.rb:12:4:12:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:12:4:12:9 | self | scopes.rb:14:4:14:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:14:4:14:9 | self | scopes.rb:15:4:15:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:15:4:15:9 | self | scopes.rb:16:4:16:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:1:1:49:4 | self | scopes.rb:16:4:16:9 | self | scopes.rb:17:4:17:9 | self |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | scopes.rb:11:4:11:4 | a |
| parameters.rb:54:9:57:3 | <captured> self | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self | parameters.rb:56:4:56:9 | self |
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self | scopes.rb:3:9:3:9 | self |
| scopes.rb:2:9:6:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self | scopes.rb:5:4:5:9 | self |
| scopes.rb:9:9:18:3 | <captured> a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | scopes.rb:11:4:11:4 | a |
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self | scopes.rb:12:4:12:9 | self |
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:12:4:12:9 | self | scopes.rb:14:4:14:9 | self |
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:14:4:14:9 | self | scopes.rb:15:4:15:9 | self |
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:15:4:15:9 | self | scopes.rb:16:4:16:9 | self |
| scopes.rb:9:9:18:3 | <captured> self | scopes.rb:1:1:49:4 | self | scopes.rb:16:4:16:9 | self | scopes.rb:17:4:17:9 | self |
| scopes.rb:13:10:13:15 | ... = ... | scopes.rb:13:10:13:15 | __synth__0__1 | scopes.rb:13:11:13:11 | __synth__0__1 | scopes.rb:13:14:13:14 | __synth__0__1 |
| scopes.rb:13:19:13:32 | ... = ... | scopes.rb:13:4:13:32 | __synth__0 | scopes.rb:13:4:13:4 | __synth__0 | scopes.rb:13:7:13:7 | __synth__0 |
| scopes.rb:13:19:13:32 | ... = ... | scopes.rb:13:4:13:32 | __synth__0 | scopes.rb:13:7:13:7 | __synth__0 | scopes.rb:13:10:13:15 | __synth__0 |
@@ -671,14 +676,14 @@ adjacentReads
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:20:10:20:10 | x | ssa.rb:21:5:21:5 | x |
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:3:39:9 | self | ssa.rb:39:8:39:9 | self |
| ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:8:39:9 | self | ssa.rb:41:3:41:13 | self |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self | ssa.rb:68:5:68:17 | self |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | ssa.rb:69:5:69:12 | captured |
| ssa.rb:66:11:70:5 | <captured> captured | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | ssa.rb:69:5:69:12 | captured |
| ssa.rb:66:11:70:5 | <captured> self | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self | ssa.rb:68:5:68:17 | self |
phi
| parameters.rb:37:3:37:18 | phi | parameters.rb:35:16:35:16 | b | parameters.rb:35:1:38:3 | <uninitialized> |
| parameters.rb:37:3:37:18 | phi | parameters.rb:35:16:35:16 | b | parameters.rb:35:16:35:20 | ... = ... |
| parameters.rb:42:3:42:18 | phi | parameters.rb:40:15:40:15 | e | parameters.rb:40:1:43:3 | <uninitialized> |
| parameters.rb:42:3:42:18 | phi | parameters.rb:40:15:40:15 | e | parameters.rb:40:15:40:19 | ... = ... |
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:54:9:57:3 | <captured> |
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:54:9:57:3 | <captured> x |
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:54:19:54:23 | ... = ... |
| ssa.rb:5:3:13:5 | phi | ssa.rb:2:3:2:3 | i | ssa.rb:6:5:6:9 | ... = ... |
| ssa.rb:5:3:13:5 | phi | ssa.rb:2:3:2:3 | i | ssa.rb:10:5:10:9 | ... = ... |