mirror of
https://github.com/github/codeql.git
synced 2026-05-02 04:05:14 +02:00
Merge pull request #7084 from hvitved/ruby/self-flow
Ruby: Cleanup flow through `self`
This commit is contained in:
@@ -24,21 +24,8 @@ class Expr extends Stmt, TExpr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to the current object. For example:
|
||||
* - `self == other`
|
||||
* - `self.method_name`
|
||||
* - `def self.method_name ... end`
|
||||
*
|
||||
* This also includes implicit references to the current object in method
|
||||
* calls. For example, the method call `foo(123)` has an implicit `self`
|
||||
* receiver, and is equivalent to the explicit `self.foo(123)`.
|
||||
*/
|
||||
class Self extends Expr, TSelf {
|
||||
final override string getAPrimaryQlClass() { result = "Self" }
|
||||
|
||||
final override string toString() { result = "self" }
|
||||
}
|
||||
/** DEPRECATED: Use `SelfVariableAccess` instead. */
|
||||
deprecated class Self = SelfVariableAccess;
|
||||
|
||||
/**
|
||||
* A sequence of expressions in the right-hand side of an assignment or
|
||||
|
||||
@@ -201,7 +201,16 @@ class ClassVariableWriteAccess extends ClassVariableAccess, VariableWriteAccess
|
||||
/** An access to a class variable where the value is read. */
|
||||
class ClassVariableReadAccess extends ClassVariableAccess, VariableReadAccess { }
|
||||
|
||||
/** An access to the `self` variable */
|
||||
/**
|
||||
* An access to the `self` variable. For example:
|
||||
* - `self == other`
|
||||
* - `self.method_name`
|
||||
* - `def self.method_name ... end`
|
||||
*
|
||||
* This also includes implicit references to the current object in method
|
||||
* calls. For example, the method call `foo(123)` has an implicit `self`
|
||||
* receiver, and is equivalent to the explicit `self.foo(123)`.
|
||||
*/
|
||||
class SelfVariableAccess extends LocalVariableAccess instanceof SelfVariableAccessImpl {
|
||||
final override string getAPrimaryQlClass() { result = "SelfVariableAccess" }
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ private module Cached {
|
||||
m = resolveConstantReadAccess(c.getReceiver())
|
||||
or
|
||||
m = enclosingModule(c).getModule() and
|
||||
c.getReceiver() instanceof Self
|
||||
c.getReceiver() instanceof SelfVariableAccess
|
||||
) and
|
||||
result = resolveConstantReadAccess(c.getAnArgument())
|
||||
}
|
||||
@@ -437,7 +437,7 @@ private module ResolveImpl {
|
||||
encl = enclosingModule(this) and
|
||||
result = [qualifiedModuleNameNonRec(encl, _, _), qualifiedModuleNameRec(encl, _, _)]
|
||||
|
|
||||
this.getReceiver() instanceof Self
|
||||
this.getReceiver() instanceof SelfVariableAccess
|
||||
or
|
||||
not exists(this.getReceiver())
|
||||
)
|
||||
|
||||
@@ -366,7 +366,23 @@ private module Cached {
|
||||
|
||||
cached
|
||||
predicate isCapturedAccess(LocalVariableAccess access) {
|
||||
access.getVariable().getDeclaringScope() != access.getCfgScope()
|
||||
exists(Scope scope1, Scope scope2 |
|
||||
scope1 = access.getVariable().getDeclaringScope() and
|
||||
scope2 = access.getCfgScope() and
|
||||
scope1 != scope2
|
||||
|
|
||||
if access instanceof SelfVariableAccess
|
||||
then
|
||||
// ```
|
||||
// class C
|
||||
// def self.m // not a captured access
|
||||
// end
|
||||
// end
|
||||
// ```
|
||||
not scope2 instanceof Toplevel or
|
||||
not access = any(SingletonMethod m).getObject()
|
||||
else any()
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -14,7 +14,7 @@ class EntryNode extends CfgNode, TEntryNode {
|
||||
|
||||
EntryNode() { this = TEntryNode(scope) }
|
||||
|
||||
final override EntryBasicBlock getBasicBlock() { result = CfgNode.super.getBasicBlock() }
|
||||
final override EntryBasicBlock getBasicBlock() { result = super.getBasicBlock() }
|
||||
|
||||
final override Location getLocation() { result = scope.getLocation() }
|
||||
|
||||
@@ -31,7 +31,7 @@ class AnnotatedExitNode extends CfgNode, TAnnotatedExitNode {
|
||||
/** Holds if this node represent a normal exit. */
|
||||
final predicate isNormal() { normal = true }
|
||||
|
||||
final override AnnotatedExitBasicBlock getBasicBlock() { result = CfgNode.super.getBasicBlock() }
|
||||
final override AnnotatedExitBasicBlock getBasicBlock() { result = super.getBasicBlock() }
|
||||
|
||||
final override Location getLocation() { result = scope.getLocation() }
|
||||
|
||||
|
||||
@@ -233,6 +233,8 @@ module Ssa {
|
||||
)
|
||||
}
|
||||
|
||||
override SelfVariable getSourceVariable() { result = v }
|
||||
|
||||
final override string toString() { result = "self (" + v.getDeclaringScope() + ")" }
|
||||
|
||||
final override Location getLocation() { result = this.getControlFlowNode().getLocation() }
|
||||
@@ -314,7 +316,7 @@ module Ssa {
|
||||
CapturedCallDefinition() {
|
||||
exists(Variable v, BasicBlock bb, int i |
|
||||
this.definesAt(v, bb, i) and
|
||||
SsaImpl::capturedCallWrite(bb, i, v)
|
||||
SsaImpl::capturedCallWrite(_, bb, i, v)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ private module Cached {
|
||||
result = lookupMethod(tp, method) and
|
||||
if result.(Method).isPrivate()
|
||||
then
|
||||
exists(Self self |
|
||||
exists(SelfVariableAccess self |
|
||||
self = call.getReceiver().getExpr() and
|
||||
pragma[only_bind_out](self.getEnclosingModule().getModule().getSuperClass*()) =
|
||||
pragma[only_bind_out](result.getEnclosingModule().getModule())
|
||||
@@ -232,6 +232,18 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a viable run-time target for the call `call`. */
|
||||
cached
|
||||
DataFlowCallable viableCallable(DataFlowCall call) {
|
||||
result = TCfgScope(getTarget(call.asCall())) and
|
||||
not call.asCall().getExpr() instanceof YieldCall // handled by `lambdaCreation`/`lambdaCall`
|
||||
or
|
||||
exists(LibraryCallable callable |
|
||||
result = TLibraryCallable(callable) and
|
||||
call.asCall().getExpr() = callable.getACall()
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TArgumentPosition =
|
||||
TSelfArgumentPosition() or
|
||||
@@ -300,28 +312,14 @@ private DataFlow::LocalSourceNode trackInstance(Module tp, TypeTracker t) {
|
||||
)
|
||||
or
|
||||
// `self` in method
|
||||
exists(Self self, Method enclosing |
|
||||
self = result.asExpr().getExpr() and
|
||||
enclosing = self.getEnclosingMethod() and
|
||||
tp = enclosing.getEnclosingModule().getModule() and
|
||||
not self.getEnclosingModule().getEnclosingMethod() = enclosing
|
||||
)
|
||||
tp = result.(SsaSelfDefinitionNode).getSelfScope().(Method).getEnclosingModule().getModule()
|
||||
or
|
||||
// `self` in singleton method
|
||||
exists(Self self, MethodBase enclosing |
|
||||
self = result.asExpr().getExpr() and
|
||||
flowsToSingletonMethodObject(trackInstance(tp), enclosing) and
|
||||
enclosing = self.getEnclosingMethod() and
|
||||
not self.getEnclosingModule().getEnclosingMethod() = enclosing
|
||||
)
|
||||
flowsToSingletonMethodObject(trackInstance(tp), result.(SsaSelfDefinitionNode).getSelfScope())
|
||||
or
|
||||
// `self` in top-level
|
||||
exists(Self self, Toplevel enclosing |
|
||||
self = result.asExpr().getExpr() and
|
||||
enclosing = self.getEnclosingModule() and
|
||||
tp = TResolved("Object") and
|
||||
not self.getEnclosingMethod().getEnclosingModule() = enclosing
|
||||
)
|
||||
result.(SsaSelfDefinitionNode).getSelfScope() instanceof Toplevel and
|
||||
tp = TResolved("Object")
|
||||
or
|
||||
// a module or class
|
||||
exists(Module m |
|
||||
@@ -371,7 +369,7 @@ private predicate singletonMethod(MethodBase method, Expr object) {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowsToSingletonMethodObject(DataFlow::LocalSourceNode nodeFrom, MethodBase method) {
|
||||
exists(DataFlow::LocalSourceNode nodeTo |
|
||||
exists(DataFlow::Node nodeTo |
|
||||
nodeFrom.flowsTo(nodeTo) and
|
||||
singletonMethod(method, nodeTo.asExpr().getExpr())
|
||||
)
|
||||
@@ -409,13 +407,8 @@ private DataFlow::LocalSourceNode trackSingletonMethod(MethodBase m, string name
|
||||
name = m.getName()
|
||||
}
|
||||
|
||||
private DataFlow::Node selfInModule(Module tp) {
|
||||
exists(Self self, ModuleBase enclosing |
|
||||
self = result.asExpr().getExpr() and
|
||||
enclosing = self.getEnclosingModule() and
|
||||
tp = enclosing.getModule() and
|
||||
not self.getEnclosingMethod().getEnclosingModule() = enclosing
|
||||
)
|
||||
private SsaSelfDefinitionNode selfInModule(Module tp) {
|
||||
tp = result.getSelfScope().(ModuleBase).getModule()
|
||||
}
|
||||
|
||||
private DataFlow::LocalSourceNode trackModule(Module tp, TypeTracker t) {
|
||||
@@ -442,17 +435,6 @@ private DataFlow::LocalSourceNode trackModule(Module tp) {
|
||||
result = trackModule(tp, TypeTracker::end())
|
||||
}
|
||||
|
||||
/** Gets a viable run-time target for the call `call`. */
|
||||
DataFlowCallable viableCallable(DataFlowCall call) {
|
||||
result = TCfgScope(getTarget(call.asCall())) and
|
||||
not call.asCall().getExpr() instanceof YieldCall // handled by `lambdaCreation`/`lambdaCall`
|
||||
or
|
||||
exists(LibraryCallable callable |
|
||||
result = TLibraryCallable(callable) and
|
||||
call.asCall().getExpr() = callable.getACall()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the set of viable implementations that can be called by `call`
|
||||
* might be improved by knowing the call context. This is the case if the
|
||||
|
||||
@@ -70,6 +70,20 @@ module LocalFlow {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the SSA definition node corresponding to the implicit `self` parameter for `m`. */
|
||||
private SsaDefinitionNode getSelfParameterDefNode(MethodBase m) {
|
||||
result.getDefinition().(Ssa::SelfDefinition).getSourceVariable().getDeclaringScope() = m
|
||||
}
|
||||
|
||||
/**
|
||||
* 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())
|
||||
or
|
||||
nodeTo = getSelfParameterDefNode(nodeFrom.(SelfParameterNode).getMethod())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a local use-use flow step from `nodeFrom` to `nodeTo`
|
||||
* involving SSA definition `def`.
|
||||
@@ -115,9 +129,6 @@ module LocalFlow {
|
||||
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
|
||||
localSsaFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
nodeFrom.(SelfParameterNode).getMethod() = nodeTo.asExpr().getExpr().getEnclosingCallable() and
|
||||
nodeTo.asExpr().getExpr() instanceof Self
|
||||
or
|
||||
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::AssignExprCfgNode).getRhs()
|
||||
or
|
||||
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::BlockArgumentCfgNode).getValue()
|
||||
@@ -236,7 +247,7 @@ private module Cached {
|
||||
or
|
||||
defaultValueFlow(nodeTo.(ParameterNode).getParameter(), nodeFrom)
|
||||
or
|
||||
nodeTo = LocalFlow::getParameterDefNode(nodeFrom.(ParameterNode).getParameter())
|
||||
LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
|
||||
or
|
||||
nodeTo.(SynthReturnNode).getAnInput() = nodeFrom
|
||||
or
|
||||
@@ -253,7 +264,7 @@ private module Cached {
|
||||
or
|
||||
defaultValueFlow(nodeTo.(ParameterNode).getParameter(), nodeFrom)
|
||||
or
|
||||
nodeTo = LocalFlow::getParameterDefNode(nodeFrom.(ParameterNode).getParameter())
|
||||
LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
|
||||
or
|
||||
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
|
||||
or
|
||||
@@ -275,27 +286,34 @@ private module Cached {
|
||||
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
private predicate entrySsaDefinition(SsaDefinitionNode n) {
|
||||
n = LocalFlow::getParameterDefNode(_)
|
||||
or
|
||||
exists(Ssa::Definition def | def = n.getDefinition() |
|
||||
def instanceof Ssa::SelfDefinition
|
||||
or
|
||||
def instanceof Ssa::CapturedEntryDefinition
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate isLocalSourceNode(Node n) {
|
||||
n instanceof ParameterNode
|
||||
or
|
||||
// This case should not be needed once we have proper use-use flow
|
||||
// for `self`. At that point, the `self`s returned by `trackInstance`
|
||||
// in `DataFlowDispatch.qll` should refer to the post-update node,
|
||||
// and we can remove this case.
|
||||
n.asExpr().getExpr() instanceof Self
|
||||
n instanceof PostUpdateNodes::ExprPostUpdateNode
|
||||
or
|
||||
// Nodes that can't be reached from another parameter or expression.
|
||||
not localFlowStepTypeTracker+(any(Node e |
|
||||
e instanceof ExprNode
|
||||
// Expressions that can't be reached from another entry definition or expression.
|
||||
not localFlowStepTypeTracker+(any(Node n0 |
|
||||
n0 instanceof ExprNode
|
||||
or
|
||||
e instanceof ParameterNode
|
||||
), n)
|
||||
entrySsaDefinition(n0)
|
||||
), n.(ExprNode))
|
||||
or
|
||||
// Ensure all parameter SSA nodes are local sources -- this is needed by type tracking.
|
||||
// Note that when the parameter has a default value, it will be reachable from an
|
||||
// expression (the default value) and therefore won't be caught by the rule above.
|
||||
n = LocalFlow::getParameterDefNode(_)
|
||||
// Ensure all entry SSA definitions are local sources -- for parameters, this
|
||||
// is needed by type tracking. Note that when the parameter has a default value,
|
||||
// it will be reachable from an expression (the default value) and therefore
|
||||
// won't be caught by the rule above.
|
||||
entrySsaDefinition(n)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -358,6 +376,16 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
|
||||
override string toStringImpl() { result = def.toString() }
|
||||
}
|
||||
|
||||
/** An SSA definition for a `self` variable. */
|
||||
class SsaSelfDefinitionNode extends LocalSourceNode, SsaDefinitionNode {
|
||||
private SelfVariable self;
|
||||
|
||||
SsaSelfDefinitionNode() { self = def.getSourceVariable() }
|
||||
|
||||
/** Gets the scope in which the `self` variable is declared. */
|
||||
Scope getSelfScope() { result = self.getDeclaringScope() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A value returning statement, viewed as a node in a data flow graph.
|
||||
*
|
||||
@@ -745,13 +773,6 @@ predicate jumpStep(Node pred, Node succ) {
|
||||
SsaImpl::captureFlowOut(pred.(SsaDefinitionNode).getDefinition(),
|
||||
succ.(SsaDefinitionNode).getDefinition())
|
||||
or
|
||||
exists(Self s, Method m |
|
||||
s = succ.asExpr().getExpr() and
|
||||
pred.(SelfParameterNode).getMethod() = m and
|
||||
m = s.getEnclosingMethod() and
|
||||
m != s.getEnclosingCallable()
|
||||
)
|
||||
or
|
||||
succ.asExpr().getExpr().(ConstantReadAccess).getValue() = pred.asExpr().getExpr()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
private import SsaImplCommon
|
||||
private import SsaImplSpecific as SsaImplSpecific
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.CFG
|
||||
private import codeql.ruby.ast.Variable
|
||||
@@ -40,58 +41,50 @@ private predicate capturedExitRead(AnnotatedExitBasicBlock bb, int i, LocalVaria
|
||||
i = bb.length()
|
||||
}
|
||||
|
||||
private CfgScope getCaptureOuterCfgScope(CfgScope scope) {
|
||||
result = scope.getOuterCfgScope() and
|
||||
(
|
||||
scope instanceof Block
|
||||
or
|
||||
scope instanceof Lambda
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if captured variable `v` is read inside `scope`. */
|
||||
/**
|
||||
* Holds if captured variable `v` is read directly inside `scope`,
|
||||
* or inside a (transitively) nested scope of `scope`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate hasCapturedRead(Variable v, CfgScope scope) {
|
||||
any(LocalVariableReadAccess read |
|
||||
read.getVariable() = v and scope = getCaptureOuterCfgScope*(read.getCfgScope())
|
||||
read.getVariable() = v and scope = read.getCfgScope().getOuterCfgScope*()
|
||||
).isCapturedAccess()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is written inside basic block `bb`, which is in the immediate
|
||||
* outer scope of `scope`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate variableWriteInOuterScope(BasicBlock bb, LocalVariable v, CfgScope scope) {
|
||||
SsaImplSpecific::variableWrite(bb, _, v, _) and
|
||||
scope.getOuterCfgScope() = bb.getScope()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasVariableWriteWithCapturedRead(BasicBlock bb, LocalVariable v, CfgScope scope) {
|
||||
hasCapturedRead(v, scope) and
|
||||
exists(VariableWriteAccess write |
|
||||
write = bb.getANode().getNode() and
|
||||
write.getVariable() = v and
|
||||
bb.getScope() = scope.getOuterCfgScope()
|
||||
)
|
||||
variableWriteInOuterScope(bb, v, scope)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call at index `i` in basic block `bb` may reach a callable
|
||||
* that reads captured variable `v`.
|
||||
* Holds if the call `call` at index `i` in basic block `bb` may reach
|
||||
* a callable that reads captured variable `v`.
|
||||
*/
|
||||
private predicate capturedCallRead(BasicBlock bb, int i, LocalVariable v) {
|
||||
private predicate capturedCallRead(Call call, BasicBlock bb, int i, LocalVariable v) {
|
||||
exists(CfgScope scope |
|
||||
hasVariableWriteWithCapturedRead(bb.getAPredecessor*(), v, scope) and
|
||||
bb.getNode(i).getNode() instanceof Call
|
||||
call = bb.getNode(i).getNode()
|
||||
|
|
||||
not scope instanceof Block
|
||||
or
|
||||
// If the read happens inside a block, we restrict to the call that
|
||||
// contains the block
|
||||
scope = any(MethodCall c | bb.getNode(i) = c.getAControlFlowNode()).getBlock()
|
||||
not scope instanceof Block
|
||||
or
|
||||
scope = call.(MethodCall).getBlock()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if captured variable `v` is written inside `scope`. */
|
||||
pragma[noinline]
|
||||
private predicate hasCapturedWrite(Variable v, CfgScope scope) {
|
||||
any(LocalVariableWriteAccess write |
|
||||
write.getVariable() = v and scope = getCaptureOuterCfgScope*(write.getCfgScope())
|
||||
).isCapturedAccess()
|
||||
}
|
||||
|
||||
/** Holds if `v` is read at index `i` in basic block `bb`. */
|
||||
private predicate variableReadActual(BasicBlock bb, int i, LocalVariable v) {
|
||||
exists(VariableReadAccess read |
|
||||
@@ -104,21 +97,38 @@ predicate variableRead(BasicBlock bb, int i, LocalVariable v, boolean certain) {
|
||||
variableReadActual(bb, i, v) and
|
||||
certain = true
|
||||
or
|
||||
capturedCallRead(bb, i, v) and
|
||||
capturedCallRead(_, bb, i, v) and
|
||||
certain = false
|
||||
or
|
||||
capturedExitRead(bb, i, v) and
|
||||
certain = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if captured variable `v` is written directly inside `scope`,
|
||||
* or inside a (transitively) nested scope of `scope`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate hasCapturedWrite(Variable v, CfgScope scope) {
|
||||
any(LocalVariableWriteAccess write |
|
||||
write.getVariable() = v and scope = write.getCfgScope().getOuterCfgScope*()
|
||||
).isCapturedAccess()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is read inside basic block `bb`, which is in the immediate
|
||||
* outer scope of `scope`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate variableReadActualInOuterScope(BasicBlock bb, LocalVariable v, CfgScope scope) {
|
||||
variableReadActual(bb, _, v) and
|
||||
bb.getScope() = scope.getOuterCfgScope()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasVariableReadWithCapturedWrite(BasicBlock bb, LocalVariable v, CfgScope scope) {
|
||||
hasCapturedWrite(v, scope) and
|
||||
exists(VariableReadAccess read |
|
||||
read = bb.getANode().getNode() and
|
||||
read.getVariable() = v and
|
||||
bb.getScope() = scope.getOuterCfgScope()
|
||||
)
|
||||
variableReadActualInOuterScope(bb, v, scope)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -134,20 +144,20 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call at index `i` in basic block `bb` may reach a callable
|
||||
* Holds if the call `call` at index `i` in basic block `bb` may reach a callable
|
||||
* that writes captured variable `v`.
|
||||
*/
|
||||
cached
|
||||
predicate capturedCallWrite(BasicBlock bb, int i, LocalVariable v) {
|
||||
predicate capturedCallWrite(Call call, BasicBlock bb, int i, LocalVariable v) {
|
||||
exists(CfgScope scope |
|
||||
hasVariableReadWithCapturedWrite(bb.getASuccessor*(), v, scope) and
|
||||
bb.getNode(i).getNode() instanceof Call
|
||||
call = bb.getNode(i).getNode()
|
||||
|
|
||||
not scope instanceof Block
|
||||
or
|
||||
// If the write happens inside a block, we restrict to the call that
|
||||
// contains the block
|
||||
scope = any(MethodCall c | bb.getNode(i) = c.getAControlFlowNode()).getBlock()
|
||||
not scope instanceof Block
|
||||
or
|
||||
scope = call.(MethodCall).getBlock()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -177,6 +187,26 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate defReachesCallReadInOuterScope(
|
||||
Definition def, Call call, LocalVariable v, CfgScope scope
|
||||
) {
|
||||
exists(BasicBlock bb, int i |
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
capturedCallRead(call, bb, i, v) and
|
||||
scope.getOuterCfgScope() = bb.getScope()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasCapturedEntryWrite(Definition entry, LocalVariable v, CfgScope scope) {
|
||||
exists(BasicBlock bb, int i |
|
||||
capturedEntryWrite(bb, i, v) and
|
||||
entry.definesAt(v, bb, i) and
|
||||
bb.getScope().getOuterCfgScope*() = scope
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is flow for a captured variable from the enclosing scope into a block.
|
||||
* ```rb
|
||||
@@ -188,13 +218,35 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate captureFlowIn(Definition def, Definition entry) {
|
||||
exists(LocalVariable v, BasicBlock bb, int i |
|
||||
exists(Call call, LocalVariable v, CfgScope scope |
|
||||
defReachesCallReadInOuterScope(def, call, v, scope) and
|
||||
hasCapturedEntryWrite(entry, v, scope)
|
||||
|
|
||||
// If the read happens inside a block, we restrict to the call that
|
||||
// contains the block
|
||||
not scope instanceof Block
|
||||
or
|
||||
scope = call.(MethodCall).getBlock()
|
||||
)
|
||||
}
|
||||
|
||||
private import codeql.ruby.dataflow.SSA
|
||||
|
||||
pragma[noinline]
|
||||
private predicate defReachesExitReadInInnerScope(Definition def, LocalVariable v, CfgScope scope) {
|
||||
exists(BasicBlock bb, int i |
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
capturedCallRead(bb, i, v) and
|
||||
exists(BasicBlock bb2, int i2 |
|
||||
capturedEntryWrite(bb2, i2, v) and
|
||||
entry.definesAt(v, bb2, i2)
|
||||
)
|
||||
capturedExitRead(bb, i, v) and
|
||||
scope = bb.getScope().getOuterCfgScope*()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasCapturedExitRead(Definition exit, Call call, LocalVariable v, CfgScope scope) {
|
||||
exists(BasicBlock bb, int i |
|
||||
capturedCallWrite(call, bb, i, v) and
|
||||
exit.definesAt(v, bb, i) and
|
||||
bb.getScope() = scope.getOuterCfgScope()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -210,13 +262,15 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate captureFlowOut(Definition def, Definition exit) {
|
||||
exists(LocalVariable v, BasicBlock bb, int i |
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
capturedExitRead(bb, i, v) and
|
||||
exists(BasicBlock bb2, int i2 |
|
||||
capturedCallWrite(bb2, i2, v) and
|
||||
exit.definesAt(v, bb2, i2)
|
||||
)
|
||||
exists(Call call, LocalVariable v, CfgScope scope |
|
||||
defReachesExitReadInInnerScope(def, v, scope) and
|
||||
hasCapturedExitRead(exit, call, v, _)
|
||||
|
|
||||
// If the read happens inside a block, we restrict to the call that
|
||||
// contains the block
|
||||
not scope instanceof Block
|
||||
or
|
||||
scope = call.(MethodCall).getBlock()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain)
|
||||
) and
|
||||
certain = true
|
||||
or
|
||||
SsaImpl::capturedCallWrite(bb, i, v) and
|
||||
SsaImpl::capturedCallWrite(_, bb, i, v) and
|
||||
certain = false
|
||||
}
|
||||
|
||||
|
||||
@@ -66,35 +66,53 @@ private CfgNodes::ExprNodes::VariableWriteAccessCfgNode variablesInPattern(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional step from `nodeFrom` to `nodeTo` should be included
|
||||
* in all global taint flow configurations.
|
||||
*/
|
||||
cached
|
||||
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// value of `case` expression into variables in patterns
|
||||
exists(CfgNodes::ExprNodes::CaseExprCfgNode case, CfgNodes::ExprNodes::InClauseCfgNode clause |
|
||||
nodeFrom.asExpr() = case.getValue() and
|
||||
clause = case.getBranch(_) and
|
||||
nodeTo.(SsaDefinitionNode).getDefinition().getControlFlowNode() =
|
||||
variablesInPattern(clause.getPattern())
|
||||
)
|
||||
or
|
||||
// operation involving `nodeFrom`
|
||||
exists(CfgNodes::ExprNodes::OperationCfgNode op |
|
||||
op = nodeTo.asExpr() and
|
||||
op.getAnOperand() = nodeFrom.asExpr() and
|
||||
not op.getExpr() instanceof AssignExpr
|
||||
)
|
||||
or
|
||||
// string interpolation of `nodeFrom` into `nodeTo`
|
||||
nodeFrom.asExpr() =
|
||||
nodeTo.asExpr().(CfgNodes::ExprNodes::StringlikeLiteralCfgNode).getAComponent()
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, false)
|
||||
or
|
||||
// Although flow through arrays is modelled precisely using stores/reads, we still
|
||||
// allow flow out of a _tainted_ array. This is needed in order to support taint-
|
||||
// tracking configurations where the source is an array.
|
||||
readStep(nodeFrom, any(DataFlow::Content::ArrayElementContent c), nodeTo)
|
||||
private module Cached {
|
||||
/**
|
||||
* Holds if the additional step from `nodeFrom` to `nodeTo` should be included
|
||||
* in all global taint flow configurations.
|
||||
*/
|
||||
cached
|
||||
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// value of `case` expression into variables in patterns
|
||||
exists(CfgNodes::ExprNodes::CaseExprCfgNode case, CfgNodes::ExprNodes::InClauseCfgNode clause |
|
||||
nodeFrom.asExpr() = case.getValue() and
|
||||
clause = case.getBranch(_) and
|
||||
nodeTo.(SsaDefinitionNode).getDefinition().getControlFlowNode() =
|
||||
variablesInPattern(clause.getPattern())
|
||||
)
|
||||
or
|
||||
// operation involving `nodeFrom`
|
||||
exists(CfgNodes::ExprNodes::OperationCfgNode op |
|
||||
op = nodeTo.asExpr() and
|
||||
op.getAnOperand() = nodeFrom.asExpr() and
|
||||
not op.getExpr() instanceof AssignExpr
|
||||
)
|
||||
or
|
||||
// string interpolation of `nodeFrom` into `nodeTo`
|
||||
nodeFrom.asExpr() =
|
||||
nodeTo.asExpr().(CfgNodes::ExprNodes::StringlikeLiteralCfgNode).getAComponent()
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, false)
|
||||
or
|
||||
// Although flow through arrays is modelled precisely using stores/reads, we still
|
||||
// allow flow out of a _tainted_ array. This is needed in order to support taint-
|
||||
// tracking configurations where the source is an array.
|
||||
readStep(nodeFrom, any(DataFlow::Content::ArrayElementContent c), nodeTo)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||
* (intra-procedural) step.
|
||||
*/
|
||||
cached
|
||||
predicate localTaintStepCached(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
defaultAdditionalTaintStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// Simple flow through library code is included in the exposed local
|
||||
// step relation, even though flow is technically inter-procedural
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStep(nodeFrom, nodeTo, false)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
@@ -20,14 +20,4 @@ predicate localExprTaint(CfgNodes::ExprCfgNode e1, CfgNodes::ExprCfgNode e2) {
|
||||
localTaint(DataFlow::exprNode(e1), DataFlow::exprNode(e2))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||
* (intra-procedural) step.
|
||||
*/
|
||||
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
defaultAdditionalTaintStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// Simple flow through library code is included in the exposed local
|
||||
// step relation, even though flow is technically inter-procedural
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStep(nodeFrom, nodeTo, false)
|
||||
}
|
||||
predicate localTaintStep = localTaintStepCached/2;
|
||||
|
||||
@@ -105,7 +105,7 @@ private class ActionControllerContextCall extends MethodCall {
|
||||
private ActionControllerControllerClass controllerClass;
|
||||
|
||||
ActionControllerContextCall() {
|
||||
this.getReceiver() instanceof Self and
|
||||
this.getReceiver() instanceof SelfVariableAccess and
|
||||
this.getEnclosingModule() = controllerClass
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ private class ActionViewHtmlEscapeCall extends HtmlEscapeCall {
|
||||
// A call in a context where some commonly used `ActionView` methods are available.
|
||||
private class ActionViewContextCall extends MethodCall {
|
||||
ActionViewContextCall() {
|
||||
this.getReceiver() instanceof Self and
|
||||
this.getReceiver() instanceof SelfVariableAccess and
|
||||
inActionViewContext(this)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.controlflow.CfgNodes
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.dataflow.internal.DataFlowDispatch
|
||||
private import codeql.ruby.dataflow.internal.DataFlowPrivate
|
||||
private import codeql.ruby.ast.internal.Module
|
||||
private import codeql.ruby.ApiGraphs
|
||||
private import codeql.ruby.frameworks.Stdlib
|
||||
@@ -100,7 +101,7 @@ class ActiveRecordModelClassMethodCall extends MethodCall {
|
||||
recvCls = this.getReceiver().(ActiveRecordModelClassMethodCall).getReceiverClass()
|
||||
or
|
||||
// e.g. self.where(...) within an ActiveRecordModelClass
|
||||
this.getReceiver() instanceof Self and
|
||||
this.getReceiver() instanceof SelfVariableAccess and
|
||||
this.getEnclosingModule() = recvCls
|
||||
}
|
||||
|
||||
@@ -283,14 +284,15 @@ private class ActiveRecordModelFinderCall extends ActiveRecordModelInstantiation
|
||||
}
|
||||
|
||||
// A `self` reference that may resolve to an active record model object
|
||||
private class ActiveRecordModelClassSelfReference extends ActiveRecordModelInstantiation {
|
||||
private class ActiveRecordModelClassSelfReference extends ActiveRecordModelInstantiation,
|
||||
SsaSelfDefinitionNode {
|
||||
private ActiveRecordModelClass cls;
|
||||
|
||||
ActiveRecordModelClassSelfReference() {
|
||||
exists(Self s |
|
||||
s.getEnclosingModule() = cls and
|
||||
s.getEnclosingMethod() = cls.getAMethod() and
|
||||
s = this.asExpr().getExpr()
|
||||
exists(MethodBase m |
|
||||
m = this.getCfgScope() and
|
||||
m.getEnclosingModule() = cls and
|
||||
m = cls.getAMethod()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -221,7 +221,7 @@ private class GraphqlSchemaObjectClassMethodCall extends MethodCall {
|
||||
recvCls.getModule() = resolveConstantReadAccess(this.getReceiver())
|
||||
or
|
||||
// e.g. self.some_method(...) within a graphql Object or Interface
|
||||
this.getReceiver() instanceof Self and
|
||||
this.getReceiver() instanceof SelfVariableAccess and
|
||||
this.getEnclosingModule() = recvCls
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ module Kernel {
|
||||
or
|
||||
methodCall instanceof UnknownMethodCall and
|
||||
(
|
||||
this.getReceiver().asExpr().getExpr() instanceof Self and
|
||||
this.getReceiver().asExpr().getExpr() instanceof SelfVariableAccess and
|
||||
isPrivateKernelMethod(methodCall.getMethodName())
|
||||
or
|
||||
isPublicKernelMethod(methodCall.getMethodName())
|
||||
|
||||
@@ -88,10 +88,7 @@ predicate callStep(Node nodeFrom, Node nodeTo) {
|
||||
// we model it as a call step, in order to avoid computing a potential
|
||||
// self-cross product of all calls to a function that returns one of its parameters
|
||||
// (only to later filter that flow out using `TypeTracker::append`).
|
||||
nodeTo =
|
||||
DataFlowPrivate::LocalFlow::getParameterDefNode(nodeFrom
|
||||
.(DataFlowPublic::ParameterNode)
|
||||
.getParameter())
|
||||
DataFlowPrivate::LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ calls/calls.rb:
|
||||
# 58| getDesugared: [MethodCall] call to []
|
||||
# 58| getReceiver: [ConstantReadAccess] Array
|
||||
# 58| getArgument: [MethodCall] call to foo
|
||||
# 58| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 58| getReceiver: [SelfVariableAccess] self
|
||||
# 59| [ArrayLiteral] [...]
|
||||
# 59| getDesugared: [MethodCall] call to []
|
||||
# 59| getReceiver: [ConstantReadAccess] Array
|
||||
@@ -15,7 +15,7 @@ calls/calls.rb:
|
||||
# 66| getAnOperand/getRightOperand: [AddExpr] ... + ...
|
||||
# 66| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] var1
|
||||
# 66| getAnOperand/getArgument/getRightOperand: [MethodCall] call to bar
|
||||
# 66| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 66| getReceiver: [SelfVariableAccess] self
|
||||
# 67| [AssignAddExpr] ... += ...
|
||||
# 67| getDesugared: [AssignExpr] ... = ...
|
||||
# 67| getAnOperand/getLeftOperand: [LocalVariableAccess] var1
|
||||
@@ -32,9 +32,9 @@ calls/calls.rb:
|
||||
# 226| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
|
||||
# 226| getAnOperand/getLeftOperand: [LocalVariableAccess] x
|
||||
# 227| getStmt: [MethodCall] call to baz
|
||||
# 227| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 227| getReceiver: [SelfVariableAccess] self
|
||||
# 226| getReceiver: [MethodCall] call to bar
|
||||
# 226| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 226| getReceiver: [SelfVariableAccess] self
|
||||
# 229| [ForExpr] for ... in ...
|
||||
# 229| getDesugared: [MethodCall] call to each
|
||||
# 229| getBlock: [BraceBlock] { ... }
|
||||
@@ -52,9 +52,9 @@ calls/calls.rb:
|
||||
# 249| getReceiver: [ConstantReadAccess] Hash
|
||||
# 249| getArgument: [Pair] Pair
|
||||
# 249| getKey: [MethodCall] call to foo
|
||||
# 249| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 249| getReceiver: [SelfVariableAccess] self
|
||||
# 249| getValue: [MethodCall] call to bar
|
||||
# 249| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 249| getReceiver: [SelfVariableAccess] self
|
||||
# 249| getArgument: [Pair] Pair
|
||||
# 249| getKey: [MethodCall] call to foo
|
||||
# 249| getReceiver: [ConstantReadAccess] X
|
||||
@@ -63,7 +63,7 @@ calls/calls.rb:
|
||||
# 314| [AssignExpr] ... = ...
|
||||
# 314| getDesugared: [StmtSequence] ...
|
||||
# 314| getStmt: [SetterMethodCall] call to foo=
|
||||
# 314| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 314| getReceiver: [SelfVariableAccess] self
|
||||
# 314| getArgument: [AssignExpr] ... = ...
|
||||
# 314| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 314| getAnOperand/getRightOperand: [IntegerLiteral] 10
|
||||
@@ -72,7 +72,7 @@ calls/calls.rb:
|
||||
# 315| getDesugared: [StmtSequence] ...
|
||||
# 315| getStmt: [SetterMethodCall] call to []=
|
||||
# 315| getReceiver: [MethodCall] call to foo
|
||||
# 315| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 315| getReceiver: [SelfVariableAccess] self
|
||||
# 315| getArgument: [AssignExpr] ... = ...
|
||||
# 315| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 315| getAnOperand/getRightOperand: [IntegerLiteral] 10
|
||||
@@ -84,7 +84,7 @@ calls/calls.rb:
|
||||
# 316| getAnOperand/getLeftOperand: [MethodCall] call to foo
|
||||
# 316| getDesugared: [StmtSequence] ...
|
||||
# 316| getStmt: [SetterMethodCall] call to foo=
|
||||
# 316| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 316| getReceiver: [SelfVariableAccess] self
|
||||
# 316| getArgument: [AssignExpr] ... = ...
|
||||
# 316| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 316| getArgument: [IntegerLiteral] 0
|
||||
@@ -95,7 +95,7 @@ calls/calls.rb:
|
||||
# 316| getAnOperand/getLeftOperand: [MethodCall] call to bar
|
||||
# 316| getDesugared: [StmtSequence] ...
|
||||
# 316| getStmt: [SetterMethodCall] call to bar=
|
||||
# 316| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 316| getReceiver: [SelfVariableAccess] self
|
||||
# 316| getArgument: [AssignExpr] ... = ...
|
||||
# 316| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 316| getArgument: [RangeLiteral] _ .. _
|
||||
@@ -109,7 +109,7 @@ calls/calls.rb:
|
||||
# 316| getDesugared: [StmtSequence] ...
|
||||
# 316| getStmt: [SetterMethodCall] call to []=
|
||||
# 316| getReceiver: [MethodCall] call to foo
|
||||
# 316| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 316| getReceiver: [SelfVariableAccess] self
|
||||
# 316| getArgument: [AssignExpr] ... = ...
|
||||
# 316| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 316| getArgument: [IntegerLiteral] -1
|
||||
@@ -139,7 +139,7 @@ calls/calls.rb:
|
||||
# 317| getDesugared: [StmtSequence] ...
|
||||
# 317| getStmt: [SetterMethodCall] call to []=
|
||||
# 317| getReceiver: [MethodCall] call to foo
|
||||
# 317| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 317| getReceiver: [SelfVariableAccess] self
|
||||
# 317| getArgument: [AssignExpr] ... = ...
|
||||
# 317| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 317| getArgument: [RangeLiteral] _ .. _
|
||||
@@ -161,7 +161,7 @@ calls/calls.rb:
|
||||
# 318| [AssignAddExpr] ... += ...
|
||||
# 318| getDesugared: [StmtSequence] ...
|
||||
# 318| getStmt: [AssignExpr] ... = ...
|
||||
# 318| getAnOperand/getRightOperand: [Self, SelfVariableAccess] self
|
||||
# 318| getAnOperand/getRightOperand: [SelfVariableAccess] self
|
||||
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 318| getStmt: [SetterMethodCall] call to count=
|
||||
# 318| getReceiver: [LocalVariableAccess] __synth__0
|
||||
@@ -177,7 +177,7 @@ calls/calls.rb:
|
||||
# 319| getDesugared: [StmtSequence] ...
|
||||
# 319| getStmt: [AssignExpr] ... = ...
|
||||
# 319| getAnOperand/getRightOperand: [MethodCall] call to foo
|
||||
# 319| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 319| getReceiver: [SelfVariableAccess] self
|
||||
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 319| getStmt: [SetterMethodCall] call to []=
|
||||
# 319| getReceiver: [LocalVariableAccess] __synth__0
|
||||
@@ -199,7 +199,7 @@ calls/calls.rb:
|
||||
# 320| getStmt: [AssignExpr] ... = ...
|
||||
# 320| getAnOperand/getRightOperand: [MethodCall] call to bar
|
||||
# 320| getReceiver: [MethodCall] call to foo
|
||||
# 320| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 320| getReceiver: [SelfVariableAccess] self
|
||||
# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
|
||||
# 320| getStmt: [SetterMethodCall] call to []=
|
||||
# 320| getReceiver: [LocalVariableAccess] __synth__0
|
||||
@@ -213,13 +213,13 @@ calls/calls.rb:
|
||||
# 320| getStmt: [AssignExpr] ... = ...
|
||||
# 320| getAnOperand/getRightOperand: [MethodCall] call to baz
|
||||
# 320| getReceiver: [MethodCall] call to foo
|
||||
# 320| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 320| getReceiver: [SelfVariableAccess] self
|
||||
# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2
|
||||
# 320| getStmt: [AssignExpr] ... = ...
|
||||
# 320| getAnOperand/getRightOperand: [AddExpr] ... + ...
|
||||
# 320| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to boo
|
||||
# 320| getReceiver: [MethodCall] call to foo
|
||||
# 320| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 320| getReceiver: [SelfVariableAccess] self
|
||||
# 320| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1
|
||||
# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3
|
||||
# 320| getStmt: [AssignExpr] ... = ...
|
||||
@@ -260,7 +260,7 @@ calls/calls.rb:
|
||||
# 340| getReceiver: [LocalVariableAccess] __synth__0__1
|
||||
# 340| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
|
||||
# 341| getStmt: [MethodCall] call to foo
|
||||
# 341| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 341| getReceiver: [SelfVariableAccess] self
|
||||
# 341| getArgument: [LocalVariableAccess] x
|
||||
# 341| getArgument: [LocalVariableAccess] y
|
||||
# 341| getArgument: [LocalVariableAccess] z
|
||||
@@ -476,7 +476,7 @@ literals/literals.rb:
|
||||
# 118| getValue: [IntegerLiteral] 7
|
||||
# 118| getArgument: [HashSplatExpr] ** ...
|
||||
# 118| getAnOperand/getOperand/getReceiver: [MethodCall] call to baz
|
||||
# 118| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 118| getReceiver: [SelfVariableAccess] self
|
||||
# 185| [HashLiteral] {...}
|
||||
# 185| getDesugared: [MethodCall] call to []
|
||||
# 185| getReceiver: [ConstantReadAccess] Hash
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
| local_dataflow.rb:1:1:7:3 | self (foo) | local_dataflow.rb:3:8:3:10 | self |
|
||||
| local_dataflow.rb:1:1:7:3 | self (local_dataflow.rb) | local_dataflow.rb:49:1:53:3 | self |
|
||||
| local_dataflow.rb:1:1:7:3 | self in foo | local_dataflow.rb:3:8:3:10 | self |
|
||||
| local_dataflow.rb:1:1:7:3 | self in foo | local_dataflow.rb:1:1:7:3 | self (foo) |
|
||||
| local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:1:9:1:9 | a |
|
||||
| local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:2:7:2:7 | a |
|
||||
| local_dataflow.rb:2:3:2:7 | ... = ... | local_dataflow.rb:3:13:3:13 | b |
|
||||
@@ -71,16 +71,7 @@
|
||||
| local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:51:20:51:20 | x |
|
||||
| local_dataflow.rb:51:9:51:15 | "break" | local_dataflow.rb:51:3:51:15 | break |
|
||||
| local_dataflow.rb:60:1:90:3 | self (test_case) | local_dataflow.rb:78:12:78:20 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:78:12:78:20 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:79:20:79:26 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:80:24:80:30 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:82:7:82:13 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:83:7:83:13 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:84:7:84:13 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:85:22:85:28 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:86:28:86:34 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:87:20:87:26 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:89:3:89:9 | self |
|
||||
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:60:1:90:3 | self (test_case) |
|
||||
| local_dataflow.rb:60:15:60:15 | x | local_dataflow.rb:60:15:60:15 | x |
|
||||
| local_dataflow.rb:60:15:60:15 | x | local_dataflow.rb:61:12:61:12 | x |
|
||||
| local_dataflow.rb:61:7:68:5 | case ... | local_dataflow.rb:61:3:68:5 | ... = ... |
|
||||
|
||||
@@ -201,7 +201,6 @@ edges
|
||||
| string_flow.rb:241:10:241:10 | b [array element] : | string_flow.rb:241:10:241:13 | ...[...] |
|
||||
| string_flow.rb:242:10:242:10 | b [array element] : | string_flow.rb:242:10:242:13 | ...[...] |
|
||||
| string_flow.rb:246:5:246:18 | ... = ... : | string_flow.rb:250:26:250:26 | a : |
|
||||
| string_flow.rb:246:5:246:18 | ... = ... : | string_flow.rb:258:27:258:27 | a : |
|
||||
| string_flow.rb:246:9:246:18 | call to source : | string_flow.rb:246:5:246:18 | ... = ... : |
|
||||
| string_flow.rb:246:9:246:18 | call to source : | string_flow.rb:247:10:247:10 | a : |
|
||||
| string_flow.rb:246:9:246:18 | call to source : | string_flow.rb:248:20:248:20 | a : |
|
||||
@@ -215,7 +214,6 @@ edges
|
||||
| string_flow.rb:250:26:250:26 | a : | string_flow.rb:250:10:250:28 | call to scrub |
|
||||
| string_flow.rb:252:10:252:10 | a : | string_flow.rb:252:10:252:22 | call to scrub! |
|
||||
| string_flow.rb:253:21:253:21 | a : | string_flow.rb:253:10:253:22 | call to scrub! |
|
||||
| string_flow.rb:255:5:255:18 | ... = ... : | string_flow.rb:250:26:250:26 | a : |
|
||||
| string_flow.rb:255:5:255:18 | ... = ... : | string_flow.rb:258:27:258:27 | a : |
|
||||
| string_flow.rb:255:9:255:18 | call to source : | string_flow.rb:255:5:255:18 | ... = ... : |
|
||||
| string_flow.rb:255:9:255:18 | call to source : | string_flow.rb:256:5:256:5 | a : |
|
||||
|
||||
@@ -5,6 +5,7 @@ track
|
||||
| type_tracker.rb:2:5:5:7 | return return in field= | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type tracker without call steps | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type tracker without call steps | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:2:16:2:18 | val | type tracker with call steps | type_tracker.rb:2:16:2:18 | val |
|
||||
@@ -16,17 +17,10 @@ track
|
||||
| type_tracker.rb:3:9:3:23 | [post] self | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:3:9:3:23 | [post] self | type tracker without call steps | type_tracker.rb:3:9:3:23 | [post] self |
|
||||
| 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:9:3:23 | self | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:3:9:3:23 | self | type tracker without call steps | type_tracker.rb:3:9:3:23 | self |
|
||||
| type_tracker.rb:3:14:3:17 | [post] self | type tracker without call steps | type_tracker.rb:3:14:3:17 | [post] self |
|
||||
| type_tracker.rb:3:14:3:17 | self | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:3:14:3:17 | self | type tracker without call steps | type_tracker.rb:3:14:3:17 | self |
|
||||
| type_tracker.rb:3:14:3:23 | [post] call to field | type tracker without call steps | type_tracker.rb:3:14:3:23 | [post] call to field |
|
||||
| type_tracker.rb:3:14:3:23 | call to field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:4:9:4:14 | @field | type tracker without call steps | type_tracker.rb:4:9:4:14 | @field |
|
||||
| type_tracker.rb:4:18:4:20 | val | type tracker without call steps | type_tracker.rb:2:5:5:7 | return return in field= |
|
||||
| type_tracker.rb:4:18:4:20 | val | type tracker without call steps | type_tracker.rb:4:18:4:20 | val |
|
||||
| type_tracker.rb:4:18:4:20 | val | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:7:5:9:7 | &block | type tracker without call steps | type_tracker.rb:7:5:9:7 | &block |
|
||||
| type_tracker.rb:7:5:9:7 | field | type tracker without call steps | type_tracker.rb:7:5:9:7 | field |
|
||||
| type_tracker.rb:7:5:9:7 | return return in field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
|
||||
@@ -41,15 +35,22 @@ track
|
||||
| type_tracker.rb:12:1:16:3 | m | type tracker without call steps | type_tracker.rb:12:1:16:3 | m |
|
||||
| type_tracker.rb:12:1:16:3 | return return in m | type tracker without call steps | type_tracker.rb:12:1:16:3 | return return in m |
|
||||
| type_tracker.rb:12:1:16:3 | self (m) | type tracker without call steps | type_tracker.rb:12:1:16:3 | self (m) |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type tracker with call steps | type_tracker.rb:12:1:16:3 | self (m) |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type tracker without call steps | type_tracker.rb:12:1:16:3 | self in m |
|
||||
| type_tracker.rb:13:5:13:7 | var | type tracker without call steps | type_tracker.rb:13:5:13:7 | var |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type tracker with call steps | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type tracker without call steps | type_tracker.rb:13:5:13:23 | ... = ... |
|
||||
| type_tracker.rb:13:11:13:19 | Container | type tracker without call steps | type_tracker.rb:13:11:13:19 | Container |
|
||||
| type_tracker.rb:13:11:13:19 | [post] Container | type tracker without call steps | type_tracker.rb:13:11:13:19 | [post] Container |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type tracker without call steps | type_tracker.rb:13:11:13:23 | call to new |
|
||||
| type_tracker.rb:14:5:14:7 | [post] var | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:14:5:14:7 | [post] var | type tracker without call steps | type_tracker.rb:14:5:14:7 | [post] var |
|
||||
| type_tracker.rb:14:5:14:13 | ... = ... | type tracker without call steps | type_tracker.rb:14:5:14:13 | ... = ... |
|
||||
| type_tracker.rb:14:5:14:13 | [post] ... = ... | type tracker without call steps | type_tracker.rb:14:5:14:13 | [post] ... = ... |
|
||||
| type_tracker.rb:14:5:14:13 | __synth__0 | type tracker without call steps | type_tracker.rb:14:5:14:13 | __synth__0 |
|
||||
| type_tracker.rb:14:5:14:13 | call to field= | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
@@ -63,7 +64,6 @@ track
|
||||
| type_tracker.rb:15:5:15:18 | [post] self | type tracker without call steps | type_tracker.rb:15:5:15:18 | [post] self |
|
||||
| type_tracker.rb:15:5:15:18 | call to puts | type tracker without call steps | type_tracker.rb:12:1:16:3 | return return in m |
|
||||
| type_tracker.rb:15:5:15:18 | call to puts | type tracker without call steps | type_tracker.rb:15:5:15:18 | call to puts |
|
||||
| type_tracker.rb:15:5:15:18 | self | type tracker without call steps | type_tracker.rb:15:5:15:18 | self |
|
||||
| type_tracker.rb:15:10:15:12 | [post] var | type tracker without call steps | type_tracker.rb:15:10:15:12 | [post] var |
|
||||
| type_tracker.rb:15:10:15:18 | [post] call to field | type tracker without call steps | type_tracker.rb:15:10:15:18 | [post] call to field |
|
||||
| type_tracker.rb:15:10:15:18 | call to field | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field |
|
||||
@@ -76,6 +76,7 @@ trackEnd
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:9:3:23 | self |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:14:3:17 | self |
|
||||
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:3:9:3:23 | self |
|
||||
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:3:14:3:17 | self |
|
||||
@@ -94,19 +95,10 @@ trackEnd
|
||||
| type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:3:14:3:17 | self |
|
||||
| type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:7:5:9:7 | self in 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:9:3:23 | self | type_tracker.rb:3:9:3:23 | self |
|
||||
| type_tracker.rb:3:9:3:23 | self | type_tracker.rb:3:14:3:17 | self |
|
||||
| type_tracker.rb:3:9:3:23 | self | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:3:14:3:17 | [post] self | type_tracker.rb:3:14:3:17 | [post] self |
|
||||
| type_tracker.rb:3:14:3:17 | self | type_tracker.rb:3:14:3:17 | self |
|
||||
| type_tracker.rb:3:14:3:17 | self | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:3:14:3:23 | [post] call to field | type_tracker.rb:3:14:3:23 | [post] call to field |
|
||||
| type_tracker.rb:3:14:3:23 | call to field | type_tracker.rb:3:14:3:23 | call to field |
|
||||
| type_tracker.rb:4:9:4:14 | @field | type_tracker.rb:4:9:4:14 | @field |
|
||||
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:2:5:5:7 | return return in field= |
|
||||
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:4:9:4:20 | ... = ... |
|
||||
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:4:18:4:20 | val |
|
||||
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
| type_tracker.rb:7:5:9:7 | &block | type_tracker.rb:7:5:9:7 | &block |
|
||||
| type_tracker.rb:7:5:9:7 | field | type_tracker.rb:1:1:10:3 | Container |
|
||||
| type_tracker.rb:7:5:9:7 | field | type_tracker.rb:7:5:9:7 | field |
|
||||
@@ -123,11 +115,21 @@ trackEnd
|
||||
| type_tracker.rb:12:1:16:3 | return return in m | type_tracker.rb:12:1:16:3 | return return in m |
|
||||
| type_tracker.rb:12:1:16:3 | self (m) | type_tracker.rb:12:1:16:3 | self (m) |
|
||||
| type_tracker.rb:12:1:16:3 | self (m) | type_tracker.rb:15:5:15:18 | self |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:12:1:16:3 | self (m) |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:12:1:16:3 | self in m |
|
||||
| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:15:5:15:18 | self |
|
||||
| type_tracker.rb:13:5:13:7 | var | type_tracker.rb:13:5:13:7 | var |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:3:9:3:23 | self |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:3:14:3:17 | self |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:13:5:13:23 | ... = ... |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:14:5:14:7 | var |
|
||||
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:15:10:15:12 | var |
|
||||
| type_tracker.rb:13:11:13:19 | Container | type_tracker.rb:13:11:13:19 | Container |
|
||||
| type_tracker.rb:13:11:13:19 | [post] Container | type_tracker.rb:13:11:13:19 | [post] Container |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:2:5:5:7 | self (field=) |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:2:5:5:7 | self in field= |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:3:9:3:23 | self |
|
||||
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:3:14:3:17 | self |
|
||||
@@ -140,6 +142,9 @@ trackEnd
|
||||
| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:7:5:9:7 | self in field |
|
||||
| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:14:5:14:7 | [post] var |
|
||||
| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:15:10:15:12 | var |
|
||||
| type_tracker.rb:14:5:14:13 | ... = ... | type_tracker.rb:14:5:14:13 | ... = ... |
|
||||
| type_tracker.rb:14:5:14:13 | ... = ... | type_tracker.rb:14:5:14:13 | __synth__0 |
|
||||
| type_tracker.rb:14:5:14:13 | ... = ... | type_tracker.rb:14:5:14:23 | ... |
|
||||
| type_tracker.rb:14:5:14:13 | [post] ... = ... | type_tracker.rb:14:5:14:13 | [post] ... = ... |
|
||||
| type_tracker.rb:14:5:14:13 | __synth__0 | type_tracker.rb:14:5:14:13 | __synth__0 |
|
||||
| type_tracker.rb:14:5:14:13 | call to field= | type_tracker.rb:14:5:14:13 | call to field= |
|
||||
@@ -157,7 +162,6 @@ trackEnd
|
||||
| type_tracker.rb:15:5:15:18 | [post] self | type_tracker.rb:15:5:15:18 | [post] self |
|
||||
| type_tracker.rb:15:5:15:18 | call to puts | type_tracker.rb:12:1:16:3 | return return in m |
|
||||
| type_tracker.rb:15:5:15:18 | call to puts | type_tracker.rb:15:5:15:18 | call to puts |
|
||||
| type_tracker.rb:15:5:15:18 | self | type_tracker.rb:15:5:15:18 | self |
|
||||
| type_tracker.rb:15:10:15:12 | [post] var | type_tracker.rb:15:10:15:12 | [post] var |
|
||||
| type_tracker.rb:15:10:15:18 | [post] call to field | type_tracker.rb:15:10:15:18 | [post] call to field |
|
||||
| type_tracker.rb:15:10:15:18 | call to field | type_tracker.rb:15:10:15:18 | call to field |
|
||||
|
||||
@@ -45,9 +45,9 @@ potentiallyUnsafeSqlExecutingMethodCall
|
||||
| ActiveRecordInjection.rb:75:5:75:29 | call to order |
|
||||
| ActiveRecordInjection.rb:80:7:80:40 | call to find_by |
|
||||
activeRecordModelInstantiations
|
||||
| ActiveRecordInjection.rb:10:5:10:68 | self | ActiveRecordInjection.rb:5:1:17:3 | User |
|
||||
| ActiveRecordInjection.rb:8:3:11:5 | self (authenticate) | ActiveRecordInjection.rb:5:1:17:3 | User |
|
||||
| ActiveRecordInjection.rb:15:5:15:40 | call to find_by | ActiveRecordInjection.rb:1:1:3:3 | UserGroup |
|
||||
| ActiveRecordInjection.rb:23:5:23:25 | self | ActiveRecordInjection.rb:19:1:25:3 | Admin |
|
||||
| ActiveRecordInjection.rb:20:3:24:5 | self (delete_by) | ActiveRecordInjection.rb:19:1:25:3 | Admin |
|
||||
| ActiveRecordInjection.rb:80:7:80:40 | call to find_by | ActiveRecordInjection.rb:5:1:17:3 | User |
|
||||
| ActiveRecordInjection.rb:85:5:85:33 | call to find_by | ActiveRecordInjection.rb:5:1:17:3 | User |
|
||||
| ActiveRecordInjection.rb:88:5:88:34 | call to find | ActiveRecordInjection.rb:5:1:17:3 | User |
|
||||
|
||||
@@ -29,12 +29,14 @@ definition
|
||||
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self |
|
||||
| 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: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 |
|
||||
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client |
|
||||
| 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:16:16:18 | key | parameters.rb:16:16:16:18 | key |
|
||||
@@ -110,6 +112,7 @@ definition
|
||||
| ssa.rb:26:3:28:5 | <captured> | 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: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 |
|
||||
|
||||
Reference in New Issue
Block a user