mirror of
https://github.com/github/codeql.git
synced 2026-04-24 08:15:14 +02:00
Merge pull request #11024 from asgerf/rb/data-flow-layer-capture2
Ruby: expand DataFlow API
This commit is contained in:
@@ -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() }
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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"]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 : |
|
||||
|
||||
@@ -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 |
|
||||
@@ -0,0 +1 @@
|
||||
import TestUtilities.InlineTypeTrackingFlowTest
|
||||
@@ -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)
|
||||
234
ruby/ql/test/library-tests/dataflow/helpers/dataflow.expected
Normal file
234
ruby/ql/test/library-tests/dataflow/helpers/dataflow.expected
Normal 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 |
|
||||
73
ruby/ql/test/library-tests/dataflow/helpers/dataflow.ql
Normal file
73
ruby/ql/test/library-tests/dataflow/helpers/dataflow.ql
Normal 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()
|
||||
}
|
||||
62
ruby/ql/test/library-tests/dataflow/helpers/tst.rb
Normal file
62
ruby/ql/test/library-tests/dataflow/helpers/tst.rb
Normal 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
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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 : |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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 | ... = ... |
|
||||
|
||||
Reference in New Issue
Block a user