mirror of
https://github.com/github/codeql.git
synced 2026-04-24 08:15:14 +02:00
Merge remote-tracking branch 'origin/main' into ruby/rails-cookie-config
This commit is contained in:
@@ -1 +1,20 @@
|
||||
import codeql.ruby.controlflow.internal.ControlFlowGraphImplShared::Consistency
|
||||
import codeql.ruby.AST
|
||||
import codeql.ruby.controlflow.internal.Completion
|
||||
import codeql.ruby.controlflow.internal.ControlFlowGraphImpl
|
||||
|
||||
/**
|
||||
* All `Expr` nodes are `PostOrderTree`s
|
||||
*/
|
||||
query predicate nonPostOrderExpr(Expr e, string cls) {
|
||||
cls = e.getPrimaryQlClasses() and
|
||||
not exists(e.getDesugared()) and
|
||||
not e instanceof BeginExpr and
|
||||
not e instanceof Namespace and
|
||||
not e instanceof Toplevel and
|
||||
exists(AstNode last, Completion c |
|
||||
last(e, last, c) and
|
||||
last != e and
|
||||
c instanceof NormalCompletion
|
||||
)
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ module API {
|
||||
* constructor is the function represented by this node.
|
||||
*
|
||||
* For example, if this node represents a use of some class `A`, then there might be a node
|
||||
* representing instances of `A`, typically corresponding to expressions `new A()` at the
|
||||
* representing instances of `A`, typically corresponding to expressions `A.new` at the
|
||||
* source level.
|
||||
*
|
||||
* This predicate may have multiple results when there are multiple constructor calls invoking this API component.
|
||||
@@ -244,7 +244,7 @@ module API {
|
||||
MkUse(DataFlow::Node nd) { isUse(nd) }
|
||||
|
||||
private string resolveTopLevel(ConstantReadAccess read) {
|
||||
TResolved(result) = resolveScopeExpr(read) and
|
||||
TResolved(result) = resolveConstantReadAccess(read) and
|
||||
not result.matches("%::%")
|
||||
}
|
||||
|
||||
|
||||
@@ -675,3 +675,32 @@ module CookieSecurityConfigurationSetting {
|
||||
abstract string getSecurityWarningMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node that logs data.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `Logging::Range` instead.
|
||||
*/
|
||||
class Logging extends DataFlow::Node {
|
||||
Logging::Range range;
|
||||
|
||||
Logging() { this = range }
|
||||
|
||||
/** Gets an input that is logged. */
|
||||
DataFlow::Node getAnInput() { result = range.getAnInput() }
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new logging mechanisms. */
|
||||
module Logging {
|
||||
/**
|
||||
* A data-flow node that logs data.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||
* extend `Logging` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/** Gets an input that is logged. */
|
||||
abstract DataFlow::Node getAnInput();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ class ConstantReadAccess extends ConstantAccess {
|
||||
this.hasGlobalScope() and
|
||||
result = lookupConst(TResolved("Object"), this.getName())
|
||||
or
|
||||
result = lookupConst(resolveScopeExpr(this.getScopeExpr()), this.getName())
|
||||
result = lookupConst(resolveConstantReadAccess(this.getScopeExpr()), this.getName())
|
||||
}
|
||||
|
||||
override string getValueText() { result = this.getValue().getValueText() }
|
||||
@@ -168,7 +168,7 @@ class ConstantWriteAccess extends ConstantAccess {
|
||||
override string getAPrimaryQlClass() { result = "ConstantWriteAccess" }
|
||||
|
||||
/**
|
||||
* Gets the fully qualified name for this constant, based on the context in
|
||||
* Gets a fully qualified name for this constant, based on the context in
|
||||
* which it is defined.
|
||||
*
|
||||
* For example, given
|
||||
@@ -184,17 +184,31 @@ class ConstantWriteAccess extends ConstantAccess {
|
||||
*
|
||||
* the constant `Baz` has the fully qualified name `Foo::Bar::Baz`, and
|
||||
* `CONST_A` has the fully qualified name `Foo::CONST_A`.
|
||||
*
|
||||
* Important note: This can return more than one value, because there are
|
||||
* situations where there can be multiple possible "fully qualified" names.
|
||||
* For example:
|
||||
* ```
|
||||
* module Mod4
|
||||
* include Mod1
|
||||
* module Mod3::Mod5 end
|
||||
* end
|
||||
* ```
|
||||
* In the above snippet, `Mod5` has two valid fully qualified names it can be
|
||||
* referred to by: `Mod1::Mod3::Mod5`, or `Mod4::Mod3::Mod5`.
|
||||
*
|
||||
* Another example has to do with the order in which module definitions are
|
||||
* executed at runtime. Because of the way that ruby dynamically looks up
|
||||
* constants up the namespace chain, the fully qualified name of a nested
|
||||
* constant can be ambiguous from just statically looking at the AST.
|
||||
*/
|
||||
string getQualifiedName() {
|
||||
/* get the qualified name for the parent module, then append w */
|
||||
exists(ConstantWriteAccess parent | parent = this.getEnclosingModule() |
|
||||
result = parent.getQualifiedName() + "::" + this.getName()
|
||||
)
|
||||
or
|
||||
/* base case - there's no parent module */
|
||||
not exists(ConstantWriteAccess parent | parent = this.getEnclosingModule()) and
|
||||
result = this.getName()
|
||||
}
|
||||
string getAQualifiedName() { result = resolveConstantWriteAccess(this) }
|
||||
|
||||
/**
|
||||
* Gets a qualified name for this constant. Deprecated in favor of
|
||||
* `getAQualifiedName` because this can return more than one value
|
||||
*/
|
||||
deprecated string getQualifiedName() { result = this.getAQualifiedName() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -102,7 +102,7 @@ class IfExpr extends ConditionalExpr, TIfExpr {
|
||||
cond = false and result = this.getElse()
|
||||
}
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getThen" and result = this.getThen()
|
||||
@@ -192,8 +192,8 @@ class UnlessExpr extends ConditionalExpr, TUnlessExpr {
|
||||
|
||||
final override string toString() { result = "unless ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = ConditionalExpr.super.getAChild(pred)
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getThen" and result = this.getThen()
|
||||
or
|
||||
@@ -229,8 +229,8 @@ class IfModifierExpr extends ConditionalExpr, TIfModifierExpr {
|
||||
|
||||
final override string toString() { result = "... if ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = ConditionalExpr.super.getAChild(pred)
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getBody" and result = this.getBody()
|
||||
}
|
||||
@@ -264,8 +264,8 @@ class UnlessModifierExpr extends ConditionalExpr, TUnlessModifierExpr {
|
||||
|
||||
final override string toString() { result = "... unless ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = ConditionalExpr.super.getAChild(pred)
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getBody" and result = this.getBody()
|
||||
}
|
||||
@@ -300,8 +300,8 @@ class TernaryIfExpr extends ConditionalExpr, TTernaryIfExpr {
|
||||
|
||||
final override string toString() { result = "... ? ... : ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = ConditionalExpr.super.getAChild(pred)
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getThen" and result = this.getThen()
|
||||
or
|
||||
@@ -361,22 +361,22 @@ class CaseExpr extends ControlExpr instanceof CaseExprImpl {
|
||||
final Expr getValue() { result = super.getValue() }
|
||||
|
||||
/**
|
||||
* Gets the `n`th branch of this case expression, either a `WhenExpr`, an
|
||||
* Gets the `n`th branch of this case expression, either a `WhenClause`, an
|
||||
* `InClause`, or a `StmtSequence`.
|
||||
*/
|
||||
final Expr getBranch(int n) { result = super.getBranch(n) }
|
||||
final AstNode getBranch(int n) { result = super.getBranch(n) }
|
||||
|
||||
/**
|
||||
* Gets a branch of this case expression, either a `WhenExpr`, an
|
||||
* Gets a branch of this case expression, either a `WhenClause`, an
|
||||
* `InClause`, or a `StmtSequence`.
|
||||
*/
|
||||
final Expr getABranch() { result = this.getBranch(_) }
|
||||
final AstNode getABranch() { result = this.getBranch(_) }
|
||||
|
||||
/** Gets the `n`th `when` branch of this case expression. */
|
||||
deprecated final WhenExpr getWhenBranch(int n) { result = this.getBranch(n) }
|
||||
deprecated final WhenClause getWhenBranch(int n) { result = this.getBranch(n) }
|
||||
|
||||
/** Gets a `when` branch of this case expression. */
|
||||
deprecated final WhenExpr getAWhenBranch() { result = this.getABranch() }
|
||||
deprecated final WhenClause getAWhenBranch() { result = this.getABranch() }
|
||||
|
||||
/** Gets the `else` branch of this case expression, if any. */
|
||||
final StmtSequence getElseBranch() { result = this.getABranch() }
|
||||
@@ -390,7 +390,7 @@ class CaseExpr extends ControlExpr instanceof CaseExprImpl {
|
||||
|
||||
final override string toString() { result = "case ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = ControlExpr.super.getAChild(pred)
|
||||
or
|
||||
pred = "getValue" and result = this.getValue()
|
||||
@@ -401,6 +401,11 @@ class CaseExpr extends ControlExpr instanceof CaseExprImpl {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `WhenClause` instead.
|
||||
*/
|
||||
deprecated class WhenExpr = WhenClause;
|
||||
|
||||
/**
|
||||
* A `when` branch of a `case` expression.
|
||||
* ```rb
|
||||
@@ -409,12 +414,12 @@ class CaseExpr extends ControlExpr instanceof CaseExprImpl {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class WhenExpr extends Expr, TWhenExpr {
|
||||
class WhenClause extends AstNode, TWhenClause {
|
||||
private Ruby::When g;
|
||||
|
||||
WhenExpr() { this = TWhenExpr(g) }
|
||||
WhenClause() { this = TWhenClause(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "WhenExpr" }
|
||||
final override string getAPrimaryQlClass() { result = "WhenClause" }
|
||||
|
||||
/** Gets the body of this case-when expression. */
|
||||
final Stmt getBody() { toGenerated(result) = g.getBody() }
|
||||
@@ -444,7 +449,7 @@ class WhenExpr extends Expr, TWhenExpr {
|
||||
|
||||
final override string toString() { result = "when ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getBody" and result = this.getBody()
|
||||
@@ -461,7 +466,7 @@ class WhenExpr extends Expr, TWhenExpr {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class InClause extends Expr, TInClause {
|
||||
class InClause extends AstNode, TInClause {
|
||||
private Ruby::InClause g;
|
||||
|
||||
InClause() { this = TInClause(g) }
|
||||
@@ -517,7 +522,7 @@ class InClause extends Expr, TInClause {
|
||||
|
||||
final override string toString() { result = "in ... then ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getBody" and result = this.getBody()
|
||||
@@ -552,7 +557,7 @@ class ConditionalLoop extends Loop, TConditionalLoop {
|
||||
Expr getCondition() { none() }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = Loop.super.getAChild(pred)
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getCondition" and result = this.getCondition()
|
||||
}
|
||||
@@ -692,7 +697,7 @@ class ForExpr extends Loop, TForExpr {
|
||||
final override StmtSequence getBody() { toGenerated(result) = g.getBody() }
|
||||
|
||||
/** Gets the pattern representing the iteration argument. */
|
||||
final Pattern getPattern() { toGenerated(result) = g.getPattern() }
|
||||
final LhsExpr getPattern() { toGenerated(result) = g.getPattern() }
|
||||
|
||||
/**
|
||||
* Gets the value being iterated over. In the following example, the result
|
||||
@@ -707,8 +712,8 @@ class ForExpr extends Loop, TForExpr {
|
||||
|
||||
final override string toString() { result = "for ... in ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = Loop.super.getAChild(pred)
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getPattern" and result = this.getPattern()
|
||||
or
|
||||
|
||||
@@ -118,7 +118,7 @@ private class ErbDirectiveFile extends File {
|
||||
|
||||
/** Gets a statement in this file. */
|
||||
pragma[nomagic]
|
||||
Stmt getAStmt(int startLine, int startColumn) {
|
||||
AstNode getAnAstNode(int startLine, int startColumn) {
|
||||
exists(Location loc |
|
||||
result.getLocation() = loc and
|
||||
loc.getFile() = this and
|
||||
@@ -142,13 +142,13 @@ class ErbDirective extends TDirectiveNode, ErbAstNode {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate containsStmtStart(Stmt s) {
|
||||
private predicate containsAstNodeStart(AstNode s) {
|
||||
// `Toplevel` statements are not contained within individual directives,
|
||||
// though their start location may appear within a directive location
|
||||
not s instanceof Toplevel and
|
||||
exists(ErbDirectiveFile file, int startLine, int startColumn |
|
||||
this.spans(file, startLine) and
|
||||
s = file.getAStmt(startLine, startColumn) and
|
||||
s = file.getAnAstNode(startLine, startColumn) and
|
||||
locationIncludesPosition(this.getLocation(), startLine, startColumn)
|
||||
)
|
||||
}
|
||||
@@ -158,8 +158,8 @@ class ErbDirective extends TDirectiveNode, ErbAstNode {
|
||||
* statement starting in this directive.
|
||||
*/
|
||||
Stmt getAChildStmt() {
|
||||
this.containsStmtStart(result) and
|
||||
not this.containsStmtStart(result.getParent())
|
||||
this.containsAstNodeStart(result) and
|
||||
not this.containsAstNodeStart(result.getParent())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -66,6 +66,87 @@ class ArgumentList extends Expr, TArgumentList {
|
||||
}
|
||||
}
|
||||
|
||||
private class LhsExpr_ =
|
||||
TVariableAccess or TTokenConstantAccess or TScopeResolutionConstantAccess or TMethodCall or
|
||||
TDestructuredLhsExpr;
|
||||
|
||||
/**
|
||||
* A "left-hand-side" (LHS) expression. An `LhsExpr` can occur on the left-hand side of
|
||||
* operator assignments (`AssignOperation`), on the left-hand side of assignments
|
||||
* (`AssignExpr`), as patterns in for loops (`ForExpr`), and as exception variables
|
||||
* in `rescue` clauses (`RescueClause`).
|
||||
*
|
||||
* An `LhsExpr` can be a simple variable, a constant, a call, or an element reference:
|
||||
*
|
||||
* ```rb
|
||||
* var = 1
|
||||
* var += 1
|
||||
* E = 1
|
||||
* foo.bar = 1
|
||||
* foo[0] = 1
|
||||
* rescue E => var
|
||||
* ```
|
||||
*/
|
||||
class LhsExpr extends Expr, LhsExpr_ {
|
||||
LhsExpr() { lhsExpr(this) }
|
||||
|
||||
/** Gets a variable used in (or introduced by) this LHS. */
|
||||
Variable getAVariable() { result = this.(VariableAccess).getVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A "left-hand-side" (LHS) expression of a destructured assignment.
|
||||
*
|
||||
* Examples:
|
||||
* ```rb
|
||||
* a, self.b = value
|
||||
* (a, b), c[3] = value
|
||||
* a, b, *rest, c, d = value
|
||||
* ```
|
||||
*/
|
||||
class DestructuredLhsExpr extends LhsExpr, TDestructuredLhsExpr {
|
||||
override string getAPrimaryQlClass() { result = "DestructuredLhsExpr" }
|
||||
|
||||
private DestructuredLhsExprImpl getImpl() { result = toGenerated(this) }
|
||||
|
||||
private Ruby::AstNode getChild(int i) { result = this.getImpl().getChildNode(i) }
|
||||
|
||||
/** Gets the `i`th element in this destructured LHS. */
|
||||
final Expr getElement(int i) {
|
||||
exists(Ruby::AstNode c | c = this.getChild(i) |
|
||||
toGenerated(result) = c.(Ruby::RestAssignment).getChild()
|
||||
or
|
||||
toGenerated(result) = c
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets an element in this destructured LHS. */
|
||||
final Expr getAnElement() { result = this.getElement(_) }
|
||||
|
||||
/**
|
||||
* Gets the index of the element with the `*` marker on it, if it exists.
|
||||
* In the example below the index is `2`.
|
||||
* ```rb
|
||||
* a, b, *rest, c, d = value
|
||||
* ```
|
||||
*/
|
||||
final int getRestIndex() { result = this.getImpl().getRestIndex() }
|
||||
|
||||
override Variable getAVariable() {
|
||||
result = this.getElement(_).(VariableWriteAccess).getVariable()
|
||||
or
|
||||
result = this.getElement(_).(DestructuredLhsExpr).getAVariable()
|
||||
}
|
||||
|
||||
override string toString() { result = "(..., ...)" }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getElement" and result = this.getElement(_)
|
||||
}
|
||||
}
|
||||
|
||||
/** A sequence of expressions. */
|
||||
class StmtSequence extends Expr, TStmtSequence {
|
||||
override string getAPrimaryQlClass() { result = "StmtSequence" }
|
||||
@@ -136,7 +217,7 @@ class BodyStmt extends StmtSequence, TBodyStmt {
|
||||
final predicate hasEnsure() { exists(this.getEnsure()) }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = StmtSequence.super.getAChild(pred)
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getRescue" and result = this.getRescue(_)
|
||||
or
|
||||
@@ -214,7 +295,7 @@ class Pair extends Expr, TPair {
|
||||
|
||||
final override string toString() { result = "Pair" }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getKey" and result = this.getKey()
|
||||
@@ -283,7 +364,7 @@ class RescueClause extends Expr, TRescueClause {
|
||||
|
||||
final override string toString() { result = "rescue ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getException" and result = this.getException(_)
|
||||
@@ -325,7 +406,7 @@ class RescueModifierExpr extends Expr, TRescueModifierExpr {
|
||||
|
||||
final override string toString() { result = "... rescue ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getBody" and result = this.getBody()
|
||||
@@ -386,7 +467,7 @@ class StringConcatenation extends Expr, TStringConcatenation {
|
||||
|
||||
final override string toString() { result = "\"...\" \"...\"" }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getString" and result = this.getString(_)
|
||||
|
||||
@@ -35,36 +35,59 @@ class MethodBase extends Callable, BodyStmt, Scope, TMethodBase {
|
||||
or
|
||||
result = BodyStmt.super.getAChild(pred)
|
||||
}
|
||||
|
||||
/** Holds if this method is private. */
|
||||
predicate isPrivate() { none() }
|
||||
}
|
||||
|
||||
/** A call to `private`. */
|
||||
private class Private extends MethodCall {
|
||||
Private() { this.getMethodName() = "private" }
|
||||
/**
|
||||
* A method call which modifies another method in some way.
|
||||
* For example, `private :foo` makes the method `foo` private.
|
||||
*/
|
||||
private class MethodModifier extends MethodCall {
|
||||
/** Gets the name of the method that this call applies to. */
|
||||
Expr getMethodArgument() { result = this.getArgument(0) }
|
||||
|
||||
/** Gets the method that this `private` call applies to, if any */
|
||||
Expr getMethod() { result = this.getArgument(0) }
|
||||
|
||||
/**
|
||||
* Holds if this `private` call happens inside `c`, and refers to a
|
||||
* method named `name`.
|
||||
*/
|
||||
/** Holds if this call modifies a method with name `name` in namespace `n`. */
|
||||
pragma[noinline]
|
||||
predicate isRef(ClassDeclaration c, string name) {
|
||||
this = c.getAStmt() and
|
||||
name = this.getMethod().(SymbolLiteral).getValueText()
|
||||
predicate modifiesMethod(Namespace n, string name) {
|
||||
this = n.getAStmt() and
|
||||
[
|
||||
this.getMethodArgument().(StringlikeLiteral).getValueText(),
|
||||
this.getMethodArgument().(MethodBase).getName()
|
||||
] = name
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this `private` call happens at position `i` inside `c`,
|
||||
* and the call has no arguments.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate hasNoArg(ClassDeclaration c, int i) {
|
||||
this = c.getStmt(i) and
|
||||
not exists(this.getMethod())
|
||||
/** A call to `private` or `private_class_method`. */
|
||||
private class Private extends MethodModifier {
|
||||
private Namespace namespace;
|
||||
private int position;
|
||||
|
||||
Private() { this.getMethodName() = "private" and namespace.getStmt(position) = this }
|
||||
|
||||
override predicate modifiesMethod(Namespace n, string name) {
|
||||
n = namespace and
|
||||
(
|
||||
// def foo
|
||||
// ...
|
||||
// private :foo
|
||||
super.modifiesMethod(n, name)
|
||||
or
|
||||
// private
|
||||
// ...
|
||||
// def foo
|
||||
not exists(this.getMethodArgument()) and
|
||||
exists(MethodBase m, int i | n.getStmt(i) = m and m.getName() = name and i > position)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to `private_class_method`. */
|
||||
private class PrivateClassMethod extends MethodModifier {
|
||||
PrivateClassMethod() { this.getMethodName() = "private_class_method" }
|
||||
}
|
||||
|
||||
/** A normal method. */
|
||||
class Method extends MethodBase, TMethod {
|
||||
private Ruby::Method g;
|
||||
@@ -90,12 +113,6 @@ class Method extends MethodBase, TMethod {
|
||||
*/
|
||||
final predicate isSetter() { g.getName() instanceof Ruby::Setter }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate isDeclaredIn(ClassDeclaration c, string name) {
|
||||
this = c.getAStmt() and
|
||||
name = this.getName()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this method is private. All methods with the name prefix
|
||||
* `private` are private below:
|
||||
@@ -122,18 +139,10 @@ class Method extends MethodBase, TMethod {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
predicate isPrivate() {
|
||||
this = any(Private p).getMethod()
|
||||
or
|
||||
exists(ClassDeclaration c, Private p, string name |
|
||||
this.isDeclaredIn(c, name) and
|
||||
p.isRef(c, name)
|
||||
)
|
||||
or
|
||||
exists(ClassDeclaration c, Private p, int i, int j |
|
||||
p.hasNoArg(c, i) and
|
||||
this = c.getStmt(j) and
|
||||
j > i
|
||||
override predicate isPrivate() {
|
||||
exists(Namespace n, string name |
|
||||
any(Private p).modifiesMethod(n, name) and
|
||||
isDeclaredIn(this, n, name)
|
||||
)
|
||||
or
|
||||
// Top-level methods are private members of the Object class
|
||||
@@ -147,6 +156,14 @@ class Method extends MethodBase, TMethod {
|
||||
final override string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the method `m` has name `name` and is declared in namespace `n`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate isDeclaredIn(MethodBase m, Namespace n, string name) {
|
||||
n = m.getEnclosingModule() and name = m.getName()
|
||||
}
|
||||
|
||||
/** A singleton method. */
|
||||
class SingletonMethod extends MethodBase, TSingletonMethod {
|
||||
private Ruby::SingletonMethod g;
|
||||
@@ -175,6 +192,36 @@ class SingletonMethod extends MethodBase, TSingletonMethod {
|
||||
or
|
||||
pred = "getObject" and result = this.getObject()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this method is private. All methods with the name prefix
|
||||
* `private` are private below:
|
||||
*
|
||||
* ```rb
|
||||
* class C
|
||||
* private_class_method def self.private1
|
||||
* end
|
||||
*
|
||||
* def self.public
|
||||
* end
|
||||
*
|
||||
* def self.private2
|
||||
* end
|
||||
* private_class_method :private2
|
||||
*
|
||||
* private # this has no effect on singleton methods
|
||||
*
|
||||
* def self.public2
|
||||
* end
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
override predicate isPrivate() {
|
||||
exists(Namespace n, string name |
|
||||
any(PrivateClassMethod p).modifiesMethod(n, name) and
|
||||
isDeclaredIn(this, n, name)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -443,14 +443,14 @@ class NoRegExpMatchExpr extends BinaryOperation, TNoRegExpMatchExpr {
|
||||
*/
|
||||
class Assignment extends Operation instanceof AssignmentImpl {
|
||||
/** Gets the left hand side of this assignment. */
|
||||
final Pattern getLeftOperand() { result = super.getLeftOperandImpl() }
|
||||
final LhsExpr getLeftOperand() { result = super.getLeftOperandImpl() }
|
||||
|
||||
/** Gets the right hand side of this assignment. */
|
||||
final Expr getRightOperand() { result = super.getRightOperandImpl() }
|
||||
|
||||
final override string toString() { result = "... " + this.getOperator() + " ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = Operation.super.getAChild(pred)
|
||||
or
|
||||
pred = "getLeftOperand" and result = this.getLeftOperand()
|
||||
|
||||
@@ -7,7 +7,14 @@ private import internal.TreeSitter
|
||||
/** A parameter. */
|
||||
class Parameter extends AstNode, TParameter {
|
||||
/** Gets the callable that this parameter belongs to. */
|
||||
final Callable getCallable() { result.getAParameter() = this }
|
||||
final Callable getCallable() {
|
||||
result.getAParameter() = this
|
||||
or
|
||||
exists(DestructuredParameter parent |
|
||||
this = parent.getAnElement() and
|
||||
result = parent.getCallable()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the zero-based position of this parameter. */
|
||||
final int getPosition() { this = any(Callable c).getParameter(result) }
|
||||
@@ -23,21 +30,63 @@ class Parameter extends AstNode, TParameter {
|
||||
}
|
||||
|
||||
/**
|
||||
* A parameter defined using destructuring. For example
|
||||
*
|
||||
* ```rb
|
||||
* def tuples((a,b))
|
||||
* puts "#{a} #{b}"
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class DestructuredParameter extends Parameter, TDestructuredParameter {
|
||||
private DestructuredParameterImpl getImpl() { result = toGenerated(this) }
|
||||
|
||||
private Ruby::AstNode getChild(int i) { result = this.getImpl().getChildNode(i) }
|
||||
|
||||
/** Gets the `i`th element in this destructured parameter. */
|
||||
final AstNode getElement(int i) {
|
||||
exists(Ruby::AstNode c | c = this.getChild(i) | toGenerated(result) = c)
|
||||
}
|
||||
|
||||
/** Gets an element in this destructured parameter. */
|
||||
final AstNode getAnElement() { result = this.getElement(_) }
|
||||
|
||||
override LocalVariable getAVariable() {
|
||||
result = this.getAnElement().(LocalVariableWriteAccess).getVariable()
|
||||
or
|
||||
result = this.getAnElement().(DestructuredParameter).getAVariable()
|
||||
}
|
||||
|
||||
override string toString() { result = "(..., ...)" }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = "getElement" and result = this.getElement(_)
|
||||
}
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "DestructuredParameter" }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED
|
||||
*
|
||||
* A parameter defined using a pattern.
|
||||
*
|
||||
* This includes both simple parameters and tuple parameters.
|
||||
*/
|
||||
class PatternParameter extends Parameter, Pattern, TPatternParameter {
|
||||
deprecated class PatternParameter extends Parameter, Pattern, TPatternParameter {
|
||||
override LocalVariable getAVariable() { result = Pattern.super.getAVariable() }
|
||||
}
|
||||
|
||||
/** A parameter defined using a tuple pattern. */
|
||||
class TuplePatternParameter extends PatternParameter, TuplePattern, TTuplePatternParameter {
|
||||
/**
|
||||
* DEPRECATED
|
||||
*
|
||||
* A parameter defined using a tuple pattern.
|
||||
*/
|
||||
deprecated class TuplePatternParameter extends PatternParameter, TuplePattern,
|
||||
TDestructuredParameter {
|
||||
final override LocalVariable getAVariable() { result = TuplePattern.super.getAVariable() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "TuplePatternParameter" }
|
||||
|
||||
override AstNode getAChild(string pred) { result = TuplePattern.super.getAChild(pred) }
|
||||
}
|
||||
|
||||
/** A named parameter. */
|
||||
@@ -72,7 +121,7 @@ class NamedParameter extends Parameter, TNamedParameter {
|
||||
}
|
||||
|
||||
/** A simple (normal) parameter. */
|
||||
class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern, TSimpleParameter instanceof SimpleParameterImpl {
|
||||
class SimpleParameter extends NamedParameter, TSimpleParameter instanceof SimpleParameterImpl {
|
||||
final override string getName() { result = SimpleParameterImpl.super.getNameImpl() }
|
||||
|
||||
final override LocalVariable getVariable() {
|
||||
|
||||
@@ -6,8 +6,12 @@ private import internal.TreeSitter
|
||||
private import internal.Variable
|
||||
private import internal.Parameter
|
||||
|
||||
/** A pattern. */
|
||||
class Pattern extends AstNode {
|
||||
/**
|
||||
* DEPRECATED
|
||||
*
|
||||
* A pattern.
|
||||
*/
|
||||
deprecated class Pattern extends AstNode {
|
||||
Pattern() {
|
||||
explicitAssignmentNode(toGenerated(this), _)
|
||||
or
|
||||
@@ -24,36 +28,18 @@ class Pattern extends AstNode {
|
||||
Variable getAVariable() { none() }
|
||||
}
|
||||
|
||||
private class LhsExpr_ =
|
||||
TVariableAccess or TTokenConstantAccess or TScopeResolutionConstantAccess or TMethodCall or
|
||||
TSimpleParameter;
|
||||
|
||||
/**
|
||||
* A "left-hand-side" expression. An `LhsExpr` can occur on the left-hand side of
|
||||
* operator assignments (`AssignOperation`), in patterns (`Pattern`) on the left-hand side of
|
||||
* an assignment (`AssignExpr`) or for loop (`ForExpr`), and as the exception
|
||||
* variable of a `rescue` clause (`RescueClause`).
|
||||
* DEPRECATED
|
||||
*
|
||||
* An `LhsExpr` can be a simple variable, a constant, a call, or an element reference:
|
||||
* ```rb
|
||||
* var = 1
|
||||
* var += 1
|
||||
* E = 1
|
||||
* foo.bar = 1
|
||||
* foo[0] = 1
|
||||
* rescue E => var
|
||||
* ```
|
||||
* A simple variable pattern.
|
||||
*/
|
||||
class LhsExpr extends Pattern, LhsExpr_, Expr {
|
||||
deprecated class VariablePattern extends Pattern, LhsExpr, TVariableAccess {
|
||||
override Variable getAVariable() { result = this.(VariableAccess).getVariable() }
|
||||
}
|
||||
|
||||
private class TVariablePattern = TVariableAccess or TSimpleParameter;
|
||||
|
||||
/** A simple variable pattern. */
|
||||
class VariablePattern extends Pattern, LhsExpr, TVariablePattern { }
|
||||
|
||||
/**
|
||||
* DEPRECATED
|
||||
*
|
||||
* A tuple pattern.
|
||||
*
|
||||
* This includes both tuple patterns in parameters and assignments. Example patterns:
|
||||
@@ -63,9 +49,7 @@ class VariablePattern extends Pattern, LhsExpr, TVariablePattern { }
|
||||
* a, b, *rest, c, d = value
|
||||
* ```
|
||||
*/
|
||||
class TuplePattern extends Pattern, TTuplePattern {
|
||||
override string getAPrimaryQlClass() { result = "TuplePattern" }
|
||||
|
||||
deprecated class TuplePattern extends Pattern, TTuplePattern {
|
||||
private TuplePatternImpl getImpl() { result = toGenerated(this) }
|
||||
|
||||
private Ruby::AstNode getChild(int i) { result = this.getImpl().getChildNode(i) }
|
||||
@@ -92,10 +76,6 @@ class TuplePattern extends Pattern, TTuplePattern {
|
||||
final int getRestIndex() { result = this.getImpl().getRestIndex() }
|
||||
|
||||
override Variable getAVariable() { result = this.getElement(_).getAVariable() }
|
||||
|
||||
override string toString() { result = "(..., ...)" }
|
||||
|
||||
override AstNode getAChild(string pred) { pred = "getElement" and result = this.getElement(_) }
|
||||
}
|
||||
|
||||
private class TPatternNode =
|
||||
|
||||
@@ -296,7 +296,7 @@ private module Cached {
|
||||
TTokenSuperCall(Ruby::Super g) { vcall(g) } or
|
||||
TToplevel(Ruby::Program g) or
|
||||
TTrueLiteral(Ruby::True g) or
|
||||
TTuplePatternParameter(Ruby::DestructuredParameter g) or
|
||||
TDestructuredParameter(Ruby::DestructuredParameter g) or
|
||||
TUnaryMinusExpr(Ruby::Unary g) { g instanceof @ruby_unary_minus } or
|
||||
TUnaryPlusExpr(Ruby::Unary g) { g instanceof @ruby_unary_plus } or
|
||||
TUndefStmt(Ruby::Undef g) or
|
||||
@@ -305,7 +305,7 @@ private module Cached {
|
||||
TUntilExpr(Ruby::Until g) or
|
||||
TUntilModifierExpr(Ruby::UntilModifier g) or
|
||||
TVariableReferencePattern(Ruby::VariableReferencePattern g) or
|
||||
TWhenExpr(Ruby::When g) or
|
||||
TWhenClause(Ruby::When g) or
|
||||
TWhileExpr(Ruby::While g) or
|
||||
TWhileModifierExpr(Ruby::WhileModifier g) or
|
||||
TYieldCall(Ruby::Yield g)
|
||||
@@ -321,9 +321,9 @@ private module Cached {
|
||||
TBraceBlockReal or TBreakStmt or TCaseEqExpr or TCaseExpr or TCaseMatch or
|
||||
TCharacterLiteral or TClassDeclaration or TClassVariableAccessReal or TComplementExpr or
|
||||
TComplexLiteral or TDefinedExpr or TDelimitedSymbolLiteral or TDestructuredLeftAssignment or
|
||||
TDivExprReal or TDo or TDoBlock or TElementReference or TElse or TElsif or TEmptyStmt or
|
||||
TEncoding or TEndBlock or TEnsure or TEqExpr or TExponentExprReal or TFalseLiteral or
|
||||
TFile or TFindPattern or TFloatLiteral or TForExpr or TForwardParameter or
|
||||
TDestructuredParameter or TDivExprReal or TDo or TDoBlock or TElementReference or TElse or
|
||||
TElsif or TEmptyStmt or TEncoding or TEndBlock or TEnsure or TEqExpr or TExponentExprReal or
|
||||
TFalseLiteral or TFile or TFindPattern or TFloatLiteral or TForExpr or TForwardParameter or
|
||||
TForwardArgument or TGEExpr or TGTExpr or TGlobalVariableAccessReal or
|
||||
THashKeySymbolLiteral or THashLiteral or THashPattern or THashSplatExpr or
|
||||
THashSplatNilParameter or THashSplatParameter or THereDoc or TIdentifierMethodCall or TIf or
|
||||
@@ -342,9 +342,9 @@ private module Cached {
|
||||
TStringConcatenation or TStringEscapeSequenceComponent or TStringInterpolationComponent or
|
||||
TStringTextComponent or TSubExprReal or TSubshellLiteral or TSymbolArrayLiteral or
|
||||
TTernaryIfExpr or TThen or TTokenConstantAccess or TTokenMethodName or TTokenSuperCall or
|
||||
TToplevel or TTrueLiteral or TTuplePatternParameter or TUnaryMinusExpr or TUnaryPlusExpr or
|
||||
TUndefStmt or TUnlessExpr or TUnlessModifierExpr or TUntilExpr or TUntilModifierExpr or
|
||||
TVariableReferencePattern or TWhenExpr or TWhileExpr or TWhileModifierExpr or TYieldCall;
|
||||
TToplevel or TTrueLiteral or TUnaryMinusExpr or TUnaryPlusExpr or TUndefStmt or
|
||||
TUnlessExpr or TUnlessModifierExpr or TUntilExpr or TUntilModifierExpr or
|
||||
TVariableReferencePattern or TWhenClause or TWhileExpr or TWhileModifierExpr or TYieldCall;
|
||||
|
||||
class TAstNodeSynth =
|
||||
TAddExprSynth or TAssignExprSynth or TBitwiseAndExprSynth or TBitwiseOrExprSynth or
|
||||
@@ -502,7 +502,7 @@ private module Cached {
|
||||
n = TTokenSuperCall(result) or
|
||||
n = TToplevel(result) or
|
||||
n = TTrueLiteral(result) or
|
||||
n = TTuplePatternParameter(result) or
|
||||
n = TDestructuredParameter(result) or
|
||||
n = TUnaryMinusExpr(result) or
|
||||
n = TUnaryPlusExpr(result) or
|
||||
n = TUndefStmt(result) or
|
||||
@@ -511,7 +511,7 @@ private module Cached {
|
||||
n = TUntilExpr(result) or
|
||||
n = TUntilModifierExpr(result) or
|
||||
n = TVariableReferencePattern(result) or
|
||||
n = TWhenExpr(result) or
|
||||
n = TWhenClause(result) or
|
||||
n = TWhileExpr(result) or
|
||||
n = TWhileModifierExpr(result) or
|
||||
n = TYieldCall(result)
|
||||
@@ -613,6 +613,15 @@ private module Cached {
|
||||
or
|
||||
result = toGenerated(n).getLocation()
|
||||
}
|
||||
|
||||
cached
|
||||
predicate lhsExpr(AST::Expr e) {
|
||||
explicitAssignmentNode(toGenerated(e), _)
|
||||
or
|
||||
implicitAssignmentNode(toGenerated(e))
|
||||
or
|
||||
e = getSynthChild(any(AST::AssignExpr ae), 0)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -645,11 +654,12 @@ class TLoop = TConditionalLoop or TForExpr;
|
||||
|
||||
class TSelf = TSelfReal or TSelfSynth;
|
||||
|
||||
class TDestructuredLhsExpr = TDestructuredLeftAssignment or TLeftAssignmentList;
|
||||
|
||||
class TExpr =
|
||||
TSelf or TArgumentList or TInClause or TRescueClause or TRescueModifierExpr or TPair or
|
||||
TStringConcatenation or TCall or TBlockArgument or TConstantAccess or TControlExpr or
|
||||
TWhenExpr or TLiteral or TCallable or TVariableAccess or TStmtSequence or TOperation or
|
||||
TSimpleParameter or TForwardArgument;
|
||||
TSelf or TArgumentList or TRescueClause or TRescueModifierExpr or TPair or TStringConcatenation or
|
||||
TCall or TBlockArgument or TConstantAccess or TControlExpr or TLiteral or TCallable or
|
||||
TVariableAccess or TStmtSequence or TOperation or TForwardArgument or TDestructuredLhsExpr;
|
||||
|
||||
class TSplatExpr = TSplatExprReal or TSplatExprSynth;
|
||||
|
||||
@@ -778,18 +788,20 @@ class TStmt =
|
||||
class TReturningStmt = TReturnStmt or TBreakStmt or TNextStmt;
|
||||
|
||||
class TParameter =
|
||||
TPatternParameter or TBlockParameter or THashSplatParameter or THashSplatNilParameter or
|
||||
TKeywordParameter or TOptionalParameter or TSplatParameter or TForwardParameter;
|
||||
TSimpleParameter or TDestructuredParameter or TBlockParameter or THashSplatParameter or
|
||||
THashSplatNilParameter or TKeywordParameter or TOptionalParameter or TSplatParameter or
|
||||
TForwardParameter;
|
||||
|
||||
class TSimpleParameter = TSimpleParameterReal or TSimpleParameterSynth;
|
||||
|
||||
class TPatternParameter = TSimpleParameter or TTuplePatternParameter;
|
||||
deprecated class TPatternParameter = TSimpleParameter or TDestructuredParameter;
|
||||
|
||||
class TNamedParameter =
|
||||
TSimpleParameter or TBlockParameter or THashSplatParameter or TKeywordParameter or
|
||||
TOptionalParameter or TSplatParameter;
|
||||
|
||||
class TTuplePattern = TTuplePatternParameter or TDestructuredLeftAssignment or TLeftAssignmentList;
|
||||
deprecated class TTuplePattern =
|
||||
TDestructuredParameter or TDestructuredLeftAssignment or TLeftAssignmentList;
|
||||
|
||||
class TVariableAccess =
|
||||
TLocalVariableAccess or TGlobalVariableAccess or TInstanceVariableAccess or
|
||||
|
||||
@@ -5,17 +5,17 @@ private import codeql.ruby.ast.internal.AST
|
||||
abstract class CaseExprImpl extends ControlExpr, TCase {
|
||||
abstract Expr getValue();
|
||||
|
||||
abstract Expr getBranch(int n);
|
||||
abstract AstNode getBranch(int n);
|
||||
}
|
||||
|
||||
class CaseWhenExpr extends CaseExprImpl, TCaseExpr {
|
||||
class CaseWhenClause extends CaseExprImpl, TCaseExpr {
|
||||
private Ruby::Case g;
|
||||
|
||||
CaseWhenExpr() { this = TCaseExpr(g) }
|
||||
CaseWhenClause() { this = TCaseExpr(g) }
|
||||
|
||||
final override Expr getValue() { toGenerated(result) = g.getValue() }
|
||||
|
||||
final override Expr getBranch(int n) {
|
||||
final override AstNode getBranch(int n) {
|
||||
toGenerated(result) = g.getChild(n) or
|
||||
toGenerated(result) = g.getChild(n)
|
||||
}
|
||||
@@ -28,7 +28,7 @@ class CaseMatch extends CaseExprImpl, TCaseMatch {
|
||||
|
||||
final override Expr getValue() { toGenerated(result) = g.getValue() }
|
||||
|
||||
final override Expr getBranch(int n) {
|
||||
final override AstNode getBranch(int n) {
|
||||
toGenerated(result) = g.getClauses(n)
|
||||
or
|
||||
n = count(g.getClauses(_)) and toGenerated(result) = g.getElse()
|
||||
|
||||
@@ -73,3 +73,29 @@ Ruby::AstNode getBodyStmtChild(TBodyStmt b, int i) {
|
||||
or
|
||||
result = any(Ruby::Begin g | b = TBeginExpr(g)).getChild(i)
|
||||
}
|
||||
|
||||
abstract class DestructuredLhsExprImpl extends Ruby::AstNode {
|
||||
abstract Ruby::AstNode getChildNode(int i);
|
||||
|
||||
final int getRestIndex() {
|
||||
result = unique(int i | this.getChildNode(i) instanceof Ruby::RestAssignment)
|
||||
}
|
||||
}
|
||||
|
||||
class DestructuredLeftAssignmentImpl extends DestructuredLhsExprImpl,
|
||||
Ruby::DestructuredLeftAssignment {
|
||||
override Ruby::AstNode getChildNode(int i) { result = this.getChild(i) }
|
||||
}
|
||||
|
||||
class LeftAssignmentListImpl extends DestructuredLhsExprImpl, Ruby::LeftAssignmentList {
|
||||
override Ruby::AstNode getChildNode(int i) {
|
||||
this =
|
||||
any(Ruby::LeftAssignmentList lal |
|
||||
if
|
||||
strictcount(int j | exists(lal.getChild(j))) = 1 and
|
||||
lal.getChild(0) instanceof Ruby::DestructuredLeftAssignment
|
||||
then result = lal.getChild(0).(Ruby::DestructuredLeftAssignment).getChild(i)
|
||||
else result = lal.getChild(i)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ private module Cached {
|
||||
result = scopeAppend(namespaceDeclaration(n.getEnclosingModule()), n.getName())
|
||||
or
|
||||
exists(string container |
|
||||
TResolved(container) = resolveScopeExpr(n.getScopeExpr()) and
|
||||
TResolved(container) = resolveConstantReadAccess(n.getScopeExpr()) and
|
||||
result = scopeAppend(container, n.getName())
|
||||
)
|
||||
}
|
||||
@@ -58,29 +58,33 @@ private module Cached {
|
||||
(
|
||||
exists(ClassDeclaration d |
|
||||
d = cls.getADeclaration() and
|
||||
result = resolveScopeExpr(d.getSuperclassExpr())
|
||||
result = resolveConstantReadAccess(d.getSuperclassExpr())
|
||||
)
|
||||
or
|
||||
result = TResolved("Object") and
|
||||
forex(ClassDeclaration d | d = cls.getADeclaration() |
|
||||
not exists(resolveScopeExpr(d.getSuperclassExpr()))
|
||||
not exists(resolveConstantReadAccess(d.getSuperclassExpr()))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private Module getACludedModule(IncludeOrPrependCall c, Module m) {
|
||||
(
|
||||
m = resolveConstantReadAccess(c.getReceiver())
|
||||
or
|
||||
m = enclosingModule(c).getModule() and
|
||||
c.getReceiver() instanceof Self
|
||||
) and
|
||||
result = resolveConstantReadAccess(c.getAnArgument())
|
||||
}
|
||||
|
||||
cached
|
||||
Module getAnIncludedModule(Module m) {
|
||||
m = TResolved("Object") and result = TResolved("Kernel")
|
||||
or
|
||||
exists(IncludeOrPrependCall c |
|
||||
c.getMethodName() = "include" and
|
||||
(
|
||||
m = resolveScopeExpr(c.getReceiver())
|
||||
or
|
||||
m = enclosingModule(c).getModule() and
|
||||
c.getReceiver() instanceof Self
|
||||
) and
|
||||
result = resolveScopeExpr(c.getAnArgument())
|
||||
result = getACludedModule(c, m)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -88,13 +92,7 @@ private module Cached {
|
||||
Module getAPrependedModule(Module m) {
|
||||
exists(IncludeOrPrependCall c |
|
||||
c.getMethodName() = "prepend" and
|
||||
(
|
||||
m = resolveScopeExpr(c.getReceiver())
|
||||
or
|
||||
m = enclosingModule(c).getModule() and
|
||||
c.getReceiver() instanceof Self
|
||||
) and
|
||||
result = resolveScopeExpr(c.getAnArgument())
|
||||
result = getACludedModule(c, m)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -102,13 +100,13 @@ private module Cached {
|
||||
* Resolve class or module read access to a qualified module name.
|
||||
*/
|
||||
cached
|
||||
TResolved resolveScopeExpr(ConstantReadAccess r) {
|
||||
TResolved resolveConstantReadAccess(ConstantReadAccess r) {
|
||||
exists(string qname | qname = resolveConstant(r) and result = TResolved(qname))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string constantDefinition1(ConstantReadAccess r) {
|
||||
exists(ConstantWriteAccess w | result = constantDefinition0(w) |
|
||||
private string constantWriteAccess1(ConstantReadAccess r) {
|
||||
exists(ConstantWriteAccess w | result = resolveConstantWriteAccess(w) |
|
||||
r = w.getScopeExpr()
|
||||
or
|
||||
r = w.(ClassDeclaration).getSuperclassExpr()
|
||||
@@ -117,8 +115,8 @@ private module Cached {
|
||||
|
||||
/**
|
||||
* Resolve constant access (class, module or otherwise) to a qualified module name.
|
||||
* `resolveScopeExpr/1` picks the best (lowest priority number) result of
|
||||
* `resolveScopeExpr/2` that resolves to a constant definition. If the constant
|
||||
* `resolveConstantReadAccess/1` picks the best (lowest priority number) result of
|
||||
* `resolveConstantReadAccess/2` that resolves to a constant definition. If the constant
|
||||
* definition is a Namespace then it is returned, if it's a constant assignment then
|
||||
* the right-hand side of the assignment is resolved.
|
||||
*/
|
||||
@@ -127,10 +125,10 @@ private module Cached {
|
||||
exists(string qname |
|
||||
qname =
|
||||
min(string qn, int p |
|
||||
isDefinedConstant(qn) and
|
||||
qn = resolveScopeExpr(r, p) and
|
||||
qn = isDefinedConstant(_, _) and
|
||||
qn = resolveConstantReadAccess(r, p) and
|
||||
// prevent classes/modules that contain/extend themselves
|
||||
not qn = constantDefinition1(r)
|
||||
not qn = constantWriteAccess1(r)
|
||||
|
|
||||
qn order by p
|
||||
)
|
||||
@@ -138,7 +136,7 @@ private module Cached {
|
||||
result = qname
|
||||
or
|
||||
exists(ConstantAssignment a |
|
||||
qname = constantDefinition0(a) and
|
||||
qname = resolveConstantWriteAccess(a) and
|
||||
result = resolveConstant(a.getParent().(Assignment).getRightOperand())
|
||||
)
|
||||
)
|
||||
@@ -154,7 +152,7 @@ private module Cached {
|
||||
exists(AssignExpr ae, ConstantWriteAccess w |
|
||||
w = ae.getLeftOperand() and
|
||||
w.getName() = name and
|
||||
m = resolveScopeExpr(w.getScopeExpr()) and
|
||||
m = resolveConstantReadAccess(w.getScopeExpr()) and
|
||||
result = ae.getRightOperand()
|
||||
)
|
||||
}
|
||||
@@ -171,141 +169,313 @@ private predicate isToplevel(ConstantAccess n) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isDefinedConstant(string qualifiedModuleName) {
|
||||
qualifiedModuleName = [builtin(), constantDefinition0(_)]
|
||||
}
|
||||
|
||||
private int maxDepth() { result = 1 + max(int level | exists(enclosing(_, level))) }
|
||||
|
||||
private ModuleBase enclosing(ModuleBase m, int level) {
|
||||
result = m and level = 0
|
||||
or
|
||||
result = enclosing(m.getEnclosingModule(), level - 1)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private Namespace enclosingNameSpaceConstantReadAccess(
|
||||
ConstantReadAccess c, int priority, string name
|
||||
) {
|
||||
result = enclosing(c.getEnclosingModule(), priority) and
|
||||
name = c.getName()
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve constant read access (typically a scope expression) to a qualified name. The
|
||||
* `priority` value indicates the precedence of the solution with respect to the lookup order.
|
||||
* A constant name without scope specifier is resolved against its enclosing modules (inner-most first);
|
||||
* if the constant is not found in any of the enclosing modules, then the constant will be resolved
|
||||
* with respect to the ancestors (prepends, includes, super classes, and their ancestors) of the
|
||||
* directly enclosing module.
|
||||
*/
|
||||
private string resolveScopeExpr(ConstantReadAccess c, int priority) {
|
||||
c.hasGlobalScope() and result = c.getName() and priority = 0
|
||||
or
|
||||
exists(string name |
|
||||
result = qualifiedModuleName(resolveScopeExprConstantReadAccess(c, priority, name), name)
|
||||
)
|
||||
or
|
||||
not exists(c.getScopeExpr()) and
|
||||
not c.hasGlobalScope() and
|
||||
(
|
||||
exists(string name |
|
||||
exists(Namespace n |
|
||||
n = enclosingNameSpaceConstantReadAccess(c, priority, name) and
|
||||
result = qualifiedModuleName(constantDefinition0(n), name)
|
||||
)
|
||||
or
|
||||
result =
|
||||
qualifiedModuleName(ancestors(qualifiedModuleNameConstantReadAccess(c, name),
|
||||
priority - maxDepth()), name)
|
||||
)
|
||||
or
|
||||
priority = maxDepth() + 4 and
|
||||
qualifiedModuleNameConstantReadAccess(c, result) != "BasicObject"
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string resolveScopeExprConstantReadAccess(ConstantReadAccess c, int priority, string name) {
|
||||
result = resolveScopeExpr(c.getScopeExpr(), priority) and
|
||||
name = c.getName()
|
||||
}
|
||||
|
||||
bindingset[qualifier, name]
|
||||
private string scopeAppend(string qualifier, string name) {
|
||||
if qualifier = "Object" then result = name else result = qualifier + "::" + name
|
||||
}
|
||||
|
||||
private string qualifiedModuleName(ModuleBase m) {
|
||||
result = "Object" and m instanceof Toplevel
|
||||
or
|
||||
result = constantDefinition0(m)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private string qualifiedModuleNameConstantWriteAccess(ConstantWriteAccess c, string name) {
|
||||
result = qualifiedModuleName(c.getEnclosingModule()) and
|
||||
name = c.getName()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private string qualifiedModuleNameConstantReadAccess(ConstantReadAccess c, string name) {
|
||||
result = qualifiedModuleName(c.getEnclosingModule()) and
|
||||
name = c.getName()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a qualified name for a constant definition. May return multiple qualified
|
||||
* names because we over-approximate when resolving scope resolutions and ignore
|
||||
* lookup order precedence. Taking lookup order into account here would lead to
|
||||
* non-monotonic recursion.
|
||||
* Provides predicates for resolving constant reads and writes to qualified names.
|
||||
*
|
||||
* Predicates suffixed with `NonRec` means that they do not depend recursively on
|
||||
* `resolveConstantReadAccess`, while predicates suffixed with `Rec` do. This serves
|
||||
* both as a performance optimization (minimize non-linear recursion), and as a way
|
||||
* to prevent infinite recursion.
|
||||
*/
|
||||
private string constantDefinition0(ConstantWriteAccess c) {
|
||||
c.hasGlobalScope() and result = c.getName()
|
||||
or
|
||||
result = scopeAppend(resolveScopeExpr(c.getScopeExpr(), _), c.getName())
|
||||
or
|
||||
not exists(c.getScopeExpr()) and
|
||||
not c.hasGlobalScope() and
|
||||
exists(string name | result = scopeAppend(qualifiedModuleNameConstantWriteAccess(c, name), name))
|
||||
}
|
||||
|
||||
/**
|
||||
* The qualified names of the ancestors of a class/module. The ancestors should be an ordered list
|
||||
* of the ancestores of `prepend`ed modules, the module itself , the ancestors or `include`d modules
|
||||
* and the ancestors of the super class. The priority value only distinguishes the kind of ancestor,
|
||||
* it does not order the ancestors within a group of the same kind. This is an over-approximation, however,
|
||||
* computing the precise order is tricky because it depends on the evaluation/file loading order.
|
||||
*/
|
||||
// TODO: the order of super classes can be determined more precisely even without knowing the evaluation
|
||||
// order, so we should be able to make this more precise.
|
||||
private string ancestors(string qname, int priority) {
|
||||
result = ancestors(prepends(qname), _) and priority = 0
|
||||
or
|
||||
result = qname and priority = 1 and isDefinedConstant(qname)
|
||||
or
|
||||
result = ancestors(includes(qname), _) and priority = 2
|
||||
or
|
||||
result = ancestors(superclass(qname), _) and priority = 3
|
||||
}
|
||||
|
||||
private class IncludeOrPrependCall extends MethodCall {
|
||||
IncludeOrPrependCall() { this.getMethodName() = ["include", "prepend"] }
|
||||
|
||||
string getAModule() { result = resolveScopeExpr(this.getAnArgument(), _) }
|
||||
|
||||
string getTarget() {
|
||||
result = resolveScopeExpr(this.getReceiver(), _)
|
||||
private module ResolveImpl {
|
||||
private ModuleBase enclosing(ModuleBase m, int level) {
|
||||
result = m and level = 0
|
||||
or
|
||||
result = qualifiedModuleName(enclosingModule(this)) and
|
||||
(
|
||||
this.getReceiver() instanceof Self
|
||||
result = enclosing(m.getEnclosingModule(), level - 1)
|
||||
}
|
||||
|
||||
private int maxDepth() { result = 1 + max(int level | exists(enclosing(_, level))) }
|
||||
|
||||
pragma[noinline]
|
||||
private Namespace constantReadAccessEnclosingNameSpace(
|
||||
ConstantReadAccess c, int priority, string name
|
||||
) {
|
||||
not exists(c.getScopeExpr()) and
|
||||
not c.hasGlobalScope() and
|
||||
result = enclosing(c.getEnclosingModule(), priority) and
|
||||
name = c.getName()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string enclosingQualifiedModuleNameNonRec(ConstantReadAccess c, string name) {
|
||||
result = qualifiedModuleNameNonRec(c.getEnclosingModule(), _, _) and
|
||||
name = c.getName() and
|
||||
not exists(c.getScopeExpr()) and
|
||||
not c.hasGlobalScope()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string enclosingQualifiedModuleNameRec(ConstantReadAccess c, string name) {
|
||||
result = qualifiedModuleNameRec(c.getEnclosingModule(), _, _) and
|
||||
name = c.getName() and
|
||||
not exists(c.getScopeExpr()) and
|
||||
not c.hasGlobalScope()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string resolveConstantReadAccessScopeNonRec(
|
||||
ConstantReadAccess c, int priority, string name
|
||||
) {
|
||||
result = resolveConstantReadAccessNonRec(c.getScopeExpr(), priority) and
|
||||
name = c.getName()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string resolveConstantReadAccessScopeRec(ConstantReadAccess c, int priority, string name) {
|
||||
result = resolveConstantReadAccessRec(c.getScopeExpr(), priority) and
|
||||
name = c.getName()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string resolveConstantReadAccessNonRec(ConstantReadAccess c, int priority) {
|
||||
c.hasGlobalScope() and result = c.getName() and priority = 0
|
||||
or
|
||||
exists(string name, string s | result = isDefinedConstantNonRec(s, name) |
|
||||
s = resolveConstantReadAccessScopeNonRec(c, priority, name)
|
||||
)
|
||||
or
|
||||
exists(string name |
|
||||
exists(Namespace n, string qname |
|
||||
n = constantReadAccessEnclosingNameSpace(c, priority, name) and
|
||||
qname = resolveConstantWriteAccessNonRec(n, _, _) and
|
||||
result = isDefinedConstantNonRec(qname, name)
|
||||
)
|
||||
)
|
||||
or
|
||||
priority = maxDepth() + 4 and
|
||||
enclosingQualifiedModuleNameNonRec(c, result) != "BasicObject"
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string resolveConstantReadAccessRec(ConstantReadAccess c, int priority) {
|
||||
exists(string name, string s |
|
||||
result = isDefinedConstantRec(s, name) and
|
||||
s = resolveConstantReadAccessScopeNonRec(c, priority, name)
|
||||
or
|
||||
not exists(this.getReceiver())
|
||||
result = isDefinedConstant(s, name) and
|
||||
s = resolveConstantReadAccessScopeRec(c, priority, name)
|
||||
)
|
||||
or
|
||||
exists(string name |
|
||||
exists(Namespace n, string qname |
|
||||
n = constantReadAccessEnclosingNameSpace(c, priority, name)
|
||||
|
|
||||
qname = resolveConstantWriteAccess(n) and
|
||||
result = isDefinedConstantRec(qname, name)
|
||||
or
|
||||
qname = resolveConstantWriteAccessRec(n, _, _) and
|
||||
result = isDefinedConstantNonRec(qname, name)
|
||||
)
|
||||
or
|
||||
exists(string encl | result = qualifiedModuleNameAncestors(encl, name, priority) |
|
||||
encl = enclosingQualifiedModuleNameNonRec(c, name)
|
||||
or
|
||||
encl = enclosingQualifiedModuleNameRec(c, name)
|
||||
)
|
||||
)
|
||||
or
|
||||
priority = maxDepth() + 4 and
|
||||
enclosingQualifiedModuleNameRec(c, result) != "BasicObject"
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve constant read access (typically a scope expression) to a qualified name. The
|
||||
* `priority` value indicates the precedence of the solution with respect to the lookup order.
|
||||
* A constant name without scope specifier is resolved against its enclosing modules (inner-most first);
|
||||
* if the constant is not found in any of the enclosing modules, then the constant will be resolved
|
||||
* with respect to the ancestors (prepends, includes, super classes, and their ancestors) of the
|
||||
* directly enclosing module.
|
||||
*/
|
||||
string resolveConstantReadAccess(ConstantReadAccess c, int priority) {
|
||||
result = resolveConstantReadAccessNonRec(c, priority)
|
||||
or
|
||||
result = resolveConstantReadAccessRec(c, priority)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string qualifiedModuleNameNonRec(ModuleBase m, string container, string name) {
|
||||
result = "Object" and
|
||||
m instanceof Toplevel and
|
||||
container = "" and
|
||||
name = result
|
||||
or
|
||||
result = resolveConstantWriteAccessNonRec(m, container, name)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string qualifiedModuleNameRec(ModuleBase m, string container, string name) {
|
||||
result = resolveConstantWriteAccessRec(m, container, name)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string qualifiedModuleNameResolveConstantWriteAccessNonRec(
|
||||
ConstantWriteAccess c, string name
|
||||
) {
|
||||
result = qualifiedModuleNameNonRec(c.getEnclosingModule(), _, _) and
|
||||
name = c.getName()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string qualifiedModuleNameResolveConstantWriteAccessRec(ConstantWriteAccess c, string name) {
|
||||
result = qualifiedModuleNameRec(c.getEnclosingModule(), _, _) and
|
||||
name = c.getName()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string resolveConstantWriteAccessNonRec(
|
||||
ConstantWriteAccess c, string container, string name
|
||||
) {
|
||||
c.hasGlobalScope() and
|
||||
result = c.getName() and
|
||||
container = "" and
|
||||
name = result
|
||||
or
|
||||
result = scopeAppend(container, name) and
|
||||
(
|
||||
container = resolveConstantReadAccessNonRec(c.getScopeExpr(), _) and name = c.getName()
|
||||
or
|
||||
not exists(c.getScopeExpr()) and
|
||||
not c.hasGlobalScope() and
|
||||
container = qualifiedModuleNameResolveConstantWriteAccessNonRec(c, name)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string resolveConstantWriteAccessRec(ConstantWriteAccess c, string container, string name) {
|
||||
result = scopeAppend(container, name) and
|
||||
(
|
||||
container = resolveConstantReadAccessRec(c.getScopeExpr(), _) and name = c.getName()
|
||||
or
|
||||
not exists(c.getScopeExpr()) and
|
||||
not c.hasGlobalScope() and
|
||||
container = qualifiedModuleNameResolveConstantWriteAccessRec(c, name)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a qualified name for a constant definition. May return multiple qualified
|
||||
* names because we over-approximate when resolving scope resolutions and ignore
|
||||
* lookup order precedence. Taking lookup order into account here would lead to
|
||||
* non-monotonic recursion.
|
||||
*/
|
||||
pragma[inline]
|
||||
string resolveConstantWriteAccess(ConstantWriteAccess c) {
|
||||
result = resolveConstantWriteAccessNonRec(c, _, _)
|
||||
or
|
||||
result = resolveConstantWriteAccessRec(c, _, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string isDefinedConstantNonRec(string container, string name) {
|
||||
result = resolveConstantWriteAccessNonRec(_, container, name)
|
||||
or
|
||||
result = builtin() and
|
||||
name = result and
|
||||
container = "Object"
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string isDefinedConstantRec(string container, string name) {
|
||||
result = resolveConstantWriteAccessRec(_, container, name)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
string isDefinedConstant(string container, string name) {
|
||||
result = isDefinedConstantNonRec(container, name)
|
||||
or
|
||||
result = isDefinedConstantRec(container, name)
|
||||
}
|
||||
|
||||
/**
|
||||
* The qualified names of the ancestors of a class/module. The ancestors should be an ordered list
|
||||
* of the ancestores of `prepend`ed modules, the module itself , the ancestors or `include`d modules
|
||||
* and the ancestors of the super class. The priority value only distinguishes the kind of ancestor,
|
||||
* it does not order the ancestors within a group of the same kind. This is an over-approximation, however,
|
||||
* computing the precise order is tricky because it depends on the evaluation/file loading order.
|
||||
*/
|
||||
// TODO: the order of super classes can be determined more precisely even without knowing the evaluation
|
||||
// order, so we should be able to make this more precise.
|
||||
private string ancestors(string qname, int priority) {
|
||||
result = ancestors(prepends(qname), _) and priority = 0
|
||||
or
|
||||
result = qname and priority = 1 and qname = isDefinedConstant(_, _)
|
||||
or
|
||||
result = ancestors(includes(qname), _) and priority = 2
|
||||
or
|
||||
result = ancestors(superclass(qname), _) and priority = 3
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string qualifiedModuleNameAncestors(string encl, string name, int priority) {
|
||||
result = isDefinedConstantNonRec(encl, name) and
|
||||
priority = 1
|
||||
or
|
||||
// avoid infinite recursion
|
||||
not exists(isDefinedConstantNonRec(encl, name)) and
|
||||
result = isDefinedConstant(ancestors(encl, priority - maxDepth()), name)
|
||||
}
|
||||
|
||||
class IncludeOrPrependCall extends MethodCall {
|
||||
IncludeOrPrependCall() { this.getMethodName() = ["include", "prepend"] }
|
||||
|
||||
string getAModule() { result = resolveConstantReadAccess(this.getAnArgument(), _) }
|
||||
|
||||
string getTarget() {
|
||||
result = resolveConstantReadAccess(this.getReceiver(), _)
|
||||
or
|
||||
exists(ModuleBase encl |
|
||||
encl = enclosingModule(this) and
|
||||
result = [qualifiedModuleNameNonRec(encl, _, _), qualifiedModuleNameRec(encl, _, _)]
|
||||
|
|
||||
this.getReceiver() instanceof Self
|
||||
or
|
||||
not exists(this.getReceiver())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string prepends(string qname) {
|
||||
exists(IncludeOrPrependCall m |
|
||||
m.getMethodName() = "prepend" and
|
||||
qname = m.getTarget() and
|
||||
result = m.getAModule()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string includes(string qname) {
|
||||
qname = "Object" and
|
||||
result = "Kernel"
|
||||
or
|
||||
exists(IncludeOrPrependCall m |
|
||||
m.getMethodName() = "include" and
|
||||
qname = m.getTarget() and
|
||||
result = m.getAModule()
|
||||
)
|
||||
}
|
||||
|
||||
private Expr superexpr(string qname) {
|
||||
exists(ClassDeclaration c |
|
||||
qname = resolveConstantWriteAccess(c) and result = c.getSuperclassExpr()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string superclass(string qname) {
|
||||
qname = "Object" and result = "BasicObject"
|
||||
or
|
||||
result = resolveConstantReadAccess(superexpr(qname), _)
|
||||
}
|
||||
}
|
||||
|
||||
import ResolveImpl
|
||||
|
||||
/**
|
||||
* A variant of AstNode::getEnclosingModule that excludes
|
||||
* results that are enclosed in a block. This is a bit wrong because
|
||||
@@ -323,45 +493,6 @@ private AstNode parent(AstNode n) {
|
||||
not result instanceof Block
|
||||
}
|
||||
|
||||
private string prepends(string qname) {
|
||||
exists(IncludeOrPrependCall m |
|
||||
m.getMethodName() = "prepend" and
|
||||
qname = m.getTarget() and
|
||||
result = m.getAModule()
|
||||
)
|
||||
}
|
||||
|
||||
private string includes(string qname) {
|
||||
qname = "Object" and
|
||||
result = "Kernel"
|
||||
or
|
||||
exists(IncludeOrPrependCall m |
|
||||
m.getMethodName() = "include" and
|
||||
qname = m.getTarget() and
|
||||
result = m.getAModule()
|
||||
)
|
||||
}
|
||||
|
||||
private Expr superexpr(string qname) {
|
||||
exists(ClassDeclaration c | qname = constantDefinition0(c) and result = c.getSuperclassExpr())
|
||||
}
|
||||
|
||||
private string superclass(string qname) {
|
||||
qname = "Object" and result = "BasicObject"
|
||||
or
|
||||
result = resolveScopeExpr(superexpr(qname), _)
|
||||
}
|
||||
|
||||
private string qualifiedModuleName(string container, string name) {
|
||||
isDefinedConstant(result) and
|
||||
(
|
||||
container = result.regexpCapture("(.+)::([^:]+)", 1) and
|
||||
name = result.regexpCapture("(.+)::([^:]+)", 2)
|
||||
or
|
||||
container = "Object" and name = result
|
||||
)
|
||||
}
|
||||
|
||||
private Module getAncestors(Module m) {
|
||||
result = m or
|
||||
result = getAncestors(m.getAnIncludedModule()) or
|
||||
|
||||
@@ -154,7 +154,7 @@ class BitwiseXorSynthExpr extends BinaryOperationSynth, TBitwiseXorExprSynth {
|
||||
}
|
||||
|
||||
abstract class AssignmentImpl extends OperationImpl, TAssignment {
|
||||
abstract Pattern getLeftOperandImpl();
|
||||
abstract Expr getLeftOperandImpl();
|
||||
|
||||
abstract Expr getRightOperandImpl();
|
||||
|
||||
@@ -172,7 +172,7 @@ class AssignExprReal extends AssignmentImpl, TAssignExprReal {
|
||||
|
||||
final override string getOperatorImpl() { result = "=" }
|
||||
|
||||
final override Pattern getLeftOperandImpl() { toGenerated(result) = g.getLeft() }
|
||||
final override Expr getLeftOperandImpl() { toGenerated(result) = g.getLeft() }
|
||||
|
||||
final override Expr getRightOperandImpl() { toGenerated(result) = g.getRight() }
|
||||
}
|
||||
@@ -180,7 +180,7 @@ class AssignExprReal extends AssignmentImpl, TAssignExprReal {
|
||||
class AssignExprSynth extends AssignmentImpl, TAssignExprSynth {
|
||||
final override string getOperatorImpl() { result = "=" }
|
||||
|
||||
final override Pattern getLeftOperandImpl() { synthChild(this, 0, result) }
|
||||
final override Expr getLeftOperandImpl() { synthChild(this, 0, result) }
|
||||
|
||||
final override Expr getRightOperandImpl() { synthChild(this, 1, result) }
|
||||
}
|
||||
@@ -192,7 +192,7 @@ class AssignOperationImpl extends AssignmentImpl, TAssignOperation {
|
||||
|
||||
final override string getOperatorImpl() { result = g.getOperator() }
|
||||
|
||||
final override Pattern getLeftOperandImpl() { toGenerated(result) = g.getLeft() }
|
||||
final override Expr getLeftOperandImpl() { toGenerated(result) = g.getLeft() }
|
||||
|
||||
final override Expr getRightOperandImpl() { toGenerated(result) = g.getRight() }
|
||||
}
|
||||
|
||||
@@ -44,3 +44,7 @@ class SimpleParameterSynthImpl extends SimpleParameterImpl, TSimpleParameterSynt
|
||||
|
||||
override string getNameImpl() { result = this.getVariableImpl().getName() }
|
||||
}
|
||||
|
||||
class DestructuredParameterImpl extends Ruby::DestructuredParameter {
|
||||
Ruby::AstNode getChildNode(int i) { result = this.getChild(i) }
|
||||
}
|
||||
|
||||
@@ -1,36 +1,28 @@
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.ast.internal.Expr
|
||||
private import codeql.ruby.ast.internal.Parameter
|
||||
private import AST
|
||||
private import TreeSitter
|
||||
|
||||
abstract class TuplePatternImpl extends Ruby::AstNode {
|
||||
abstract Ruby::AstNode getChildNode(int i);
|
||||
deprecated class TuplePatternImpl extends Ruby::AstNode {
|
||||
TuplePatternImpl() {
|
||||
this instanceof DestructuredParameterImpl or
|
||||
this instanceof DestructuredLhsExprImpl
|
||||
}
|
||||
|
||||
Ruby::AstNode getChildNode(int i) {
|
||||
result =
|
||||
[
|
||||
this.(DestructuredParameterImpl).getChildNode(i),
|
||||
this.(DestructuredLhsExprImpl).getChildNode(i)
|
||||
]
|
||||
}
|
||||
|
||||
final int getRestIndex() {
|
||||
result = unique(int i | this.getChildNode(i) instanceof Ruby::RestAssignment)
|
||||
}
|
||||
}
|
||||
|
||||
class TuplePatternParameterImpl extends TuplePatternImpl, Ruby::DestructuredParameter {
|
||||
override Ruby::AstNode getChildNode(int i) { result = this.getChild(i) }
|
||||
}
|
||||
|
||||
class DestructuredLeftAssignmentImpl extends TuplePatternImpl, Ruby::DestructuredLeftAssignment {
|
||||
override Ruby::AstNode getChildNode(int i) { result = this.getChild(i) }
|
||||
}
|
||||
|
||||
class LeftAssignmentListImpl extends TuplePatternImpl, Ruby::LeftAssignmentList {
|
||||
override Ruby::AstNode getChildNode(int i) {
|
||||
this =
|
||||
any(Ruby::LeftAssignmentList lal |
|
||||
if
|
||||
strictcount(int j | exists(lal.getChild(j))) = 1 and
|
||||
lal.getChild(0) instanceof Ruby::DestructuredLeftAssignment
|
||||
then result = lal.getChild(0).(Ruby::DestructuredLeftAssignment).getChild(i)
|
||||
else result = lal.getChild(i)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is a case pattern.
|
||||
*/
|
||||
|
||||
@@ -636,36 +636,36 @@ private module AssignOperationDesugar {
|
||||
}
|
||||
}
|
||||
|
||||
private module CompoundAssignDesugar {
|
||||
/** An assignment where the left-hand side is a tuple pattern. */
|
||||
private class TupleAssignExpr extends AssignExpr {
|
||||
private TuplePattern tp;
|
||||
private module DestructuredAssignDesugar {
|
||||
/** A destructured assignment. */
|
||||
private class DestructuredAssignExpr extends AssignExpr {
|
||||
private DestructuredLhsExpr lhs;
|
||||
|
||||
pragma[nomagic]
|
||||
TupleAssignExpr() { tp = this.getLeftOperand() }
|
||||
DestructuredAssignExpr() { lhs = this.getLeftOperand() }
|
||||
|
||||
TuplePattern getTuplePattern() { result = tp }
|
||||
DestructuredLhsExpr getLhs() { result = lhs }
|
||||
|
||||
pragma[nomagic]
|
||||
Pattern getElement(int i) { result = tp.getElement(i) }
|
||||
Expr getElement(int i) { result = lhs.getElement(i) }
|
||||
|
||||
pragma[nomagic]
|
||||
int getNumberOfElements() {
|
||||
toGenerated(tp) = any(TuplePatternImpl impl | result = count(impl.getChildNode(_)))
|
||||
toGenerated(lhs) = any(DestructuredLhsExprImpl impl | result = count(impl.getChildNode(_)))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
int getRestIndexOrNumberOfElements() {
|
||||
result = tp.getRestIndex()
|
||||
result = lhs.getRestIndex()
|
||||
or
|
||||
toGenerated(tp) = any(TuplePatternImpl impl | not exists(impl.getRestIndex())) and
|
||||
toGenerated(lhs) = any(DestructuredLhsExprImpl impl | not exists(impl.getRestIndex())) and
|
||||
result = this.getNumberOfElements()
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate compoundAssignSynthesis(AstNode parent, int i, Child child) {
|
||||
exists(TupleAssignExpr tae |
|
||||
private predicate destructuredAssignSynthesis(AstNode parent, int i, Child child) {
|
||||
exists(DestructuredAssignExpr tae |
|
||||
parent = tae and
|
||||
i = -1 and
|
||||
child = SynthChild(StmtSequenceKind())
|
||||
@@ -689,8 +689,8 @@ private module CompoundAssignDesugar {
|
||||
child = childRef(tae.getRightOperand())
|
||||
)
|
||||
or
|
||||
exists(Pattern p, int j, int restIndex |
|
||||
p = tae.getElement(j) and
|
||||
exists(AstNode elem, int j, int restIndex |
|
||||
elem = tae.getElement(j) and
|
||||
restIndex = tae.getRestIndexOrNumberOfElements()
|
||||
|
|
||||
parent = seq and
|
||||
@@ -700,7 +700,7 @@ private module CompoundAssignDesugar {
|
||||
exists(AstNode assign | assign = TAssignExprSynth(seq, j + 1) |
|
||||
parent = assign and
|
||||
i = 0 and
|
||||
child = childRef(p)
|
||||
child = childRef(elem)
|
||||
or
|
||||
parent = assign and
|
||||
i = 1 and
|
||||
@@ -756,26 +756,26 @@ private module CompoundAssignDesugar {
|
||||
* z = __synth__0[-1];
|
||||
* ```
|
||||
*/
|
||||
private class CompoundAssignSynthesis extends Synthesis {
|
||||
private class DestructuredAssignSynthesis extends Synthesis {
|
||||
final override predicate child(AstNode parent, int i, Child child) {
|
||||
compoundAssignSynthesis(parent, i, child)
|
||||
destructuredAssignSynthesis(parent, i, child)
|
||||
}
|
||||
|
||||
final override predicate location(AstNode n, Location l) {
|
||||
exists(TupleAssignExpr tae, StmtSequence seq | seq = tae.getDesugared() |
|
||||
exists(DestructuredAssignExpr tae, StmtSequence seq | seq = tae.getDesugared() |
|
||||
n = seq.getStmt(0) and
|
||||
hasLocation(tae.getRightOperand(), l)
|
||||
or
|
||||
exists(Pattern p, int j |
|
||||
p = tae.getElement(j) and
|
||||
exists(AstNode elem, int j |
|
||||
elem = tae.getElement(j) and
|
||||
n = seq.getStmt(j + 1) and
|
||||
hasLocation(p, l)
|
||||
hasLocation(elem, l)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate localVariable(AstNode n, int i) {
|
||||
n instanceof TupleAssignExpr and
|
||||
n instanceof DestructuredAssignExpr and
|
||||
i = 0
|
||||
}
|
||||
|
||||
@@ -784,10 +784,6 @@ private module CompoundAssignDesugar {
|
||||
setter = false and
|
||||
arity = 1
|
||||
}
|
||||
|
||||
final override predicate excludeFromControlFlowTree(AstNode n) {
|
||||
n = any(TupleAssignExpr tae).getTuplePattern()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -820,7 +816,7 @@ private module ArrayLiteralDesugar {
|
||||
* ::Array.[](1, 2, 3)
|
||||
* ```
|
||||
*/
|
||||
private class CompoundAssignSynthesis extends Synthesis {
|
||||
private class ArrayLiteralSynthesis extends Synthesis {
|
||||
final override predicate child(AstNode parent, int i, Child child) {
|
||||
arrayLiteralSynthesis(parent, i, child)
|
||||
}
|
||||
|
||||
@@ -338,7 +338,7 @@ module ExprNodes {
|
||||
}
|
||||
|
||||
private class CaseExprChildMapping extends ExprChildMapping, CaseExpr {
|
||||
override predicate relevantChild(Expr e) { e = this.getValue() or e = this.getBranch(_) }
|
||||
override predicate relevantChild(Expr e) { e = this.getValue() }
|
||||
}
|
||||
|
||||
/** A control-flow node that wraps a `MethodCall` AST expression. */
|
||||
@@ -356,11 +356,6 @@ module ExprNodes {
|
||||
|
||||
/** Gets the expression being compared, if any. */
|
||||
final ExprCfgNode getValue() { e.hasCfgChild(e.getValue(), this, result) }
|
||||
|
||||
/**
|
||||
* Gets the `n`th branch of this case expression.
|
||||
*/
|
||||
final ExprCfgNode getBranch(int n) { e.hasCfgChild(e.getBranch(n), this, result) }
|
||||
}
|
||||
|
||||
private class ConditionalExprChildMapping extends ExprChildMapping, ConditionalExpr {
|
||||
|
||||
@@ -23,7 +23,7 @@ private newtype TCompletion =
|
||||
TRetryCompletion() or
|
||||
TRaiseCompletion() or // TODO: Add exception type?
|
||||
TExitCompletion() or
|
||||
TNestedCompletion(Completion inner, Completion outer, int nestLevel) {
|
||||
TNestedCompletion(TCompletion inner, TCompletion outer, int nestLevel) {
|
||||
inner = TBreakCompletion() and
|
||||
outer instanceof NonNestedNormalCompletion and
|
||||
nestLevel = 0
|
||||
@@ -37,7 +37,7 @@ private newtype TCompletion =
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nestedEnsureCompletion(Completion outer, int nestLevel) {
|
||||
private predicate nestedEnsureCompletion(TCompletion outer, int nestLevel) {
|
||||
(
|
||||
outer = TReturnCompletion()
|
||||
or
|
||||
@@ -107,11 +107,7 @@ abstract class Completion extends TCompletion {
|
||||
n = any(RescueModifierExpr parent).getBody() and
|
||||
this = [TSimpleCompletion().(TCompletion), TRaiseCompletion()]
|
||||
or
|
||||
(
|
||||
mayRaise(n)
|
||||
or
|
||||
n instanceof CaseMatch and not exists(n.(CaseExpr).getElseBranch())
|
||||
) and
|
||||
mayRaise(n) and
|
||||
(
|
||||
this = TRaiseCompletion()
|
||||
or
|
||||
@@ -209,7 +205,7 @@ private predicate inBooleanContext(AstNode n) {
|
||||
or
|
||||
n = any(StmtSequence parent | inBooleanContext(parent)).getLastStmt()
|
||||
or
|
||||
exists(CaseExpr c, WhenExpr w |
|
||||
exists(CaseExpr c, WhenClause w |
|
||||
not exists(c.getValue()) and
|
||||
c.getABranch() = w and
|
||||
w.getPattern(_) = n
|
||||
@@ -231,7 +227,7 @@ private predicate mustHaveMatchingCompletion(AstNode n) {
|
||||
private predicate inMatchingContext(AstNode n) {
|
||||
n = any(RescueClause r).getException(_)
|
||||
or
|
||||
exists(CaseExpr c, WhenExpr w |
|
||||
exists(CaseExpr c, WhenClause w |
|
||||
exists(c.getValue()) and
|
||||
c.getABranch() = w and
|
||||
w.getPattern(_) = n
|
||||
|
||||
@@ -107,14 +107,8 @@ module Trees {
|
||||
}
|
||||
}
|
||||
|
||||
private class ArgumentListTree extends StandardTree, ArgumentList {
|
||||
private class ArgumentListTree extends StandardPostOrderTree, ArgumentList {
|
||||
final override ControlFlowTree getChildElement(int i) { result = this.getElement(i) }
|
||||
|
||||
final override predicate first(AstNode first) { first(this.getFirstChildElement(), first) }
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
last(this.getLastChildElement(), last, c)
|
||||
}
|
||||
}
|
||||
|
||||
private class AssignExprTree extends StandardPostOrderTree, AssignExpr {
|
||||
@@ -252,7 +246,7 @@ module Trees {
|
||||
)
|
||||
or
|
||||
// Last element from any matching `rescue` block continues to the `ensure` block
|
||||
this.getRescue(_).(RescueTree).lastMatch(result, c) and
|
||||
last(this.getRescue(_), result, c) and
|
||||
ensurable = true
|
||||
or
|
||||
// If the last `rescue` block does not match, continue to the `ensure` block
|
||||
@@ -378,35 +372,18 @@ module Trees {
|
||||
override ControlFlowTree getChildElement(int i) { result = this.getArgument(i) }
|
||||
}
|
||||
|
||||
private class CaseTree extends PreOrderTree, CaseExpr, ASTInternal::TCaseExpr {
|
||||
private class CaseTree extends PostOrderTree, CaseExpr, ASTInternal::TCaseExpr {
|
||||
final override predicate propagatesAbnormal(AstNode child) {
|
||||
child = this.getValue() or child = this.getABranch()
|
||||
}
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
last(this.getValue(), last, c) and not exists(this.getABranch())
|
||||
final override predicate first(AstNode first) {
|
||||
first(this.getValue(), first)
|
||||
or
|
||||
last(this.getABranch().(WhenExpr).getBody(), last, c)
|
||||
or
|
||||
exists(int i, ControlFlowTree lastBranch |
|
||||
lastBranch = this.getBranch(i) and
|
||||
not exists(this.getBranch(i + 1)) and
|
||||
last(lastBranch, last, c)
|
||||
)
|
||||
not exists(this.getValue()) and first(this.getBranch(0), first)
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
exists(AstNode next |
|
||||
pred = this and
|
||||
first(next, succ) and
|
||||
c instanceof SimpleCompletion
|
||||
|
|
||||
next = this.getValue()
|
||||
or
|
||||
not exists(this.getValue()) and
|
||||
next = this.getBranch(0)
|
||||
)
|
||||
or
|
||||
last(this.getValue(), pred, c) and
|
||||
first(this.getBranch(0), succ) and
|
||||
c instanceof SimpleCompletion
|
||||
@@ -416,20 +393,35 @@ module Trees {
|
||||
first(this.getBranch(i + 1), succ) and
|
||||
c.(ConditionalCompletion).getValue() = false
|
||||
)
|
||||
or
|
||||
succ = this and
|
||||
c instanceof NormalCompletion and
|
||||
(
|
||||
last(this.getValue(), pred, c) and not exists(this.getABranch())
|
||||
or
|
||||
last(this.getABranch().(WhenClause).getBody(), pred, c)
|
||||
or
|
||||
exists(int i, ControlFlowTree lastBranch |
|
||||
lastBranch = this.getBranch(i) and
|
||||
not exists(this.getBranch(i + 1)) and
|
||||
last(lastBranch, pred, c)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class CaseMatchTree extends PreOrderTree, CaseExpr, ASTInternal::TCaseMatch {
|
||||
private class CaseMatchTree extends PostOrderTree, CaseExpr, ASTInternal::TCaseMatch {
|
||||
final override predicate propagatesAbnormal(AstNode child) {
|
||||
child = this.getValue() or child = this.getABranch()
|
||||
}
|
||||
|
||||
final override predicate first(AstNode first) { first(this.getValue(), first) }
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
last(this.getABranch(), last, c) and
|
||||
not c.(MatchingCompletion).getValue() = false
|
||||
super.last(last, c)
|
||||
or
|
||||
not exists(this.getElseBranch()) and
|
||||
exists(MatchingCompletion lc, Expr lastBranch |
|
||||
exists(MatchingCompletion lc, AstNode lastBranch |
|
||||
lastBranch = max(int i | | this.getBranch(i) order by i) and
|
||||
lc.getValue() = false and
|
||||
last(lastBranch, last, lc) and
|
||||
@@ -439,19 +431,24 @@ module Trees {
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
pred = this and
|
||||
first(this.getValue(), succ) and
|
||||
c instanceof SimpleCompletion
|
||||
or
|
||||
last(this.getValue(), pred, c) and
|
||||
first(this.getBranch(0), succ) and
|
||||
c instanceof SimpleCompletion
|
||||
or
|
||||
exists(int i, Expr branch | branch = this.getBranch(i) |
|
||||
exists(int i, AstNode branch | branch = this.getBranch(i) |
|
||||
last(branch, pred, c) and
|
||||
first(this.getBranch(i + 1), succ) and
|
||||
c.(MatchingCompletion).getValue() = false
|
||||
)
|
||||
or
|
||||
succ = this and
|
||||
c instanceof NormalCompletion and
|
||||
(
|
||||
last(this.getABranch(), pred, c) and
|
||||
not c.(MatchingCompletion).getValue() = false
|
||||
or
|
||||
last(this.getElseBranch(), pred, c)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -935,6 +932,10 @@ module Trees {
|
||||
}
|
||||
}
|
||||
|
||||
private class DestructuredParameterTree extends StandardPostOrderTree, DestructuredParameter {
|
||||
final override ControlFlowTree getChildElement(int i) { result = this.getElement(i) }
|
||||
}
|
||||
|
||||
private class DesugaredTree extends ControlFlowTree {
|
||||
ControlFlowTree desugared;
|
||||
|
||||
@@ -977,6 +978,8 @@ module Trees {
|
||||
}
|
||||
}
|
||||
|
||||
private class ForwardedArgumentsTree extends LeafTree, ForwardedArguments { }
|
||||
|
||||
private class ForwardParameterTree extends LeafTree, ForwardParameter { }
|
||||
|
||||
private class GlobalVariableTree extends LeafTree, GlobalVariableAccess { }
|
||||
@@ -989,7 +992,7 @@ module Trees {
|
||||
|
||||
private class HashSplatParameterTree extends NonDefaultValueParameterTree, HashSplatParameter { }
|
||||
|
||||
private class HereDocTree extends StandardPreOrderTree, HereDoc {
|
||||
private class HereDocTree extends StandardPostOrderTree, HereDoc {
|
||||
final override ControlFlowTree getChildElement(int i) { result = this.getComponent(i) }
|
||||
}
|
||||
|
||||
@@ -1151,90 +1154,70 @@ module Trees {
|
||||
|
||||
private class RedoStmtTree extends LeafTree, RedoStmt { }
|
||||
|
||||
private class RescueModifierTree extends PreOrderTree, RescueModifierExpr {
|
||||
private class RescueModifierTree extends PostOrderTree, RescueModifierExpr {
|
||||
final override predicate propagatesAbnormal(AstNode child) { child = this.getHandler() }
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
last(this.getBody(), last, c) and
|
||||
not c instanceof RaiseCompletion
|
||||
or
|
||||
last(this.getHandler(), last, c)
|
||||
}
|
||||
final override predicate first(AstNode first) { first(this.getBody(), first) }
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
pred = this and
|
||||
first(this.getBody(), succ) and
|
||||
c instanceof SimpleCompletion
|
||||
or
|
||||
last(this.getBody(), pred, c) and
|
||||
c instanceof RaiseCompletion and
|
||||
first(this.getHandler(), succ)
|
||||
(
|
||||
c instanceof RaiseCompletion and
|
||||
first(this.getHandler(), succ)
|
||||
or
|
||||
not c instanceof RaiseCompletion and
|
||||
succ = this
|
||||
)
|
||||
or
|
||||
last(this.getHandler(), pred, c) and
|
||||
c instanceof NormalCompletion and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
|
||||
private class RescueTree extends PreOrderTree, RescueClause {
|
||||
final override predicate propagatesAbnormal(AstNode child) { child = this.getAnException() }
|
||||
|
||||
private Expr getLastException() {
|
||||
exists(int i | result = this.getException(i) and not exists(this.getException(i + 1)))
|
||||
private class RescueTree extends PostOrderTree, RescueClause {
|
||||
final override predicate propagatesAbnormal(AstNode child) {
|
||||
child = this.getAnException() or
|
||||
child = this.getBody()
|
||||
}
|
||||
|
||||
predicate lastMatch(AstNode last, Completion c) {
|
||||
last(this.getBody(), last, c)
|
||||
final override predicate first(AstNode first) {
|
||||
first(this.getException(0), first)
|
||||
or
|
||||
not exists(this.getBody()) and
|
||||
not exists(this.getException(0)) and
|
||||
(
|
||||
last(this.getVariableExpr(), last, c)
|
||||
first(this.getVariableExpr(), first)
|
||||
or
|
||||
not exists(this.getVariableExpr()) and
|
||||
(
|
||||
last(this.getAnException(), last, c) and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
first(this.getBody(), first)
|
||||
or
|
||||
not exists(this.getAnException()) and
|
||||
last = this and
|
||||
c.isValidFor(this)
|
||||
not exists(this.getBody()) and first = this
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private Expr getLastException() {
|
||||
exists(int i | result = this.getException(i) and not exists(this.getException(i + 1)))
|
||||
}
|
||||
|
||||
predicate lastNoMatch(AstNode last, Completion c) {
|
||||
last(this.getLastException(), last, c) and
|
||||
c.(MatchingCompletion).getValue() = false
|
||||
}
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
this.lastNoMatch(last, c)
|
||||
or
|
||||
this.lastMatch(last, c)
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
exists(AstNode next |
|
||||
pred = this and
|
||||
first(next, succ) and
|
||||
c instanceof SimpleCompletion
|
||||
|
|
||||
next = this.getException(0)
|
||||
or
|
||||
not exists(this.getException(0)) and
|
||||
(
|
||||
next = this.getVariableExpr()
|
||||
or
|
||||
not exists(this.getVariableExpr()) and
|
||||
next = this.getBody()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(AstNode next |
|
||||
last(this.getAnException(), pred, c) and
|
||||
first(next, succ) and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
|
|
||||
next = this.getVariableExpr()
|
||||
last(this.getAnException(), pred, c) and
|
||||
c.(MatchingCompletion).getValue() = true and
|
||||
(
|
||||
first(this.getVariableExpr(), succ)
|
||||
or
|
||||
not exists(this.getVariableExpr()) and
|
||||
next = this.getBody()
|
||||
(
|
||||
first(this.getBody(), succ)
|
||||
or
|
||||
not exists(this.getBody()) and succ = this
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(int i |
|
||||
@@ -1244,8 +1227,16 @@ module Trees {
|
||||
)
|
||||
or
|
||||
last(this.getVariableExpr(), pred, c) and
|
||||
first(this.getBody(), succ) and
|
||||
c instanceof NormalCompletion
|
||||
c instanceof NormalCompletion and
|
||||
(
|
||||
first(this.getBody(), succ)
|
||||
or
|
||||
not exists(this.getBody()) and succ = this
|
||||
)
|
||||
or
|
||||
last(this.getBody(), pred, c) and
|
||||
c instanceof NormalCompletion and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1349,14 +1340,8 @@ module Trees {
|
||||
}
|
||||
}
|
||||
|
||||
private class StringConcatenationTree extends StandardTree, StringConcatenation {
|
||||
private class StringConcatenationTree extends StandardPostOrderTree, StringConcatenation {
|
||||
final override ControlFlowTree getChildElement(int i) { result = this.getString(i) }
|
||||
|
||||
final override predicate first(AstNode first) { first(this.getFirstChildElement(), first) }
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
last(this.getLastChildElement(), last, c)
|
||||
}
|
||||
}
|
||||
|
||||
private class StringlikeLiteralTree extends StandardPostOrderTree, StringlikeLiteral {
|
||||
@@ -1381,15 +1366,11 @@ module Trees {
|
||||
}
|
||||
}
|
||||
|
||||
private class TuplePatternTree extends StandardPostOrderTree, TuplePattern {
|
||||
final override ControlFlowTree getChildElement(int i) { result = this.getElement(i) }
|
||||
}
|
||||
|
||||
private class UndefStmtTree extends StandardPreOrderTree, UndefStmt {
|
||||
final override ControlFlowTree getChildElement(int i) { result = this.getMethodName(i) }
|
||||
}
|
||||
|
||||
private class WhenTree extends PreOrderTree, WhenExpr {
|
||||
private class WhenTree extends PreOrderTree, WhenClause {
|
||||
final override predicate propagatesAbnormal(AstNode child) { child = this.getAPattern() }
|
||||
|
||||
final Expr getLastPattern() {
|
||||
|
||||
@@ -23,10 +23,10 @@ module SummaryComponent {
|
||||
predicate content = SC::content/1;
|
||||
|
||||
/** Gets a summary component that represents a qualifier. */
|
||||
SummaryComponent qualifier() { result = argument(-1) }
|
||||
SummaryComponent qualifier() { result = argument(any(ParameterPosition pos | pos.isSelf())) }
|
||||
|
||||
/** Gets a summary component that represents a block argument. */
|
||||
SummaryComponent block() { result = argument(-2) }
|
||||
SummaryComponent block() { result = argument(any(ParameterPosition pos | pos.isBlock())) }
|
||||
|
||||
/** Gets a summary component that represents the return value of a call. */
|
||||
SummaryComponent return() { result = SC::return(any(NormalReturnKind rk)) }
|
||||
@@ -102,10 +102,10 @@ abstract class SummarizedCallable extends LibraryCallable {
|
||||
|
||||
/**
|
||||
* Holds if values stored inside `content` are cleared on objects passed as
|
||||
* the `i`th argument to this callable.
|
||||
* arguments at position `pos` to this callable.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate clearsContent(int i, DataFlow::Content content) { none() }
|
||||
predicate clearsContent(ParameterPosition pos, DataFlow::Content content) { none() }
|
||||
}
|
||||
|
||||
private class SummarizedCallableAdapter extends Impl::Public::SummarizedCallable {
|
||||
@@ -119,8 +119,8 @@ private class SummarizedCallableAdapter extends Impl::Public::SummarizedCallable
|
||||
sc.propagatesFlow(input, output, preservesValue)
|
||||
}
|
||||
|
||||
final override predicate clearsContent(ParameterPosition i, DataFlow::Content content) {
|
||||
sc.clearsContent(i, content)
|
||||
final override predicate clearsContent(ParameterPosition pos, DataFlow::Content content) {
|
||||
sc.clearsContent(pos, content)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ private import DataFlowPrivate
|
||||
private import codeql.ruby.typetracking.TypeTracker
|
||||
private import codeql.ruby.ast.internal.Module
|
||||
private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
|
||||
private import codeql.ruby.dataflow.FlowSummary
|
||||
|
||||
newtype TReturnKind =
|
||||
@@ -230,6 +231,30 @@ private module Cached {
|
||||
result = yieldCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TArgumentPosition =
|
||||
TSelfArgumentPosition() or
|
||||
TBlockArgumentPosition() or
|
||||
TPositionalArgumentPosition(int pos) {
|
||||
exists(Call c | exists(c.getArgument(pos)))
|
||||
or
|
||||
FlowSummaryImplSpecific::ParsePositions::isParsedParameterPosition(_, pos)
|
||||
} or
|
||||
TKeywordArgumentPosition(string name) { name = any(KeywordParameter kp).getName() }
|
||||
|
||||
cached
|
||||
newtype TParameterPosition =
|
||||
TSelfParameterPosition() or
|
||||
TBlockParameterPosition() or
|
||||
TPositionalParameterPosition(int pos) {
|
||||
pos = any(Parameter p).getPosition()
|
||||
or
|
||||
pos in [0 .. 10] // TODO: remove once `Argument[_]` summaries are replaced with `Argument[i..]`
|
||||
or
|
||||
FlowSummaryImplSpecific::ParsePositions::isParsedArgumentPosition(_, pos)
|
||||
} or
|
||||
TKeywordParameterPosition(string name) { name = any(KeywordParameter kp).getName() }
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -400,7 +425,7 @@ private DataFlow::LocalSourceNode trackModule(Module tp, TypeTracker t) {
|
||||
t.start() and
|
||||
(
|
||||
// ConstantReadAccess to Module
|
||||
resolveScopeExpr(result.asExpr().getExpr()) = tp
|
||||
resolveConstantReadAccess(result.asExpr().getExpr()) = tp
|
||||
or
|
||||
// `self` reference to Module
|
||||
result = selfInModule(tp)
|
||||
@@ -458,18 +483,66 @@ predicate exprNodeReturnedFrom(DataFlow::ExprNode e, Callable c) {
|
||||
)
|
||||
}
|
||||
|
||||
private int parameterPosition() { result in [-2 .. max([any(Parameter p).getPosition(), 10])] }
|
||||
/** A parameter position. */
|
||||
class ParameterPosition extends TParameterPosition {
|
||||
/** Holds if this position represents a `self` parameter. */
|
||||
predicate isSelf() { this = TSelfParameterPosition() }
|
||||
|
||||
/** A parameter position represented by an integer. */
|
||||
class ParameterPosition extends int {
|
||||
ParameterPosition() { this = parameterPosition() }
|
||||
/** Holds if this position represents a block parameter. */
|
||||
predicate isBlock() { this = TBlockParameterPosition() }
|
||||
|
||||
/** Holds if this position represents a positional parameter at position `pos`. */
|
||||
predicate isPositional(int pos) { this = TPositionalParameterPosition(pos) }
|
||||
|
||||
/** Holds if this position represents a keyword parameter named `name`. */
|
||||
predicate isKeyword(string name) { this = TKeywordParameterPosition(name) }
|
||||
|
||||
/** Gets a textual representation of this position. */
|
||||
string toString() {
|
||||
this.isSelf() and result = "self"
|
||||
or
|
||||
this.isBlock() and result = "block"
|
||||
or
|
||||
exists(int pos | this.isPositional(pos) and result = "position " + pos)
|
||||
or
|
||||
exists(string name | this.isKeyword(name) and result = "keyword " + name)
|
||||
}
|
||||
}
|
||||
|
||||
/** An argument position represented by an integer. */
|
||||
class ArgumentPosition extends int {
|
||||
ArgumentPosition() { this = parameterPosition() }
|
||||
/** An argument position. */
|
||||
class ArgumentPosition extends TArgumentPosition {
|
||||
/** Holds if this position represents a `self` argument. */
|
||||
predicate isSelf() { this = TSelfArgumentPosition() }
|
||||
|
||||
/** Holds if this position represents a block argument. */
|
||||
predicate isBlock() { this = TBlockArgumentPosition() }
|
||||
|
||||
/** Holds if this position represents a positional argument at position `pos`. */
|
||||
predicate isPositional(int pos) { this = TPositionalArgumentPosition(pos) }
|
||||
|
||||
/** Holds if this position represents a keyword argument named `name`. */
|
||||
predicate isKeyword(string name) { this = TKeywordArgumentPosition(name) }
|
||||
|
||||
/** Gets a textual representation of this position. */
|
||||
string toString() {
|
||||
this.isSelf() and result = "self"
|
||||
or
|
||||
this.isBlock() and result = "block"
|
||||
or
|
||||
exists(int pos | this.isPositional(pos) and result = "position " + pos)
|
||||
or
|
||||
exists(string name | this.isKeyword(name) and result = "keyword " + name)
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
pragma[inline]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
|
||||
ppos.isSelf() and apos.isSelf()
|
||||
or
|
||||
ppos.isBlock() and apos.isBlock()
|
||||
or
|
||||
exists(int pos | ppos.isPositional(pos) and apos.isPositional(pos))
|
||||
or
|
||||
exists(string name | ppos.isKeyword(name) and apos.isKeyword(name))
|
||||
}
|
||||
|
||||
@@ -15,11 +15,23 @@ module Consistency {
|
||||
class ConsistencyConfiguration extends TConsistencyConfiguration {
|
||||
string toString() { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `uniqueEnclosingCallable`. */
|
||||
predicate uniqueEnclosingCallableExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `uniqueNodeLocation`. */
|
||||
predicate uniqueNodeLocationExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `missingLocation`. */
|
||||
predicate missingLocationExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
|
||||
predicate postWithInFlowExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
|
||||
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `reverseRead`. */
|
||||
predicate reverseReadExclude(Node n) { none() }
|
||||
}
|
||||
|
||||
private class RelevantNode extends Node {
|
||||
@@ -46,6 +58,7 @@ module Consistency {
|
||||
n instanceof RelevantNode and
|
||||
c = count(nodeGetEnclosingCallable(n)) and
|
||||
c != 1 and
|
||||
not any(ConsistencyConfiguration conf).uniqueEnclosingCallableExclude(n) and
|
||||
msg = "Node should have one enclosing callable but has " + c + "."
|
||||
)
|
||||
}
|
||||
@@ -66,6 +79,7 @@ module Consistency {
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
) and
|
||||
c != 1 and
|
||||
not any(ConsistencyConfiguration conf).uniqueNodeLocationExclude(n) and
|
||||
msg = "Node should have one location but has " + c + "."
|
||||
)
|
||||
}
|
||||
@@ -76,7 +90,8 @@ module Consistency {
|
||||
strictcount(Node n |
|
||||
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
)
|
||||
) and
|
||||
not any(ConsistencyConfiguration conf).missingLocationExclude(n)
|
||||
) and
|
||||
msg = "Nodes without location: " + c
|
||||
)
|
||||
@@ -172,6 +187,7 @@ module Consistency {
|
||||
|
||||
query predicate reverseRead(Node n, string msg) {
|
||||
exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and
|
||||
not any(ConsistencyConfiguration conf).reverseReadExclude(n) and
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +126,16 @@ module LocalFlow {
|
||||
or
|
||||
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::ConditionalExprCfgNode).getBranch(_)
|
||||
or
|
||||
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::CaseExprCfgNode).getBranch(_)
|
||||
exists(CfgNode n, Stmt stmt, CaseExpr c |
|
||||
c = nodeTo.asExpr().getExpr() and
|
||||
n = nodeFrom.asExpr() and
|
||||
n = nodeTo.asExpr().getAPredecessor() and
|
||||
stmt = n.getNode()
|
||||
|
|
||||
stmt = c.getElseBranch() or
|
||||
stmt = c.getABranch().(InClause).getBody() or
|
||||
stmt = c.getABranch().(WhenClause).getBody()
|
||||
)
|
||||
or
|
||||
exists(CfgNodes::ExprCfgNode exprTo, ReturningStatementNode n |
|
||||
nodeFrom = n and
|
||||
@@ -152,17 +161,29 @@ module LocalFlow {
|
||||
/** An argument of a call (including qualifier arguments, excluding block arguments). */
|
||||
private class Argument extends CfgNodes::ExprCfgNode {
|
||||
private CfgNodes::ExprNodes::CallCfgNode call;
|
||||
private int arg;
|
||||
private ArgumentPosition arg;
|
||||
|
||||
Argument() {
|
||||
this = call.getArgument(arg) and
|
||||
not this.getExpr() instanceof BlockArgument
|
||||
exists(int i |
|
||||
this = call.getArgument(i) and
|
||||
not this.getExpr() instanceof BlockArgument and
|
||||
not exists(this.getExpr().(Pair).getKey().getValueText()) and
|
||||
arg.isPositional(i)
|
||||
)
|
||||
or
|
||||
this = call.getReceiver() and arg = -1
|
||||
exists(CfgNodes::ExprNodes::PairCfgNode p |
|
||||
p = call.getArgument(_) and
|
||||
this = p.getValue() and
|
||||
arg.isKeyword(p.getKey().getValueText())
|
||||
)
|
||||
or
|
||||
this = call.getReceiver() and arg.isSelf()
|
||||
}
|
||||
|
||||
/** Holds if this expression is the `i`th argument of `c`. */
|
||||
predicate isArgumentOf(CfgNodes::ExprNodes::CallCfgNode c, int i) { c = call and i = arg }
|
||||
predicate isArgumentOf(CfgNodes::ExprNodes::CallCfgNode c, ArgumentPosition pos) {
|
||||
c = call and pos = arg
|
||||
}
|
||||
}
|
||||
|
||||
/** A collection of cached types and predicates to be evaluated in the same stage. */
|
||||
@@ -179,7 +200,11 @@ private module Cached {
|
||||
)
|
||||
} or
|
||||
TSsaDefinitionNode(Ssa::Definition def) or
|
||||
TNormalParameterNode(Parameter p) { not p instanceof BlockParameter } or
|
||||
TNormalParameterNode(Parameter p) {
|
||||
p instanceof SimpleParameter or
|
||||
p instanceof OptionalParameter or
|
||||
p instanceof KeywordParameter
|
||||
} or
|
||||
TSelfParameterNode(MethodBase m) or
|
||||
TBlockParameterNode(MethodBase m) or
|
||||
TExprPostUpdateNode(CfgNodes::ExprCfgNode n) { n instanceof Argument } or
|
||||
@@ -189,8 +214,8 @@ private module Cached {
|
||||
) {
|
||||
FlowSummaryImpl::Private::summaryNodeRange(c, state)
|
||||
} or
|
||||
TSummaryParameterNode(FlowSummaryImpl::Public::SummarizedCallable c, int i) {
|
||||
FlowSummaryImpl::Private::summaryParameterNodeRange(c, i)
|
||||
TSummaryParameterNode(FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition pos) {
|
||||
FlowSummaryImpl::Private::summaryParameterNodeRange(c, pos)
|
||||
}
|
||||
|
||||
class TParameterNode =
|
||||
@@ -331,10 +356,10 @@ private module ParameterNodes {
|
||||
abstract class ParameterNodeImpl extends NodeImpl {
|
||||
abstract Parameter getParameter();
|
||||
|
||||
abstract predicate isSourceParameterOf(Callable c, int i);
|
||||
abstract predicate isSourceParameterOf(Callable c, ParameterPosition pos);
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.isSourceParameterOf(c.asCallable(), i)
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.isSourceParameterOf(c.asCallable(), pos)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,10 +374,18 @@ private module ParameterNodes {
|
||||
|
||||
override Parameter getParameter() { result = parameter }
|
||||
|
||||
override predicate isSourceParameterOf(Callable c, int i) { c.getParameter(i) = parameter }
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.isSourceParameterOf(c.asCallable(), i)
|
||||
override predicate isSourceParameterOf(Callable c, ParameterPosition pos) {
|
||||
exists(int i | pos.isPositional(i) and c.getParameter(i) = parameter |
|
||||
parameter instanceof SimpleParameter
|
||||
or
|
||||
parameter instanceof OptionalParameter
|
||||
)
|
||||
or
|
||||
parameter =
|
||||
any(KeywordParameter kp |
|
||||
c.getAParameter() = kp and
|
||||
pos.isKeyword(kp.getName())
|
||||
)
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { result = parameter.getCallable() }
|
||||
@@ -375,10 +408,8 @@ private module ParameterNodes {
|
||||
|
||||
override Parameter getParameter() { none() }
|
||||
|
||||
override predicate isSourceParameterOf(Callable c, int i) { method = c and i = -1 }
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.isSourceParameterOf(c.asCallable(), i)
|
||||
override predicate isSourceParameterOf(Callable c, ParameterPosition pos) {
|
||||
method = c and pos.isSelf()
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { result = method }
|
||||
@@ -403,10 +434,8 @@ private module ParameterNodes {
|
||||
result = method.getAParameter() and result instanceof BlockParameter
|
||||
}
|
||||
|
||||
override predicate isSourceParameterOf(Callable c, int i) { c = method and i = -2 }
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.isSourceParameterOf(c.asCallable(), i)
|
||||
override predicate isSourceParameterOf(Callable c, ParameterPosition pos) {
|
||||
c = method and pos.isBlock()
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { result = method }
|
||||
@@ -427,15 +456,17 @@ private module ParameterNodes {
|
||||
/** A parameter for a library callable with a flow summary. */
|
||||
class SummaryParameterNode extends ParameterNodeImpl, TSummaryParameterNode {
|
||||
private FlowSummaryImpl::Public::SummarizedCallable sc;
|
||||
private int pos;
|
||||
private ParameterPosition pos_;
|
||||
|
||||
SummaryParameterNode() { this = TSummaryParameterNode(sc, pos) }
|
||||
SummaryParameterNode() { this = TSummaryParameterNode(sc, pos_) }
|
||||
|
||||
override Parameter getParameter() { none() }
|
||||
|
||||
override predicate isSourceParameterOf(Callable c, int i) { none() }
|
||||
override predicate isSourceParameterOf(Callable c, ParameterPosition pos) { none() }
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, int i) { sc = c and i = pos }
|
||||
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
sc = c and pos = pos_
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { none() }
|
||||
|
||||
@@ -443,7 +474,7 @@ private module ParameterNodes {
|
||||
|
||||
override EmptyLocation getLocationImpl() { any() }
|
||||
|
||||
override string toStringImpl() { result = "parameter " + pos + " of " + sc }
|
||||
override string toStringImpl() { result = "parameter " + pos_ + " of " + sc }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,9 +499,9 @@ class SummaryNode extends NodeImpl, TSummaryNode {
|
||||
/** A data-flow node that represents a call argument. */
|
||||
abstract class ArgumentNode extends Node {
|
||||
/** Holds if this argument occurs at the given position in the given call. */
|
||||
abstract predicate argumentOf(DataFlowCall call, int pos);
|
||||
abstract predicate argumentOf(DataFlowCall call, ArgumentPosition pos);
|
||||
|
||||
abstract predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, int pos);
|
||||
abstract predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos);
|
||||
|
||||
/** Gets the call in which this node is an argument. */
|
||||
final DataFlowCall getCall() { this.argumentOf(result, _) }
|
||||
@@ -483,18 +514,18 @@ private module ArgumentNodes {
|
||||
|
||||
ExplicitArgumentNode() { this.asExpr() = arg }
|
||||
|
||||
override predicate argumentOf(DataFlowCall call, int pos) {
|
||||
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
this.sourceArgumentOf(call.asCall(), pos)
|
||||
}
|
||||
|
||||
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, int pos) {
|
||||
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) {
|
||||
arg.isArgumentOf(call, pos)
|
||||
}
|
||||
}
|
||||
|
||||
/** A data-flow node that represents the `self` argument of a call. */
|
||||
class SelfArgumentNode extends ExplicitArgumentNode {
|
||||
SelfArgumentNode() { arg.isArgumentOf(_, -1) }
|
||||
SelfArgumentNode() { arg.isArgumentOf(_, any(ArgumentPosition pos | pos.isSelf())) }
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a block argument. */
|
||||
@@ -504,12 +535,12 @@ private module ArgumentNodes {
|
||||
exists(CfgNodes::ExprNodes::CallCfgNode c | c.getBlock() = this.asExpr())
|
||||
}
|
||||
|
||||
override predicate argumentOf(DataFlowCall call, int pos) {
|
||||
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
this.sourceArgumentOf(call.asCall(), pos)
|
||||
}
|
||||
|
||||
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, int pos) {
|
||||
pos = -2 and
|
||||
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) {
|
||||
pos.isBlock() and
|
||||
(
|
||||
this.asExpr() = call.getBlock()
|
||||
or
|
||||
@@ -525,9 +556,11 @@ private module ArgumentNodes {
|
||||
private class SummaryArgumentNode extends SummaryNode, ArgumentNode {
|
||||
SummaryArgumentNode() { FlowSummaryImpl::Private::summaryArgumentNode(_, this, _) }
|
||||
|
||||
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, int pos) { none() }
|
||||
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate argumentOf(DataFlowCall call, int pos) {
|
||||
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
FlowSummaryImpl::Private::summaryArgumentNode(call, this, pos)
|
||||
}
|
||||
}
|
||||
@@ -838,7 +871,7 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
|
||||
)
|
||||
or
|
||||
receiver = call.(SummaryCall).getReceiver() and
|
||||
if receiver.(ParameterNodeImpl).isParameterOf(_, -2)
|
||||
if receiver.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pos | pos.isBlock()))
|
||||
then kind = TYieldCallKind()
|
||||
else kind = TLambdaCallKind()
|
||||
}
|
||||
|
||||
@@ -61,6 +61,12 @@ class CallNode extends LocalSourceNode {
|
||||
|
||||
/** Gets the name of the the method called by the method call (if any) corresponding to this data-flow node */
|
||||
string getMethodName() { result = node.getExpr().(MethodCall).getMethodName() }
|
||||
|
||||
/** Gets the number of arguments of this call. */
|
||||
int getNumberOfArguments() { result = node.getNumberOfArguments() }
|
||||
|
||||
/** Gets the block of this call. */
|
||||
Node getBlock() { result.asExpr() = node.getBlock() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -736,10 +736,17 @@ module Private {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private ParamNode summaryArgParam(ArgNode arg, ReturnKindExt rk, OutNodeExt out) {
|
||||
exists(DataFlowCall call, ParameterPosition ppos, SummarizedCallable sc |
|
||||
private ParamNode summaryArgParam0(DataFlowCall call, ArgNode arg) {
|
||||
exists(ParameterPosition ppos, SummarizedCallable sc |
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
viableParam(call, sc, ppos, result) and
|
||||
viableParam(call, sc, ppos, result)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private ParamNode summaryArgParam(ArgNode arg, ReturnKindExt rk, OutNodeExt out) {
|
||||
exists(DataFlowCall call |
|
||||
result = summaryArgParam0(call, arg) and
|
||||
out = rk.getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ private import FlowSummaryImpl::Public
|
||||
private import codeql.ruby.dataflow.FlowSummary as FlowSummary
|
||||
|
||||
/** Gets the parameter position of the instance parameter. */
|
||||
int instanceParameterPosition() { none() } // disables implicit summary flow to `self` for callbacks
|
||||
ArgumentPosition instanceParameterPosition() { none() } // disables implicit summary flow to `self` for callbacks
|
||||
|
||||
/** Gets the synthesized summary data-flow node for the given values. */
|
||||
Node summaryNode(SummarizedCallable c, SummaryNodeState state) { result = TSummaryNode(c, state) }
|
||||
@@ -31,8 +31,8 @@ DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) { any() }
|
||||
* Gets the type of the `i`th parameter in a synthesized call that targets a
|
||||
* callback of type `t`.
|
||||
*/
|
||||
bindingset[t, i]
|
||||
DataFlowType getCallbackParameterType(DataFlowType t, int i) { any() }
|
||||
bindingset[t, pos]
|
||||
DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos) { any() }
|
||||
|
||||
/**
|
||||
* Gets the return type of kind `rk` in a synthesized call that targets a
|
||||
@@ -63,12 +63,13 @@ SummaryComponent interpretComponentSpecific(string c) {
|
||||
result = FlowSummary::SummaryComponent::block()
|
||||
or
|
||||
c = "Argument[_]" and
|
||||
result = FlowSummary::SummaryComponent::argument(any(int i | i >= 0))
|
||||
result = FlowSummary::SummaryComponent::argument(any(ParameterPosition pos | pos.isPositional(_)))
|
||||
}
|
||||
|
||||
/** Gets the textual representation of a summary component in the format used for flow summaries. */
|
||||
string getComponentSpecificCsv(SummaryComponent sc) {
|
||||
sc = TArgumentSummaryComponent(-2) and result = "BlockArgument"
|
||||
sc = TArgumentSummaryComponent(any(ParameterPosition pos | pos.isBlock())) and
|
||||
result = "BlockArgument"
|
||||
}
|
||||
|
||||
/** Gets the textual representation of a parameter position in the format used for flow summaries. */
|
||||
@@ -127,21 +128,57 @@ private module UnusedSourceSinkInterpretation {
|
||||
|
||||
import UnusedSourceSinkInterpretation
|
||||
|
||||
bindingset[s]
|
||||
private int parsePosition(string s) {
|
||||
result = s.regexpCapture("([-0-9]+)", 1).toInt()
|
||||
or
|
||||
exists(int n1, int n2 |
|
||||
s.regexpCapture("([-0-9]+)\\.\\.([0-9]+)", 1).toInt() = n1 and
|
||||
s.regexpCapture("([-0-9]+)\\.\\.([0-9]+)", 2).toInt() = n2 and
|
||||
result in [n1 .. n2]
|
||||
)
|
||||
module ParsePositions {
|
||||
private import FlowSummaryImpl
|
||||
|
||||
private predicate isParamBody(string body) {
|
||||
exists(string c |
|
||||
Private::External::specSplit(_, c, _) and
|
||||
body = c.regexpCapture("Parameter\\[([^\\]]*)\\]", 1)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isArgBody(string body) {
|
||||
exists(string c |
|
||||
Private::External::specSplit(_, c, _) and
|
||||
body = c.regexpCapture("Argument\\[([^\\]]*)\\]", 1)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[s]
|
||||
private int parsePosition(string s) {
|
||||
result = s.regexpCapture("([-0-9]+)", 1).toInt()
|
||||
or
|
||||
exists(int n1, int n2 |
|
||||
s.regexpCapture("([-0-9]+)\\.\\.([0-9]+)", 1).toInt() = n1 and
|
||||
s.regexpCapture("([-0-9]+)\\.\\.([0-9]+)", 2).toInt() = n2 and
|
||||
result in [n1 .. n2]
|
||||
)
|
||||
}
|
||||
|
||||
predicate isParsedParameterPosition(string c, int i) {
|
||||
isParamBody(c) and
|
||||
i = parsePosition(c)
|
||||
}
|
||||
|
||||
predicate isParsedArgumentPosition(string c, int i) {
|
||||
isArgBody(c) and
|
||||
i = parsePosition(c)
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the argument position obtained by parsing `X` in `Parameter[X]`. */
|
||||
bindingset[s]
|
||||
ArgumentPosition parseParamBody(string s) { result = parsePosition(s) }
|
||||
ArgumentPosition parseParamBody(string s) {
|
||||
exists(int i |
|
||||
ParsePositions::isParsedParameterPosition(s, i) and
|
||||
result.isPositional(i)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */
|
||||
bindingset[s]
|
||||
ParameterPosition parseArgBody(string s) { result = parsePosition(s) }
|
||||
ParameterPosition parseArgBody(string s) {
|
||||
exists(int i |
|
||||
ParsePositions::isParsedArgumentPosition(s, i) and
|
||||
result.isPositional(i)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ class ActionControllerControllerClass extends ClassDeclaration {
|
||||
or
|
||||
// class BarController < FooController
|
||||
exists(ActionControllerControllerClass other |
|
||||
other.getModule() = resolveScopeExpr(this.getSuperclassExpr())
|
||||
other.getModule() = resolveConstantReadAccess(this.getSuperclassExpr())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -54,13 +54,13 @@ class ActionControllerControllerClass extends ClassDeclaration {
|
||||
}
|
||||
|
||||
/**
|
||||
* An instance method defined within an `ActionController` controller class.
|
||||
* A public instance method defined within an `ActionController` controller class.
|
||||
* 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;
|
||||
|
||||
ActionControllerActionMethod() { this = controllerClass.getAMethod() }
|
||||
ActionControllerActionMethod() { this = controllerClass.getAMethod() and not this.isPrivate() }
|
||||
|
||||
/**
|
||||
* Establishes a mapping between a method within the file
|
||||
|
||||
@@ -59,7 +59,7 @@ class ActiveRecordModelClass extends ClassDeclaration {
|
||||
or
|
||||
// class Bar < Foo
|
||||
exists(ActiveRecordModelClass other |
|
||||
other.getModule() = resolveScopeExpr(this.getSuperclassExpr())
|
||||
other.getModule() = resolveConstantReadAccess(this.getSuperclassExpr())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ class ActiveRecordModelClassMethodCall extends MethodCall {
|
||||
|
||||
ActiveRecordModelClassMethodCall() {
|
||||
// e.g. Foo.where(...)
|
||||
recvCls.getModule() = resolveScopeExpr(this.getReceiver())
|
||||
recvCls.getModule() = resolveConstantReadAccess(this.getReceiver())
|
||||
or
|
||||
// e.g. Foo.joins(:bars).where(...)
|
||||
recvCls = this.getReceiver().(ActiveRecordModelClassMethodCall).getReceiverClass()
|
||||
@@ -278,7 +278,7 @@ private class ActiveRecordModelFinderCall extends ActiveRecordModelInstantiation
|
||||
ActiveRecordModelFinderCall() {
|
||||
call = this.asExpr().getExpr() and
|
||||
recv = getUltimateReceiver(call) and
|
||||
resolveConstant(recv) = cls.getQualifiedName() and
|
||||
resolveConstant(recv) = cls.getAQualifiedName() and
|
||||
call.getMethodName() = finderMethodName()
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,9 @@ private class RailtieClassAccess extends ConstantReadAccess {
|
||||
private class RailtieClass extends ClassDeclaration {
|
||||
RailtieClass() {
|
||||
this.getSuperclassExpr() instanceof RailtieClassAccess or
|
||||
exists(RailtieClass other | other.getModule() = resolveScopeExpr(this.getSuperclassExpr()))
|
||||
exists(RailtieClass other |
|
||||
other.getModule() = resolveConstantReadAccess(this.getSuperclassExpr())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +42,7 @@ private DataFlow::CallNode getAConfigureCallNode() {
|
||||
// `Rails::Application.configure`
|
||||
exists(ConstantReadAccess read, RailtieClass cls |
|
||||
read = result.getReceiver().asExpr().getExpr() and
|
||||
resolveScopeExpr(read) = cls.getModule() and
|
||||
resolveConstantReadAccess(read) = cls.getModule() and
|
||||
result.asExpr().getExpr().(MethodCall).getMethodName() = "configure"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.ApiGraphs
|
||||
private import codeql.ruby.dataflow.FlowSummary
|
||||
private import codeql.ruby.dataflow.internal.DataFlowDispatch
|
||||
private import codeql.ruby.CFG
|
||||
|
||||
/**
|
||||
* The `Kernel` module is included by the `Object` class, so its methods are available
|
||||
@@ -26,8 +28,6 @@ class KernelMethodCall extends DataFlow::CallNode {
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
int getNumberOfArguments() { result = methodCall.getNumberOfArguments() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,3 +349,103 @@ class RegexpEscapeSummary extends SummarizedCallable {
|
||||
preservesValue = false
|
||||
}
|
||||
}
|
||||
|
||||
/** A reference to a `Logger` instance */
|
||||
private DataFlow::Node loggerInstance() {
|
||||
result = API::getTopLevelMember("Logger").getAnInstantiation()
|
||||
or
|
||||
exists(DataFlow::Node inst |
|
||||
inst = loggerInstance() and
|
||||
inst.(DataFlow::LocalSourceNode).flowsTo(result)
|
||||
)
|
||||
or
|
||||
// Assume that a variable assigned as a `Logger` instance is always a
|
||||
// `Logger` instance. This covers class and instance variables where we can't
|
||||
// necessarily trace a dataflow path from assignment to use.
|
||||
exists(Variable v, Assignment a |
|
||||
a.getLeftOperand().getAVariable() = v and
|
||||
a.getRightOperand() = loggerInstance().asExpr().getExpr() and
|
||||
result.asExpr().getExpr().(VariableReadAccess).getVariable() = v
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a `Logger` instance method that causes a message to be logged.
|
||||
*/
|
||||
abstract class LoggerLoggingCall extends Logging::Range, DataFlow::CallNode {
|
||||
LoggerLoggingCall() { this.getReceiver() = loggerInstance() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `Logger#add` or its alias `Logger#log`.
|
||||
*/
|
||||
private class LoggerAddCall extends LoggerLoggingCall {
|
||||
LoggerAddCall() { this.getMethodName() = ["add", "log"] }
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
// Both the message and the progname are form part of the log output:
|
||||
// Logger#add(severity, message) / Logger#add(severity, message, progname)
|
||||
result = this.getArgument(1)
|
||||
or
|
||||
result = this.getArgument(2)
|
||||
or
|
||||
// a return value from the block in Logger#add(severity) <block> or in
|
||||
// Logger#add(severity, nil, progname) <block>
|
||||
(
|
||||
this.getNumberOfArguments() = 1
|
||||
or
|
||||
// TODO: this could track the value of the `message` argument to make
|
||||
// this check more accurate
|
||||
this.getArgument(1).asExpr().getExpr() instanceof NilLiteral
|
||||
) and
|
||||
exprNodeReturnedFrom(result, this.getBlock().asExpr().getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `Logger#<<`.
|
||||
*/
|
||||
private class LoggerPushCall extends LoggerLoggingCall {
|
||||
LoggerPushCall() { this.getMethodName() = "<<" }
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
// Logger#<<(msg)
|
||||
result = this.getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a `Logger` method that logs at a preset severity level.
|
||||
*
|
||||
* Specifically, these methods are `debug`, `error`, `fatal`, `info`,
|
||||
* `unknown`, and `warn`.
|
||||
*/
|
||||
private class LoggerInfoStyleCall extends LoggerLoggingCall {
|
||||
LoggerInfoStyleCall() {
|
||||
this.getMethodName() = ["debug", "error", "fatal", "info", "unknown", "warn"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
// `msg` from `Logger#info(msg)`,
|
||||
// or `progname` from `Logger#info(progname) <block>`
|
||||
result = this.getArgument(0)
|
||||
or
|
||||
// a return value from the block in `Logger#info(progname) <block>`
|
||||
exprNodeReturnedFrom(result, this.getBlock().asExpr().getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `Logger#progname=`. This sets a default progname.
|
||||
* This call does not log anything directly, but the assigned value can appear
|
||||
* in future log messages that do not specify a `progname` argument.
|
||||
*/
|
||||
private class LoggerSetPrognameCall extends LoggerLoggingCall {
|
||||
LoggerSetPrognameCall() { this.getMethodName() = "progname=" }
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
exists(CfgNodes::ExprNodes::AssignExprCfgNode a | this.getArgument(0).asExpr() = a |
|
||||
result.asExpr() = a.getRhs()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Provides default sources, sinks, and sanitizers for reasoning about bypass of
|
||||
* sensitive action guards, as well as extension points for adding your own.
|
||||
*/
|
||||
|
||||
private import codeql.ruby.CFG
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.controlflow.BasicBlocks
|
||||
private import codeql.ruby.dataflow.RemoteFlowSources
|
||||
private import codeql.ruby.security.SensitiveActions
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks, and sanitizers for reasoning about bypass of
|
||||
* sensitive action guards, as well as extension points for adding your own.
|
||||
*/
|
||||
module ConditionalBypass {
|
||||
/**
|
||||
* A data flow source for bypass of sensitive action guards.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for bypass of sensitive action guards.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the guarded sensitive action.
|
||||
*/
|
||||
abstract SensitiveAction getAction();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sanitizer for bypass of sensitive action guards.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A source of remote user input, considered as a flow source for bypass of
|
||||
* sensitive action guards.
|
||||
*/
|
||||
class RemoteFlowSourceAsSource extends Source {
|
||||
RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource }
|
||||
}
|
||||
|
||||
/**
|
||||
* A conditional that guards a sensitive action, e.g. `ok` in `if (ok) login()`.
|
||||
*/
|
||||
class SensitiveActionGuardConditional extends Sink {
|
||||
SensitiveAction action;
|
||||
|
||||
SensitiveActionGuardConditional() {
|
||||
exists(ConditionBlock cb, BasicBlock controlled |
|
||||
cb.controls(controlled, _) and
|
||||
controlled.getANode() = action.asExpr() and
|
||||
cb.getLastNode() = this.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override SensitiveAction getAction() { result = action }
|
||||
}
|
||||
}
|
||||
28
ruby/ql/lib/codeql/ruby/security/ConditionalBypassQuery.qll
Normal file
28
ruby/ql/lib/codeql/ruby/security/ConditionalBypassQuery.qll
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Provides a taint tracking configuration for reasoning about bypass of sensitive action guards.
|
||||
*
|
||||
* Note, for performance reasons: only import this file if
|
||||
* `ConditionalBypass::Configuration` is needed, otherwise
|
||||
* `ConditionalBypassCustomizations` should be imported instead.
|
||||
*/
|
||||
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.TaintTracking
|
||||
private import codeql.ruby.security.SensitiveActions
|
||||
import ConditionalBypassCustomizations::ConditionalBypass
|
||||
|
||||
/**
|
||||
* A taint tracking configuration for bypass of sensitive action guards.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "ConditionalBypass" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node) or
|
||||
node instanceof Sanitizer
|
||||
}
|
||||
}
|
||||
98
ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll
Normal file
98
ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Provides classes modeling cryptographic algorithms, separated into strong and weak variants.
|
||||
*
|
||||
* The classification into strong and weak are based on Wikipedia, OWASP and Google (2021).
|
||||
*/
|
||||
|
||||
private import internal.CryptoAlgorithmNames
|
||||
|
||||
/**
|
||||
* A cryptographic algorithm.
|
||||
*/
|
||||
private newtype TCryptographicAlgorithm =
|
||||
MkHashingAlgorithm(string name, boolean isWeak) {
|
||||
isStrongHashingAlgorithm(name) and isWeak = false
|
||||
or
|
||||
isWeakHashingAlgorithm(name) and isWeak = true
|
||||
} or
|
||||
MkEncryptionAlgorithm(string name, boolean isWeak) {
|
||||
isStrongEncryptionAlgorithm(name) and isWeak = false
|
||||
or
|
||||
isWeakEncryptionAlgorithm(name) and isWeak = true
|
||||
} or
|
||||
MkPasswordHashingAlgorithm(string name, boolean isWeak) {
|
||||
isStrongPasswordHashingAlgorithm(name) and isWeak = false
|
||||
or
|
||||
isWeakPasswordHashingAlgorithm(name) and isWeak = true
|
||||
}
|
||||
|
||||
/**
|
||||
* A cryptographic algorithm.
|
||||
*/
|
||||
abstract class CryptographicAlgorithm extends TCryptographicAlgorithm {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = getName() }
|
||||
|
||||
/**
|
||||
* Gets the normalized name of this algorithm (upper-case, no spaces, dashes or underscores).
|
||||
*/
|
||||
abstract string getName();
|
||||
|
||||
/**
|
||||
* Holds if the name of this algorithm matches `name` modulo case,
|
||||
* white space, dashes, underscores, and anything after a dash in the name
|
||||
* (to ignore modes of operation, such as CBC or ECB).
|
||||
*/
|
||||
bindingset[name]
|
||||
predicate matchesName(string name) {
|
||||
[name.toUpperCase(), name.toUpperCase().regexpCapture("^(\\w+)(?:-.*)?$", 1)]
|
||||
.regexpReplaceAll("[-_ ]", "") = getName()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this algorithm is weak.
|
||||
*/
|
||||
abstract predicate isWeak();
|
||||
}
|
||||
|
||||
/**
|
||||
* A hashing algorithm such as `MD5` or `SHA512`.
|
||||
*/
|
||||
class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm {
|
||||
string name;
|
||||
boolean isWeak;
|
||||
|
||||
HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) }
|
||||
|
||||
override string getName() { result = name }
|
||||
|
||||
override predicate isWeak() { isWeak = true }
|
||||
}
|
||||
|
||||
/**
|
||||
* An encryption algorithm such as `DES` or `AES512`.
|
||||
*/
|
||||
class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm {
|
||||
string name;
|
||||
boolean isWeak;
|
||||
|
||||
EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) }
|
||||
|
||||
override string getName() { result = name }
|
||||
|
||||
override predicate isWeak() { isWeak = true }
|
||||
}
|
||||
|
||||
/**
|
||||
* A password hashing algorithm such as `PBKDF2` or `SCRYPT`.
|
||||
*/
|
||||
class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm {
|
||||
string name;
|
||||
boolean isWeak;
|
||||
|
||||
PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) }
|
||||
|
||||
override string getName() { result = name }
|
||||
|
||||
override predicate isWeak() { isWeak = true }
|
||||
}
|
||||
311
ruby/ql/lib/codeql/ruby/security/OpenSSL.qll
Normal file
311
ruby/ql/lib/codeql/ruby/security/OpenSSL.qll
Normal file
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* Provides classes modeling parts of the Ruby `OpenSSL` library, which wraps
|
||||
* an underlying OpenSSL or LibreSSL C library.
|
||||
*/
|
||||
|
||||
private import internal.CryptoAlgorithmNames
|
||||
|
||||
bindingset[algorithmString]
|
||||
private string algorithmRegex(string algorithmString) {
|
||||
// Algorithms usually appear in names surrounded by characters that are not
|
||||
// alphabetical characters in the same case. This handles the upper and lower
|
||||
// case cases.
|
||||
result =
|
||||
"((^|.*[^A-Z])(" + algorithmString + ")([^A-Z].*|$))" +
|
||||
// or...
|
||||
"|" +
|
||||
// For lowercase, we want to be careful to avoid being confused by camelCase
|
||||
// hence we require two preceding uppercase letters to be sure of a case switch,
|
||||
// or a preceding non-alphabetic character
|
||||
"((^|.*[A-Z]{2}|.*[^a-zA-Z])(" + algorithmString.toLowerCase() + ")([^a-z].*|$))"
|
||||
}
|
||||
|
||||
private string rankedInsecureAlgorithm(int i) {
|
||||
// In this case we know these are being used for encryption, so we want to match
|
||||
// weak hash algorithms and block modes as well.
|
||||
result =
|
||||
rank[i](string s |
|
||||
isWeakEncryptionAlgorithm(s) or isWeakHashingAlgorithm(s) or isWeakBlockMode(s)
|
||||
)
|
||||
}
|
||||
|
||||
private string insecureAlgorithmString(int i) {
|
||||
i = 1 and result = rankedInsecureAlgorithm(i)
|
||||
or
|
||||
result = rankedInsecureAlgorithm(i) + "|" + insecureAlgorithmString(i - 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the regular expression used for matching strings that look like they
|
||||
* contain an algorithm that is known to be insecure.
|
||||
*/
|
||||
private string getInsecureAlgorithmRegex() {
|
||||
result = algorithmRegex(insecureAlgorithmString(max(int i | exists(rankedInsecureAlgorithm(i)))))
|
||||
}
|
||||
|
||||
private string rankedSecureAlgorithm(int i) {
|
||||
result = rank[i](string s | isStrongEncryptionAlgorithm(s))
|
||||
}
|
||||
|
||||
private string secureAlgorithmString(int i) {
|
||||
i = 1 and result = rankedSecureAlgorithm(i)
|
||||
or
|
||||
result = rankedSecureAlgorithm(i) + "|" + secureAlgorithmString(i - 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a regular expression for matching strings that look like they
|
||||
* contain an algorithm that is known to be secure.
|
||||
*/
|
||||
string getSecureAlgorithmRegex() {
|
||||
result = algorithmRegex(secureAlgorithmString(max(int i | exists(rankedSecureAlgorithm(i)))))
|
||||
}
|
||||
|
||||
/**
|
||||
* Names of known ciphers supported by the Ruby `OpenSSL` library, and
|
||||
* classification into strong and weak ciphers. Cipher support in practice
|
||||
* depends on the underlying `OpenSSL`/`LibreSSL` library.
|
||||
*/
|
||||
module Ciphers {
|
||||
/**
|
||||
* Holds if `name` is a known `OpenSSL::Cipher`. Supported ciphers depend on the
|
||||
* version of `OpenSSL` or `LibreSSL` specified when installing the `openssl` gem.
|
||||
* Ciphers listed here are sourced from OpenSSL 1.1.1 and LibreSSL 3.4.1.
|
||||
*
|
||||
* In the general case, a name will include the cipher name, the key length,
|
||||
* and the block encryption mode.
|
||||
*
|
||||
* Note that since the cipher name itself always comes first in these names
|
||||
* and always uses a "-" to demark to block mode, we can safely uppercase
|
||||
* these names when checking against an `algorithmRegex`.
|
||||
*
|
||||
* See https://ruby-doc.org/stdlib-3.0.1/libdoc/openssl/rdoc/OpenSSL/Cipher.html
|
||||
*/
|
||||
predicate isOpenSSLCipher(string name) {
|
||||
name =
|
||||
[
|
||||
"aes-128-cbc", "aes-128-cbc-hmac-sha1", "aes-128-cbc-hmac-sha256", "aes-128-ccm",
|
||||
"aes-128-cfb", "aes-128-cfb1", "aes-128-cfb8", "aes-128-ctr", "aes-128-ecb", "aes-128-gcm",
|
||||
"aes-128-ocb", "aes-128-ofb", "aes-128-xts", "aes-192-cbc", "aes-192-ccm", "aes-192-cfb",
|
||||
"aes-192-cfb1", "aes-192-cfb8", "aes-192-ctr", "aes-192-ecb", "aes-192-gcm", "aes-192-ocb",
|
||||
"aes-192-ofb", "aes-256-cbc", "aes-256-cbc-hmac-sha1", "aes-256-cbc-hmac-sha256",
|
||||
"aes-256-ccm", "aes-256-cfb", "aes-256-cfb1", "aes-256-cfb8", "aes-256-ctr", "aes-256-ecb",
|
||||
"aes-256-gcm", "aes-256-ocb", "aes-256-ofb", "aes-256-xts", "aes128", "aes192", "aes256",
|
||||
"aria-128-cbc", "aria-128-ccm", "aria-128-cfb", "aria-128-cfb1", "aria-128-cfb8",
|
||||
"aria-128-ctr", "aria-128-ecb", "aria-128-gcm", "aria-128-ofb", "aria-192-cbc",
|
||||
"aria-192-ccm", "aria-192-cfb", "aria-192-cfb1", "aria-192-cfb8", "aria-192-ctr",
|
||||
"aria-192-ecb", "aria-192-gcm", "aria-192-ofb", "aria-256-cbc", "aria-256-ccm",
|
||||
"aria-256-cfb", "aria-256-cfb1", "aria-256-cfb8", "aria-256-ctr", "aria-256-ecb",
|
||||
"aria-256-gcm", "aria-256-ofb", "aria128", "aria192", "aria256", "bf", "bf-cbc", "bf-cfb",
|
||||
"bf-ecb", "bf-ofb", "blowfish", "camellia-128-cbc", "camellia-128-cfb", "camellia-128-cfb1",
|
||||
"camellia-128-cfb8", "camellia-128-ctr", "camellia-128-ecb", "camellia-128-ofb",
|
||||
"camellia-192-cbc", "camellia-192-cfb", "camellia-192-cfb1", "camellia-192-cfb8",
|
||||
"camellia-192-ctr", "camellia-192-ecb", "camellia-192-ofb", "camellia-256-cbc",
|
||||
"camellia-256-cfb", "camellia-256-cfb1", "camellia-256-cfb8", "camellia-256-ctr",
|
||||
"camellia-256-ecb", "camellia-256-ofb", "camellia128", "camellia192", "camellia256", "cast",
|
||||
"cast-cbc", "cast5-cbc", "cast5-cfb", "cast5-ecb", "cast5-ofb", "chacha20",
|
||||
"chacha20-poly1305", "des", "des-cbc", "des-cfb", "des-cfb1", "des-cfb8", "des-ecb",
|
||||
"des-ede", "des-ede-cbc", "des-ede-cfb", "des-ede-ecb", "des-ede-ofb", "des-ede3",
|
||||
"des-ede3-cbc", "des-ede3-cfb", "des-ede3-cfb1", "des-ede3-cfb8", "des-ede3-ecb",
|
||||
"des-ede3-ofb", "des-ofb", "des3", "desx", "desx-cbc", "id-aes128-CCM", "id-aes128-GCM",
|
||||
"id-aes192-CCM", "id-aes192-GCM", "id-aes256-CCM", "id-aes256-GCM", "idea", "idea-cbc",
|
||||
"idea-cfb", "idea-ecb", "idea-ofb", "rc2", "rc2-128", "rc2-40", "rc2-40-cbc", "rc2-64",
|
||||
"rc2-64-cbc", "rc2-cbc", "rc2-cfb", "rc2-ecb", "rc2-ofb", "rc4", "rc4-40", "rc4-hmac-md5",
|
||||
"seed", "seed-cbc", "seed-cfb", "seed-ecb", "seed-ofb", "sm4", "sm4-cbc", "sm4-cfb",
|
||||
"sm4-ctr", "sm4-ecb", "sm4-ofb", "AES-128-CBC", "AES-128-CBC-HMAC-SHA1", "AES-128-CFB",
|
||||
"AES-128-CFB1", "AES-128-CFB8", "AES-128-CTR", "AES-128-ECB", "AES-128-OFB", "AES-128-XTS",
|
||||
"AES-192-CBC", "AES-192-CFB", "AES-192-CFB1", "AES-192-CFB8", "AES-192-CTR", "AES-192-ECB",
|
||||
"AES-192-OFB", "AES-256-CBC", "AES-256-CBC-HMAC-SHA1", "AES-256-CFB", "AES-256-CFB1",
|
||||
"AES-256-CFB8", "AES-256-CTR", "AES-256-ECB", "AES-256-OFB", "AES-256-XTS", "AES128",
|
||||
"AES192", "AES256", "BF", "BF-CBC", "BF-CFB", "BF-ECB", "BF-OFB", "CAMELLIA-128-CBC",
|
||||
"CAMELLIA-128-CFB", "CAMELLIA-128-CFB1", "CAMELLIA-128-CFB8", "CAMELLIA-128-ECB",
|
||||
"CAMELLIA-128-OFB", "CAMELLIA-192-CBC", "CAMELLIA-192-CFB", "CAMELLIA-192-CFB1",
|
||||
"CAMELLIA-192-CFB8", "CAMELLIA-192-ECB", "CAMELLIA-192-OFB", "CAMELLIA-256-CBC",
|
||||
"CAMELLIA-256-CFB", "CAMELLIA-256-CFB1", "CAMELLIA-256-CFB8", "CAMELLIA-256-ECB",
|
||||
"CAMELLIA-256-OFB", "CAMELLIA128", "CAMELLIA192", "CAMELLIA256", "CAST", "CAST-cbc",
|
||||
"CAST5-CBC", "CAST5-CFB", "CAST5-ECB", "CAST5-OFB", "ChaCha", "DES", "DES-CBC", "DES-CFB",
|
||||
"DES-CFB1", "DES-CFB8", "DES-ECB", "DES-EDE", "DES-EDE-CBC", "DES-EDE-CFB", "DES-EDE-OFB",
|
||||
"DES-EDE3", "DES-EDE3-CBC", "DES-EDE3-CFB", "DES-EDE3-CFB1", "DES-EDE3-CFB8",
|
||||
"DES-EDE3-OFB", "DES-OFB", "DES3", "DESX", "DESX-CBC", "GOST 28147-89", "IDEA", "IDEA-CBC",
|
||||
"IDEA-CFB", "IDEA-ECB", "IDEA-OFB", "RC2", "RC2-40-CBC", "RC2-64-CBC", "RC2-CBC", "RC2-CFB",
|
||||
"RC2-ECB", "RC2-OFB", "RC4", "RC4-40", "RC4-HMAC-MD5", "SM4", "SM4-CBC", "SM4-CFB",
|
||||
"SM4-CTR", "SM4-ECB", "SM4-OFB", "chacha", "gost89", "gost89-cnt", "gost89-ecb"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the canonical cipher name in cases where this isn't simply an
|
||||
* upcased version of the provided name. This may be because a default block
|
||||
* mode is appended, or due to some other normalization.
|
||||
*/
|
||||
private string getSpecialCanonicalCipherName(string name) {
|
||||
name = "AES128" and result = "AES-128-CBC"
|
||||
or
|
||||
name = "AES192" and result = "AES-192-CBC"
|
||||
or
|
||||
name = "AES256" and result = "AES-256-CBC"
|
||||
or
|
||||
name = "BF" and result = "BF-CBC"
|
||||
or
|
||||
name = "CAMELLIA128" and result = "CAMELLIA-128-CBC"
|
||||
or
|
||||
name = "CAMELLIA192" and result = "CAMELLIA-192-CBC"
|
||||
or
|
||||
name = "CAMELLIA256" and result = "CAMELLIA-256-CBC"
|
||||
or
|
||||
name = "CAST" and result = "CAST5-CBC"
|
||||
or
|
||||
name = "CAST-cbc" and result = "CAST5-CBC"
|
||||
or
|
||||
name = "ChaCha" and result = "ChaCha"
|
||||
or
|
||||
name = "DES" and result = "DES-CBC"
|
||||
or
|
||||
name = "DES3" and result = "DES-EDE3-CBC"
|
||||
or
|
||||
name = "DESX" and result = "DESX-CBC"
|
||||
or
|
||||
name = "GOST 28147-89" and result = "gost89"
|
||||
or
|
||||
name = "IDEA" and result = "IDEA-CBC"
|
||||
or
|
||||
name = "RC2" and result = "RC2-CBC"
|
||||
or
|
||||
name = "SM4" and result = "SM4-CBC"
|
||||
or
|
||||
name = "aes-128-ccm" and result = "id-aes128-CCM"
|
||||
or
|
||||
name = "aes-128-gcm" and result = "id-aes128-GCM"
|
||||
or
|
||||
name = "aes-192-ccm" and result = "id-aes192-CCM"
|
||||
or
|
||||
name = "aes-192-gcm" and result = "id-aes192-GCM"
|
||||
or
|
||||
name = "aes-256-ccm" and result = "id-aes256-CCM"
|
||||
or
|
||||
name = "aes-256-gcm" and result = "id-aes256-GCM"
|
||||
or
|
||||
name = "aes128" and result = "AES-128-CBC"
|
||||
or
|
||||
name = "aes192" and result = "AES-192-CBC"
|
||||
or
|
||||
name = "aes256" and result = "AES-256-CBC"
|
||||
or
|
||||
name = "bf" and result = "BF-CBC"
|
||||
or
|
||||
name = "blowfish" and result = "BF-CBC"
|
||||
or
|
||||
name = "camellia128" and result = "CAMELLIA-128-CBC"
|
||||
or
|
||||
name = "camellia192" and result = "CAMELLIA-192-CBC"
|
||||
or
|
||||
name = "camellia256" and result = "CAMELLIA-256-CBC"
|
||||
or
|
||||
name = "cast" and result = "CAST5-CBC"
|
||||
or
|
||||
name = "cast-cbc" and result = "CAST5-CBC"
|
||||
or
|
||||
name = "chacha" and result = "ChaCha"
|
||||
or
|
||||
name = "des" and result = "DES-CBC"
|
||||
or
|
||||
name = "des3" and result = "DES-EDE3-CBC"
|
||||
or
|
||||
name = "desx" and result = "DESX-CBC"
|
||||
or
|
||||
name = "gost89" and result = "gost89"
|
||||
or
|
||||
name = "gost89-cnt" and result = "gost89-cnt"
|
||||
or
|
||||
name = "gost89-ecb" and result = "gost89-ecb"
|
||||
or
|
||||
name = "id-aes128-CCM" and result = "id-aes128-CCM"
|
||||
or
|
||||
name = "id-aes128-GCM" and result = "id-aes128-GCM"
|
||||
or
|
||||
name = "id-aes192-CCM" and result = "id-aes192-CCM"
|
||||
or
|
||||
name = "id-aes192-GCM" and result = "id-aes192-GCM"
|
||||
or
|
||||
name = "id-aes256-CCM" and result = "id-aes256-CCM"
|
||||
or
|
||||
name = "id-aes256-GCM" and result = "id-aes256-GCM"
|
||||
or
|
||||
name = "idea" and result = "IDEA-CBC"
|
||||
or
|
||||
name = "rc2" and result = "RC2-CBC"
|
||||
or
|
||||
name = "sm4" and result = "SM4-CBC"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the canonical version of `name`, as reported by `OpenSSL::Cipher#name`.
|
||||
* No result if `name` is not a known OpenSSL cipher name.
|
||||
*/
|
||||
string getCanonicalCipherName(string name) {
|
||||
isOpenSSLCipher(name) and
|
||||
(
|
||||
result = getSpecialCanonicalCipherName(name)
|
||||
or
|
||||
not exists(getSpecialCanonicalCipherName(name)) and
|
||||
result = name.toUpperCase()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` is the name of an OpenSSL cipher that is known to be weak.
|
||||
*/
|
||||
predicate isWeakOpenSSLCipher(string name) {
|
||||
isOpenSSLCipher(name) and
|
||||
name.toUpperCase().regexpMatch(getInsecureAlgorithmRegex())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` is the name of an OpenSSL cipher that is known to be strong.
|
||||
*/
|
||||
predicate isStrongOpenSSLCipher(string name) {
|
||||
isOpenSSLCipher(name) and
|
||||
name.toUpperCase().regexpMatch(getSecureAlgorithmRegex()) and
|
||||
// exclude algorithms that include a weak component
|
||||
not name.toUpperCase().regexpMatch(getInsecureAlgorithmRegex())
|
||||
}
|
||||
}
|
||||
|
||||
private import Ciphers
|
||||
|
||||
/**
|
||||
* An OpenSSL cipher.
|
||||
*/
|
||||
private newtype TOpenSSLCipher =
|
||||
MkOpenSSLCipher(string name, boolean isWeak) {
|
||||
isStrongOpenSSLCipher(name) and isWeak = false
|
||||
or
|
||||
isWeakOpenSSLCipher(name) and isWeak = true
|
||||
}
|
||||
|
||||
/**
|
||||
* A known OpenSSL cipher. This may include information about the block
|
||||
* encryption mode, which can affect if the cipher is marked as being weak.
|
||||
*/
|
||||
class OpenSSLCipher extends MkOpenSSLCipher {
|
||||
string name;
|
||||
boolean isWeak;
|
||||
|
||||
OpenSSLCipher() { this = MkOpenSSLCipher(name, isWeak) }
|
||||
|
||||
/**
|
||||
* Gets a name of this cipher.
|
||||
*/
|
||||
string getName() { result = name }
|
||||
|
||||
/**
|
||||
* Gets a name of this cipher in canonical form.
|
||||
*/
|
||||
string getCanonicalName() { result = getCanonicalCipherName(this.getName()) }
|
||||
|
||||
/** Holds if this algorithm is weak. */
|
||||
predicate isWeak() { isWeak = true }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getCanonicalName() }
|
||||
}
|
||||
68
ruby/ql/lib/codeql/ruby/security/SensitiveActions.qll
Normal file
68
ruby/ql/lib/codeql/ruby/security/SensitiveActions.qll
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Provides classes and predicates for identifying sensitive data and methods for security.
|
||||
*
|
||||
* 'Sensitive' data in general is anything that should not be sent around in unencrypted form. This
|
||||
* library tries to guess where sensitive data may either be stored in a variable or produced by a
|
||||
* method.
|
||||
*
|
||||
* In addition, there are methods that ought not to be executed or not in a fashion that the user
|
||||
* can control. This includes authorization methods such as logins, and sending of data, etc.
|
||||
*/
|
||||
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.DataFlow
|
||||
|
||||
/**
|
||||
* A sensitive action, such as transfer of sensitive data.
|
||||
*/
|
||||
abstract class SensitiveAction extends DataFlow::Node { }
|
||||
|
||||
/** Holds if the return value from call `c` is ignored. */
|
||||
private predicate callWithIgnoredReturnValue(Call c) {
|
||||
exists(StmtSequence s, int i |
|
||||
(
|
||||
// If the call is a top-level statement within a statement sequence, its
|
||||
// return value (if any) is unused.
|
||||
c = s.getStmt(i)
|
||||
or
|
||||
// Or if the statement is an if-/unless-modifier expr and the call is its
|
||||
// branch.
|
||||
exists(ConditionalExpr cond |
|
||||
cond = s.getStmt(i) and
|
||||
c = cond.getBranch(_) and
|
||||
(cond instanceof IfModifierExpr or cond instanceof UnlessModifierExpr)
|
||||
)
|
||||
) and
|
||||
// But exclude calls that are the last statement, since they are evaluated
|
||||
// as the overall value of the sequence.
|
||||
exists(s.getStmt(i + 1))
|
||||
) and
|
||||
not c instanceof YieldCall and
|
||||
// Ignore statements in ERB output directives, which are evaluated.
|
||||
not exists(ErbOutputDirective d | d.getAChildStmt() = c)
|
||||
}
|
||||
|
||||
/** A call that may perform authorization. */
|
||||
class AuthorizationCall extends SensitiveAction, DataFlow::CallNode {
|
||||
AuthorizationCall() {
|
||||
exists(MethodCall c, string s |
|
||||
c = this.asExpr().getExpr() and
|
||||
s = c.getMethodName() // name contains `login` or `auth`, but not as part of `loginfo` or `unauth`;
|
||||
|
|
||||
// also exclude `author`
|
||||
s.regexpMatch("(?i).*(log_?in(?!fo)|(?<!un)auth(?!or\\b)|verify).*") and
|
||||
// but it does not start with `get` or `set`
|
||||
not s.regexpMatch("(?i)(get|set).*") and
|
||||
// Setter calls are unlikely to be sensitive actions.
|
||||
not c instanceof SetterMethodCall and
|
||||
(
|
||||
// Calls that have no return value (or ignore it) are likely to be
|
||||
// to methods that are actions.
|
||||
callWithIgnoredReturnValue(c)
|
||||
or
|
||||
// Method names ending in `!` are likely to be actions.
|
||||
s.matches("%!")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -227,7 +227,7 @@ private module Shared {
|
||||
isHelperMethod(helperMethod, name, template) and
|
||||
isMethodCall(helperMethodCall.getExpr(), name, template) and
|
||||
helperMethodCall.getArgument(pragma[only_bind_into](argIdx)) = node1.asExpr() and
|
||||
helperMethod.getParameter(pragma[only_bind_into](argIdx)) = node2.asExpr().getExpr()
|
||||
helperMethod.getParameter(pragma[only_bind_into](argIdx)) = node2.asParameter()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Names of cryptographic algorithms, separated into strong and weak variants.
|
||||
*
|
||||
* The names are normalized: upper-case, no spaces, dashes or underscores.
|
||||
*
|
||||
* The names are inspired by the names used in real world crypto libraries.
|
||||
*
|
||||
* The classification into strong and weak are based on Wikipedia, OWASP and Google (2021).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a strong hashing algorithm.
|
||||
*/
|
||||
predicate isStrongHashingAlgorithm(string name) {
|
||||
name =
|
||||
[
|
||||
"DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2",
|
||||
"SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a weak hashing algorithm.
|
||||
*/
|
||||
predicate isWeakHashingAlgorithm(string name) {
|
||||
name =
|
||||
[
|
||||
"HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256", "RIPEMD160",
|
||||
"RIPEMD320", "SHA0", "SHA1"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a strong encryption algorithm.
|
||||
*/
|
||||
predicate isStrongEncryptionAlgorithm(string name) {
|
||||
name =
|
||||
[
|
||||
"AES", "AES128", "AES192", "AES256", "AES512", "AES-128", "AES-192", "AES-256", "AES-512",
|
||||
"ARIA", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5", "CAMELLIA", "CAMELLIA128", "CAMELLIA192",
|
||||
"CAMELLIA256", "CAMELLIA-128", "CAMELLIA-192", "CAMELLIA-256", "CHACHA", "GOST", "GOST89",
|
||||
"IDEA", "RABBIT", "RSA", "SEED", "SM4"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a weak encryption algorithm.
|
||||
*/
|
||||
predicate isWeakEncryptionAlgorithm(string name) {
|
||||
name =
|
||||
[
|
||||
"DES", "3DES", "DES3", "TRIPLEDES", "DESX", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4",
|
||||
"ARCFOUR", "ARC5", "RC5"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a strong password hashing algorithm.
|
||||
*/
|
||||
predicate isStrongPasswordHashingAlgorithm(string name) {
|
||||
name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a weak password hashing algorithm.
|
||||
*/
|
||||
predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" }
|
||||
|
||||
/**
|
||||
* Holds if `name` corresponds to a weak block cipher mode of operation.
|
||||
*/
|
||||
predicate isWeakBlockMode(string name) { name = "ECB" }
|
||||
@@ -23,6 +23,28 @@ predicate jumpStep = DataFlowPrivate::jumpStep/2;
|
||||
*/
|
||||
string getPossibleContentName() { result = getSetterCallAttributeName(_) }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate argumentPositionMatch(
|
||||
ExprNodes::CallCfgNode call, DataFlowPrivate::ArgumentNode arg,
|
||||
DataFlowDispatch::ParameterPosition ppos
|
||||
) {
|
||||
exists(DataFlowDispatch::ArgumentPosition apos |
|
||||
arg.sourceArgumentOf(call, apos) and
|
||||
DataFlowDispatch::parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate viableParam(
|
||||
ExprNodes::CallCfgNode call, DataFlowPrivate::ParameterNodeImpl p,
|
||||
DataFlowDispatch::ParameterPosition ppos
|
||||
) {
|
||||
exists(CFG::CfgScope callable |
|
||||
DataFlowDispatch::getTarget(call) = callable and
|
||||
p.isSourceParameterOf(callable, ppos)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call.
|
||||
*
|
||||
@@ -31,10 +53,9 @@ string getPossibleContentName() { result = getSetterCallAttributeName(_) }
|
||||
* methods is done using API graphs (which uses type tracking).
|
||||
*/
|
||||
predicate callStep(Node nodeFrom, Node nodeTo) {
|
||||
exists(ExprNodes::CallCfgNode call, CFG::CfgScope callable, int i |
|
||||
DataFlowDispatch::getTarget(call) = callable and
|
||||
nodeFrom.(DataFlowPrivate::ArgumentNode).sourceArgumentOf(call, i) and
|
||||
nodeTo.(DataFlowPrivate::ParameterNodeImpl).isSourceParameterOf(callable, i)
|
||||
exists(ExprNodes::CallCfgNode call, DataFlowDispatch::ParameterPosition pos |
|
||||
argumentPositionMatch(call, nodeFrom, pos) and
|
||||
viableParam(call, nodeTo, pos)
|
||||
)
|
||||
or
|
||||
// In normal data-flow, this will be a local flow step. But for type tracking
|
||||
|
||||
36
ruby/ql/src/experimental/cwe-807/ConditionalBypass.qhelp
Normal file
36
ruby/ql/src/experimental/cwe-807/ConditionalBypass.qhelp
Normal file
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
Using user-controlled data in a permissions check may allow a user to gain
|
||||
unauthorized access to protected functionality or data.
|
||||
</p>
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>
|
||||
When checking whether a user is authorized for a particular activity, do
|
||||
not use data that is entirely controlled by that user in the permissions
|
||||
check. If necessary, always validate the input, ideally against a fixed
|
||||
list of expected values.
|
||||
</p>
|
||||
<p>
|
||||
Similarly, do not decide which permission to check based on user data. In
|
||||
particular, avoid using computation to decide which permissions to check
|
||||
for. Use fixed permissions for particular actions, rather than generating
|
||||
the permission to check for.
|
||||
</p>
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>
|
||||
In this example, the controller decided whether or not to authenticate the
|
||||
user based on the value of a request parameter.
|
||||
</p>
|
||||
<sample src="examples/bypass.rb" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
82
ruby/ql/src/experimental/cwe-807/ConditionalBypass.ql
Normal file
82
ruby/ql/src/experimental/cwe-807/ConditionalBypass.ql
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @name User-controlled bypass of security check
|
||||
* @description Conditions controlled by the user are not suited for making security-related decisions.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 7.8
|
||||
* @precision medium
|
||||
* @id rb/user-controlled-bypass
|
||||
* @tags security
|
||||
* external/cwe/cwe-807
|
||||
* external/cwe/cwe-290
|
||||
*/
|
||||
|
||||
import ruby
|
||||
import codeql.ruby.DataFlow
|
||||
import codeql.ruby.dataflow.internal.DataFlowPublic
|
||||
import codeql.ruby.security.ConditionalBypassQuery
|
||||
import codeql.ruby.security.SensitiveActions
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* Holds if the value of `nd` flows into `guard`.
|
||||
*/
|
||||
predicate flowsToGuardExpr(DataFlow::Node nd, SensitiveActionGuardConditional guard) {
|
||||
nd = guard
|
||||
or
|
||||
exists(DataFlow::Node succ | localFlowStep(nd, succ) | flowsToGuardExpr(succ, guard))
|
||||
}
|
||||
|
||||
/**
|
||||
* A comparison that guards a sensitive action, e.g. the comparison in:
|
||||
* ```rb
|
||||
* ok = x == y
|
||||
* if ok
|
||||
* login
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class SensitiveActionGuardComparison extends ComparisonOperation {
|
||||
SensitiveActionGuardConditional guard;
|
||||
|
||||
SensitiveActionGuardComparison() {
|
||||
exists(DataFlow::Node node | this = node.asExpr().getExpr() | flowsToGuardExpr(node, guard))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the guard that uses this comparison.
|
||||
*/
|
||||
SensitiveActionGuardConditional getGuard() { result = guard }
|
||||
}
|
||||
|
||||
/**
|
||||
* An intermediary sink to enable reuse of the taint configuration.
|
||||
* This sink should not be presented to the client of this query.
|
||||
*/
|
||||
class SensitiveActionGuardComparisonOperand extends Sink {
|
||||
SensitiveActionGuardComparison comparison;
|
||||
|
||||
SensitiveActionGuardComparisonOperand() { this.asExpr().getExpr() = comparison.getAnOperand() }
|
||||
|
||||
override SensitiveAction getAction() { result = comparison.getGuard().getAction() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sink` guards `action`, and `source` taints `sink`.
|
||||
*
|
||||
* If flow from `source` taints `sink`, then an attacker can
|
||||
* control if `action` should be executed or not.
|
||||
*/
|
||||
predicate isTaintedGuardForSensitiveAction(
|
||||
DataFlow::PathNode sink, DataFlow::PathNode source, SensitiveAction action
|
||||
) {
|
||||
action = sink.getNode().(Sink).getAction() and
|
||||
// exclude the intermediary sink
|
||||
not sink.getNode() instanceof SensitiveActionGuardComparisonOperand and
|
||||
exists(Configuration cfg | cfg.hasFlowPath(source, sink))
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, SensitiveAction action
|
||||
where isTaintedGuardForSensitiveAction(sink, source, action)
|
||||
select sink.getNode(), source, sink, "This condition guards a sensitive $@, but $@ controls it.",
|
||||
action, "action", source.getNode(), "a user-provided value"
|
||||
10
ruby/ql/src/experimental/cwe-807/examples/bypass.rb
Normal file
10
ruby/ql/src/experimental/cwe-807/examples/bypass.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
class UsersController < ActionController::Base
|
||||
def example
|
||||
user = User.find_by(login: params[:login])
|
||||
if params[:authenticate]
|
||||
# BAD: decision to take sensitive action based on user-controlled data
|
||||
log_in user
|
||||
redirect_to user
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -78,7 +78,7 @@ ConstantWriteAccess definitionOf(string fqn) {
|
||||
fqn = resolveConstant(_) and
|
||||
result =
|
||||
min(ConstantWriteAccess w, Location l |
|
||||
w.getQualifiedName() = fqn and l = w.getLocation()
|
||||
w.getAQualifiedName() = fqn and l = w.getLocation()
|
||||
|
|
||||
w
|
||||
order by
|
||||
|
||||
@@ -170,7 +170,7 @@ calls/calls.rb:
|
||||
# 106| getStmt: [CaseExpr] case ...
|
||||
# 106| getValue: [MethodCall] call to foo
|
||||
# 106| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 107| getBranch: [WhenExpr] when ...
|
||||
# 107| getBranch: [WhenClause] when ...
|
||||
# 107| getPattern: [MethodCall] call to bar
|
||||
# 107| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 107| getBody: [StmtSequence] then ...
|
||||
@@ -179,7 +179,7 @@ calls/calls.rb:
|
||||
# 110| getStmt: [CaseExpr] case ...
|
||||
# 110| getValue: [MethodCall] call to foo
|
||||
# 110| getReceiver: [ConstantReadAccess] X
|
||||
# 111| getBranch: [WhenExpr] when ...
|
||||
# 111| getBranch: [WhenClause] when ...
|
||||
# 111| getPattern: [MethodCall] call to bar
|
||||
# 111| getReceiver: [ConstantReadAccess] X
|
||||
# 111| getBody: [StmtSequence] then ...
|
||||
@@ -559,7 +559,7 @@ calls/calls.rb:
|
||||
# 315| getArgument: [IntegerLiteral] 0
|
||||
# 315| getAnOperand/getRightOperand: [IntegerLiteral] 10
|
||||
# 316| getStmt: [AssignExpr] ... = ...
|
||||
# 316| getLeftOperand: [TuplePattern] (..., ...)
|
||||
# 316| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
|
||||
# 316| getElement: [MethodCall] call to foo
|
||||
# 316| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 316| getElement: [MethodCall] call to bar
|
||||
@@ -574,7 +574,7 @@ calls/calls.rb:
|
||||
# 316| getElement: [IntegerLiteral] 3
|
||||
# 316| getElement: [IntegerLiteral] 4
|
||||
# 317| getStmt: [AssignExpr] ... = ...
|
||||
# 317| getLeftOperand: [TuplePattern] (..., ...)
|
||||
# 317| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
|
||||
# 317| getElement: [LocalVariableAccess] a
|
||||
# 317| getElement: [ElementReference] ...[...]
|
||||
# 317| getReceiver: [MethodCall] call to foo
|
||||
@@ -654,7 +654,7 @@ calls/calls.rb:
|
||||
# 336| getArgument: [LocalVariableAccess] b
|
||||
# 336| getArgument: [ForwardedArguments] ...
|
||||
# 340| getStmt: [ForExpr] for ... in ...
|
||||
# 340| getPattern: [TuplePattern] (..., ...)
|
||||
# 340| getPattern: [DestructuredLhsExpr] (..., ...)
|
||||
# 340| getElement: [LocalVariableAccess] x
|
||||
# 340| getElement: [LocalVariableAccess] y
|
||||
# 340| getElement: [LocalVariableAccess] z
|
||||
@@ -689,11 +689,11 @@ control/cases.rb:
|
||||
# 5| getAnOperand/getRightOperand: [IntegerLiteral] 0
|
||||
# 8| getStmt: [CaseExpr] case ...
|
||||
# 8| getValue: [LocalVariableAccess] a
|
||||
# 9| getBranch: [WhenExpr] when ...
|
||||
# 9| getBranch: [WhenClause] when ...
|
||||
# 9| getPattern: [LocalVariableAccess] b
|
||||
# 9| getBody: [StmtSequence] then ...
|
||||
# 10| getStmt: [IntegerLiteral] 100
|
||||
# 11| getBranch: [WhenExpr] when ...
|
||||
# 11| getBranch: [WhenClause] when ...
|
||||
# 11| getPattern: [LocalVariableAccess] c
|
||||
# 11| getPattern: [LocalVariableAccess] d
|
||||
# 11| getBody: [StmtSequence] then ...
|
||||
@@ -701,19 +701,19 @@ control/cases.rb:
|
||||
# 13| getBranch/getElseBranch: [StmtSequence] else ...
|
||||
# 14| getStmt: [IntegerLiteral] 300
|
||||
# 18| getStmt: [CaseExpr] case ...
|
||||
# 19| getBranch: [WhenExpr] when ...
|
||||
# 19| getBranch: [WhenClause] when ...
|
||||
# 19| getPattern: [GTExpr] ... > ...
|
||||
# 19| getAnOperand/getGreaterOperand/getLeftOperand/getReceiver: [LocalVariableAccess] a
|
||||
# 19| getAnOperand/getArgument/getLesserOperand/getRightOperand: [LocalVariableAccess] b
|
||||
# 19| getBody: [StmtSequence] then ...
|
||||
# 19| getStmt: [IntegerLiteral] 10
|
||||
# 20| getBranch: [WhenExpr] when ...
|
||||
# 20| getBranch: [WhenClause] when ...
|
||||
# 20| getPattern: [EqExpr] ... == ...
|
||||
# 20| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] a
|
||||
# 20| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] b
|
||||
# 20| getBody: [StmtSequence] then ...
|
||||
# 20| getStmt: [IntegerLiteral] 20
|
||||
# 21| getBranch: [WhenExpr] when ...
|
||||
# 21| getBranch: [WhenClause] when ...
|
||||
# 21| getPattern: [LTExpr] ... < ...
|
||||
# 21| getAnOperand/getLeftOperand/getLesserOperand/getReceiver: [LocalVariableAccess] a
|
||||
# 21| getAnOperand/getArgument/getGreaterOperand/getRightOperand: [LocalVariableAccess] b
|
||||
@@ -1333,24 +1333,76 @@ constants/constants.rb:
|
||||
# 31| getScopeExpr: [ConstantReadAccess] ModuleA
|
||||
# 31| getSuperclassExpr: [ConstantReadAccess] ClassA
|
||||
# 31| getScopeExpr: [ConstantReadAccess] ModuleA
|
||||
# 34| getStmt: [ModuleDeclaration] ModuleC
|
||||
# 34| getScopeExpr: [ConstantReadAccess] ModuleA
|
||||
# 37| getStmt: [AssignExpr] ... = ...
|
||||
# 37| getAnOperand/getLeftOperand: [ConstantAssignment] MAX_SIZE
|
||||
# 37| getScopeExpr: [ConstantReadAccess] ModuleB
|
||||
# 37| getScopeExpr: [ConstantReadAccess] ModuleA
|
||||
# 37| getAnOperand/getRightOperand: [IntegerLiteral] 1024
|
||||
# 39| getStmt: [MethodCall] call to puts
|
||||
# 39| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 39| getArgument: [ConstantReadAccess] MAX_SIZE
|
||||
# 32| getStmt: [AssignExpr] ... = ...
|
||||
# 32| getAnOperand/getLeftOperand: [ConstantAssignment] FOURTY_TWO
|
||||
# 32| getAnOperand/getRightOperand: [IntegerLiteral] 42
|
||||
# 35| getStmt: [ModuleDeclaration] ModuleC
|
||||
# 35| getScopeExpr: [ConstantReadAccess] ModuleA
|
||||
# 36| getStmt: [AssignExpr] ... = ...
|
||||
# 36| getAnOperand/getLeftOperand: [ConstantAssignment] FOURTY_THREE
|
||||
# 36| getAnOperand/getRightOperand: [IntegerLiteral] 43
|
||||
# 39| getStmt: [AssignExpr] ... = ...
|
||||
# 39| getAnOperand/getLeftOperand: [ConstantAssignment] MAX_SIZE
|
||||
# 39| getScopeExpr: [ConstantReadAccess] ModuleB
|
||||
# 39| getScopeExpr: [ConstantReadAccess] ModuleA
|
||||
# 39| getAnOperand/getRightOperand: [IntegerLiteral] 1024
|
||||
# 41| getStmt: [MethodCall] call to puts
|
||||
# 41| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 41| getArgument: [ConstantReadAccess] GREETING
|
||||
# 42| getStmt: [MethodCall] call to puts
|
||||
# 42| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 42| getArgument: [ConstantReadAccess] GREETING
|
||||
# 41| getArgument: [ConstantReadAccess] MAX_SIZE
|
||||
# 41| getScopeExpr: [ConstantReadAccess] ModuleB
|
||||
# 41| getScopeExpr: [ConstantReadAccess] ModuleA
|
||||
# 43| getStmt: [MethodCall] call to puts
|
||||
# 43| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 43| getArgument: [ConstantReadAccess] GREETING
|
||||
# 44| getStmt: [MethodCall] call to puts
|
||||
# 44| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 44| getArgument: [ConstantReadAccess] GREETING
|
||||
# 46| getStmt: [ModuleDeclaration] ModuleB
|
||||
# 46| getScopeExpr: [ConstantReadAccess] ModuleA
|
||||
# 47| getStmt: [ClassDeclaration] ClassB
|
||||
# 47| getSuperclassExpr: [ConstantReadAccess] Base
|
||||
# 48| getStmt: [AssignExpr] ... = ...
|
||||
# 48| getAnOperand/getLeftOperand: [ConstantAssignment] FOURTY_ONE
|
||||
# 48| getAnOperand/getRightOperand: [IntegerLiteral] 41
|
||||
# 52| getStmt: [ModuleDeclaration] ModuleA
|
||||
# 53| getStmt: [AssignExpr] ... = ...
|
||||
# 53| getAnOperand/getLeftOperand: [ConstantAssignment] FOURTY_FOUR
|
||||
# 53| getAnOperand/getRightOperand: [StringLiteral] "fourty-four"
|
||||
# 53| getComponent: [StringTextComponent] fourty-four
|
||||
# 54| getStmt: [ClassDeclaration] ClassB
|
||||
# 54| getScopeExpr: [ConstantReadAccess] ModuleB
|
||||
# 54| getSuperclassExpr: [ConstantReadAccess] Base
|
||||
# 55| getStmt: [AssignExpr] ... = ...
|
||||
# 55| getAnOperand/getLeftOperand: [ClassVariableAccess] @@fourty_four
|
||||
# 55| getAnOperand/getRightOperand: [ConstantReadAccess] FOURTY_FOUR
|
||||
# 56| getStmt: [AssignExpr] ... = ...
|
||||
# 56| getAnOperand/getLeftOperand: [ConstantAssignment] FOURTY_FOUR
|
||||
# 56| getAnOperand/getRightOperand: [IntegerLiteral] 44
|
||||
# 57| getStmt: [AssignExpr] ... = ...
|
||||
# 57| getAnOperand/getLeftOperand: [ClassVariableAccess] @@fourty_four
|
||||
# 57| getAnOperand/getRightOperand: [ConstantReadAccess] FOURTY_FOUR
|
||||
# 61| getStmt: [ModuleDeclaration] Mod1
|
||||
# 62| getStmt: [ModuleDeclaration] Mod3
|
||||
# 63| getStmt: [AssignExpr] ... = ...
|
||||
# 63| getAnOperand/getLeftOperand: [ConstantAssignment] FOURTY_FIVE
|
||||
# 63| getAnOperand/getRightOperand: [IntegerLiteral] 45
|
||||
# 65| getStmt: [AssignExpr] ... = ...
|
||||
# 65| getAnOperand/getLeftOperand: [ClassVariableAccess] @@fourty_five
|
||||
# 65| getAnOperand/getRightOperand: [ConstantReadAccess] FOURTY_FIVE
|
||||
# 65| getScopeExpr: [ConstantReadAccess] Mod3
|
||||
# 68| getStmt: [ModuleDeclaration] Mod4
|
||||
# 69| getStmt: [MethodCall] call to include
|
||||
# 69| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 69| getArgument: [ConstantReadAccess] Mod1
|
||||
# 70| getStmt: [ModuleDeclaration] Mod5
|
||||
# 70| getScopeExpr: [ConstantReadAccess] Mod3
|
||||
# 71| getStmt: [AssignExpr] ... = ...
|
||||
# 71| getAnOperand/getLeftOperand: [ConstantAssignment] FOURTY_SIX
|
||||
# 71| getAnOperand/getRightOperand: [IntegerLiteral] 46
|
||||
# 73| getStmt: [AssignExpr] ... = ...
|
||||
# 73| getAnOperand/getLeftOperand: [ClassVariableAccess] @@fourty_six
|
||||
# 73| getAnOperand/getRightOperand: [ConstantReadAccess] FOURTY_SIX
|
||||
# 73| getScopeExpr: [ConstantReadAccess] Mod3
|
||||
literals/literals.rb:
|
||||
# 1| [Toplevel] literals.rb
|
||||
# 2| getStmt: [NilLiteral] nil
|
||||
@@ -1845,7 +1897,7 @@ control/loops.rb:
|
||||
# 18| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
|
||||
# 18| getAnOperand/getRightOperand: [LocalVariableAccess] n
|
||||
# 22| getStmt: [ForExpr] for ... in ...
|
||||
# 22| getPattern: [TuplePattern] (..., ...)
|
||||
# 22| getPattern: [DestructuredLhsExpr] (..., ...)
|
||||
# 22| getElement: [LocalVariableAccess] key
|
||||
# 22| getElement: [LocalVariableAccess] value
|
||||
# 22| getValue: [HashLiteral] {...}
|
||||
@@ -1863,7 +1915,7 @@ control/loops.rb:
|
||||
# 24| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
|
||||
# 24| getAnOperand/getRightOperand: [LocalVariableAccess] value
|
||||
# 28| getStmt: [ForExpr] for ... in ...
|
||||
# 28| getPattern: [TuplePattern] (..., ...)
|
||||
# 28| getPattern: [DestructuredLhsExpr] (..., ...)
|
||||
# 28| getElement: [LocalVariableAccess] key
|
||||
# 28| getElement: [LocalVariableAccess] value
|
||||
# 28| getValue: [HashLiteral] {...}
|
||||
@@ -2367,7 +2419,7 @@ params/params.rb:
|
||||
# 14| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo
|
||||
# 14| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] bar
|
||||
# 17| getStmt: [Method] destructured_method_param
|
||||
# 17| getParameter: [TuplePatternParameter] (..., ...)
|
||||
# 17| getParameter: [DestructuredParameter] (..., ...)
|
||||
# 17| getElement: [LocalVariableAccess] a
|
||||
# 17| getElement: [LocalVariableAccess] b
|
||||
# 17| getElement: [LocalVariableAccess] c
|
||||
@@ -2377,7 +2429,7 @@ params/params.rb:
|
||||
# 22| getStmt: [MethodCall] call to each
|
||||
# 22| getReceiver: [LocalVariableAccess] array
|
||||
# 22| getBlock: [BraceBlock] { ... }
|
||||
# 22| getParameter: [TuplePatternParameter] (..., ...)
|
||||
# 22| getParameter: [DestructuredParameter] (..., ...)
|
||||
# 22| getElement: [LocalVariableAccess] a
|
||||
# 22| getElement: [LocalVariableAccess] b
|
||||
# 22| getStmt: [MethodCall] call to puts
|
||||
@@ -2388,10 +2440,10 @@ params/params.rb:
|
||||
# 25| getStmt: [AssignExpr] ... = ...
|
||||
# 25| getAnOperand/getLeftOperand: [LocalVariableAccess] sum_four_values
|
||||
# 25| getAnOperand/getRightOperand: [Lambda] -> { ... }
|
||||
# 25| getParameter: [TuplePatternParameter] (..., ...)
|
||||
# 25| getParameter: [DestructuredParameter] (..., ...)
|
||||
# 25| getElement: [LocalVariableAccess] first
|
||||
# 25| getElement: [LocalVariableAccess] second
|
||||
# 25| getParameter: [TuplePatternParameter] (..., ...)
|
||||
# 25| getParameter: [DestructuredParameter] (..., ...)
|
||||
# 25| getElement: [LocalVariableAccess] third
|
||||
# 25| getElement: [LocalVariableAccess] fourth
|
||||
# 26| getStmt: [AddExpr] ... + ...
|
||||
|
||||
@@ -245,7 +245,7 @@ calls/calls.rb:
|
||||
# 340| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 340| getArgument: [IntegerLiteral] 2
|
||||
# 340| getReceiver: [LocalVariableAccess] __synth__0__1
|
||||
# 340| getLeftOperand: [TuplePattern] (..., ...)
|
||||
# 340| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
|
||||
# 341| getStmt: [MethodCall] call to foo
|
||||
# 341| getReceiver: [Self, SelfVariableAccess] self
|
||||
# 341| getArgument: [LocalVariableAccess] x
|
||||
@@ -477,7 +477,7 @@ control/loops.rb:
|
||||
# 22| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 22| getArgument: [IntegerLiteral] 1
|
||||
# 22| getReceiver: [LocalVariableAccess] __synth__0__1
|
||||
# 22| getLeftOperand: [TuplePattern] (..., ...)
|
||||
# 22| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
|
||||
# 23| getStmt: [AssignAddExpr] ... += ...
|
||||
# 23| getDesugared: [AssignExpr] ... = ...
|
||||
# 23| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
|
||||
@@ -518,7 +518,7 @@ control/loops.rb:
|
||||
# 28| getAnOperand/getRightOperand: [MethodCall] call to []
|
||||
# 28| getArgument: [IntegerLiteral] 1
|
||||
# 28| getReceiver: [LocalVariableAccess] __synth__0__1
|
||||
# 28| getLeftOperand: [TuplePattern] (..., ...)
|
||||
# 28| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
|
||||
# 29| getStmt: [AssignAddExpr] ... += ...
|
||||
# 29| getDesugared: [AssignExpr] ... = ...
|
||||
# 29| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
|
||||
|
||||
@@ -74,8 +74,20 @@
|
||||
| constants/constants.rb:20:22:20:28 | "Chuck" | Chuck |
|
||||
| constants/constants.rb:20:31:20:36 | "Dave" | Dave |
|
||||
| constants/constants.rb:28:11:28:15 | "foo" | foo |
|
||||
| constants/constants.rb:37:30:37:33 | 1024 | 1024 |
|
||||
| constants/constants.rb:39:6:39:31 | MAX_SIZE | 1024 |
|
||||
| constants/constants.rb:32:16:32:17 | 42 | 42 |
|
||||
| constants/constants.rb:36:18:36:19 | 43 | 43 |
|
||||
| constants/constants.rb:39:30:39:33 | 1024 | 1024 |
|
||||
| constants/constants.rb:41:6:41:31 | MAX_SIZE | 1024 |
|
||||
| constants/constants.rb:48:18:48:19 | 41 | 41 |
|
||||
| constants/constants.rb:53:17:53:29 | "fourty-four" | fourty-four |
|
||||
| constants/constants.rb:55:21:55:31 | FOURTY_FOUR | 44 |
|
||||
| constants/constants.rb:55:21:55:31 | FOURTY_FOUR | fourty-four |
|
||||
| constants/constants.rb:56:19:56:20 | 44 | 44 |
|
||||
| constants/constants.rb:57:21:57:31 | FOURTY_FOUR | 44 |
|
||||
| constants/constants.rb:57:21:57:31 | FOURTY_FOUR | fourty-four |
|
||||
| constants/constants.rb:63:19:63:20 | 45 | 45 |
|
||||
| constants/constants.rb:65:19:65:35 | FOURTY_FIVE | 45 |
|
||||
| constants/constants.rb:71:18:71:19 | 46 | 46 |
|
||||
| control/cases.rb:2:5:2:5 | 0 | 0 |
|
||||
| control/cases.rb:3:5:3:5 | 0 | 0 |
|
||||
| control/cases.rb:4:5:4:5 | 0 | 0 |
|
||||
|
||||
@@ -20,41 +20,87 @@ constantAccess
|
||||
| constants.rb:20:13:20:37 | Array | read | Array | ConstantReadAccess |
|
||||
| constants.rb:22:5:22:9 | Names | read | Names | ConstantReadAccess |
|
||||
| constants.rb:23:18:23:25 | GREETING | read | GREETING | ConstantReadAccess |
|
||||
| constants.rb:31:1:32:3 | ClassD | write | ClassD | ClassDeclaration |
|
||||
| constants.rb:31:1:33:3 | ClassD | write | ClassD | ClassDeclaration |
|
||||
| constants.rb:31:7:31:13 | ModuleA | read | ModuleA | ConstantReadAccess |
|
||||
| constants.rb:31:25:31:31 | ModuleA | read | ModuleA | ConstantReadAccess |
|
||||
| constants.rb:31:25:31:39 | ClassA | read | ClassA | ConstantReadAccess |
|
||||
| constants.rb:34:1:35:3 | ModuleC | write | ModuleC | ModuleDeclaration |
|
||||
| constants.rb:34:8:34:14 | ModuleA | read | ModuleA | ConstantReadAccess |
|
||||
| constants.rb:37:1:37:7 | ModuleA | read | ModuleA | ConstantReadAccess |
|
||||
| constants.rb:37:1:37:16 | ModuleB | read | ModuleB | ConstantReadAccess |
|
||||
| constants.rb:37:1:37:26 | MAX_SIZE | write | MAX_SIZE | ConstantAssignment |
|
||||
| constants.rb:39:6:39:12 | ModuleA | read | ModuleA | ConstantReadAccess |
|
||||
| constants.rb:39:6:39:21 | ModuleB | read | ModuleB | ConstantReadAccess |
|
||||
| constants.rb:39:6:39:31 | MAX_SIZE | read | MAX_SIZE | ConstantReadAccess |
|
||||
| constants.rb:41:6:41:13 | GREETING | read | GREETING | ConstantReadAccess |
|
||||
| constants.rb:42:6:42:15 | GREETING | read | GREETING | ConstantReadAccess |
|
||||
| constants.rb:32:3:32:12 | FOURTY_TWO | write | FOURTY_TWO | ConstantAssignment |
|
||||
| constants.rb:35:1:37:3 | ModuleC | write | ModuleC | ModuleDeclaration |
|
||||
| constants.rb:35:8:35:14 | ModuleA | read | ModuleA | ConstantReadAccess |
|
||||
| constants.rb:36:3:36:14 | FOURTY_THREE | write | FOURTY_THREE | ConstantAssignment |
|
||||
| constants.rb:39:1:39:7 | ModuleA | read | ModuleA | ConstantReadAccess |
|
||||
| constants.rb:39:1:39:16 | ModuleB | read | ModuleB | ConstantReadAccess |
|
||||
| constants.rb:39:1:39:26 | MAX_SIZE | write | MAX_SIZE | ConstantAssignment |
|
||||
| constants.rb:41:6:41:12 | ModuleA | read | ModuleA | ConstantReadAccess |
|
||||
| constants.rb:41:6:41:21 | ModuleB | read | ModuleB | ConstantReadAccess |
|
||||
| constants.rb:41:6:41:31 | MAX_SIZE | read | MAX_SIZE | ConstantReadAccess |
|
||||
| constants.rb:43:6:43:13 | GREETING | read | GREETING | ConstantReadAccess |
|
||||
| constants.rb:44:6:44:15 | GREETING | read | GREETING | ConstantReadAccess |
|
||||
| constants.rb:46:1:50:3 | ModuleB | write | ModuleB | ModuleDeclaration |
|
||||
| constants.rb:46:8:46:14 | ModuleA | read | ModuleA | ConstantReadAccess |
|
||||
| constants.rb:47:3:49:5 | ClassB | write | ClassB | ClassDeclaration |
|
||||
| constants.rb:47:18:47:21 | Base | read | Base | ConstantReadAccess |
|
||||
| constants.rb:48:5:48:14 | FOURTY_ONE | write | FOURTY_ONE | ConstantAssignment |
|
||||
| constants.rb:52:1:59:3 | ModuleA | write | ModuleA | ModuleDeclaration |
|
||||
| constants.rb:53:3:53:13 | FOURTY_FOUR | write | FOURTY_FOUR | ConstantAssignment |
|
||||
| constants.rb:54:3:58:5 | ClassB | write | ClassB | ClassDeclaration |
|
||||
| constants.rb:54:9:54:15 | ModuleB | read | ModuleB | ConstantReadAccess |
|
||||
| constants.rb:54:27:54:30 | Base | read | Base | ConstantReadAccess |
|
||||
| constants.rb:55:21:55:31 | FOURTY_FOUR | read | FOURTY_FOUR | ConstantReadAccess |
|
||||
| constants.rb:56:5:56:15 | FOURTY_FOUR | write | FOURTY_FOUR | ConstantAssignment |
|
||||
| constants.rb:57:21:57:31 | FOURTY_FOUR | read | FOURTY_FOUR | ConstantReadAccess |
|
||||
| constants.rb:61:1:66:3 | Mod1 | write | Mod1 | ModuleDeclaration |
|
||||
| constants.rb:62:3:64:5 | Mod3 | write | Mod3 | ModuleDeclaration |
|
||||
| constants.rb:63:5:63:15 | FOURTY_FIVE | write | FOURTY_FIVE | ConstantAssignment |
|
||||
| constants.rb:65:19:65:22 | Mod3 | read | Mod3 | ConstantReadAccess |
|
||||
| constants.rb:65:19:65:35 | FOURTY_FIVE | read | FOURTY_FIVE | ConstantReadAccess |
|
||||
| constants.rb:68:1:74:3 | Mod4 | write | Mod4 | ModuleDeclaration |
|
||||
| constants.rb:69:11:69:14 | Mod1 | read | Mod1 | ConstantReadAccess |
|
||||
| constants.rb:70:3:72:5 | Mod5 | write | Mod5 | ModuleDeclaration |
|
||||
| constants.rb:70:10:70:13 | Mod3 | read | Mod3 | ConstantReadAccess |
|
||||
| constants.rb:71:5:71:14 | FOURTY_SIX | write | FOURTY_SIX | ConstantAssignment |
|
||||
| constants.rb:73:18:73:21 | Mod3 | read | Mod3 | ConstantReadAccess |
|
||||
| constants.rb:73:18:73:33 | FOURTY_SIX | read | FOURTY_SIX | ConstantReadAccess |
|
||||
getConst
|
||||
| constants.rb:1:1:15:3 | ModuleA | CONST_B | constants.rb:6:15:6:23 | "const_b" |
|
||||
| constants.rb:1:1:15:3 | ModuleA | FOURTY_FOUR | constants.rb:53:17:53:29 | "fourty-four" |
|
||||
| constants.rb:2:5:4:7 | ModuleA::ClassA | CONST_A | constants.rb:3:19:3:27 | "const_a" |
|
||||
| constants.rb:31:1:33:3 | ModuleA::ClassD | FOURTY_TWO | constants.rb:32:16:32:17 | 42 |
|
||||
| constants.rb:35:1:37:3 | ModuleA::ModuleC | FOURTY_THREE | constants.rb:36:18:36:19 | 43 |
|
||||
| constants.rb:54:3:58:5 | ModuleA::ModuleB::ClassB | FOURTY_FOUR | constants.rb:56:19:56:20 | 44 |
|
||||
| constants.rb:54:3:58:5 | ModuleA::ModuleB::ClassB | FOURTY_ONE | constants.rb:48:18:48:19 | 41 |
|
||||
| constants.rb:62:3:64:5 | Mod1::Mod3 | FOURTY_FIVE | constants.rb:63:19:63:20 | 45 |
|
||||
| constants.rb:70:3:72:5 | Mod1::Mod3::Mod5 | FOURTY_SIX | constants.rb:71:18:71:19 | 46 |
|
||||
| file://:0:0:0:0 | Object | GREETING | constants.rb:17:12:17:64 | ... + ... |
|
||||
lookupConst
|
||||
| constants.rb:1:1:15:3 | ModuleA | CONST_B | constants.rb:6:15:6:23 | "const_b" |
|
||||
| constants.rb:1:1:15:3 | ModuleA | FOURTY_FOUR | constants.rb:53:17:53:29 | "fourty-four" |
|
||||
| constants.rb:2:5:4:7 | ModuleA::ClassA | CONST_A | constants.rb:3:19:3:27 | "const_a" |
|
||||
| constants.rb:2:5:4:7 | ModuleA::ClassA | GREETING | constants.rb:17:12:17:64 | ... + ... |
|
||||
| constants.rb:8:5:14:7 | ModuleA::ModuleB | MAX_SIZE | constants.rb:37:30:37:33 | 1024 |
|
||||
| constants.rb:9:9:10:11 | ModuleA::ModuleB::ClassB | GREETING | constants.rb:17:12:17:64 | ... + ... |
|
||||
| constants.rb:8:5:14:7 | ModuleA::ModuleB | MAX_SIZE | constants.rb:39:30:39:33 | 1024 |
|
||||
| constants.rb:12:9:13:11 | ModuleA::ModuleB::ClassC | GREETING | constants.rb:17:12:17:64 | ... + ... |
|
||||
| constants.rb:31:1:32:3 | ModuleA::ClassD | CONST_A | constants.rb:3:19:3:27 | "const_a" |
|
||||
| constants.rb:31:1:32:3 | ModuleA::ClassD | GREETING | constants.rb:17:12:17:64 | ... + ... |
|
||||
| constants.rb:31:1:33:3 | ModuleA::ClassD | CONST_A | constants.rb:3:19:3:27 | "const_a" |
|
||||
| constants.rb:31:1:33:3 | ModuleA::ClassD | FOURTY_TWO | constants.rb:32:16:32:17 | 42 |
|
||||
| constants.rb:31:1:33:3 | ModuleA::ClassD | GREETING | constants.rb:17:12:17:64 | ... + ... |
|
||||
| constants.rb:35:1:37:3 | ModuleA::ModuleC | FOURTY_THREE | constants.rb:36:18:36:19 | 43 |
|
||||
| constants.rb:54:3:58:5 | ModuleA::ModuleB::ClassB | FOURTY_FOUR | constants.rb:56:19:56:20 | 44 |
|
||||
| constants.rb:54:3:58:5 | ModuleA::ModuleB::ClassB | FOURTY_ONE | constants.rb:48:18:48:19 | 41 |
|
||||
| constants.rb:54:3:58:5 | ModuleA::ModuleB::ClassB | GREETING | constants.rb:17:12:17:64 | ... + ... |
|
||||
| constants.rb:62:3:64:5 | Mod1::Mod3 | FOURTY_FIVE | constants.rb:63:19:63:20 | 45 |
|
||||
| constants.rb:70:3:72:5 | Mod1::Mod3::Mod5 | FOURTY_SIX | constants.rb:71:18:71:19 | 46 |
|
||||
| file://:0:0:0:0 | Object | GREETING | constants.rb:17:12:17:64 | ... + ... |
|
||||
constantValue
|
||||
| constants.rb:17:22:17:45 | CONST_A | constants.rb:3:19:3:27 | "const_a" |
|
||||
| constants.rb:17:49:17:64 | CONST_B | constants.rb:6:15:6:23 | "const_b" |
|
||||
| constants.rb:23:18:23:25 | GREETING | constants.rb:17:12:17:64 | ... + ... |
|
||||
| constants.rb:39:6:39:31 | MAX_SIZE | constants.rb:37:30:37:33 | 1024 |
|
||||
| constants.rb:41:6:41:13 | GREETING | constants.rb:17:12:17:64 | ... + ... |
|
||||
| constants.rb:42:6:42:15 | GREETING | constants.rb:17:12:17:64 | ... + ... |
|
||||
| constants.rb:41:6:41:31 | MAX_SIZE | constants.rb:39:30:39:33 | 1024 |
|
||||
| constants.rb:43:6:43:13 | GREETING | constants.rb:17:12:17:64 | ... + ... |
|
||||
| constants.rb:44:6:44:15 | GREETING | constants.rb:17:12:17:64 | ... + ... |
|
||||
| constants.rb:55:21:55:31 | FOURTY_FOUR | constants.rb:53:17:53:29 | "fourty-four" |
|
||||
| constants.rb:55:21:55:31 | FOURTY_FOUR | constants.rb:56:19:56:20 | 44 |
|
||||
| constants.rb:57:21:57:31 | FOURTY_FOUR | constants.rb:53:17:53:29 | "fourty-four" |
|
||||
| constants.rb:57:21:57:31 | FOURTY_FOUR | constants.rb:56:19:56:20 | 44 |
|
||||
| constants.rb:65:19:65:35 | FOURTY_FIVE | constants.rb:63:19:63:20 | 45 |
|
||||
constantWriteAccessQualifiedName
|
||||
| constants.rb:1:1:15:3 | ModuleA | ModuleA |
|
||||
| constants.rb:2:5:4:7 | ClassA | ModuleA::ClassA |
|
||||
@@ -65,6 +111,25 @@ constantWriteAccessQualifiedName
|
||||
| constants.rb:12:9:13:11 | ClassC | ModuleA::ModuleB::ClassC |
|
||||
| constants.rb:17:1:17:8 | GREETING | GREETING |
|
||||
| constants.rb:20:5:20:9 | Names | Names |
|
||||
| constants.rb:31:1:32:3 | ClassD | ClassD |
|
||||
| constants.rb:34:1:35:3 | ModuleC | ModuleC |
|
||||
| constants.rb:37:1:37:26 | MAX_SIZE | MAX_SIZE |
|
||||
| constants.rb:31:1:33:3 | ClassD | ModuleA::ClassD |
|
||||
| constants.rb:32:3:32:12 | FOURTY_TWO | ModuleA::ClassD::FOURTY_TWO |
|
||||
| constants.rb:35:1:37:3 | ModuleC | ModuleA::ModuleC |
|
||||
| constants.rb:36:3:36:14 | FOURTY_THREE | ModuleA::ModuleC::FOURTY_THREE |
|
||||
| constants.rb:39:1:39:26 | MAX_SIZE | ModuleA::ModuleB::MAX_SIZE |
|
||||
| constants.rb:46:1:50:3 | ModuleB | ModuleA::ModuleB |
|
||||
| constants.rb:47:3:49:5 | ClassB | ModuleA::ModuleB::ClassB |
|
||||
| constants.rb:48:5:48:14 | FOURTY_ONE | ModuleA::ModuleB::ClassB::FOURTY_ONE |
|
||||
| constants.rb:52:1:59:3 | ModuleA | ModuleA |
|
||||
| constants.rb:53:3:53:13 | FOURTY_FOUR | ModuleA::FOURTY_FOUR |
|
||||
| constants.rb:54:3:58:5 | ClassB | ModuleA::ModuleB::ClassB |
|
||||
| constants.rb:54:3:58:5 | ClassB | ModuleB::ClassB |
|
||||
| constants.rb:56:5:56:15 | FOURTY_FOUR | ModuleA::ModuleB::ClassB::FOURTY_FOUR |
|
||||
| constants.rb:56:5:56:15 | FOURTY_FOUR | ModuleB::ClassB::FOURTY_FOUR |
|
||||
| constants.rb:61:1:66:3 | Mod1 | Mod1 |
|
||||
| constants.rb:62:3:64:5 | Mod3 | Mod1::Mod3 |
|
||||
| constants.rb:63:5:63:15 | FOURTY_FIVE | Mod1::Mod3::FOURTY_FIVE |
|
||||
| constants.rb:68:1:74:3 | Mod4 | Mod4 |
|
||||
| constants.rb:70:3:72:5 | Mod5 | Mod1::Mod3::Mod5 |
|
||||
| constants.rb:70:3:72:5 | Mod5 | Mod3::Mod5 |
|
||||
| constants.rb:71:5:71:14 | FOURTY_SIX | Mod1::Mod3::Mod5::FOURTY_SIX |
|
||||
| constants.rb:71:5:71:14 | FOURTY_SIX | Mod3::Mod5::FOURTY_SIX |
|
||||
|
||||
@@ -18,5 +18,5 @@ query Expr lookupConst(Module m, string name) { result = M::lookupConst(m, name)
|
||||
query predicate constantValue(ConstantReadAccess a, Expr e) { e = a.getValue() }
|
||||
|
||||
query predicate constantWriteAccessQualifiedName(ConstantWriteAccess w, string qualifiedName) {
|
||||
w.getQualifiedName() = qualifiedName
|
||||
w.getAQualifiedName() = qualifiedName
|
||||
}
|
||||
|
||||
@@ -29,9 +29,11 @@ def foo
|
||||
end
|
||||
|
||||
class ModuleA::ClassD < ModuleA::ClassA
|
||||
FOURTY_TWO = 42
|
||||
end
|
||||
|
||||
module ModuleA::ModuleC
|
||||
FOURTY_THREE = 43
|
||||
end
|
||||
|
||||
ModuleA::ModuleB::MAX_SIZE = 1024
|
||||
@@ -40,3 +42,33 @@ puts ModuleA::ModuleB::MAX_SIZE
|
||||
|
||||
puts GREETING
|
||||
puts ::GREETING
|
||||
|
||||
module ModuleA::ModuleB
|
||||
class ClassB < Base
|
||||
FOURTY_ONE = 41
|
||||
end
|
||||
end
|
||||
|
||||
module ModuleA
|
||||
FOURTY_FOUR = "fourty-four"
|
||||
class ModuleB::ClassB < Base
|
||||
@@fourty_four = FOURTY_FOUR # refers to ::ModuleA::FOURTY_FOUR
|
||||
FOURTY_FOUR = 44
|
||||
@@fourty_four = FOURTY_FOUR # refers to ::ModuleA::ModuleB::ClassB::FOURTY_FOUR
|
||||
end
|
||||
end
|
||||
|
||||
module Mod1
|
||||
module Mod3
|
||||
FOURTY_FIVE = 45
|
||||
end
|
||||
@@fourty_five = Mod3::FOURTY_FIVE
|
||||
end
|
||||
|
||||
module Mod4
|
||||
include Mod1
|
||||
module Mod3::Mod5
|
||||
FOURTY_SIX = 46
|
||||
end
|
||||
@@fourty_six = Mod3::FOURTY_SIX
|
||||
end
|
||||
|
||||
@@ -10,10 +10,10 @@ query predicate caseElseBranches(CaseExpr c, StmtSequence elseBranch) {
|
||||
|
||||
query predicate caseNoElseBranches(CaseExpr c) { not exists(c.getElseBranch()) }
|
||||
|
||||
query predicate caseWhenBranches(CaseExpr c, WhenExpr when, int pIndex, Expr p, StmtSequence body) {
|
||||
query predicate caseWhenBranches(CaseExpr c, WhenClause when, int pIndex, Expr p, StmtSequence body) {
|
||||
when = c.getABranch() and
|
||||
p = when.getPattern(pIndex) and
|
||||
body = when.getBody()
|
||||
}
|
||||
|
||||
query predicate caseAllBranches(CaseExpr c, int n, Expr branch) { branch = c.getBranch(n) }
|
||||
query predicate caseAllBranches(CaseExpr c, int n, AstNode branch) { branch = c.getBranch(n) }
|
||||
|
||||
@@ -13,13 +13,13 @@ query predicate conditionalLoops(
|
||||
cond = l.getCondition()
|
||||
}
|
||||
|
||||
query predicate forExprs(ForExpr f, Pattern p, StmtSequence body, int i, Stmt bodyChild) {
|
||||
query predicate forExprs(ForExpr f, LhsExpr p, StmtSequence body, int i, Stmt bodyChild) {
|
||||
p = f.getPattern() and
|
||||
body = f.getBody() and
|
||||
bodyChild = body.getStmt(i)
|
||||
}
|
||||
|
||||
query predicate forExprsTuplePatterns(ForExpr f, TuplePattern tp, int i, Pattern cp) {
|
||||
query predicate forExprsTuplePatterns(ForExpr f, DestructuredLhsExpr tp, int i, Expr cp) {
|
||||
tp = f.getPattern() and
|
||||
cp = tp.getElement(i)
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ paramsInMethods
|
||||
| params.rb:4:1:5:3 | identifier_method_params | 0 | params.rb:4:30:4:32 | foo | SimpleParameter |
|
||||
| params.rb:4:1:5:3 | identifier_method_params | 1 | params.rb:4:35:4:37 | bar | SimpleParameter |
|
||||
| params.rb:4:1:5:3 | identifier_method_params | 2 | params.rb:4:40:4:42 | baz | SimpleParameter |
|
||||
| params.rb:17:1:18:3 | destructured_method_param | 0 | params.rb:17:31:17:39 | (..., ...) | TuplePatternParameter |
|
||||
| params.rb:17:1:18:3 | destructured_method_param | 0 | params.rb:17:31:17:39 | (..., ...) | DestructuredParameter |
|
||||
| params.rb:30:1:31:3 | method_with_splat | 0 | params.rb:30:23:30:28 | wibble | SimpleParameter |
|
||||
| params.rb:30:1:31:3 | method_with_splat | 1 | params.rb:30:31:30:36 | *splat | SplatParameter |
|
||||
| params.rb:30:1:31:3 | method_with_splat | 2 | params.rb:30:39:30:52 | **double_splat | HashSplatParameter |
|
||||
@@ -90,7 +90,7 @@ paramsInMethods
|
||||
paramsInBlocks
|
||||
| params.rb:9:11:11:3 | do ... end | 0 | params.rb:9:15:9:17 | key | SimpleParameter |
|
||||
| params.rb:9:11:11:3 | do ... end | 1 | params.rb:9:20:9:24 | value | SimpleParameter |
|
||||
| params.rb:22:12:22:32 | { ... } | 0 | params.rb:22:15:22:20 | (..., ...) | TuplePatternParameter |
|
||||
| params.rb:22:12:22:32 | { ... } | 0 | params.rb:22:15:22:20 | (..., ...) | DestructuredParameter |
|
||||
| params.rb:34:12:35:3 | do ... end | 0 | params.rb:34:16:34:18 | val | SimpleParameter |
|
||||
| params.rb:34:12:35:3 | do ... end | 1 | params.rb:34:21:34:26 | *splat | SplatParameter |
|
||||
| params.rb:34:12:35:3 | do ... end | 2 | params.rb:34:29:34:42 | **double_splat | HashSplatParameter |
|
||||
@@ -103,8 +103,8 @@ paramsInBlocks
|
||||
paramsInLambdas
|
||||
| params.rb:14:7:14:33 | -> { ... } | 0 | params.rb:14:11:14:13 | foo | SimpleParameter |
|
||||
| params.rb:14:7:14:33 | -> { ... } | 1 | params.rb:14:16:14:18 | bar | SimpleParameter |
|
||||
| params.rb:25:19:27:1 | -> { ... } | 0 | params.rb:25:23:25:37 | (..., ...) | TuplePatternParameter |
|
||||
| params.rb:25:19:27:1 | -> { ... } | 1 | params.rb:25:40:25:54 | (..., ...) | TuplePatternParameter |
|
||||
| params.rb:25:19:27:1 | -> { ... } | 0 | params.rb:25:23:25:37 | (..., ...) | DestructuredParameter |
|
||||
| params.rb:25:19:27:1 | -> { ... } | 1 | params.rb:25:40:25:54 | (..., ...) | DestructuredParameter |
|
||||
| params.rb:38:22:38:47 | -> { ... } | 0 | params.rb:38:26:38:26 | x | SimpleParameter |
|
||||
| params.rb:38:22:38:47 | -> { ... } | 1 | params.rb:38:29:38:33 | *blah | SplatParameter |
|
||||
| params.rb:38:22:38:47 | -> { ... } | 2 | params.rb:38:36:38:43 | **wibble | HashSplatParameter |
|
||||
@@ -122,10 +122,10 @@ params
|
||||
| params.rb:9:20:9:24 | value | 1 | SimpleParameter |
|
||||
| params.rb:14:11:14:13 | foo | 0 | SimpleParameter |
|
||||
| params.rb:14:16:14:18 | bar | 1 | SimpleParameter |
|
||||
| params.rb:17:31:17:39 | (..., ...) | 0 | TuplePatternParameter |
|
||||
| params.rb:22:15:22:20 | (..., ...) | 0 | TuplePatternParameter |
|
||||
| params.rb:25:23:25:37 | (..., ...) | 0 | TuplePatternParameter |
|
||||
| params.rb:25:40:25:54 | (..., ...) | 1 | TuplePatternParameter |
|
||||
| params.rb:17:31:17:39 | (..., ...) | 0 | DestructuredParameter |
|
||||
| params.rb:22:15:22:20 | (..., ...) | 0 | DestructuredParameter |
|
||||
| params.rb:25:23:25:37 | (..., ...) | 0 | DestructuredParameter |
|
||||
| params.rb:25:40:25:54 | (..., ...) | 1 | DestructuredParameter |
|
||||
| params.rb:30:23:30:28 | wibble | 0 | SimpleParameter |
|
||||
| params.rb:30:31:30:36 | *splat | 1 | SplatParameter |
|
||||
| params.rb:30:39:30:52 | **double_splat | 2 | HashSplatParameter |
|
||||
|
||||
@@ -6,7 +6,7 @@ query predicate idParams(NamedParameter np, string name) { name = np.getName() }
|
||||
|
||||
query predicate blockParams(BlockParameter bp, string name) { name = bp.getName() }
|
||||
|
||||
query predicate patternParams(TuplePatternParameter tpp, Pattern child, int childIndex) {
|
||||
query predicate patternParams(DestructuredParameter tpp, AstNode child, int childIndex) {
|
||||
tpp.getElement(childIndex) = child
|
||||
}
|
||||
|
||||
|
||||
@@ -486,7 +486,7 @@ break_ensure.rb:
|
||||
|
||||
case.rb:
|
||||
# 1| enter if_in_case
|
||||
#-----| -> case ...
|
||||
#-----| -> self
|
||||
|
||||
# 1| enter case.rb
|
||||
#-----| -> if_in_case
|
||||
@@ -505,7 +505,7 @@ case.rb:
|
||||
#-----| -> exit case.rb
|
||||
|
||||
# 2| case ...
|
||||
#-----| -> self
|
||||
#-----| -> exit if_in_case (normal)
|
||||
|
||||
# 2| call to x1
|
||||
#-----| -> when ...
|
||||
@@ -521,7 +521,7 @@ case.rb:
|
||||
#-----| match -> self
|
||||
|
||||
# 3| then ...
|
||||
#-----| -> exit if_in_case (normal)
|
||||
#-----| -> case ...
|
||||
|
||||
# 3| ( ... )
|
||||
#-----| -> then ...
|
||||
@@ -552,11 +552,11 @@ case.rb:
|
||||
#-----| -> 2
|
||||
|
||||
# 4| 2
|
||||
#-----| no-match -> case ...
|
||||
#-----| match -> self
|
||||
#-----| no-match -> exit if_in_case (normal)
|
||||
|
||||
# 4| then ...
|
||||
#-----| -> exit if_in_case (normal)
|
||||
#-----| -> case ...
|
||||
|
||||
# 4| call to puts
|
||||
#-----| -> then ...
|
||||
@@ -579,10 +579,10 @@ case.rb:
|
||||
#-----| -> exit case_match
|
||||
|
||||
# 8| value
|
||||
#-----| -> case ...
|
||||
#-----| -> value
|
||||
|
||||
# 9| case ...
|
||||
#-----| -> value
|
||||
#-----| -> exit case_match (normal)
|
||||
|
||||
# 9| value
|
||||
#-----| -> in ... then ...
|
||||
@@ -591,8 +591,8 @@ case.rb:
|
||||
#-----| -> 0
|
||||
|
||||
# 10| 0
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match (normal)
|
||||
|
||||
# 11| in ... then ...
|
||||
#-----| -> 1
|
||||
@@ -602,7 +602,7 @@ case.rb:
|
||||
#-----| match -> 3
|
||||
|
||||
# 11| then ...
|
||||
#-----| -> exit case_match (normal)
|
||||
#-----| -> case ...
|
||||
|
||||
# 11| 3
|
||||
#-----| -> then ...
|
||||
@@ -615,7 +615,7 @@ case.rb:
|
||||
#-----| match -> 4
|
||||
|
||||
# 12| then ...
|
||||
#-----| -> exit case_match (normal)
|
||||
#-----| -> case ...
|
||||
|
||||
# 13| 4
|
||||
#-----| -> then ...
|
||||
@@ -637,7 +637,7 @@ case.rb:
|
||||
#-----| -> ... == ...
|
||||
|
||||
# 14| then ...
|
||||
#-----| -> exit case_match (normal)
|
||||
#-----| -> case ...
|
||||
|
||||
# 14| 6
|
||||
#-----| -> then ...
|
||||
@@ -659,13 +659,13 @@ case.rb:
|
||||
#-----| -> ... < ...
|
||||
|
||||
# 15| then ...
|
||||
#-----| -> exit case_match (normal)
|
||||
#-----| -> case ...
|
||||
|
||||
# 15| 7
|
||||
#-----| -> then ...
|
||||
|
||||
# 16| else ...
|
||||
#-----| -> exit case_match (normal)
|
||||
#-----| -> case ...
|
||||
|
||||
# 16| 8
|
||||
#-----| -> else ...
|
||||
@@ -685,10 +685,10 @@ case.rb:
|
||||
#-----| -> exit case_match_no_match
|
||||
|
||||
# 20| value
|
||||
#-----| -> case ...
|
||||
#-----| -> value
|
||||
|
||||
# 21| case ...
|
||||
#-----| -> value
|
||||
#-----| -> exit case_match_no_match (normal)
|
||||
|
||||
# 21| value
|
||||
#-----| -> in ... then ...
|
||||
@@ -697,8 +697,8 @@ case.rb:
|
||||
#-----| -> 1
|
||||
|
||||
# 22| 1
|
||||
#-----| match -> case ...
|
||||
#-----| raise -> exit case_match_no_match (abnormal)
|
||||
#-----| match -> exit case_match_no_match (normal)
|
||||
|
||||
# 26| enter case_match_raise
|
||||
#-----| -> value
|
||||
@@ -715,10 +715,10 @@ case.rb:
|
||||
#-----| -> exit case_match_raise
|
||||
|
||||
# 26| value
|
||||
#-----| -> case ...
|
||||
#-----| -> value
|
||||
|
||||
# 27| case ...
|
||||
#-----| -> value
|
||||
#-----| -> exit case_match_raise (normal)
|
||||
|
||||
# 27| value
|
||||
#-----| -> in ... then ...
|
||||
@@ -730,8 +730,8 @@ case.rb:
|
||||
#-----| -> x
|
||||
|
||||
# 28| -> { ... }
|
||||
#-----| match -> case ...
|
||||
#-----| raise -> exit case_match_raise (abnormal)
|
||||
#-----| match -> exit case_match_raise (normal)
|
||||
|
||||
# 28| exit -> { ... }
|
||||
|
||||
@@ -765,10 +765,10 @@ case.rb:
|
||||
#-----| -> exit case_match_array
|
||||
|
||||
# 32| value
|
||||
#-----| -> case ...
|
||||
#-----| -> value
|
||||
|
||||
# 33| case ...
|
||||
#-----| -> value
|
||||
#-----| -> exit case_match_array (normal)
|
||||
|
||||
# 33| value
|
||||
#-----| -> in ... then ...
|
||||
@@ -777,8 +777,8 @@ case.rb:
|
||||
#-----| -> [ ..., * ]
|
||||
|
||||
# 34| [ ..., * ]
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_array (normal)
|
||||
|
||||
# 35| in ... then ...
|
||||
#-----| -> [ ..., * ]
|
||||
@@ -788,7 +788,7 @@ case.rb:
|
||||
#-----| match -> x
|
||||
|
||||
# 35| x
|
||||
#-----| match -> exit case_match_array (normal)
|
||||
#-----| match -> case ...
|
||||
|
||||
# 36| in ... then ...
|
||||
#-----| -> [ ..., * ]
|
||||
@@ -798,7 +798,7 @@ case.rb:
|
||||
#-----| match -> x
|
||||
|
||||
# 36| x
|
||||
#-----| match -> exit case_match_array (normal)
|
||||
#-----| match -> case ...
|
||||
|
||||
# 37| in ... then ...
|
||||
#-----| -> Bar
|
||||
@@ -824,7 +824,7 @@ case.rb:
|
||||
#-----| match -> e
|
||||
|
||||
# 37| e
|
||||
#-----| match -> exit case_match_array (normal)
|
||||
#-----| match -> case ...
|
||||
|
||||
# 41| enter case_match_find
|
||||
#-----| -> value
|
||||
@@ -841,10 +841,10 @@ case.rb:
|
||||
#-----| -> exit case_match_find
|
||||
|
||||
# 41| value
|
||||
#-----| -> case ...
|
||||
#-----| -> value
|
||||
|
||||
# 42| case ...
|
||||
#-----| -> value
|
||||
#-----| -> exit case_match_find (normal)
|
||||
|
||||
# 42| value
|
||||
#-----| -> in ... then ...
|
||||
@@ -868,7 +868,7 @@ case.rb:
|
||||
#-----| raise -> exit case_match_find (abnormal)
|
||||
|
||||
# 43| y
|
||||
#-----| -> exit case_match_find (normal)
|
||||
#-----| -> case ...
|
||||
|
||||
# 47| enter case_match_hash
|
||||
#-----| -> value
|
||||
@@ -885,10 +885,10 @@ case.rb:
|
||||
#-----| -> exit case_match_hash
|
||||
|
||||
# 47| value
|
||||
#-----| -> case ...
|
||||
#-----| -> value
|
||||
|
||||
# 48| case ...
|
||||
#-----| -> value
|
||||
#-----| -> exit case_match_hash (normal)
|
||||
|
||||
# 48| value
|
||||
#-----| -> in ... then ...
|
||||
@@ -912,7 +912,7 @@ case.rb:
|
||||
#-----| match -> rest
|
||||
|
||||
# 49| rest
|
||||
#-----| -> exit case_match_hash (normal)
|
||||
#-----| -> case ...
|
||||
|
||||
# 50| in ... then ...
|
||||
#-----| -> Bar
|
||||
@@ -926,15 +926,15 @@ case.rb:
|
||||
#-----| no-match -> in ... then ...
|
||||
|
||||
# 50| 1
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_hash (normal)
|
||||
|
||||
# 51| in ... then ...
|
||||
#-----| -> Bar
|
||||
|
||||
# 51| { ..., ** }
|
||||
#-----| match -> case ...
|
||||
#-----| raise -> exit case_match_hash (abnormal)
|
||||
#-----| match -> exit case_match_hash (normal)
|
||||
|
||||
# 51| Bar
|
||||
#-----| match -> { ..., ** }
|
||||
@@ -952,10 +952,10 @@ case.rb:
|
||||
#-----| -> exit case_match_variable
|
||||
|
||||
# 55| value
|
||||
#-----| -> case ...
|
||||
#-----| -> value
|
||||
|
||||
# 56| case ...
|
||||
#-----| -> value
|
||||
#-----| -> exit case_match_variable (normal)
|
||||
|
||||
# 56| value
|
||||
#-----| -> in ... then ...
|
||||
@@ -964,14 +964,14 @@ case.rb:
|
||||
#-----| -> 5
|
||||
|
||||
# 57| 5
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_variable (normal)
|
||||
|
||||
# 58| in ... then ...
|
||||
#-----| -> var
|
||||
|
||||
# 58| var
|
||||
#-----| match -> exit case_match_variable (normal)
|
||||
#-----| match -> case ...
|
||||
|
||||
# 63| enter case_match_underscore
|
||||
#-----| -> value
|
||||
@@ -985,10 +985,10 @@ case.rb:
|
||||
#-----| -> exit case_match_underscore
|
||||
|
||||
# 63| value
|
||||
#-----| -> case ...
|
||||
#-----| -> value
|
||||
|
||||
# 64| case ...
|
||||
#-----| -> value
|
||||
#-----| -> exit case_match_underscore (normal)
|
||||
|
||||
# 64| value
|
||||
#-----| -> in ... then ...
|
||||
@@ -1000,11 +1000,11 @@ case.rb:
|
||||
#-----| -> 5
|
||||
|
||||
# 65| 5
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> _
|
||||
#-----| match -> exit case_match_underscore (normal)
|
||||
|
||||
# 65| _
|
||||
#-----| match -> exit case_match_underscore (normal)
|
||||
#-----| match -> case ...
|
||||
|
||||
# 69| enter case_match_various
|
||||
#-----| -> value
|
||||
@@ -1024,7 +1024,7 @@ case.rb:
|
||||
#-----| -> foo
|
||||
|
||||
# 70| ... = ...
|
||||
#-----| -> case ...
|
||||
#-----| -> value
|
||||
|
||||
# 70| foo
|
||||
#-----| -> 42
|
||||
@@ -1033,7 +1033,7 @@ case.rb:
|
||||
#-----| -> ... = ...
|
||||
|
||||
# 72| case ...
|
||||
#-----| -> value
|
||||
#-----| -> exit case_match_various (normal)
|
||||
|
||||
# 72| value
|
||||
#-----| -> in ... then ...
|
||||
@@ -1042,8 +1042,8 @@ case.rb:
|
||||
#-----| -> 5
|
||||
|
||||
# 73| 5
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 74| in ... then ...
|
||||
#-----| -> ^...
|
||||
@@ -1052,22 +1052,22 @@ case.rb:
|
||||
#-----| -> foo
|
||||
|
||||
# 74| foo
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 75| in ... then ...
|
||||
#-----| -> "string"
|
||||
|
||||
# 75| "string"
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 76| in ... then ...
|
||||
#-----| -> Array
|
||||
|
||||
# 76| call to []
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 76| Array
|
||||
#-----| -> "foo"
|
||||
@@ -1082,8 +1082,8 @@ case.rb:
|
||||
#-----| -> Array
|
||||
|
||||
# 77| call to []
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 77| Array
|
||||
#-----| -> :"foo"
|
||||
@@ -1098,8 +1098,8 @@ case.rb:
|
||||
#-----| -> /.*abc[0-9]/
|
||||
|
||||
# 78| /.*abc[0-9]/
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 79| in ... then ...
|
||||
#-----| -> 5
|
||||
@@ -1108,8 +1108,8 @@ case.rb:
|
||||
#-----| -> 10
|
||||
|
||||
# 79| _ .. _
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 79| 10
|
||||
#-----| -> _ .. _
|
||||
@@ -1118,8 +1118,8 @@ case.rb:
|
||||
#-----| -> 10
|
||||
|
||||
# 80| _ .. _
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 80| 10
|
||||
#-----| -> _ .. _
|
||||
@@ -1131,8 +1131,8 @@ case.rb:
|
||||
#-----| -> _ .. _
|
||||
|
||||
# 81| _ .. _
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 82| in ... then ...
|
||||
#-----| -> ... => ...
|
||||
@@ -1145,7 +1145,7 @@ case.rb:
|
||||
#-----| match -> x
|
||||
|
||||
# 82| x
|
||||
#-----| -> exit case_match_various (normal)
|
||||
#-----| -> case ...
|
||||
|
||||
# 83| in ... then ...
|
||||
#-----| -> ... | ...
|
||||
@@ -1154,26 +1154,26 @@ case.rb:
|
||||
#-----| -> 5
|
||||
|
||||
# 83| 5
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> ^...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 83| ^...
|
||||
#-----| -> foo
|
||||
|
||||
# 83| foo
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> "string"
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 83| "string"
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 84| in ... then ...
|
||||
#-----| -> Foo
|
||||
|
||||
# 84| Bar
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 84| Foo
|
||||
#-----| -> Bar
|
||||
@@ -1185,8 +1185,8 @@ case.rb:
|
||||
#-----| -> x
|
||||
|
||||
# 85| -> { ... }
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 85| exit -> { ... }
|
||||
|
||||
@@ -1209,15 +1209,15 @@ case.rb:
|
||||
#-----| -> :foo
|
||||
|
||||
# 86| :foo
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 87| in ... then ...
|
||||
#-----| -> :"foo bar"
|
||||
|
||||
# 87| :"foo bar"
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 88| in ... then ...
|
||||
#-----| -> ... | ...
|
||||
@@ -1226,15 +1226,15 @@ case.rb:
|
||||
#-----| -> 5
|
||||
|
||||
# 88| - ...
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> 10
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 88| 5
|
||||
#-----| -> - ...
|
||||
|
||||
# 88| + ...
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 88| 10
|
||||
#-----| -> + ...
|
||||
@@ -1246,32 +1246,32 @@ case.rb:
|
||||
#-----| -> nil
|
||||
|
||||
# 89| nil
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> self
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 89| self
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> true
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 89| true
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> false
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 89| false
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> __LINE__
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 89| __LINE__
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> __FILE__
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 89| __FILE__
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> __ENCODING__
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 89| __ENCODING__
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 90| in ... then ...
|
||||
#-----| -> ( ... )
|
||||
@@ -1283,8 +1283,8 @@ case.rb:
|
||||
#-----| -> _ .. _
|
||||
|
||||
# 90| _ .. _
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 91| in ... then ...
|
||||
#-----| -> ( ... )
|
||||
@@ -1296,20 +1296,20 @@ case.rb:
|
||||
#-----| -> 0
|
||||
|
||||
# 91| 0
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> ""
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 91| ""
|
||||
#-----| no-match -> [ ..., * ]
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
#-----| match -> case ...
|
||||
|
||||
# 91| [ ..., * ]
|
||||
#-----| match -> case ...
|
||||
#-----| no-match -> { ..., ** }
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 91| { ..., ** }
|
||||
#-----| match -> case ...
|
||||
#-----| raise -> exit case_match_various (abnormal)
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 95| enter case_match_guard_no_else
|
||||
#-----| -> value
|
||||
@@ -1326,10 +1326,10 @@ case.rb:
|
||||
#-----| -> exit case_match_guard_no_else
|
||||
|
||||
# 95| value
|
||||
#-----| -> case ...
|
||||
#-----| -> value
|
||||
|
||||
# 96| case ...
|
||||
#-----| -> value
|
||||
#-----| -> exit case_match_guard_no_else (normal)
|
||||
|
||||
# 96| value
|
||||
#-----| -> in ... then ...
|
||||
@@ -1351,7 +1351,7 @@ case.rb:
|
||||
#-----| -> ... == ...
|
||||
|
||||
# 97| then ...
|
||||
#-----| -> exit case_match_guard_no_else (normal)
|
||||
#-----| -> case ...
|
||||
|
||||
# 97| 6
|
||||
#-----| -> then ...
|
||||
@@ -1703,7 +1703,7 @@ cfg.rb:
|
||||
#-----| false -> if ...
|
||||
|
||||
# 39| call to puts
|
||||
#-----| -> case ...
|
||||
#-----| -> 10
|
||||
|
||||
# 39| self
|
||||
#-----| -> 42
|
||||
@@ -1712,7 +1712,7 @@ cfg.rb:
|
||||
#-----| -> call to puts
|
||||
|
||||
# 41| case ...
|
||||
#-----| -> 10
|
||||
#-----| -> when ...
|
||||
|
||||
# 41| 10
|
||||
#-----| -> when ...
|
||||
@@ -1776,7 +1776,7 @@ cfg.rb:
|
||||
#-----| -> call to puts
|
||||
|
||||
# 47| case ...
|
||||
#-----| -> when ...
|
||||
#-----| -> chained
|
||||
|
||||
# 48| when ...
|
||||
#-----| -> b
|
||||
@@ -1792,7 +1792,7 @@ cfg.rb:
|
||||
#-----| -> ... == ...
|
||||
|
||||
# 48| then ...
|
||||
#-----| -> chained
|
||||
#-----| -> case ...
|
||||
|
||||
# 48| call to puts
|
||||
#-----| -> then ...
|
||||
@@ -1817,7 +1817,7 @@ cfg.rb:
|
||||
#-----| -> ... == ...
|
||||
|
||||
# 49| ... > ...
|
||||
#-----| false -> chained
|
||||
#-----| false -> case ...
|
||||
#-----| true -> self
|
||||
|
||||
# 49| b
|
||||
@@ -1827,7 +1827,7 @@ cfg.rb:
|
||||
#-----| -> ... > ...
|
||||
|
||||
# 49| then ...
|
||||
#-----| -> chained
|
||||
#-----| -> case ...
|
||||
|
||||
# 49| call to puts
|
||||
#-----| -> then ...
|
||||
@@ -1847,6 +1847,9 @@ cfg.rb:
|
||||
# 52| "a"
|
||||
#-----| -> chained
|
||||
|
||||
# 52| "..." "..."
|
||||
#-----| -> ... = ...
|
||||
|
||||
# 52| "#{...}"
|
||||
#-----| -> "string"
|
||||
|
||||
@@ -1857,7 +1860,7 @@ cfg.rb:
|
||||
#-----| -> #{...}
|
||||
|
||||
# 52| "string"
|
||||
#-----| -> ... = ...
|
||||
#-----| -> "..." "..."
|
||||
|
||||
# 54| ... = ...
|
||||
#-----| -> Silly
|
||||
@@ -1941,12 +1944,12 @@ cfg.rb:
|
||||
# 62| call to []
|
||||
#-----| -> * ...
|
||||
|
||||
# 62| ...
|
||||
#-----| -> ...
|
||||
|
||||
# 62| 1
|
||||
#-----| -> call to []
|
||||
|
||||
# 62| ...
|
||||
#-----| -> ...
|
||||
|
||||
# 62| __synth__0
|
||||
#-----| -> 1
|
||||
|
||||
@@ -2416,13 +2419,13 @@ cfg.rb:
|
||||
#-----| -> b
|
||||
|
||||
# 108| self
|
||||
#-----| -> <<SQL
|
||||
#-----| -> table
|
||||
|
||||
# 108| ( ... )
|
||||
#-----| -> call to puts
|
||||
|
||||
# 108| <<SQL
|
||||
#-----| -> table
|
||||
#-----| -> ( ... )
|
||||
|
||||
# 109| #{...}
|
||||
#-----| -> type
|
||||
@@ -2431,7 +2434,7 @@ cfg.rb:
|
||||
#-----| -> #{...}
|
||||
|
||||
# 110| #{...}
|
||||
#-----| -> ( ... )
|
||||
#-----| -> <<SQL
|
||||
|
||||
# 110| type
|
||||
#-----| -> #{...}
|
||||
@@ -2641,23 +2644,23 @@ cfg.rb:
|
||||
#-----| -> EmptyModule
|
||||
|
||||
# 134| EmptyModule
|
||||
#-----| -> ... rescue ...
|
||||
#-----| -> 1
|
||||
|
||||
# 136| ... / ...
|
||||
#-----| -> ... rescue ...
|
||||
#-----| raise -> self
|
||||
#-----| -> __synth__0
|
||||
|
||||
# 136| 1
|
||||
#-----| -> 0
|
||||
|
||||
# 136| ... rescue ...
|
||||
#-----| -> 1
|
||||
#-----| -> __synth__0
|
||||
|
||||
# 136| 0
|
||||
#-----| -> ... / ...
|
||||
|
||||
# 136| call to puts
|
||||
#-----| -> __synth__0
|
||||
#-----| -> ... rescue ...
|
||||
|
||||
# 136| self
|
||||
#-----| -> "div by zero"
|
||||
@@ -2704,6 +2707,9 @@ cfg.rb:
|
||||
# 138| __synth__0
|
||||
#-----| -> -1
|
||||
|
||||
# 138| ..., ...
|
||||
#-----| -> * ...
|
||||
|
||||
# 138| 1
|
||||
#-----| -> 2
|
||||
|
||||
@@ -2720,7 +2726,7 @@ cfg.rb:
|
||||
#-----| -> 3
|
||||
|
||||
# 138| 3
|
||||
#-----| -> * ...
|
||||
#-----| -> ..., ...
|
||||
|
||||
# 140| M
|
||||
#-----| -> Constant
|
||||
@@ -3270,6 +3276,9 @@ cfg.rb:
|
||||
#-----| -> b
|
||||
|
||||
# 197| b
|
||||
#-----| -> ...
|
||||
|
||||
# 197| ...
|
||||
#-----| -> call to bar
|
||||
|
||||
desugar.rb:
|
||||
@@ -3626,12 +3635,12 @@ desugar.rb:
|
||||
# 22| call to []
|
||||
#-----| -> ... = ...
|
||||
|
||||
# 22| ...
|
||||
#-----| -> ...
|
||||
|
||||
# 22| -1
|
||||
#-----| -> call to []
|
||||
|
||||
# 22| ...
|
||||
#-----| -> ...
|
||||
|
||||
# 22| __synth__0
|
||||
#-----| -> -1
|
||||
|
||||
@@ -3706,12 +3715,12 @@ desugar.rb:
|
||||
# 26| call to []
|
||||
#-----| -> * ...
|
||||
|
||||
# 26| ...
|
||||
#-----| -> ...
|
||||
|
||||
# 26| 1
|
||||
#-----| -> call to []
|
||||
|
||||
# 26| ...
|
||||
#-----| -> ...
|
||||
|
||||
# 26| __synth__0
|
||||
#-----| -> 1
|
||||
|
||||
@@ -4905,7 +4914,7 @@ raise.rb:
|
||||
#-----| true -> self
|
||||
|
||||
# 17| call to raise
|
||||
#-----| raise -> rescue ...
|
||||
#-----| raise -> ExceptionA
|
||||
|
||||
# 17| self
|
||||
#-----| -> ExceptionA
|
||||
@@ -4914,14 +4923,14 @@ raise.rb:
|
||||
#-----| -> call to raise
|
||||
|
||||
# 19| rescue ...
|
||||
#-----| -> ExceptionA
|
||||
#-----| -> self
|
||||
|
||||
# 19| ExceptionA
|
||||
#-----| match -> self
|
||||
#-----| raise -> exit m2 (abnormal)
|
||||
|
||||
# 19| then ...
|
||||
#-----| -> self
|
||||
#-----| -> rescue ...
|
||||
|
||||
# 20| call to puts
|
||||
#-----| -> then ...
|
||||
@@ -4963,7 +4972,7 @@ raise.rb:
|
||||
#-----| true -> self
|
||||
|
||||
# 28| call to raise
|
||||
#-----| raise -> rescue ...
|
||||
#-----| raise -> self
|
||||
|
||||
# 28| self
|
||||
#-----| -> ExceptionA
|
||||
@@ -4975,7 +4984,7 @@ raise.rb:
|
||||
#-----| -> self
|
||||
|
||||
# 30| then ...
|
||||
#-----| -> self
|
||||
#-----| -> rescue ...
|
||||
|
||||
# 31| call to puts
|
||||
#-----| -> then ...
|
||||
@@ -5017,7 +5026,7 @@ raise.rb:
|
||||
#-----| true -> self
|
||||
|
||||
# 39| call to raise
|
||||
#-----| raise -> rescue ...
|
||||
#-----| raise -> e
|
||||
|
||||
# 39| self
|
||||
#-----| -> ExceptionA
|
||||
@@ -5026,13 +5035,13 @@ raise.rb:
|
||||
#-----| -> call to raise
|
||||
|
||||
# 41| rescue ...
|
||||
#-----| -> e
|
||||
#-----| -> self
|
||||
|
||||
# 41| e
|
||||
#-----| -> self
|
||||
|
||||
# 41| then ...
|
||||
#-----| -> self
|
||||
#-----| -> rescue ...
|
||||
|
||||
# 42| call to puts
|
||||
#-----| -> then ...
|
||||
@@ -5074,7 +5083,7 @@ raise.rb:
|
||||
#-----| true -> self
|
||||
|
||||
# 50| call to raise
|
||||
#-----| raise -> rescue ...
|
||||
#-----| raise -> e
|
||||
|
||||
# 50| self
|
||||
#-----| -> ExceptionA
|
||||
@@ -5083,10 +5092,10 @@ raise.rb:
|
||||
#-----| -> call to raise
|
||||
|
||||
# 52| rescue ...
|
||||
#-----| -> e
|
||||
#-----| -> self
|
||||
|
||||
# 52| e
|
||||
#-----| -> self
|
||||
#-----| -> rescue ...
|
||||
|
||||
# 54| call to puts
|
||||
#-----| -> exit m5 (normal)
|
||||
@@ -5122,7 +5131,7 @@ raise.rb:
|
||||
#-----| true -> self
|
||||
|
||||
# 60| call to raise
|
||||
#-----| raise -> rescue ...
|
||||
#-----| raise -> ExceptionA
|
||||
|
||||
# 60| self
|
||||
#-----| -> ExceptionA
|
||||
@@ -5131,7 +5140,7 @@ raise.rb:
|
||||
#-----| -> call to raise
|
||||
|
||||
# 62| rescue ...
|
||||
#-----| -> ExceptionA
|
||||
#-----| -> self
|
||||
|
||||
# 62| ExceptionA
|
||||
#-----| no-match -> ExceptionB
|
||||
@@ -5145,7 +5154,7 @@ raise.rb:
|
||||
#-----| -> self
|
||||
|
||||
# 62| then ...
|
||||
#-----| -> self
|
||||
#-----| -> rescue ...
|
||||
|
||||
# 63| call to puts
|
||||
#-----| -> then ...
|
||||
@@ -5804,7 +5813,7 @@ raise.rb:
|
||||
#-----| true -> self
|
||||
|
||||
# 131| call to raise
|
||||
#-----| raise -> rescue ...
|
||||
#-----| raise -> ExceptionA
|
||||
|
||||
# 131| self
|
||||
#-----| -> ExceptionA
|
||||
@@ -5813,21 +5822,21 @@ raise.rb:
|
||||
#-----| -> call to raise
|
||||
|
||||
# 133| rescue ...
|
||||
#-----| -> ExceptionA
|
||||
#-----| -> self
|
||||
|
||||
# 133| ExceptionA
|
||||
#-----| no-match -> rescue ...
|
||||
#-----| match -> self
|
||||
#-----| match -> rescue ...
|
||||
#-----| no-match -> ExceptionB
|
||||
|
||||
# 134| rescue ...
|
||||
#-----| -> ExceptionB
|
||||
#-----| -> self
|
||||
|
||||
# 134| ExceptionB
|
||||
#-----| match -> self
|
||||
#-----| raise -> [ensure: raise] self
|
||||
|
||||
# 134| then ...
|
||||
#-----| -> self
|
||||
#-----| -> rescue ...
|
||||
|
||||
# 135| call to puts
|
||||
#-----| -> then ...
|
||||
|
||||
@@ -191,6 +191,7 @@ positionalArguments
|
||||
| cfg.rb:191:3:191:10 | yield ... | cfg.rb:191:9:191:10 | 42 |
|
||||
| cfg.rb:194:16:194:21 | call to puts | cfg.rb:194:21:194:21 | x |
|
||||
| cfg.rb:197:3:197:13 | call to bar | cfg.rb:197:7:197:7 | b |
|
||||
| cfg.rb:197:3:197:13 | call to bar | cfg.rb:197:10:197:12 | ... |
|
||||
| desugar.rb:2:5:2:6 | ... + ... | desugar.rb:2:8:2:8 | 1 |
|
||||
| desugar.rb:6:3:6:13 | call to count= | desugar.rb:6:3:6:13 | ... = ... |
|
||||
| desugar.rb:10:3:10:10 | call to []= | desugar.rb:10:3:10:10 | ... = ... |
|
||||
|
||||
@@ -70,3 +70,33 @@
|
||||
| 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 |
|
||||
| local_dataflow.rb:51:9:51:15 | "break" | local_dataflow.rb:51:3:51:15 | break |
|
||||
| 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 | ... = ... |
|
||||
| local_dataflow.rb:61:12:61:12 | x | local_dataflow.rb:63:15:63:15 | x |
|
||||
| local_dataflow.rb:61:12:61:12 | x | local_dataflow.rb:65:6:65:6 | x |
|
||||
| local_dataflow.rb:61:12:61:12 | x | local_dataflow.rb:67:5:67:5 | x |
|
||||
| local_dataflow.rb:61:12:61:12 | x | local_dataflow.rb:69:12:69:12 | x |
|
||||
| local_dataflow.rb:62:10:62:15 | then ... | local_dataflow.rb:61:7:68:5 | case ... |
|
||||
| local_dataflow.rb:62:15:62:15 | 3 | local_dataflow.rb:62:10:62:15 | then ... |
|
||||
| local_dataflow.rb:63:10:63:15 | then ... | local_dataflow.rb:61:7:68:5 | case ... |
|
||||
| local_dataflow.rb:63:15:63:15 | x | local_dataflow.rb:63:10:63:15 | then ... |
|
||||
| local_dataflow.rb:63:15:63:15 | x | local_dataflow.rb:69:12:69:12 | x |
|
||||
| local_dataflow.rb:64:9:65:6 | then ... | local_dataflow.rb:61:7:68:5 | case ... |
|
||||
| local_dataflow.rb:65:6:65:6 | x | local_dataflow.rb:64:9:65:6 | then ... |
|
||||
| local_dataflow.rb:65:6:65:6 | x | local_dataflow.rb:69:12:69:12 | x |
|
||||
| local_dataflow.rb:66:3:67:5 | else ... | local_dataflow.rb:61:7:68:5 | case ... |
|
||||
| local_dataflow.rb:67:5:67:5 | x | local_dataflow.rb:66:3:67:5 | else ... |
|
||||
| local_dataflow.rb:67:5:67:5 | x | local_dataflow.rb:69:12:69:12 | x |
|
||||
| local_dataflow.rb:69:7:76:5 | case ... | local_dataflow.rb:69:3:76:5 | ... = ... |
|
||||
| local_dataflow.rb:69:12:69:12 | x | local_dataflow.rb:71:13:71:13 | x |
|
||||
| local_dataflow.rb:69:12:69:12 | x | local_dataflow.rb:73:7:73:7 | x |
|
||||
| local_dataflow.rb:69:12:69:12 | x | local_dataflow.rb:75:6:75:6 | x |
|
||||
| local_dataflow.rb:70:8:70:13 | then ... | local_dataflow.rb:69:7:76:5 | case ... |
|
||||
| local_dataflow.rb:70:13:70:13 | 4 | local_dataflow.rb:70:8:70:13 | then ... |
|
||||
| local_dataflow.rb:71:8:71:13 | then ... | local_dataflow.rb:69:7:76:5 | case ... |
|
||||
| local_dataflow.rb:71:13:71:13 | x | local_dataflow.rb:71:8:71:13 | then ... |
|
||||
| local_dataflow.rb:72:7:73:7 | then ... | local_dataflow.rb:69:7:76:5 | case ... |
|
||||
| local_dataflow.rb:73:7:73:7 | x | local_dataflow.rb:72:7:73:7 | then ... |
|
||||
| local_dataflow.rb:74:3:75:6 | else ... | local_dataflow.rb:69:7:76:5 | case ... |
|
||||
| local_dataflow.rb:75:6:75:6 | x | local_dataflow.rb:74:3:75:6 | else ... |
|
||||
|
||||
@@ -12,39 +12,40 @@ ret
|
||||
| local_dataflow.rb:50:3:50:13 | next |
|
||||
| local_dataflow.rb:51:3:51:15 | break |
|
||||
| local_dataflow.rb:52:3:52:10 | "normal" |
|
||||
| local_dataflow.rb:69:3:76:5 | ... = ... |
|
||||
arg
|
||||
| local_dataflow.rb:3:8:3:10 | self | local_dataflow.rb:3:8:3:10 | call to p | -1 |
|
||||
| local_dataflow.rb:3:10:3:10 | a | local_dataflow.rb:3:8:3:10 | call to p | 0 |
|
||||
| local_dataflow.rb:6:8:6:8 | a | local_dataflow.rb:6:10:6:11 | ... + ... | -1 |
|
||||
| local_dataflow.rb:6:13:6:13 | b | local_dataflow.rb:6:10:6:11 | ... + ... | 0 |
|
||||
| local_dataflow.rb:9:9:9:15 | Array | local_dataflow.rb:9:9:9:15 | call to [] | -1 |
|
||||
| local_dataflow.rb:9:10:9:10 | 1 | local_dataflow.rb:9:9:9:15 | call to [] | 0 |
|
||||
| local_dataflow.rb:9:12:9:12 | 2 | local_dataflow.rb:9:9:9:15 | call to [] | 1 |
|
||||
| local_dataflow.rb:9:14:9:14 | 3 | local_dataflow.rb:9:9:9:15 | call to [] | 2 |
|
||||
| local_dataflow.rb:10:5:13:3 | { ... } | local_dataflow.rb:10:5:13:3 | call to each | -2 |
|
||||
| local_dataflow.rb:10:14:10:18 | array | local_dataflow.rb:10:5:13:3 | call to each | -1 |
|
||||
| local_dataflow.rb:11:1:11:2 | self | local_dataflow.rb:11:1:11:2 | call to do | -1 |
|
||||
| local_dataflow.rb:12:3:12:5 | self | local_dataflow.rb:12:3:12:5 | call to p | -1 |
|
||||
| local_dataflow.rb:12:5:12:5 | x | local_dataflow.rb:12:3:12:5 | call to p | 0 |
|
||||
| local_dataflow.rb:15:1:17:3 | { ... } | local_dataflow.rb:15:1:17:3 | call to each | -2 |
|
||||
| local_dataflow.rb:15:10:15:14 | array | local_dataflow.rb:15:1:17:3 | call to each | -1 |
|
||||
| local_dataflow.rb:19:1:21:3 | { ... } | local_dataflow.rb:19:1:21:3 | call to each | -2 |
|
||||
| local_dataflow.rb:19:10:19:14 | array | local_dataflow.rb:19:1:21:3 | call to each | -1 |
|
||||
| local_dataflow.rb:20:6:20:6 | x | local_dataflow.rb:20:6:20:10 | ... > ... | -1 |
|
||||
| local_dataflow.rb:20:10:20:10 | 1 | local_dataflow.rb:20:6:20:10 | ... > ... | 0 |
|
||||
| local_dataflow.rb:35:6:35:6 | x | local_dataflow.rb:35:6:35:11 | ... == ... | -1 |
|
||||
| local_dataflow.rb:35:11:35:11 | 4 | local_dataflow.rb:35:6:35:11 | ... == ... | 0 |
|
||||
| local_dataflow.rb:42:6:42:6 | x | local_dataflow.rb:42:6:42:11 | ... == ... | -1 |
|
||||
| local_dataflow.rb:42:11:42:11 | 4 | local_dataflow.rb:42:6:42:11 | ... == ... | 0 |
|
||||
| local_dataflow.rb:49:1:53:3 | self | local_dataflow.rb:49:1:53:3 | call to m | -1 |
|
||||
| local_dataflow.rb:49:3:53:3 | do ... end | local_dataflow.rb:49:1:53:3 | call to m | -2 |
|
||||
| local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:50:18:50:22 | ... < ... | -1 |
|
||||
| local_dataflow.rb:50:22:50:22 | 4 | local_dataflow.rb:50:18:50:22 | ... < ... | 0 |
|
||||
| local_dataflow.rb:51:20:51:20 | x | local_dataflow.rb:51:20:51:24 | ... < ... | -1 |
|
||||
| local_dataflow.rb:51:24:51:24 | 9 | local_dataflow.rb:51:20:51:24 | ... < ... | 0 |
|
||||
| local_dataflow.rb:55:1:55:14 | self | local_dataflow.rb:55:1:55:14 | call to foo | -1 |
|
||||
| local_dataflow.rb:55:5:55:13 | Array | local_dataflow.rb:55:5:55:13 | call to [] | -1 |
|
||||
| local_dataflow.rb:55:5:55:13 | call to [] | local_dataflow.rb:55:1:55:14 | call to foo | 0 |
|
||||
| local_dataflow.rb:55:6:55:6 | 1 | local_dataflow.rb:55:5:55:13 | call to [] | 0 |
|
||||
| local_dataflow.rb:55:9:55:9 | 2 | local_dataflow.rb:55:5:55:13 | call to [] | 1 |
|
||||
| local_dataflow.rb:55:12:55:12 | 3 | local_dataflow.rb:55:5:55:13 | call to [] | 2 |
|
||||
| local_dataflow.rb:3:8:3:10 | self | local_dataflow.rb:3:8:3:10 | call to p | self |
|
||||
| local_dataflow.rb:3:10:3:10 | a | local_dataflow.rb:3:8:3:10 | call to p | position 0 |
|
||||
| local_dataflow.rb:6:8:6:8 | a | local_dataflow.rb:6:10:6:11 | ... + ... | self |
|
||||
| local_dataflow.rb:6:13:6:13 | b | local_dataflow.rb:6:10:6:11 | ... + ... | position 0 |
|
||||
| local_dataflow.rb:9:9:9:15 | Array | local_dataflow.rb:9:9:9:15 | call to [] | self |
|
||||
| local_dataflow.rb:9:10:9:10 | 1 | local_dataflow.rb:9:9:9:15 | call to [] | position 0 |
|
||||
| local_dataflow.rb:9:12:9:12 | 2 | local_dataflow.rb:9:9:9:15 | call to [] | position 1 |
|
||||
| local_dataflow.rb:9:14:9:14 | 3 | local_dataflow.rb:9:9:9:15 | call to [] | position 2 |
|
||||
| local_dataflow.rb:10:5:13:3 | { ... } | local_dataflow.rb:10:5:13:3 | call to each | block |
|
||||
| local_dataflow.rb:10:14:10:18 | array | local_dataflow.rb:10:5:13:3 | call to each | self |
|
||||
| local_dataflow.rb:11:1:11:2 | self | local_dataflow.rb:11:1:11:2 | call to do | self |
|
||||
| local_dataflow.rb:12:3:12:5 | self | local_dataflow.rb:12:3:12:5 | call to p | self |
|
||||
| local_dataflow.rb:12:5:12:5 | x | local_dataflow.rb:12:3:12:5 | call to p | position 0 |
|
||||
| local_dataflow.rb:15:1:17:3 | { ... } | local_dataflow.rb:15:1:17:3 | call to each | block |
|
||||
| local_dataflow.rb:15:10:15:14 | array | local_dataflow.rb:15:1:17:3 | call to each | self |
|
||||
| local_dataflow.rb:19:1:21:3 | { ... } | local_dataflow.rb:19:1:21:3 | call to each | block |
|
||||
| local_dataflow.rb:19:10:19:14 | array | local_dataflow.rb:19:1:21:3 | call to each | self |
|
||||
| local_dataflow.rb:20:6:20:6 | x | local_dataflow.rb:20:6:20:10 | ... > ... | self |
|
||||
| local_dataflow.rb:20:10:20:10 | 1 | local_dataflow.rb:20:6:20:10 | ... > ... | position 0 |
|
||||
| local_dataflow.rb:35:6:35:6 | x | local_dataflow.rb:35:6:35:11 | ... == ... | self |
|
||||
| local_dataflow.rb:35:11:35:11 | 4 | local_dataflow.rb:35:6:35:11 | ... == ... | position 0 |
|
||||
| local_dataflow.rb:42:6:42:6 | x | local_dataflow.rb:42:6:42:11 | ... == ... | self |
|
||||
| local_dataflow.rb:42:11:42:11 | 4 | local_dataflow.rb:42:6:42:11 | ... == ... | position 0 |
|
||||
| local_dataflow.rb:49:1:53:3 | self | local_dataflow.rb:49:1:53:3 | call to m | self |
|
||||
| local_dataflow.rb:49:3:53:3 | do ... end | local_dataflow.rb:49:1:53:3 | call to m | block |
|
||||
| local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:50:18:50:22 | ... < ... | self |
|
||||
| local_dataflow.rb:50:22:50:22 | 4 | local_dataflow.rb:50:18:50:22 | ... < ... | position 0 |
|
||||
| local_dataflow.rb:51:20:51:20 | x | local_dataflow.rb:51:20:51:24 | ... < ... | self |
|
||||
| local_dataflow.rb:51:24:51:24 | 9 | local_dataflow.rb:51:20:51:24 | ... < ... | position 0 |
|
||||
| local_dataflow.rb:55:1:55:14 | self | local_dataflow.rb:55:1:55:14 | call to foo | self |
|
||||
| local_dataflow.rb:55:5:55:13 | Array | local_dataflow.rb:55:5:55:13 | call to [] | self |
|
||||
| local_dataflow.rb:55:5:55:13 | call to [] | local_dataflow.rb:55:1:55:14 | call to foo | position 0 |
|
||||
| local_dataflow.rb:55:6:55:6 | 1 | local_dataflow.rb:55:5:55:13 | call to [] | position 0 |
|
||||
| local_dataflow.rb:55:9:55:9 | 2 | local_dataflow.rb:55:5:55:13 | call to [] | position 1 |
|
||||
| local_dataflow.rb:55:12:55:12 | 3 | local_dataflow.rb:55:5:55:13 | call to [] | position 2 |
|
||||
|
||||
@@ -4,4 +4,6 @@ import codeql.ruby.dataflow.internal.DataFlowDispatch
|
||||
|
||||
query predicate ret(ReturningNode node) { any() }
|
||||
|
||||
query predicate arg(ArgumentNode n, DataFlowCall call, int pos) { n.argumentOf(call, pos) }
|
||||
query predicate arg(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) {
|
||||
n.argumentOf(call, pos)
|
||||
}
|
||||
|
||||
@@ -56,3 +56,23 @@ foo([1, 2, 3])
|
||||
|
||||
def foo x
|
||||
end
|
||||
|
||||
def test_case x
|
||||
y = case x
|
||||
when 1 then 3
|
||||
when 2 then x
|
||||
when 3
|
||||
x
|
||||
else
|
||||
x
|
||||
end
|
||||
z = case x
|
||||
in 1 then 4
|
||||
in 2 then x
|
||||
in 3
|
||||
x
|
||||
else
|
||||
x
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
failures
|
||||
edges
|
||||
| params_flow.rb:9:16:9:17 | p1 : | params_flow.rb:10:10:10:11 | p1 |
|
||||
| params_flow.rb:9:20:9:21 | p2 : | params_flow.rb:11:10:11:11 | p2 |
|
||||
| params_flow.rb:14:12:14:19 | call to taint : | params_flow.rb:9:16:9:17 | p1 : |
|
||||
| params_flow.rb:14:22:14:29 | call to taint : | params_flow.rb:9:20:9:21 | p2 : |
|
||||
| params_flow.rb:16:13:16:14 | p1 : | params_flow.rb:17:10:17:11 | p1 |
|
||||
| params_flow.rb:16:18:16:19 | p2 : | params_flow.rb:18:10:18:11 | p2 |
|
||||
| params_flow.rb:21:13:21:20 | call to taint : | params_flow.rb:16:13:16:14 | p1 : |
|
||||
| params_flow.rb:21:27:21:34 | call to taint : | params_flow.rb:16:18:16:19 | p2 : |
|
||||
| params_flow.rb:22:13:22:20 | call to taint : | params_flow.rb:16:18:16:19 | p2 : |
|
||||
| params_flow.rb:22:27:22:34 | call to taint : | params_flow.rb:16:13:16:14 | p1 : |
|
||||
nodes
|
||||
| params_flow.rb:9:16:9:17 | p1 : | semmle.label | p1 : |
|
||||
| params_flow.rb:9:20:9:21 | p2 : | semmle.label | p2 : |
|
||||
| params_flow.rb:10:10:10:11 | p1 | semmle.label | p1 |
|
||||
| params_flow.rb:11:10:11:11 | p2 | semmle.label | p2 |
|
||||
| params_flow.rb:14:12:14:19 | call to taint : | semmle.label | call to taint : |
|
||||
| params_flow.rb:14:22:14:29 | call to taint : | semmle.label | call to taint : |
|
||||
| params_flow.rb:16:13:16:14 | p1 : | semmle.label | p1 : |
|
||||
| params_flow.rb:16:18:16:19 | p2 : | semmle.label | p2 : |
|
||||
| params_flow.rb:17:10:17:11 | p1 | semmle.label | p1 |
|
||||
| params_flow.rb:18:10:18:11 | p2 | semmle.label | p2 |
|
||||
| params_flow.rb:21:13:21:20 | call to taint : | semmle.label | call to taint : |
|
||||
| params_flow.rb:21:27:21:34 | call to taint : | semmle.label | call to taint : |
|
||||
| params_flow.rb:22:13:22:20 | call to taint : | semmle.label | call to taint : |
|
||||
| params_flow.rb:22:27:22:34 | call to taint : | semmle.label | call to taint : |
|
||||
subpaths
|
||||
#select
|
||||
| params_flow.rb:10:10:10:11 | p1 | params_flow.rb:14:12:14:19 | call to taint : | params_flow.rb:10:10:10:11 | p1 | $@ | params_flow.rb:14:12:14:19 | call to taint : | call to taint : |
|
||||
| params_flow.rb:11:10:11:11 | p2 | params_flow.rb:14:22:14:29 | call to taint : | params_flow.rb:11:10:11:11 | p2 | $@ | params_flow.rb:14:22:14:29 | call to taint : | call to taint : |
|
||||
| params_flow.rb:17:10:17:11 | p1 | params_flow.rb:21:13:21:20 | call to taint : | params_flow.rb:17:10:17:11 | p1 | $@ | params_flow.rb:21:13:21:20 | call to taint : | call to taint : |
|
||||
| params_flow.rb:17:10:17:11 | p1 | params_flow.rb:22:27:22:34 | call to taint : | params_flow.rb:17:10:17:11 | p1 | $@ | params_flow.rb:22:27:22:34 | call to taint : | call to taint : |
|
||||
| params_flow.rb:18:10:18:11 | p2 | params_flow.rb:21:27:21:34 | call to taint : | params_flow.rb:18:10:18:11 | p2 | $@ | params_flow.rb:21:27:21:34 | call to taint : | call to taint : |
|
||||
| params_flow.rb:18:10:18:11 | p2 | params_flow.rb:22:13:22:20 | call to taint : | params_flow.rb:18:10:18:11 | p2 | $@ | params_flow.rb:22:13:22:20 | call to taint : | call to taint : |
|
||||
15
ruby/ql/test/library-tests/dataflow/params/params-flow.ql
Normal file
15
ruby/ql/test/library-tests/dataflow/params/params-flow.ql
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import ruby
|
||||
import TestUtilities.InlineFlowTest
|
||||
import PathGraph
|
||||
|
||||
class HasFlowTest extends InlineFlowTest {
|
||||
override DataFlow::Configuration getTaintFlowConfig() { none() }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultValueFlowConf conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select sink, source, sink, "$@", source, source.toString()
|
||||
22
ruby/ql/test/library-tests/dataflow/params/params_flow.rb
Normal file
22
ruby/ql/test/library-tests/dataflow/params/params_flow.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
def taint x
|
||||
x
|
||||
end
|
||||
|
||||
def sink x
|
||||
puts x
|
||||
end
|
||||
|
||||
def positional(p1, p2)
|
||||
sink p1 # $ hasValueFlow=1
|
||||
sink p2 # $ hasValueFlow=2
|
||||
end
|
||||
|
||||
positional(taint(1), taint(2))
|
||||
|
||||
def keyword(p1:, p2:)
|
||||
sink p1 # $ hasValueFlow=3 $ hasValueFlow=6
|
||||
sink p2 # $ hasValueFlow=4 $ hasValueFlow=5
|
||||
end
|
||||
|
||||
keyword(p1: taint(3), p2: taint(4))
|
||||
keyword(p2: taint(5), p1: taint(6))
|
||||
@@ -2,7 +2,7 @@ actionControllerControllerClasses
|
||||
| ActiveRecordInjection.rb:27:1:58:3 | FooController |
|
||||
| ActiveRecordInjection.rb:60:1:90:3 | BarController |
|
||||
| ActiveRecordInjection.rb:92:1:96:3 | BazController |
|
||||
| app/controllers/foo/bars_controller.rb:3:1:25:3 | BarsController |
|
||||
| app/controllers/foo/bars_controller.rb:3:1:31:3 | BarsController |
|
||||
actionControllerActionMethods
|
||||
| ActiveRecordInjection.rb:32:3:57:5 | some_request_handler |
|
||||
| ActiveRecordInjection.rb:61:3:69:5 | some_other_request_handler |
|
||||
@@ -57,8 +57,8 @@ redirectToCalls
|
||||
| app/controllers/foo/bars_controller.rb:17:5:17:30 | call to redirect_to |
|
||||
actionControllerHelperMethods
|
||||
getAssociatedControllerClasses
|
||||
| app/controllers/foo/bars_controller.rb:3:1:25:3 | BarsController | app/views/foo/bars/_widget.html.erb:0:0:0:0 | app/views/foo/bars/_widget.html.erb |
|
||||
| app/controllers/foo/bars_controller.rb:3:1:25:3 | BarsController | app/views/foo/bars/show.html.erb:0:0:0:0 | app/views/foo/bars/show.html.erb |
|
||||
| app/controllers/foo/bars_controller.rb:3:1:31:3 | BarsController | app/views/foo/bars/_widget.html.erb:0:0:0:0 | app/views/foo/bars/_widget.html.erb |
|
||||
| app/controllers/foo/bars_controller.rb:3:1:31:3 | BarsController | app/views/foo/bars/show.html.erb:0:0:0:0 | app/views/foo/bars/show.html.erb |
|
||||
controllerTemplateFiles
|
||||
| app/controllers/foo/bars_controller.rb:3:1:25:3 | BarsController | app/views/foo/bars/_widget.html.erb:0:0:0:0 | app/views/foo/bars/_widget.html.erb |
|
||||
| app/controllers/foo/bars_controller.rb:3:1:25:3 | BarsController | app/views/foo/bars/show.html.erb:0:0:0:0 | app/views/foo/bars/show.html.erb |
|
||||
| app/controllers/foo/bars_controller.rb:3:1:31:3 | BarsController | app/views/foo/bars/_widget.html.erb:0:0:0:0 | app/views/foo/bars/_widget.html.erb |
|
||||
| app/controllers/foo/bars_controller.rb:3:1:31:3 | BarsController | app/views/foo/bars/show.html.erb:0:0:0:0 | app/views/foo/bars/show.html.erb |
|
||||
|
||||
@@ -14,6 +14,7 @@ rawCalls
|
||||
renderCalls
|
||||
| app/controllers/foo/bars_controller.rb:6:5:6:37 | call to render |
|
||||
| app/controllers/foo/bars_controller.rb:23:5:23:76 | call to render |
|
||||
| app/controllers/foo/bars_controller.rb:29:5:29:17 | call to render |
|
||||
| app/views/foo/bars/show.html.erb:31:5:31:89 | call to render |
|
||||
renderToCalls
|
||||
| app/controllers/foo/bars_controller.rb:15:16:15:97 | call to render_to_string |
|
||||
|
||||
76
ruby/ql/test/library-tests/frameworks/Logging.rb
Normal file
76
ruby/ql/test/library-tests/frameworks/Logging.rb
Normal file
@@ -0,0 +1,76 @@
|
||||
require 'logger'
|
||||
|
||||
class LoggerTest
|
||||
@@cls_logger = Logger.new STDERR
|
||||
@@cls_logger.progname = "LoggerTest"
|
||||
|
||||
def init_logger
|
||||
if @logger == nil
|
||||
@logger = Logger.new STDOUT
|
||||
end
|
||||
end
|
||||
|
||||
def debug_log(msg)
|
||||
init_logger
|
||||
@logger.debug msg
|
||||
end
|
||||
|
||||
def error_log(msg)
|
||||
init_logger
|
||||
@logger.error do
|
||||
msg + "!"
|
||||
end
|
||||
end
|
||||
|
||||
def fatal_log(msg)
|
||||
init_logger
|
||||
@logger.fatal msg
|
||||
end
|
||||
|
||||
def warn_log(msg)
|
||||
init_logger
|
||||
@logger.warn msg
|
||||
end
|
||||
|
||||
def unknown_log(msg)
|
||||
init_logger
|
||||
@logger.unknown("unknown prog") { msg }
|
||||
end
|
||||
|
||||
def info_log(msg)
|
||||
init_logger
|
||||
@logger.info do
|
||||
if msg.size > 100
|
||||
msg[0..91] + "..." + msg[-5..msg.size]
|
||||
else
|
||||
msg
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def push_log(msg)
|
||||
logger = Logger.new STDERR
|
||||
logger_alias = logger
|
||||
logger_alias << ("test message: " + msg)
|
||||
end
|
||||
|
||||
def add_log(msg)
|
||||
@@cls_logger.add(Logger::INFO) { "block" }
|
||||
# Includes both progname and block return if 'message' is 'nil'
|
||||
@@cls_logger.add(Logger::INFO, nil, "progname1") { "block" }
|
||||
|
||||
# block return value is ignored if `message` is specified
|
||||
@@cls_logger.add(Logger::WARN, "message1") { "not logged" }
|
||||
@@cls_logger.add(Logger::WARN, "message2", "progname2") { "not logged" }
|
||||
end
|
||||
|
||||
def log_log(msg)
|
||||
@@cls_logger.log(Logger::INFO) { "block" }
|
||||
# Includes both progname and block return if 'message' is 'nil'
|
||||
@@cls_logger.log(Logger::INFO, nil, "progname1") { "block" }
|
||||
|
||||
# block return value is ignored if `message` is specified
|
||||
@@cls_logger.log(Logger::WARN, "message1") { "not logged" }
|
||||
@@cls_logger.log(Logger::WARN, "message2", "progname2") { "not logged" }
|
||||
end
|
||||
end
|
||||
@@ -69,3 +69,27 @@ classEvalCallCodeExecutions
|
||||
| Eval.rb:25:1:25:47 | call to class_eval | Eval.rb:25:16:25:32 | "def foo; 1; end" |
|
||||
moduleEvalCallCodeExecutions
|
||||
| Eval.rb:26:1:26:54 | call to module_eval | Eval.rb:26:17:26:33 | "def bar; 1; end" |
|
||||
loggerLoggingCallInputs
|
||||
| Logging.rb:5:3:5:23 | call to progname= | Logging.rb:5:27:5:38 | "LoggerTest" |
|
||||
| Logging.rb:15:5:15:21 | call to debug | Logging.rb:15:19:15:21 | msg |
|
||||
| Logging.rb:20:5:22:7 | call to error | Logging.rb:21:7:21:15 | ... + ... |
|
||||
| Logging.rb:27:5:27:21 | call to fatal | Logging.rb:27:19:27:21 | msg |
|
||||
| Logging.rb:32:5:32:20 | call to warn | Logging.rb:32:18:32:20 | msg |
|
||||
| Logging.rb:37:5:37:43 | call to unknown | Logging.rb:37:21:37:34 | "unknown prog" |
|
||||
| Logging.rb:37:5:37:43 | call to unknown | Logging.rb:37:39:37:41 | msg |
|
||||
| Logging.rb:42:5:48:7 | call to info | Logging.rb:43:7:47:9 | if ... |
|
||||
| Logging.rb:54:5:54:44 | ... << ... | Logging.rb:54:21:54:44 | ( ... ) |
|
||||
| Logging.rb:58:5:58:46 | call to add | Logging.rb:58:38:58:44 | "block" |
|
||||
| Logging.rb:60:5:60:64 | call to add | Logging.rb:60:36:60:38 | nil |
|
||||
| Logging.rb:60:5:60:64 | call to add | Logging.rb:60:41:60:51 | "progname1" |
|
||||
| Logging.rb:60:5:60:64 | call to add | Logging.rb:60:56:60:62 | "block" |
|
||||
| Logging.rb:63:5:63:63 | call to add | Logging.rb:63:36:63:45 | "message1" |
|
||||
| Logging.rb:64:5:64:76 | call to add | Logging.rb:64:36:64:45 | "message2" |
|
||||
| Logging.rb:64:5:64:76 | call to add | Logging.rb:64:48:64:58 | "progname2" |
|
||||
| Logging.rb:68:5:68:46 | call to log | Logging.rb:68:38:68:44 | "block" |
|
||||
| Logging.rb:70:5:70:64 | call to log | Logging.rb:70:36:70:38 | nil |
|
||||
| Logging.rb:70:5:70:64 | call to log | Logging.rb:70:41:70:51 | "progname1" |
|
||||
| Logging.rb:70:5:70:64 | call to log | Logging.rb:70:56:70:62 | "block" |
|
||||
| Logging.rb:73:5:73:63 | call to log | Logging.rb:73:36:73:45 | "message1" |
|
||||
| Logging.rb:74:5:74:76 | call to log | Logging.rb:74:36:74:45 | "message2" |
|
||||
| Logging.rb:74:5:74:76 | call to log | Logging.rb:74:48:74:58 | "progname2" |
|
||||
|
||||
@@ -30,3 +30,5 @@ query DataFlow::Node classEvalCallCodeExecutions(ClassEvalCallCodeExecution e) {
|
||||
query DataFlow::Node moduleEvalCallCodeExecutions(ModuleEvalCallCodeExecution e) {
|
||||
result = e.getCode()
|
||||
}
|
||||
|
||||
query DataFlow::Node loggerLoggingCallInputs(LoggerLoggingCall c) { result = c.getAnInput() }
|
||||
|
||||
@@ -22,4 +22,10 @@ class BarsController < ApplicationController
|
||||
dt = params[:text]
|
||||
render "foo/bars/show", locals: { display_text: dt, safe_text: "hello" }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def unreachable_action
|
||||
render "show"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,6 +13,7 @@ calls.rb:
|
||||
# 97| Object
|
||||
#-----| include -> Kernel
|
||||
#-----| super -> BasicObject
|
||||
#-----| prepend -> A
|
||||
|
||||
# 106| Array
|
||||
#-----| super -> Object
|
||||
@@ -49,12 +50,10 @@ calls.rb:
|
||||
|
||||
# 15| M
|
||||
|
||||
private.rb:
|
||||
# 1| C
|
||||
# 29| C
|
||||
#-----| super -> Object
|
||||
#-----| include -> M
|
||||
|
||||
calls.rb:
|
||||
# 51| D
|
||||
#-----| super -> C
|
||||
|
||||
@@ -66,6 +65,8 @@ calls.rb:
|
||||
|
||||
# 150| A
|
||||
#-----| super -> S
|
||||
#-----| super -> B
|
||||
#-----| prepend -> A::B
|
||||
|
||||
# 155| B
|
||||
#-----| super -> S
|
||||
@@ -110,6 +111,13 @@ modules.rb:
|
||||
|
||||
# 115| XX
|
||||
|
||||
private.rb:
|
||||
# 1| E
|
||||
#-----| super -> Object
|
||||
|
||||
# 42| F
|
||||
|
||||
modules.rb:
|
||||
# 5| Foo::Bar
|
||||
|
||||
# 19| Foo::ClassInFoo
|
||||
@@ -134,6 +142,14 @@ modules.rb:
|
||||
|
||||
# 71| Test::Foo2::Foo2
|
||||
|
||||
modules_rec.rb:
|
||||
# 1| B::A
|
||||
#-----| super -> Object
|
||||
|
||||
# 4| A::B
|
||||
#-----| super -> Object
|
||||
|
||||
modules.rb:
|
||||
# 108| MM::MM
|
||||
|
||||
# 49| Foo::Bar::ClassInAnotherDefinitionOfFooBar
|
||||
|
||||
@@ -75,16 +75,21 @@ getTarget
|
||||
| modules.rb:90:24:90:36 | call to prepend | calls.rb:93:5:93:20 | prepend |
|
||||
| modules.rb:96:3:96:14 | call to include | calls.rb:92:5:92:20 | include |
|
||||
| modules.rb:102:3:102:16 | call to prepend | calls.rb:93:5:93:20 | prepend |
|
||||
| modules_rec.rb:8:3:8:11 | call to prepend | calls.rb:93:5:93:20 | prepend |
|
||||
| modules_rec.rb:11:1:11:9 | call to prepend | calls.rb:93:5:93:20 | prepend |
|
||||
| private.rb:2:3:3:5 | call to private | calls.rb:94:5:94:20 | private |
|
||||
| private.rb:10:3:10:19 | call to private | calls.rb:94:5:94:20 | private |
|
||||
| private.rb:12:3:12:9 | call to private | calls.rb:94:5:94:20 | private |
|
||||
| private.rb:24:1:24:5 | call to new | calls.rb:99:5:99:16 | new |
|
||||
| private.rb:25:1:25:5 | call to new | calls.rb:99:5:99:16 | new |
|
||||
| private.rb:26:1:26:5 | call to new | calls.rb:99:5:99:16 | new |
|
||||
| private.rb:27:1:27:5 | call to new | calls.rb:99:5:99:16 | new |
|
||||
| private.rb:28:1:28:5 | call to new | calls.rb:99:5:99:16 | new |
|
||||
| private.rb:28:1:28:12 | call to public | private.rb:5:3:6:5 | public |
|
||||
| private.rb:30:1:30:15 | call to private_on_main | private.rb:21:1:22:3 | private_on_main |
|
||||
| private.rb:34:1:34:5 | call to new | calls.rb:99:5:99:16 | new |
|
||||
| private.rb:35:1:35:5 | call to new | calls.rb:99:5:99:16 | new |
|
||||
| private.rb:36:1:36:5 | call to new | calls.rb:99:5:99:16 | new |
|
||||
| private.rb:37:1:37:5 | call to new | calls.rb:99:5:99:16 | new |
|
||||
| private.rb:38:1:38:5 | call to new | calls.rb:99:5:99:16 | new |
|
||||
| private.rb:38:1:38:12 | call to public | private.rb:5:3:6:5 | public |
|
||||
| private.rb:40:1:40:15 | call to private_on_main | private.rb:31:1:32:3 | private_on_main |
|
||||
| private.rb:43:3:44:5 | call to private | calls.rb:94:5:94:20 | private |
|
||||
| private.rb:51:3:51:19 | call to private | calls.rb:94:5:94:20 | private |
|
||||
| private.rb:53:3:53:9 | call to private | calls.rb:94:5:94:20 | private |
|
||||
unresolvedCall
|
||||
| calls.rb:19:5:19:14 | call to instance_m |
|
||||
| calls.rb:20:5:20:19 | call to instance_m |
|
||||
@@ -110,10 +115,12 @@ unresolvedCall
|
||||
| hello.rb:20:16:20:26 | ... + ... |
|
||||
| hello.rb:20:16:20:34 | ... + ... |
|
||||
| hello.rb:20:16:20:40 | ... + ... |
|
||||
| private.rb:24:1:24:14 | call to private1 |
|
||||
| private.rb:25:1:25:14 | call to private2 |
|
||||
| private.rb:26:1:26:14 | call to private3 |
|
||||
| private.rb:27:1:27:14 | call to private4 |
|
||||
| private.rb:23:3:24:5 | call to private_class_method |
|
||||
| private.rb:28:3:28:32 | call to private_class_method |
|
||||
| private.rb:34:1:34:14 | call to private1 |
|
||||
| private.rb:35:1:35:14 | call to private2 |
|
||||
| private.rb:36:1:36:14 | call to private3 |
|
||||
| private.rb:37:1:37:14 | call to private4 |
|
||||
privateMethod
|
||||
| calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:62:1:65:3 | optional_arg |
|
||||
@@ -126,4 +133,10 @@ privateMethod
|
||||
| private.rb:8:3:9:5 | private2 |
|
||||
| private.rb:14:3:15:5 | private3 |
|
||||
| private.rb:17:3:18:5 | private4 |
|
||||
| private.rb:21:1:22:3 | private_on_main |
|
||||
| private.rb:23:24:24:5 | private5 |
|
||||
| private.rb:26:3:27:5 | private6 |
|
||||
| private.rb:31:1:32:3 | private_on_main |
|
||||
| private.rb:43:11:44:5 | private1 |
|
||||
| private.rb:49:3:50:5 | private2 |
|
||||
| private.rb:55:3:56:5 | private3 |
|
||||
| private.rb:58:3:59:5 | private4 |
|
||||
|
||||
@@ -4,4 +4,4 @@ query Callable getTarget(Call call) { result = call.getATarget() }
|
||||
|
||||
query predicate unresolvedCall(Call call) { not exists(call.getATarget()) }
|
||||
|
||||
query predicate privateMethod(Method m) { m.isPrivate() }
|
||||
query predicate privateMethod(MethodBase m) { m.isPrivate() }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
getMethod
|
||||
| calls.rb:15:1:24:3 | M | instance_m | calls.rb:16:5:16:23 | instance_m |
|
||||
| calls.rb:29:1:44:3 | C | baz | calls.rb:37:5:43:7 | baz |
|
||||
| calls.rb:51:1:55:3 | D | baz | calls.rb:52:5:54:7 | baz |
|
||||
| calls.rb:77:1:80:3 | Integer | abs | calls.rb:79:5:79:16 | abs |
|
||||
| calls.rb:77:1:80:3 | Integer | bit_length | calls.rb:78:5:78:23 | bit_length |
|
||||
@@ -17,7 +18,7 @@ getMethod
|
||||
| calls.rb:97:1:100:3 | Object | new | calls.rb:99:5:99:16 | new |
|
||||
| calls.rb:97:1:100:3 | Object | optional_arg | calls.rb:62:1:65:3 | optional_arg |
|
||||
| calls.rb:97:1:100:3 | Object | private_on_main | calls.rb:164:1:165:3 | private_on_main |
|
||||
| calls.rb:97:1:100:3 | Object | private_on_main | private.rb:21:1:22:3 | private_on_main |
|
||||
| calls.rb:97:1:100:3 | Object | private_on_main | private.rb:31:1:32:3 | private_on_main |
|
||||
| calls.rb:102:1:104:3 | Hash | [] | calls.rb:103:5:103:15 | [] |
|
||||
| calls.rb:106:1:117:3 | Array | [] | calls.rb:107:3:107:13 | [] |
|
||||
| calls.rb:106:1:117:3 | Array | foreach | calls.rb:110:3:116:5 | foreach |
|
||||
@@ -35,13 +36,28 @@ getMethod
|
||||
| modules.rb:5:3:14:5 | Foo::Bar | method_in_foo_bar | modules.rb:9:5:10:7 | method_in_foo_bar |
|
||||
| modules.rb:37:1:46:3 | Bar | method_a | modules.rb:38:3:39:5 | method_a |
|
||||
| modules.rb:37:1:46:3 | Bar | method_b | modules.rb:41:3:42:5 | method_b |
|
||||
| private.rb:1:1:19:3 | C | baz | calls.rb:37:5:43:7 | baz |
|
||||
| private.rb:1:1:19:3 | C | private2 | private.rb:8:3:9:5 | private2 |
|
||||
| private.rb:1:1:19:3 | C | private3 | private.rb:14:3:15:5 | private3 |
|
||||
| private.rb:1:1:19:3 | C | private4 | private.rb:17:3:18:5 | private4 |
|
||||
| private.rb:1:1:19:3 | C | public | private.rb:5:3:6:5 | public |
|
||||
| private.rb:1:1:29:3 | E | private2 | private.rb:8:3:9:5 | private2 |
|
||||
| private.rb:1:1:29:3 | E | private3 | private.rb:14:3:15:5 | private3 |
|
||||
| private.rb:1:1:29:3 | E | private4 | private.rb:17:3:18:5 | private4 |
|
||||
| private.rb:1:1:29:3 | E | public | private.rb:5:3:6:5 | public |
|
||||
| private.rb:42:1:60:3 | F | private2 | private.rb:49:3:50:5 | private2 |
|
||||
| private.rb:42:1:60:3 | F | private3 | private.rb:55:3:56:5 | private3 |
|
||||
| private.rb:42:1:60:3 | F | private4 | private.rb:58:3:59:5 | private4 |
|
||||
| private.rb:42:1:60:3 | F | public | private.rb:46:3:47:5 | public |
|
||||
lookupMethod
|
||||
| calls.rb:15:1:24:3 | M | instance_m | calls.rb:16:5:16:23 | instance_m |
|
||||
| calls.rb:29:1:44:3 | C | baz | calls.rb:37:5:43:7 | baz |
|
||||
| calls.rb:29:1:44:3 | C | call_block | calls.rb:67:1:69:3 | call_block |
|
||||
| calls.rb:29:1:44:3 | C | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:29:1:44:3 | C | foo | calls.rb:71:1:75:3 | foo |
|
||||
| calls.rb:29:1:44:3 | C | funny | calls.rb:119:1:121:3 | funny |
|
||||
| calls.rb:29:1:44:3 | C | indirect | calls.rb:137:1:139:3 | indirect |
|
||||
| calls.rb:29:1:44:3 | C | instance_m | calls.rb:16:5:16:23 | instance_m |
|
||||
| calls.rb:29:1:44:3 | C | new | calls.rb:99:5:99:16 | new |
|
||||
| calls.rb:29:1:44:3 | C | optional_arg | calls.rb:62:1:65:3 | optional_arg |
|
||||
| calls.rb:29:1:44:3 | C | private_on_main | calls.rb:164:1:165:3 | private_on_main |
|
||||
| calls.rb:29:1:44:3 | C | puts | calls.rb:87:5:87:17 | puts |
|
||||
| calls.rb:29:1:44:3 | C | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| calls.rb:51:1:55:3 | D | baz | calls.rb:52:5:54:7 | baz |
|
||||
| calls.rb:51:1:55:3 | D | call_block | calls.rb:67:1:69:3 | call_block |
|
||||
| calls.rb:51:1:55:3 | D | foo | calls.rb:1:1:3:3 | foo |
|
||||
@@ -51,16 +67,14 @@ lookupMethod
|
||||
| calls.rb:51:1:55:3 | D | instance_m | calls.rb:16:5:16:23 | instance_m |
|
||||
| calls.rb:51:1:55:3 | D | new | calls.rb:99:5:99:16 | new |
|
||||
| calls.rb:51:1:55:3 | D | optional_arg | calls.rb:62:1:65:3 | optional_arg |
|
||||
| calls.rb:51:1:55:3 | D | private2 | private.rb:8:3:9:5 | private2 |
|
||||
| calls.rb:51:1:55:3 | D | private3 | private.rb:14:3:15:5 | private3 |
|
||||
| calls.rb:51:1:55:3 | D | private4 | private.rb:17:3:18:5 | private4 |
|
||||
| calls.rb:51:1:55:3 | D | private_on_main | calls.rb:164:1:165:3 | private_on_main |
|
||||
| calls.rb:51:1:55:3 | D | public | private.rb:5:3:6:5 | public |
|
||||
| calls.rb:51:1:55:3 | D | puts | calls.rb:87:5:87:17 | puts |
|
||||
| calls.rb:51:1:55:3 | D | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| calls.rb:77:1:80:3 | Integer | abs | calls.rb:79:5:79:16 | abs |
|
||||
| calls.rb:77:1:80:3 | Integer | bit_length | calls.rb:78:5:78:23 | bit_length |
|
||||
| calls.rb:77:1:80:3 | Integer | new | calls.rb:99:5:99:16 | new |
|
||||
| calls.rb:77:1:80:3 | Integer | puts | calls.rb:87:5:87:17 | puts |
|
||||
| calls.rb:77:1:80:3 | Integer | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| calls.rb:82:1:84:3 | String | call_block | calls.rb:67:1:69:3 | call_block |
|
||||
| calls.rb:82:1:84:3 | String | capitalize | calls.rb:83:5:83:23 | capitalize |
|
||||
| calls.rb:82:1:84:3 | String | foo | calls.rb:1:1:3:3 | foo |
|
||||
@@ -71,6 +85,7 @@ lookupMethod
|
||||
| calls.rb:82:1:84:3 | String | optional_arg | calls.rb:62:1:65:3 | optional_arg |
|
||||
| calls.rb:82:1:84:3 | String | private_on_main | calls.rb:164:1:165:3 | private_on_main |
|
||||
| calls.rb:82:1:84:3 | String | puts | calls.rb:87:5:87:17 | puts |
|
||||
| calls.rb:82:1:84:3 | String | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| calls.rb:86:1:88:3 | Kernel | puts | calls.rb:87:5:87:17 | puts |
|
||||
| calls.rb:90:1:95:3 | Module | call_block | calls.rb:67:1:69:3 | call_block |
|
||||
| calls.rb:90:1:95:3 | Module | foo | calls.rb:1:1:3:3 | foo |
|
||||
@@ -85,6 +100,7 @@ lookupMethod
|
||||
| calls.rb:90:1:95:3 | Module | private | calls.rb:94:5:94:20 | private |
|
||||
| calls.rb:90:1:95:3 | Module | private_on_main | calls.rb:164:1:165:3 | private_on_main |
|
||||
| calls.rb:90:1:95:3 | Module | puts | calls.rb:87:5:87:17 | puts |
|
||||
| calls.rb:90:1:95:3 | Module | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| calls.rb:97:1:100:3 | Object | call_block | calls.rb:67:1:69:3 | call_block |
|
||||
| calls.rb:97:1:100:3 | Object | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:97:1:100:3 | Object | foo | calls.rb:71:1:75:3 | foo |
|
||||
@@ -93,8 +109,9 @@ lookupMethod
|
||||
| calls.rb:97:1:100:3 | Object | new | calls.rb:99:5:99:16 | new |
|
||||
| calls.rb:97:1:100:3 | Object | optional_arg | calls.rb:62:1:65:3 | optional_arg |
|
||||
| calls.rb:97:1:100:3 | Object | private_on_main | calls.rb:164:1:165:3 | private_on_main |
|
||||
| calls.rb:97:1:100:3 | Object | private_on_main | private.rb:21:1:22:3 | private_on_main |
|
||||
| calls.rb:97:1:100:3 | Object | private_on_main | private.rb:31:1:32:3 | private_on_main |
|
||||
| calls.rb:97:1:100:3 | Object | puts | calls.rb:87:5:87:17 | puts |
|
||||
| calls.rb:97:1:100:3 | Object | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| calls.rb:102:1:104:3 | Hash | [] | calls.rb:103:5:103:15 | [] |
|
||||
| calls.rb:102:1:104:3 | Hash | call_block | calls.rb:67:1:69:3 | call_block |
|
||||
| calls.rb:102:1:104:3 | Hash | foo | calls.rb:1:1:3:3 | foo |
|
||||
@@ -105,6 +122,7 @@ lookupMethod
|
||||
| calls.rb:102:1:104:3 | Hash | optional_arg | calls.rb:62:1:65:3 | optional_arg |
|
||||
| calls.rb:102:1:104:3 | Hash | private_on_main | calls.rb:164:1:165:3 | private_on_main |
|
||||
| calls.rb:102:1:104:3 | Hash | puts | calls.rb:87:5:87:17 | puts |
|
||||
| calls.rb:102:1:104:3 | Hash | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| calls.rb:106:1:117:3 | Array | [] | calls.rb:107:3:107:13 | [] |
|
||||
| calls.rb:106:1:117:3 | Array | call_block | calls.rb:67:1:69:3 | call_block |
|
||||
| calls.rb:106:1:117:3 | Array | foo | calls.rb:1:1:3:3 | foo |
|
||||
@@ -117,6 +135,7 @@ lookupMethod
|
||||
| calls.rb:106:1:117:3 | Array | optional_arg | calls.rb:62:1:65:3 | optional_arg |
|
||||
| calls.rb:106:1:117:3 | Array | private_on_main | calls.rb:164:1:165:3 | private_on_main |
|
||||
| calls.rb:106:1:117:3 | Array | puts | calls.rb:87:5:87:17 | puts |
|
||||
| calls.rb:106:1:117:3 | Array | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| calls.rb:144:1:148:3 | S | call_block | calls.rb:67:1:69:3 | call_block |
|
||||
| calls.rb:144:1:148:3 | S | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:144:1:148:3 | S | foo | calls.rb:71:1:75:3 | foo |
|
||||
@@ -127,6 +146,7 @@ lookupMethod
|
||||
| calls.rb:144:1:148:3 | S | private_on_main | calls.rb:164:1:165:3 | private_on_main |
|
||||
| calls.rb:144:1:148:3 | S | puts | calls.rb:87:5:87:17 | puts |
|
||||
| calls.rb:144:1:148:3 | S | s_method | calls.rb:145:5:147:7 | s_method |
|
||||
| calls.rb:144:1:148:3 | S | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| calls.rb:150:1:153:3 | A | call_block | calls.rb:67:1:69:3 | call_block |
|
||||
| calls.rb:150:1:153:3 | A | foo | calls.rb:1:1:3:3 | foo |
|
||||
| calls.rb:150:1:153:3 | A | foo | calls.rb:71:1:75:3 | foo |
|
||||
@@ -155,31 +175,41 @@ lookupMethod
|
||||
| file://:0:0:0:0 | Class | prepend | calls.rb:93:5:93:20 | prepend |
|
||||
| file://:0:0:0:0 | Class | private | calls.rb:94:5:94:20 | private |
|
||||
| file://:0:0:0:0 | Class | puts | calls.rb:87:5:87:17 | puts |
|
||||
| file://:0:0:0:0 | Class | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| file://:0:0:0:0 | Complex | new | calls.rb:99:5:99:16 | new |
|
||||
| file://:0:0:0:0 | Complex | puts | calls.rb:87:5:87:17 | puts |
|
||||
| file://:0:0:0:0 | Complex | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| file://:0:0:0:0 | FalseClass | new | calls.rb:99:5:99:16 | new |
|
||||
| file://:0:0:0:0 | FalseClass | puts | calls.rb:87:5:87:17 | puts |
|
||||
| file://:0:0:0:0 | FalseClass | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| file://:0:0:0:0 | Float | new | calls.rb:99:5:99:16 | new |
|
||||
| file://:0:0:0:0 | Float | puts | calls.rb:87:5:87:17 | puts |
|
||||
| file://:0:0:0:0 | Float | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| file://:0:0:0:0 | NilClass | new | calls.rb:99:5:99:16 | new |
|
||||
| file://:0:0:0:0 | NilClass | puts | calls.rb:87:5:87:17 | puts |
|
||||
| file://:0:0:0:0 | NilClass | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| file://:0:0:0:0 | Numeric | new | calls.rb:99:5:99:16 | new |
|
||||
| file://:0:0:0:0 | Numeric | puts | calls.rb:87:5:87:17 | puts |
|
||||
| file://:0:0:0:0 | Numeric | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| file://:0:0:0:0 | Rational | new | calls.rb:99:5:99:16 | new |
|
||||
| file://:0:0:0:0 | Rational | puts | calls.rb:87:5:87:17 | puts |
|
||||
| file://:0:0:0:0 | Rational | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| file://:0:0:0:0 | TrueClass | new | calls.rb:99:5:99:16 | new |
|
||||
| file://:0:0:0:0 | TrueClass | puts | calls.rb:87:5:87:17 | puts |
|
||||
| file://:0:0:0:0 | TrueClass | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| hello.rb:1:1:8:3 | EnglishWords | hello | hello.rb:2:5:4:7 | hello |
|
||||
| hello.rb:1:1:8:3 | EnglishWords | world | hello.rb:5:5:7:7 | world |
|
||||
| hello.rb:11:1:16:3 | Greeting | hello | hello.rb:2:5:4:7 | hello |
|
||||
| hello.rb:11:1:16:3 | Greeting | message | hello.rb:13:5:15:7 | message |
|
||||
| hello.rb:11:1:16:3 | Greeting | new | calls.rb:99:5:99:16 | new |
|
||||
| hello.rb:11:1:16:3 | Greeting | puts | calls.rb:87:5:87:17 | puts |
|
||||
| hello.rb:11:1:16:3 | Greeting | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| hello.rb:11:1:16:3 | Greeting | world | hello.rb:5:5:7:7 | world |
|
||||
| hello.rb:18:1:22:3 | HelloWorld | hello | hello.rb:2:5:4:7 | hello |
|
||||
| hello.rb:18:1:22:3 | HelloWorld | message | hello.rb:19:5:21:7 | message |
|
||||
| hello.rb:18:1:22:3 | HelloWorld | new | calls.rb:99:5:99:16 | new |
|
||||
| hello.rb:18:1:22:3 | HelloWorld | puts | calls.rb:87:5:87:17 | puts |
|
||||
| hello.rb:18:1:22:3 | HelloWorld | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| hello.rb:18:1:22:3 | HelloWorld | world | hello.rb:5:5:7:7 | world |
|
||||
| modules.rb:4:1:24:3 | Foo | method_in_another_definition_of_foo | modules.rb:27:3:28:5 | method_in_another_definition_of_foo |
|
||||
| modules.rb:4:1:24:3 | Foo | method_in_foo | modules.rb:16:3:17:5 | method_in_foo |
|
||||
@@ -187,37 +217,48 @@ lookupMethod
|
||||
| modules.rb:5:3:14:5 | Foo::Bar | method_in_foo_bar | modules.rb:9:5:10:7 | method_in_foo_bar |
|
||||
| modules.rb:6:5:7:7 | Foo::Bar::ClassInFooBar | new | calls.rb:99:5:99:16 | new |
|
||||
| modules.rb:6:5:7:7 | Foo::Bar::ClassInFooBar | puts | calls.rb:87:5:87:17 | puts |
|
||||
| modules.rb:6:5:7:7 | Foo::Bar::ClassInFooBar | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| modules.rb:19:3:20:5 | Foo::ClassInFoo | new | calls.rb:99:5:99:16 | new |
|
||||
| modules.rb:19:3:20:5 | Foo::ClassInFoo | puts | calls.rb:87:5:87:17 | puts |
|
||||
| modules.rb:19:3:20:5 | Foo::ClassInFoo | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| modules.rb:30:3:31:5 | Foo::ClassInAnotherDefinitionOfFoo | new | calls.rb:99:5:99:16 | new |
|
||||
| modules.rb:30:3:31:5 | Foo::ClassInAnotherDefinitionOfFoo | puts | calls.rb:87:5:87:17 | puts |
|
||||
| modules.rb:30:3:31:5 | Foo::ClassInAnotherDefinitionOfFoo | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| modules.rb:37:1:46:3 | Bar | method_a | modules.rb:38:3:39:5 | method_a |
|
||||
| modules.rb:37:1:46:3 | Bar | method_b | modules.rb:41:3:42:5 | method_b |
|
||||
| modules.rb:37:1:46:3 | Bar | new | calls.rb:99:5:99:16 | new |
|
||||
| modules.rb:37:1:46:3 | Bar | puts | calls.rb:87:5:87:17 | puts |
|
||||
| modules.rb:37:1:46:3 | Bar | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| modules.rb:49:3:50:5 | Foo::Bar::ClassInAnotherDefinitionOfFooBar | new | calls.rb:99:5:99:16 | new |
|
||||
| modules.rb:49:3:50:5 | Foo::Bar::ClassInAnotherDefinitionOfFooBar | puts | calls.rb:87:5:87:17 | puts |
|
||||
| modules.rb:49:3:50:5 | Foo::Bar::ClassInAnotherDefinitionOfFooBar | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| modules.rb:66:5:67:7 | Test::Foo1::Bar | new | calls.rb:99:5:99:16 | new |
|
||||
| modules.rb:66:5:67:7 | Test::Foo1::Bar | puts | calls.rb:87:5:87:17 | puts |
|
||||
| modules.rb:66:5:67:7 | Test::Foo1::Bar | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| modules.rb:72:5:73:7 | Test::Foo2::Foo2::Bar | new | calls.rb:99:5:99:16 | new |
|
||||
| modules.rb:72:5:73:7 | Test::Foo2::Foo2::Bar | puts | calls.rb:87:5:87:17 | puts |
|
||||
| modules.rb:72:5:73:7 | Test::Foo2::Foo2::Bar | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| modules.rb:112:1:113:3 | YY | new | calls.rb:99:5:99:16 | new |
|
||||
| modules.rb:112:1:113:3 | YY | puts | calls.rb:87:5:87:17 | puts |
|
||||
| modules.rb:112:1:113:3 | YY | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| modules.rb:116:7:117:9 | XX::YY | new | calls.rb:99:5:99:16 | new |
|
||||
| modules.rb:116:7:117:9 | XX::YY | puts | calls.rb:87:5:87:17 | puts |
|
||||
| private.rb:1:1:19:3 | C | baz | calls.rb:37:5:43:7 | baz |
|
||||
| private.rb:1:1:19:3 | C | call_block | calls.rb:67:1:69:3 | call_block |
|
||||
| private.rb:1:1:19:3 | C | foo | calls.rb:1:1:3:3 | foo |
|
||||
| private.rb:1:1:19:3 | C | foo | calls.rb:71:1:75:3 | foo |
|
||||
| private.rb:1:1:19:3 | C | funny | calls.rb:119:1:121:3 | funny |
|
||||
| private.rb:1:1:19:3 | C | indirect | calls.rb:137:1:139:3 | indirect |
|
||||
| private.rb:1:1:19:3 | C | instance_m | calls.rb:16:5:16:23 | instance_m |
|
||||
| private.rb:1:1:19:3 | C | new | calls.rb:99:5:99:16 | new |
|
||||
| private.rb:1:1:19:3 | C | optional_arg | calls.rb:62:1:65:3 | optional_arg |
|
||||
| private.rb:1:1:19:3 | C | private2 | private.rb:8:3:9:5 | private2 |
|
||||
| private.rb:1:1:19:3 | C | private3 | private.rb:14:3:15:5 | private3 |
|
||||
| private.rb:1:1:19:3 | C | private4 | private.rb:17:3:18:5 | private4 |
|
||||
| private.rb:1:1:19:3 | C | private_on_main | calls.rb:164:1:165:3 | private_on_main |
|
||||
| private.rb:1:1:19:3 | C | private_on_main | private.rb:21:1:22:3 | private_on_main |
|
||||
| private.rb:1:1:19:3 | C | public | private.rb:5:3:6:5 | public |
|
||||
| private.rb:1:1:19:3 | C | puts | calls.rb:87:5:87:17 | puts |
|
||||
| modules.rb:116:7:117:9 | XX::YY | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| modules_rec.rb:1:1:2:3 | B::A | new | calls.rb:99:5:99:16 | new |
|
||||
| modules_rec.rb:1:1:2:3 | B::A | puts | calls.rb:87:5:87:17 | puts |
|
||||
| modules_rec.rb:1:1:2:3 | B::A | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| modules_rec.rb:4:1:5:3 | A::B | new | calls.rb:99:5:99:16 | new |
|
||||
| modules_rec.rb:4:1:5:3 | A::B | puts | calls.rb:87:5:87:17 | puts |
|
||||
| modules_rec.rb:4:1:5:3 | A::B | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| private.rb:1:1:29:3 | E | new | calls.rb:99:5:99:16 | new |
|
||||
| private.rb:1:1:29:3 | E | private2 | private.rb:8:3:9:5 | private2 |
|
||||
| private.rb:1:1:29:3 | E | private3 | private.rb:14:3:15:5 | private3 |
|
||||
| private.rb:1:1:29:3 | E | private4 | private.rb:17:3:18:5 | private4 |
|
||||
| private.rb:1:1:29:3 | E | private_on_main | private.rb:31:1:32:3 | private_on_main |
|
||||
| private.rb:1:1:29:3 | E | public | private.rb:5:3:6:5 | public |
|
||||
| private.rb:1:1:29:3 | E | puts | calls.rb:87:5:87:17 | puts |
|
||||
| private.rb:1:1:29:3 | E | to_s | calls.rb:151:5:152:7 | to_s |
|
||||
| private.rb:42:1:60:3 | F | private2 | private.rb:49:3:50:5 | private2 |
|
||||
| private.rb:42:1:60:3 | F | private3 | private.rb:55:3:56:5 | private3 |
|
||||
| private.rb:42:1:60:3 | F | private4 | private.rb:58:3:59:5 | private4 |
|
||||
| private.rb:42:1:60:3 | F | public | private.rb:46:3:47:5 | public |
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
getModule
|
||||
| calls.rb:15:1:24:3 | M |
|
||||
| calls.rb:29:1:44:3 | C |
|
||||
| calls.rb:51:1:55:3 | D |
|
||||
| calls.rb:77:1:80:3 | Integer |
|
||||
| calls.rb:82:1:84:3 | String |
|
||||
@@ -55,9 +56,13 @@ getModule
|
||||
| modules.rb:115:1:118:3 | XX |
|
||||
| modules.rb:116:7:117:9 | XX::YY |
|
||||
| modules.rb:120:1:121:3 | Test::Foo1::Bar::Baz |
|
||||
| private.rb:1:1:19:3 | C |
|
||||
| modules_rec.rb:1:1:2:3 | B::A |
|
||||
| modules_rec.rb:4:1:5:3 | A::B |
|
||||
| private.rb:1:1:29:3 | E |
|
||||
| private.rb:42:1:60:3 | F |
|
||||
getADeclaration
|
||||
| calls.rb:15:1:24:3 | M | calls.rb:15:1:24:3 | M |
|
||||
| calls.rb:29:1:44:3 | C | calls.rb:29:1:44:3 | C |
|
||||
| calls.rb:51:1:55:3 | D | calls.rb:51:1:55:3 | D |
|
||||
| calls.rb:77:1:80:3 | Integer | calls.rb:77:1:80:3 | Integer |
|
||||
| calls.rb:82:1:84:3 | String | calls.rb:82:1:84:3 | String |
|
||||
@@ -66,12 +71,14 @@ getADeclaration
|
||||
| calls.rb:97:1:100:3 | Object | calls.rb:1:1:167:16 | calls.rb |
|
||||
| calls.rb:97:1:100:3 | Object | calls.rb:97:1:100:3 | Object |
|
||||
| calls.rb:97:1:100:3 | Object | hello.rb:1:1:22:3 | hello.rb |
|
||||
| calls.rb:97:1:100:3 | Object | modules.rb:1:1:122:1 | modules.rb |
|
||||
| calls.rb:97:1:100:3 | Object | private.rb:1:1:30:15 | private.rb |
|
||||
| calls.rb:97:1:100:3 | Object | modules.rb:1:1:121:4 | modules.rb |
|
||||
| calls.rb:97:1:100:3 | Object | modules_rec.rb:1:1:11:10 | modules_rec.rb |
|
||||
| calls.rb:97:1:100:3 | Object | private.rb:1:1:60:3 | private.rb |
|
||||
| calls.rb:102:1:104:3 | Hash | calls.rb:102:1:104:3 | Hash |
|
||||
| calls.rb:106:1:117:3 | Array | calls.rb:106:1:117:3 | Array |
|
||||
| calls.rb:144:1:148:3 | S | calls.rb:144:1:148:3 | S |
|
||||
| calls.rb:150:1:153:3 | A | calls.rb:150:1:153:3 | A |
|
||||
| calls.rb:150:1:153:3 | A | modules_rec.rb:7:1:9:3 | A |
|
||||
| calls.rb:155:1:158:3 | B | calls.rb:155:1:158:3 | B |
|
||||
| hello.rb:1:1:8:3 | EnglishWords | hello.rb:1:1:8:3 | EnglishWords |
|
||||
| hello.rb:11:1:16:3 | Greeting | hello.rb:11:1:16:3 | Greeting |
|
||||
@@ -109,10 +116,13 @@ getADeclaration
|
||||
| modules.rb:115:1:118:3 | XX | modules.rb:115:1:118:3 | XX |
|
||||
| modules.rb:116:7:117:9 | XX::YY | modules.rb:116:7:117:9 | YY |
|
||||
| modules.rb:120:1:121:3 | Test::Foo1::Bar::Baz | modules.rb:120:1:121:3 | Baz |
|
||||
| private.rb:1:1:19:3 | C | calls.rb:29:1:44:3 | C |
|
||||
| private.rb:1:1:19:3 | C | private.rb:1:1:19:3 | C |
|
||||
| modules_rec.rb:1:1:2:3 | B::A | modules_rec.rb:1:1:2:3 | A |
|
||||
| modules_rec.rb:4:1:5:3 | A::B | modules_rec.rb:4:1:5:3 | B |
|
||||
| private.rb:1:1:29:3 | E | private.rb:1:1:29:3 | E |
|
||||
| private.rb:42:1:60:3 | F | private.rb:42:1:60:3 | F |
|
||||
getSuperClass
|
||||
| calls.rb:51:1:55:3 | D | private.rb:1:1:19:3 | C |
|
||||
| calls.rb:29:1:44:3 | C | calls.rb:97:1:100:3 | Object |
|
||||
| calls.rb:51:1:55:3 | D | calls.rb:29:1:44:3 | C |
|
||||
| calls.rb:77:1:80:3 | Integer | file://:0:0:0:0 | Numeric |
|
||||
| calls.rb:82:1:84:3 | String | calls.rb:97:1:100:3 | Object |
|
||||
| calls.rb:90:1:95:3 | Module | calls.rb:97:1:100:3 | Object |
|
||||
@@ -121,6 +131,7 @@ getSuperClass
|
||||
| calls.rb:106:1:117:3 | Array | calls.rb:97:1:100:3 | Object |
|
||||
| calls.rb:144:1:148:3 | S | calls.rb:97:1:100:3 | Object |
|
||||
| calls.rb:150:1:153:3 | A | calls.rb:144:1:148:3 | S |
|
||||
| calls.rb:150:1:153:3 | A | calls.rb:155:1:158:3 | B |
|
||||
| calls.rb:155:1:158:3 | B | calls.rb:144:1:148:3 | S |
|
||||
| file://:0:0:0:0 | Class | calls.rb:90:1:95:3 | Module |
|
||||
| file://:0:0:0:0 | Complex | file://:0:0:0:0 | Numeric |
|
||||
@@ -141,12 +152,130 @@ getSuperClass
|
||||
| modules.rb:72:5:73:7 | Test::Foo2::Foo2::Bar | calls.rb:97:1:100:3 | Object |
|
||||
| modules.rb:112:1:113:3 | YY | calls.rb:97:1:100:3 | Object |
|
||||
| modules.rb:116:7:117:9 | XX::YY | modules.rb:112:1:113:3 | YY |
|
||||
| private.rb:1:1:19:3 | C | calls.rb:97:1:100:3 | Object |
|
||||
| modules_rec.rb:1:1:2:3 | B::A | calls.rb:97:1:100:3 | Object |
|
||||
| modules_rec.rb:4:1:5:3 | A::B | calls.rb:97:1:100:3 | Object |
|
||||
| private.rb:1:1:29:3 | E | calls.rb:97:1:100:3 | Object |
|
||||
getAPrependedModule
|
||||
| calls.rb:97:1:100:3 | Object | calls.rb:150:1:153:3 | A |
|
||||
| calls.rb:150:1:153:3 | A | modules_rec.rb:4:1:5:3 | A::B |
|
||||
| modules.rb:101:1:105:3 | PrependTest | modules.rb:63:1:81:3 | Test |
|
||||
getAnIncludedModule
|
||||
| calls.rb:29:1:44:3 | C | calls.rb:15:1:24:3 | M |
|
||||
| calls.rb:97:1:100:3 | Object | calls.rb:86:1:88:3 | Kernel |
|
||||
| hello.rb:11:1:16:3 | Greeting | hello.rb:1:1:8:3 | EnglishWords |
|
||||
| modules.rb:88:1:93:3 | IncludeTest | modules.rb:63:1:81:3 | Test |
|
||||
| modules.rb:95:1:99:3 | IncludeTest2 | modules.rb:63:1:81:3 | Test |
|
||||
| private.rb:1:1:19:3 | C | calls.rb:15:1:24:3 | M |
|
||||
resolveConstantReadAccess
|
||||
| calls.rb:26:1:26:1 | M | M |
|
||||
| calls.rb:27:1:27:1 | M | M |
|
||||
| calls.rb:30:13:30:13 | M | M |
|
||||
| calls.rb:46:5:46:5 | C | C |
|
||||
| calls.rb:51:11:51:11 | C | C |
|
||||
| calls.rb:57:5:57:5 | D | D |
|
||||
| calls.rb:72:11:72:14 | Hash | Hash |
|
||||
| calls.rb:97:16:97:21 | Module | Module |
|
||||
| calls.rb:98:13:98:18 | Kernel | Kernel |
|
||||
| calls.rb:129:1:129:13 | Array | Array |
|
||||
| calls.rb:131:1:131:7 | Array | Array |
|
||||
| calls.rb:133:1:133:7 | Array | Array |
|
||||
| calls.rb:135:1:135:8 | Array | Array |
|
||||
| calls.rb:150:11:150:11 | S | S |
|
||||
| calls.rb:155:11:155:11 | S | S |
|
||||
| calls.rb:160:1:160:1 | S | S |
|
||||
| calls.rb:161:1:161:1 | A | A |
|
||||
| calls.rb:162:1:162:1 | B | B |
|
||||
| hello.rb:12:13:12:24 | EnglishWords | EnglishWords |
|
||||
| hello.rb:18:20:18:27 | Greeting | Greeting |
|
||||
| modules.rb:48:8:48:10 | Foo | Foo |
|
||||
| modules.rb:66:11:66:14 | Foo1 | Test::Foo1 |
|
||||
| modules.rb:72:11:72:14 | Foo2 | Test::Foo2::Foo2 |
|
||||
| modules.rb:77:12:77:17 | Object | Object |
|
||||
| modules.rb:78:11:78:14 | Foo3 | Object |
|
||||
| modules.rb:89:11:89:16 | Test | Test |
|
||||
| modules.rb:90:3:90:8 | Object | Object |
|
||||
| modules.rb:90:32:90:36 | Other | Other |
|
||||
| modules.rb:91:10:91:13 | Foo1 | Test::Foo1 |
|
||||
| modules.rb:96:11:96:14 | Test | Test |
|
||||
| modules.rb:97:10:97:13 | Foo1 | Test::Foo1 |
|
||||
| modules.rb:102:11:102:16 | Test | Test |
|
||||
| modules.rb:103:10:103:13 | Foo2 | Test::Foo2 |
|
||||
| modules.rb:108:10:108:11 | MM | MM |
|
||||
| modules.rb:116:18:116:19 | YY | YY |
|
||||
| modules.rb:120:8:120:11 | Test | Test |
|
||||
| modules.rb:120:8:120:17 | Foo1 | Test::Foo1 |
|
||||
| modules.rb:120:8:120:22 | Bar | Test::Foo1::Bar |
|
||||
| modules_rec.rb:1:7:1:7 | B | B |
|
||||
| modules_rec.rb:4:7:4:7 | A | A |
|
||||
| modules_rec.rb:7:11:7:11 | B | B |
|
||||
| modules_rec.rb:8:11:8:11 | B | A::B |
|
||||
| modules_rec.rb:11:9:11:9 | A | A |
|
||||
| private.rb:34:1:34:1 | E | E |
|
||||
| private.rb:35:1:35:1 | E | E |
|
||||
| private.rb:36:1:36:1 | E | E |
|
||||
| private.rb:37:1:37:1 | E | E |
|
||||
| private.rb:38:1:38:1 | E | E |
|
||||
resolveConstantWriteAccess
|
||||
| calls.rb:15:1:24:3 | M | M |
|
||||
| calls.rb:29:1:44:3 | C | C |
|
||||
| calls.rb:51:1:55:3 | D | D |
|
||||
| calls.rb:77:1:80:3 | Integer | Integer |
|
||||
| calls.rb:82:1:84:3 | String | String |
|
||||
| calls.rb:86:1:88:3 | Kernel | Kernel |
|
||||
| calls.rb:90:1:95:3 | Module | Module |
|
||||
| calls.rb:97:1:100:3 | Object | Object |
|
||||
| calls.rb:102:1:104:3 | Hash | Hash |
|
||||
| calls.rb:106:1:117:3 | Array | Array |
|
||||
| calls.rb:144:1:148:3 | S | S |
|
||||
| calls.rb:150:1:153:3 | A | A |
|
||||
| calls.rb:155:1:158:3 | B | B |
|
||||
| hello.rb:1:1:8:3 | EnglishWords | EnglishWords |
|
||||
| hello.rb:11:1:16:3 | Greeting | Greeting |
|
||||
| hello.rb:18:1:22:3 | HelloWorld | HelloWorld |
|
||||
| modules.rb:1:1:2:3 | Empty | Empty |
|
||||
| modules.rb:4:1:24:3 | Foo | Foo |
|
||||
| modules.rb:5:3:14:5 | Bar | Foo::Bar |
|
||||
| modules.rb:6:5:7:7 | ClassInFooBar | Foo::Bar::ClassInFooBar |
|
||||
| modules.rb:19:3:20:5 | ClassInFoo | Foo::ClassInFoo |
|
||||
| modules.rb:26:1:35:3 | Foo | Foo |
|
||||
| modules.rb:30:3:31:5 | ClassInAnotherDefinitionOfFoo | Foo::ClassInAnotherDefinitionOfFoo |
|
||||
| modules.rb:37:1:46:3 | Bar | Bar |
|
||||
| modules.rb:48:1:57:3 | Bar | Foo::Bar |
|
||||
| modules.rb:49:3:50:5 | ClassInAnotherDefinitionOfFooBar | Foo::Bar::ClassInAnotherDefinitionOfFooBar |
|
||||
| modules.rb:60:1:61:3 | MyModuleInGlobalScope | MyModuleInGlobalScope |
|
||||
| modules.rb:63:1:81:3 | Test | Test |
|
||||
| modules.rb:65:3:68:5 | Foo1 | Test::Foo1 |
|
||||
| modules.rb:66:5:67:7 | Bar | Foo1::Bar |
|
||||
| modules.rb:66:5:67:7 | Bar | Test::Foo1::Bar |
|
||||
| modules.rb:70:3:74:5 | Foo2 | Test::Foo2 |
|
||||
| modules.rb:71:5:71:19 | Foo2 | Test::Foo2::Foo2 |
|
||||
| modules.rb:72:5:73:7 | Bar | Foo2::Bar |
|
||||
| modules.rb:72:5:73:7 | Bar | Test::Foo2::Bar |
|
||||
| modules.rb:72:5:73:7 | Bar | Test::Foo2::Foo2::Bar |
|
||||
| modules.rb:76:3:80:5 | Foo3 | Test::Foo3 |
|
||||
| modules.rb:77:5:77:8 | Foo3 | Test::Foo3::Foo3 |
|
||||
| modules.rb:78:5:79:7 | Bar | Foo3::Bar |
|
||||
| modules.rb:78:5:79:7 | Bar | Test::Foo3::Bar |
|
||||
| modules.rb:78:5:79:7 | Bar | Test::Foo3::Foo3::Bar |
|
||||
| modules.rb:83:1:86:3 | Other | Other |
|
||||
| modules.rb:84:3:85:5 | Foo1 | Other::Foo1 |
|
||||
| modules.rb:88:1:93:3 | IncludeTest | IncludeTest |
|
||||
| modules.rb:91:3:92:5 | Y | Foo1::Y |
|
||||
| modules.rb:91:3:92:5 | Y | Test::Foo1::Y |
|
||||
| modules.rb:95:1:99:3 | IncludeTest2 | IncludeTest2 |
|
||||
| modules.rb:97:3:98:5 | Z | Foo1::Z |
|
||||
| modules.rb:97:3:98:5 | Z | Test::Foo1::Z |
|
||||
| modules.rb:101:1:105:3 | PrependTest | PrependTest |
|
||||
| modules.rb:103:3:104:5 | Y | Foo2::Y |
|
||||
| modules.rb:103:3:104:5 | Y | Test::Foo2::Y |
|
||||
| modules.rb:107:1:110:3 | MM | MM |
|
||||
| modules.rb:108:3:109:5 | MM | MM::MM |
|
||||
| modules.rb:108:3:109:5 | MM | MM::MM::MM |
|
||||
| modules.rb:112:1:113:3 | YY | YY |
|
||||
| modules.rb:115:1:118:3 | XX | XX |
|
||||
| modules.rb:116:7:117:9 | YY | XX::YY |
|
||||
| modules.rb:120:1:121:3 | Baz | Test::Foo1::Bar::Baz |
|
||||
| modules_rec.rb:1:1:2:3 | A | B::A |
|
||||
| modules_rec.rb:4:1:5:3 | B | A::B |
|
||||
| modules_rec.rb:7:1:9:3 | A | A |
|
||||
| private.rb:1:1:29:3 | E | E |
|
||||
| private.rb:42:1:60:3 | F | F |
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import ruby
|
||||
private import codeql.ruby.ast.internal.Module as Internal
|
||||
|
||||
query Module getModule() { any() }
|
||||
|
||||
@@ -9,3 +10,11 @@ query Module getSuperClass(Module m) { result = m.getSuperClass() }
|
||||
query Module getAPrependedModule(Module m) { result = m.getAPrependedModule() }
|
||||
|
||||
query Module getAnIncludedModule(Module m) { result = m.getAnIncludedModule() }
|
||||
|
||||
query predicate resolveConstantReadAccess(ConstantReadAccess a, string s) {
|
||||
Internal::TResolved(s) = Internal::resolveConstantReadAccess(a)
|
||||
}
|
||||
|
||||
query predicate resolveConstantWriteAccess(ConstantWriteAccess c, string s) {
|
||||
s = Internal::resolveConstantWriteAccess(c)
|
||||
}
|
||||
|
||||
@@ -119,4 +119,3 @@ end
|
||||
|
||||
module Test::Foo1::Bar::Baz
|
||||
end
|
||||
|
||||
|
||||
11
ruby/ql/test/library-tests/modules/modules_rec.rb
Normal file
11
ruby/ql/test/library-tests/modules/modules_rec.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
class B::A
|
||||
end
|
||||
|
||||
class A::B
|
||||
end
|
||||
|
||||
class A < B
|
||||
prepend B
|
||||
end
|
||||
|
||||
prepend A
|
||||
@@ -1,4 +1,4 @@
|
||||
class C
|
||||
class E
|
||||
private def private1
|
||||
end
|
||||
|
||||
@@ -16,15 +16,45 @@ class C
|
||||
|
||||
def private4
|
||||
end
|
||||
|
||||
def self.public2
|
||||
end
|
||||
|
||||
private_class_method def self.private5
|
||||
end
|
||||
|
||||
def self.private6
|
||||
end
|
||||
private_class_method :private6
|
||||
end
|
||||
|
||||
def private_on_main
|
||||
end
|
||||
|
||||
C.new.private1
|
||||
C.new.private2
|
||||
C.new.private3
|
||||
C.new.private4
|
||||
C.new.public
|
||||
E.new.private1
|
||||
E.new.private2
|
||||
E.new.private3
|
||||
E.new.private4
|
||||
E.new.public
|
||||
|
||||
private_on_main
|
||||
private_on_main
|
||||
|
||||
module F
|
||||
private def private1
|
||||
end
|
||||
|
||||
def public
|
||||
end
|
||||
|
||||
def private2
|
||||
end
|
||||
private :private2
|
||||
|
||||
private
|
||||
|
||||
def private3
|
||||
end
|
||||
|
||||
def private4
|
||||
end
|
||||
end
|
||||
@@ -48,11 +48,9 @@ calls.rb:
|
||||
|
||||
# 15| M
|
||||
|
||||
private.rb:
|
||||
# 1| C
|
||||
# 29| C
|
||||
#-----| -> Object
|
||||
|
||||
calls.rb:
|
||||
# 51| D
|
||||
#-----| -> C
|
||||
|
||||
@@ -64,6 +62,7 @@ calls.rb:
|
||||
|
||||
# 150| A
|
||||
#-----| -> S
|
||||
#-----| -> B
|
||||
|
||||
# 155| B
|
||||
#-----| -> S
|
||||
@@ -104,6 +103,13 @@ modules.rb:
|
||||
|
||||
# 115| XX
|
||||
|
||||
private.rb:
|
||||
# 1| E
|
||||
#-----| -> Object
|
||||
|
||||
# 42| F
|
||||
|
||||
modules.rb:
|
||||
# 5| Foo::Bar
|
||||
|
||||
# 19| Foo::ClassInFoo
|
||||
@@ -128,6 +134,14 @@ modules.rb:
|
||||
|
||||
# 71| Test::Foo2::Foo2
|
||||
|
||||
modules_rec.rb:
|
||||
# 1| B::A
|
||||
#-----| -> Object
|
||||
|
||||
# 4| A::B
|
||||
#-----| -> Object
|
||||
|
||||
modules.rb:
|
||||
# 108| MM::MM
|
||||
|
||||
# 49| Foo::Bar::ClassInAnotherDefinitionOfFooBar
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
weakHashingAlgorithms
|
||||
| HAVEL128 |
|
||||
| MD2 |
|
||||
| MD4 |
|
||||
| MD5 |
|
||||
| PANAMA |
|
||||
| RIPEMD |
|
||||
| RIPEMD128 |
|
||||
| RIPEMD160 |
|
||||
| RIPEMD256 |
|
||||
| RIPEMD320 |
|
||||
| SHA0 |
|
||||
| SHA1 |
|
||||
strongHashingAlgorithms
|
||||
| DSA |
|
||||
| ECDSA256 |
|
||||
| ECDSA384 |
|
||||
| ECDSA512 |
|
||||
| ED25519 |
|
||||
| ES256 |
|
||||
| ES384 |
|
||||
| ES512 |
|
||||
| SHA2 |
|
||||
| SHA3 |
|
||||
| SHA224 |
|
||||
| SHA256 |
|
||||
| SHA384 |
|
||||
| SHA512 |
|
||||
| SHA3224 |
|
||||
| SHA3256 |
|
||||
| SHA3384 |
|
||||
| SHA3512 |
|
||||
weakEncryptionAlgorithms
|
||||
| 3DES |
|
||||
| ARC2 |
|
||||
| ARC4 |
|
||||
| ARC5 |
|
||||
| ARCFOUR |
|
||||
| DES |
|
||||
| DES3 |
|
||||
| DESX |
|
||||
| RC2 |
|
||||
| RC4 |
|
||||
| RC5 |
|
||||
| TDEA |
|
||||
| TRIPLEDEA |
|
||||
| TRIPLEDES |
|
||||
strongEncryptionAlgorithms
|
||||
| AES |
|
||||
| AES128 |
|
||||
| AES192 |
|
||||
| AES256 |
|
||||
| AES512 |
|
||||
| AES-128 |
|
||||
| AES-192 |
|
||||
| AES-256 |
|
||||
| AES-512 |
|
||||
| ARIA |
|
||||
| BF |
|
||||
| BLOWFISH |
|
||||
| CAMELLIA |
|
||||
| CAMELLIA128 |
|
||||
| CAMELLIA192 |
|
||||
| CAMELLIA256 |
|
||||
| CAMELLIA-128 |
|
||||
| CAMELLIA-192 |
|
||||
| CAMELLIA-256 |
|
||||
| CAST |
|
||||
| CAST5 |
|
||||
| CHACHA |
|
||||
| ECIES |
|
||||
| GOST |
|
||||
| GOST89 |
|
||||
| IDEA |
|
||||
| RABBIT |
|
||||
| RSA |
|
||||
| SEED |
|
||||
| SM4 |
|
||||
weakPasswordHashingAlgorithms
|
||||
| EVPKDF |
|
||||
strongPasswordHashingAlgorithms
|
||||
| ARGON2 |
|
||||
| BCRYPT |
|
||||
| PBKDF2 |
|
||||
| SCRYPT |
|
||||
14
ruby/ql/test/library-tests/security/CryptoAlgorithms.ql
Normal file
14
ruby/ql/test/library-tests/security/CryptoAlgorithms.ql
Normal file
@@ -0,0 +1,14 @@
|
||||
import ruby
|
||||
import codeql.ruby.security.CryptoAlgorithms
|
||||
|
||||
query predicate weakHashingAlgorithms(HashingAlgorithm ha) { ha.isWeak() }
|
||||
|
||||
query predicate strongHashingAlgorithms(HashingAlgorithm ha) { not ha.isWeak() }
|
||||
|
||||
query predicate weakEncryptionAlgorithms(EncryptionAlgorithm ea) { ea.isWeak() }
|
||||
|
||||
query predicate strongEncryptionAlgorithms(EncryptionAlgorithm ea) { not ea.isWeak() }
|
||||
|
||||
query predicate weakPasswordHashingAlgorithms(PasswordHashingAlgorithm pha) { pha.isWeak() }
|
||||
|
||||
query predicate strongPasswordHashingAlgorithms(PasswordHashingAlgorithm pha) { not pha.isWeak() }
|
||||
274
ruby/ql/test/library-tests/security/OpenSSL.expected
Normal file
274
ruby/ql/test/library-tests/security/OpenSSL.expected
Normal file
@@ -0,0 +1,274 @@
|
||||
weakOpenSSLCipherAlgorithms
|
||||
| AES-128-CBC-HMAC-SHA1 |
|
||||
| AES-128-CBC-HMAC-SHA1 |
|
||||
| AES-128-ECB |
|
||||
| AES-128-ECB |
|
||||
| AES-192-ECB |
|
||||
| AES-192-ECB |
|
||||
| AES-256-CBC-HMAC-SHA1 |
|
||||
| AES-256-CBC-HMAC-SHA1 |
|
||||
| AES-256-ECB |
|
||||
| AES-256-ECB |
|
||||
| ARIA-128-ECB |
|
||||
| ARIA-192-ECB |
|
||||
| ARIA-256-ECB |
|
||||
| BF-ECB |
|
||||
| BF-ECB |
|
||||
| CAMELLIA-128-ECB |
|
||||
| CAMELLIA-128-ECB |
|
||||
| CAMELLIA-192-ECB |
|
||||
| CAMELLIA-192-ECB |
|
||||
| CAMELLIA-256-ECB |
|
||||
| CAMELLIA-256-ECB |
|
||||
| CAST5-ECB |
|
||||
| CAST5-ECB |
|
||||
| DES-CBC |
|
||||
| DES-CBC |
|
||||
| DES-CBC |
|
||||
| DES-CBC |
|
||||
| DES-CFB |
|
||||
| DES-CFB |
|
||||
| DES-CFB1 |
|
||||
| DES-CFB1 |
|
||||
| DES-CFB8 |
|
||||
| DES-CFB8 |
|
||||
| DES-ECB |
|
||||
| DES-ECB |
|
||||
| DES-EDE |
|
||||
| DES-EDE |
|
||||
| DES-EDE3 |
|
||||
| DES-EDE3 |
|
||||
| DES-EDE3-CBC |
|
||||
| DES-EDE3-CBC |
|
||||
| DES-EDE3-CBC |
|
||||
| DES-EDE3-CBC |
|
||||
| DES-EDE3-CFB |
|
||||
| DES-EDE3-CFB |
|
||||
| DES-EDE3-CFB1 |
|
||||
| DES-EDE3-CFB1 |
|
||||
| DES-EDE3-CFB8 |
|
||||
| DES-EDE3-CFB8 |
|
||||
| DES-EDE3-ECB |
|
||||
| DES-EDE3-OFB |
|
||||
| DES-EDE3-OFB |
|
||||
| DES-EDE-CBC |
|
||||
| DES-EDE-CBC |
|
||||
| DES-EDE-CFB |
|
||||
| DES-EDE-CFB |
|
||||
| DES-EDE-ECB |
|
||||
| DES-EDE-OFB |
|
||||
| DES-EDE-OFB |
|
||||
| DES-OFB |
|
||||
| DES-OFB |
|
||||
| DESX-CBC |
|
||||
| DESX-CBC |
|
||||
| DESX-CBC |
|
||||
| DESX-CBC |
|
||||
| IDEA-ECB |
|
||||
| IDEA-ECB |
|
||||
| RC2-40 |
|
||||
| RC2-40-CBC |
|
||||
| RC2-40-CBC |
|
||||
| RC2-64 |
|
||||
| RC2-64-CBC |
|
||||
| RC2-64-CBC |
|
||||
| RC2-128 |
|
||||
| RC2-CBC |
|
||||
| RC2-CBC |
|
||||
| RC2-CBC |
|
||||
| RC2-CBC |
|
||||
| RC2-CFB |
|
||||
| RC2-CFB |
|
||||
| RC2-ECB |
|
||||
| RC2-ECB |
|
||||
| RC2-OFB |
|
||||
| RC2-OFB |
|
||||
| RC4 |
|
||||
| RC4 |
|
||||
| RC4-40 |
|
||||
| RC4-40 |
|
||||
| RC4-HMAC-MD5 |
|
||||
| RC4-HMAC-MD5 |
|
||||
| SEED-ECB |
|
||||
| SM4-ECB |
|
||||
| SM4-ECB |
|
||||
| gost89-ecb |
|
||||
strongOpenSSLCipherAlgorithms
|
||||
| AES-128-CBC |
|
||||
| AES-128-CBC |
|
||||
| AES-128-CBC |
|
||||
| AES-128-CBC |
|
||||
| AES-128-CBC-HMAC-SHA256 |
|
||||
| AES-128-CFB |
|
||||
| AES-128-CFB |
|
||||
| AES-128-CFB1 |
|
||||
| AES-128-CFB1 |
|
||||
| AES-128-CFB8 |
|
||||
| AES-128-CFB8 |
|
||||
| AES-128-CTR |
|
||||
| AES-128-CTR |
|
||||
| AES-128-OCB |
|
||||
| AES-128-OFB |
|
||||
| AES-128-OFB |
|
||||
| AES-128-XTS |
|
||||
| AES-128-XTS |
|
||||
| AES-192-CBC |
|
||||
| AES-192-CBC |
|
||||
| AES-192-CBC |
|
||||
| AES-192-CBC |
|
||||
| AES-192-CFB |
|
||||
| AES-192-CFB |
|
||||
| AES-192-CFB1 |
|
||||
| AES-192-CFB1 |
|
||||
| AES-192-CFB8 |
|
||||
| AES-192-CFB8 |
|
||||
| AES-192-CTR |
|
||||
| AES-192-CTR |
|
||||
| AES-192-OCB |
|
||||
| AES-192-OFB |
|
||||
| AES-192-OFB |
|
||||
| AES-256-CBC |
|
||||
| AES-256-CBC |
|
||||
| AES-256-CBC |
|
||||
| AES-256-CBC |
|
||||
| AES-256-CBC-HMAC-SHA256 |
|
||||
| AES-256-CFB |
|
||||
| AES-256-CFB |
|
||||
| AES-256-CFB1 |
|
||||
| AES-256-CFB1 |
|
||||
| AES-256-CFB8 |
|
||||
| AES-256-CFB8 |
|
||||
| AES-256-CTR |
|
||||
| AES-256-CTR |
|
||||
| AES-256-OCB |
|
||||
| AES-256-OFB |
|
||||
| AES-256-OFB |
|
||||
| AES-256-XTS |
|
||||
| AES-256-XTS |
|
||||
| ARIA128 |
|
||||
| ARIA192 |
|
||||
| ARIA256 |
|
||||
| ARIA-128-CBC |
|
||||
| ARIA-128-CCM |
|
||||
| ARIA-128-CFB |
|
||||
| ARIA-128-CFB1 |
|
||||
| ARIA-128-CFB8 |
|
||||
| ARIA-128-CTR |
|
||||
| ARIA-128-GCM |
|
||||
| ARIA-128-OFB |
|
||||
| ARIA-192-CBC |
|
||||
| ARIA-192-CCM |
|
||||
| ARIA-192-CFB |
|
||||
| ARIA-192-CFB1 |
|
||||
| ARIA-192-CFB8 |
|
||||
| ARIA-192-CTR |
|
||||
| ARIA-192-GCM |
|
||||
| ARIA-192-OFB |
|
||||
| ARIA-256-CBC |
|
||||
| ARIA-256-CCM |
|
||||
| ARIA-256-CFB |
|
||||
| ARIA-256-CFB1 |
|
||||
| ARIA-256-CFB8 |
|
||||
| ARIA-256-CTR |
|
||||
| ARIA-256-GCM |
|
||||
| ARIA-256-OFB |
|
||||
| BF-CBC |
|
||||
| BF-CBC |
|
||||
| BF-CBC |
|
||||
| BF-CBC |
|
||||
| BF-CBC |
|
||||
| BF-CFB |
|
||||
| BF-CFB |
|
||||
| BF-OFB |
|
||||
| BF-OFB |
|
||||
| CAMELLIA-128-CBC |
|
||||
| CAMELLIA-128-CBC |
|
||||
| CAMELLIA-128-CBC |
|
||||
| CAMELLIA-128-CBC |
|
||||
| CAMELLIA-128-CFB |
|
||||
| CAMELLIA-128-CFB |
|
||||
| CAMELLIA-128-CFB1 |
|
||||
| CAMELLIA-128-CFB1 |
|
||||
| CAMELLIA-128-CFB8 |
|
||||
| CAMELLIA-128-CFB8 |
|
||||
| CAMELLIA-128-CTR |
|
||||
| CAMELLIA-128-OFB |
|
||||
| CAMELLIA-128-OFB |
|
||||
| CAMELLIA-192-CBC |
|
||||
| CAMELLIA-192-CBC |
|
||||
| CAMELLIA-192-CBC |
|
||||
| CAMELLIA-192-CBC |
|
||||
| CAMELLIA-192-CFB |
|
||||
| CAMELLIA-192-CFB |
|
||||
| CAMELLIA-192-CFB1 |
|
||||
| CAMELLIA-192-CFB1 |
|
||||
| CAMELLIA-192-CFB8 |
|
||||
| CAMELLIA-192-CFB8 |
|
||||
| CAMELLIA-192-CTR |
|
||||
| CAMELLIA-192-OFB |
|
||||
| CAMELLIA-192-OFB |
|
||||
| CAMELLIA-256-CBC |
|
||||
| CAMELLIA-256-CBC |
|
||||
| CAMELLIA-256-CBC |
|
||||
| CAMELLIA-256-CBC |
|
||||
| CAMELLIA-256-CFB |
|
||||
| CAMELLIA-256-CFB |
|
||||
| CAMELLIA-256-CFB1 |
|
||||
| CAMELLIA-256-CFB1 |
|
||||
| CAMELLIA-256-CFB8 |
|
||||
| CAMELLIA-256-CFB8 |
|
||||
| CAMELLIA-256-CTR |
|
||||
| CAMELLIA-256-OFB |
|
||||
| CAMELLIA-256-OFB |
|
||||
| CAST5-CBC |
|
||||
| CAST5-CBC |
|
||||
| CAST5-CBC |
|
||||
| CAST5-CBC |
|
||||
| CAST5-CBC |
|
||||
| CAST5-CBC |
|
||||
| CAST5-CFB |
|
||||
| CAST5-CFB |
|
||||
| CAST5-OFB |
|
||||
| CAST5-OFB |
|
||||
| CHACHA20 |
|
||||
| CHACHA20-POLY1305 |
|
||||
| ChaCha |
|
||||
| ChaCha |
|
||||
| IDEA-CBC |
|
||||
| IDEA-CBC |
|
||||
| IDEA-CBC |
|
||||
| IDEA-CBC |
|
||||
| IDEA-CFB |
|
||||
| IDEA-CFB |
|
||||
| IDEA-OFB |
|
||||
| IDEA-OFB |
|
||||
| SEED |
|
||||
| SEED-CBC |
|
||||
| SEED-CFB |
|
||||
| SEED-OFB |
|
||||
| SM4-CBC |
|
||||
| SM4-CBC |
|
||||
| SM4-CBC |
|
||||
| SM4-CBC |
|
||||
| SM4-CFB |
|
||||
| SM4-CFB |
|
||||
| SM4-CTR |
|
||||
| SM4-CTR |
|
||||
| SM4-OFB |
|
||||
| SM4-OFB |
|
||||
| gost89 |
|
||||
| gost89 |
|
||||
| gost89-cnt |
|
||||
| id-aes128-CCM |
|
||||
| id-aes128-CCM |
|
||||
| id-aes128-GCM |
|
||||
| id-aes128-GCM |
|
||||
| id-aes192-CCM |
|
||||
| id-aes192-CCM |
|
||||
| id-aes192-GCM |
|
||||
| id-aes192-GCM |
|
||||
| id-aes256-CCM |
|
||||
| id-aes256-CCM |
|
||||
| id-aes256-GCM |
|
||||
| id-aes256-GCM |
|
||||
missingOpenSSLCipherAlgorithms
|
||||
11
ruby/ql/test/library-tests/security/OpenSSL.ql
Normal file
11
ruby/ql/test/library-tests/security/OpenSSL.ql
Normal file
@@ -0,0 +1,11 @@
|
||||
import ruby
|
||||
import codeql.ruby.security.OpenSSL
|
||||
|
||||
query predicate weakOpenSSLCipherAlgorithms(OpenSSLCipher c) { c.isWeak() }
|
||||
|
||||
query predicate strongOpenSSLCipherAlgorithms(OpenSSLCipher c) { not c.isWeak() }
|
||||
|
||||
query predicate missingOpenSSLCipherAlgorithms(string name) {
|
||||
Ciphers::isOpenSSLCipher(name) and
|
||||
not exists(OpenSSLCipher c | c.getName() = name)
|
||||
}
|
||||
0
ruby/ql/test/library-tests/security/empty.rb
Normal file
0
ruby/ql/test/library-tests/security/empty.rb
Normal file
@@ -23,6 +23,11 @@ parameterVariable
|
||||
| parameters.rb:49:12:49:16 | (..., ...) | parameters.rb:49:13:49:13 | a |
|
||||
| parameters.rb:49:12:49:16 | (..., ...) | parameters.rb:49:15:49:15 | b |
|
||||
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y |
|
||||
| parameters.rb:59:19:59:27 | (..., ...) | parameters.rb:59:20:59:20 | a |
|
||||
| parameters.rb:59:19:59:27 | (..., ...) | parameters.rb:59:23:59:23 | b |
|
||||
| parameters.rb:59:19:59:27 | (..., ...) | parameters.rb:59:25:59:25 | c |
|
||||
| parameters.rb:59:22:59:26 | (..., ...) | parameters.rb:59:23:59:23 | b |
|
||||
| parameters.rb:59:22:59:26 | (..., ...) | parameters.rb:59:25:59:25 | c |
|
||||
| scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x |
|
||||
| scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x |
|
||||
| ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b |
|
||||
|
||||
@@ -56,3 +56,7 @@ x = 10
|
||||
puts y
|
||||
end
|
||||
|
||||
def tuples_nested((a,(b,c)))
|
||||
puts "#{a} #{b} #{c}"
|
||||
end
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ 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:9:5:3 | <captured> | parameters.rb:1:1:58: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 |
|
||||
@@ -63,11 +63,15 @@ 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:58:1 | self |
|
||||
| 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: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 |
|
||||
| parameters.rb:59:1:61:3 | self (tuples_nested) | parameters.rb:59:1:61:3 | self |
|
||||
| parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a |
|
||||
| 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:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a |
|
||||
@@ -180,8 +184,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:58:1 | self | parameters.rb:3:4:3:9 | self |
|
||||
| parameters.rb:1:9:5:3 | <captured> | parameters.rb:1:1:58:1 | self | parameters.rb:4:4:4:9 | self |
|
||||
| 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: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 |
|
||||
@@ -215,10 +219,14 @@ 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:58:1 | self | parameters.rb:55:4:55:9 | self |
|
||||
| parameters.rb:54:9:57:3 | <captured> | parameters.rb:1:1:58:1 | self | parameters.rb:56:4:56:9 | self |
|
||||
| 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: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 |
|
||||
| parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a | parameters.rb:60:11:60:11 | a |
|
||||
| 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 |
|
||||
@@ -339,7 +347,7 @@ firstRead
|
||||
| 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:58: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: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 |
|
||||
@@ -371,9 +379,13 @@ 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:58: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: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 |
|
||||
| parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a | parameters.rb:60:11:60:11 | a |
|
||||
| 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:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
|
||||
@@ -464,7 +476,7 @@ lastRead
|
||||
| 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:58:1 | self | parameters.rb:4:4:4: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: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 |
|
||||
@@ -496,9 +508,13 @@ 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:58:1 | self | parameters.rb:56:4:56: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: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 |
|
||||
| parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a | parameters.rb:60:11:60:11 | a |
|
||||
| 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:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
|
||||
@@ -568,11 +584,11 @@ 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:58:1 | self | parameters.rb:3:4:3:9 | self | parameters.rb:4:4:4:9 | 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: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:58:1 | self | parameters.rb:55:4:55:9 | self | parameters.rb:56:4:56:9 | self |
|
||||
| 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 |
|
||||
|
||||
@@ -73,9 +73,9 @@ variableAccess
|
||||
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:1:9:5:3 | do ... end |
|
||||
| parameters.rb:1:18:1:18 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | do ... end |
|
||||
| parameters.rb:2:4:2:4 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | do ... end |
|
||||
| parameters.rb:3:4:3:9 | self | parameters.rb:1:1:58:1 | self | parameters.rb:1:1:58:1 | parameters.rb |
|
||||
| parameters.rb:3:4:3:9 | self | parameters.rb:1:1:62:1 | self | parameters.rb:1:1:62:1 | parameters.rb |
|
||||
| parameters.rb:3:9:3:9 | x | parameters.rb:1:14:1:14 | x | parameters.rb:1:9:5:3 | do ... end |
|
||||
| parameters.rb:4:4:4:9 | self | parameters.rb:1:1:58:1 | self | parameters.rb:1:1:58:1 | parameters.rb |
|
||||
| parameters.rb:4:4:4:9 | self | parameters.rb:1:1:62:1 | self | parameters.rb:1:1:62:1 | parameters.rb |
|
||||
| parameters.rb:4:9:4:9 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | do ... end |
|
||||
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | order_pizza |
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | order_pizza |
|
||||
@@ -108,7 +108,7 @@ variableAccess
|
||||
| parameters.rb:31:11:31:15 | first | parameters.rb:30:15:30:19 | first | parameters.rb:30:1:32:3 | key_param |
|
||||
| parameters.rb:31:20:31:25 | middle | parameters.rb:30:24:30:29 | middle | parameters.rb:30:1:32:3 | key_param |
|
||||
| parameters.rb:31:30:31:33 | last | parameters.rb:30:36:30:39 | last | parameters.rb:30:1:32:3 | key_param |
|
||||
| parameters.rb:34:1:34:1 | b | parameters.rb:34:1:34:1 | b | parameters.rb:1:1:58:1 | parameters.rb |
|
||||
| parameters.rb:34:1:34:1 | b | parameters.rb:34:1:34:1 | b | parameters.rb:1:1:62:1 | parameters.rb |
|
||||
| parameters.rb:35:11:35:11 | a | parameters.rb:35:11:35:11 | a | parameters.rb:35:1:38:3 | multi |
|
||||
| parameters.rb:35:16:35:16 | b | parameters.rb:35:16:35:16 | b | parameters.rb:35:1:38:3 | multi |
|
||||
| parameters.rb:37:3:37:18 | self | parameters.rb:35:1:38:3 | self | parameters.rb:35:1:38:3 | multi |
|
||||
@@ -127,13 +127,20 @@ variableAccess
|
||||
| parameters.rb:50:3:50:18 | self | parameters.rb:49:1:51:3 | self | parameters.rb:49:1:51:3 | tuples |
|
||||
| parameters.rb:50:11:50:11 | a | parameters.rb:49:13:49:13 | a | parameters.rb:49:1:51:3 | tuples |
|
||||
| parameters.rb:50:16:50:16 | b | parameters.rb:49:15:49:15 | b | parameters.rb:49:1:51:3 | tuples |
|
||||
| parameters.rb:53:1:53:1 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | parameters.rb |
|
||||
| parameters.rb:53:1:53:1 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:62:1 | parameters.rb |
|
||||
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:54:9:57:3 | do ... end |
|
||||
| parameters.rb:54:19:54:19 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | parameters.rb |
|
||||
| parameters.rb:55:4:55:9 | self | parameters.rb:1:1:58:1 | self | parameters.rb:1:1:58:1 | parameters.rb |
|
||||
| parameters.rb:55:9:55:9 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | parameters.rb |
|
||||
| parameters.rb:56:4:56:9 | self | parameters.rb:1:1:58:1 | self | parameters.rb:1:1:58:1 | parameters.rb |
|
||||
| parameters.rb:54:19:54:19 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:62:1 | parameters.rb |
|
||||
| parameters.rb:55:4:55:9 | self | parameters.rb:1:1:62:1 | self | parameters.rb:1:1:62:1 | parameters.rb |
|
||||
| parameters.rb:55:9:55:9 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:62:1 | parameters.rb |
|
||||
| parameters.rb:56:4:56:9 | self | parameters.rb:1:1:62:1 | self | parameters.rb:1:1:62:1 | parameters.rb |
|
||||
| parameters.rb:56:9:56:9 | y | parameters.rb:54:14:54:14 | y | parameters.rb:54:9:57:3 | do ... end |
|
||||
| parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a | parameters.rb:59:1:61:3 | tuples_nested |
|
||||
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:59:1:61:3 | tuples_nested |
|
||||
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:59:1:61:3 | tuples_nested |
|
||||
| parameters.rb:60:3:60:23 | self | parameters.rb:59:1:61:3 | self | parameters.rb:59:1:61:3 | tuples_nested |
|
||||
| parameters.rb:60:11:60:11 | a | parameters.rb:59:20:59:20 | a | parameters.rb:59:1:61:3 | tuples_nested |
|
||||
| parameters.rb:60:16:60:16 | b | parameters.rb:59:23:59:23 | b | parameters.rb:59:1:61:3 | tuples_nested |
|
||||
| parameters.rb:60:21:60:21 | c | parameters.rb:59:25:59:25 | c | parameters.rb:59:1:61:3 | tuples_nested |
|
||||
| scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x | scopes.rb:2:9:6:3 | do ... end |
|
||||
| scopes.rb:3:4:3:9 | self | scopes.rb:1:1:49:4 | self | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:3:9:3:9 | self | scopes.rb:1:1:49:4 | self | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
@@ -354,6 +361,9 @@ implicitWrite
|
||||
| parameters.rb:49:13:49:13 | a |
|
||||
| parameters.rb:49:15:49:15 | b |
|
||||
| parameters.rb:54:14:54:14 | y |
|
||||
| parameters.rb:59:20:59:20 | a |
|
||||
| parameters.rb:59:23:59:23 | b |
|
||||
| parameters.rb:59:25:59:25 | c |
|
||||
| scopes.rb:2:14:2:14 | x |
|
||||
| scopes.rb:9:14:9:14 | x |
|
||||
| ssa.rb:1:7:1:7 | b |
|
||||
@@ -452,6 +462,10 @@ readAccess
|
||||
| parameters.rb:55:9:55:9 | x |
|
||||
| parameters.rb:56:4:56:9 | self |
|
||||
| parameters.rb:56:9:56:9 | y |
|
||||
| parameters.rb:60:3:60:23 | self |
|
||||
| parameters.rb:60:11:60:11 | a |
|
||||
| parameters.rb:60:16:60:16 | b |
|
||||
| parameters.rb:60:21:60:21 | c |
|
||||
| scopes.rb:3:4:3:9 | self |
|
||||
| scopes.rb:3:9:3:9 | self |
|
||||
| scopes.rb:5:4:5:9 | self |
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
| nested_scopes.rb:30:7:33:9 | self |
|
||||
| nested_scopes.rb:31:11:31:11 | a |
|
||||
| nested_scopes.rb:40:1:40:1 | d |
|
||||
| parameters.rb:1:1:58:1 | self |
|
||||
| parameters.rb:1:1:62:1 | self |
|
||||
| parameters.rb:1:14:1:14 | x |
|
||||
| parameters.rb:1:18:1:18 | y |
|
||||
| parameters.rb:7:1:13:3 | self |
|
||||
@@ -89,6 +89,10 @@
|
||||
| parameters.rb:49:15:49:15 | b |
|
||||
| parameters.rb:53:1:53:1 | x |
|
||||
| parameters.rb:54:14:54:14 | y |
|
||||
| parameters.rb:59:1:61:3 | self |
|
||||
| parameters.rb:59:20:59:20 | a |
|
||||
| parameters.rb:59:23:59:23 | b |
|
||||
| parameters.rb:59:25:59:25 | c |
|
||||
| scopes.rb:1:1:1:15 | self |
|
||||
| scopes.rb:1:1:49:4 | self |
|
||||
| scopes.rb:2:14:2:14 | x |
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
| nested_scopes.rb:22:9:24:11 | show_a2 |
|
||||
| nested_scopes.rb:27:7:29:9 | show |
|
||||
| nested_scopes.rb:30:7:33:9 | class << ... |
|
||||
| parameters.rb:1:1:58:1 | parameters.rb |
|
||||
| parameters.rb:1:1:62:1 | parameters.rb |
|
||||
| parameters.rb:1:9:5:3 | do ... end |
|
||||
| parameters.rb:7:1:13:3 | order_pizza |
|
||||
| parameters.rb:15:1:19:3 | print_map |
|
||||
@@ -45,6 +45,7 @@
|
||||
| parameters.rb:45:1:47:3 | dup_underscore |
|
||||
| parameters.rb:49:1:51:3 | tuples |
|
||||
| parameters.rb:54:9:57:3 | do ... end |
|
||||
| parameters.rb:59:1:61:3 | tuples_nested |
|
||||
| scopes.rb:1:1:1:15 | a |
|
||||
| scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:2:9:6:3 | do ... end |
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
edges
|
||||
| HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : | HardcodedCredentials.rb:1:23:1:30 | password |
|
||||
| HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." : | HardcodedCredentials.rb:1:33:1:36 | cert |
|
||||
| HardcodedCredentials.rb:18:19:18:72 | ... + ... : | HardcodedCredentials.rb:1:23:1:30 | password |
|
||||
| HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." : | HardcodedCredentials.rb:18:19:18:72 | ... + ... : |
|
||||
| HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." : | HardcodedCredentials.rb:23:19:23:20 | pw : |
|
||||
@@ -10,10 +11,12 @@ edges
|
||||
| HardcodedCredentials.rb:43:57:43:70 | "abcdef123456" : | HardcodedCredentials.rb:43:46:43:53 | password |
|
||||
nodes
|
||||
| HardcodedCredentials.rb:1:23:1:30 | password | semmle.label | password |
|
||||
| HardcodedCredentials.rb:1:33:1:36 | cert | semmle.label | cert |
|
||||
| HardcodedCredentials.rb:4:20:4:65 | "xwjVWdfzfRlbcgKkbSfG/xSrUeHYq..." | semmle.label | "xwjVWdfzfRlbcgKkbSfG/xSrUeHYq..." |
|
||||
| HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | semmle.label | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." |
|
||||
| HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : | semmle.label | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : |
|
||||
| HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | semmle.label | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." |
|
||||
| HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." : | semmle.label | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." : |
|
||||
| HardcodedCredentials.rb:18:19:18:72 | ... + ... : | semmle.label | ... + ... : |
|
||||
| HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." : | semmle.label | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." : |
|
||||
| HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." : | semmle.label | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." : |
|
||||
@@ -31,6 +34,7 @@ subpaths
|
||||
| HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | Use of $@. | HardcodedCredentials.rb:8:30:8:75 | "X6BLgRWSAtAWG/GaHS+WGGW2K7zZF..." | hardcoded credentials |
|
||||
| HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:12:19:12:64 | "4NQX/CqB5Ae98zFUmwj1DMpF7azsh..." | hardcoded credentials |
|
||||
| HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | Use of $@. | HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | hardcoded credentials |
|
||||
| HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." : | HardcodedCredentials.rb:1:33:1:36 | cert | Use of $@. | HardcodedCredentials.rb:15:30:15:75 | "WLC17dLQ9P8YlQvqm77qplOMm5pd1..." | hardcoded credentials |
|
||||
| HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." | HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:18:27:18:72 | "ogH6qSYWGdbR/2WOGYa7eZ/tObL+G..." | hardcoded credentials |
|
||||
| HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." | HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:20:11:20:76 | "3jOe7sXKX6Tx52qHWUVqh2t9LNsE+..." | hardcoded credentials |
|
||||
| HardcodedCredentials.rb:21:12:21:37 | "4fQuzXef4f2yow8KWvIJTA==" | HardcodedCredentials.rb:21:12:21:37 | "4fQuzXef4f2yow8KWvIJTA==" : | HardcodedCredentials.rb:1:23:1:30 | password | Use of $@. | HardcodedCredentials.rb:21:12:21:37 | "4fQuzXef4f2yow8KWvIJTA==" | hardcoded credentials |
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
edges
|
||||
| ConditionalBypass.rb:3:13:3:18 | call to params : | ConditionalBypass.rb:6:8:6:12 | check |
|
||||
| ConditionalBypass.rb:14:14:14:19 | call to params : | ConditionalBypass.rb:14:14:14:27 | ...[...] |
|
||||
| ConditionalBypass.rb:25:10:25:15 | call to params : | ConditionalBypass.rb:25:10:25:22 | ...[...] |
|
||||
| ConditionalBypass.rb:25:10:25:15 | call to params : | ConditionalBypass.rb:25:10:25:22 | ...[...] : |
|
||||
| ConditionalBypass.rb:25:10:25:15 | call to params : | ConditionalBypass.rb:27:8:27:8 | p |
|
||||
| ConditionalBypass.rb:25:10:25:22 | ...[...] : | ConditionalBypass.rb:27:8:27:8 | p |
|
||||
nodes
|
||||
| ConditionalBypass.rb:3:13:3:18 | call to params : | semmle.label | call to params : |
|
||||
| ConditionalBypass.rb:6:8:6:12 | check | semmle.label | check |
|
||||
| ConditionalBypass.rb:14:14:14:19 | call to params : | semmle.label | call to params : |
|
||||
| ConditionalBypass.rb:14:14:14:27 | ...[...] | semmle.label | ...[...] |
|
||||
| ConditionalBypass.rb:25:10:25:15 | call to params : | semmle.label | call to params : |
|
||||
| ConditionalBypass.rb:25:10:25:22 | ...[...] | semmle.label | ...[...] |
|
||||
| ConditionalBypass.rb:25:10:25:22 | ...[...] : | semmle.label | ...[...] : |
|
||||
| ConditionalBypass.rb:27:8:27:8 | p | semmle.label | p |
|
||||
subpaths
|
||||
#select
|
||||
| ConditionalBypass.rb:6:8:6:12 | check | ConditionalBypass.rb:3:13:3:18 | call to params : | ConditionalBypass.rb:6:8:6:12 | check | This condition guards a sensitive $@, but $@ controls it. | ConditionalBypass.rb:8:7:8:29 | call to authenticate_user! | action | ConditionalBypass.rb:3:13:3:18 | call to params | a user-provided value |
|
||||
| ConditionalBypass.rb:14:14:14:27 | ...[...] | ConditionalBypass.rb:14:14:14:19 | call to params : | ConditionalBypass.rb:14:14:14:27 | ...[...] | This condition guards a sensitive $@, but $@ controls it. | ConditionalBypass.rb:14:5:14:9 | call to login | action | ConditionalBypass.rb:14:14:14:19 | call to params | a user-provided value |
|
||||
| ConditionalBypass.rb:27:8:27:8 | p | ConditionalBypass.rb:25:10:25:15 | call to params : | ConditionalBypass.rb:27:8:27:8 | p | This condition guards a sensitive $@, but $@ controls it. | ConditionalBypass.rb:28:7:28:13 | call to verify! | action | ConditionalBypass.rb:25:10:25:15 | call to params | a user-provided value |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/cwe-807/ConditionalBypass.ql
|
||||
@@ -0,0 +1,39 @@
|
||||
class FooController < ActionController::Base
|
||||
def bad_handler1
|
||||
check = params[:check]
|
||||
name = params[:name]
|
||||
|
||||
if check
|
||||
# BAD
|
||||
authenticate_user! name
|
||||
end
|
||||
end
|
||||
|
||||
def bad_handler2
|
||||
# BAD
|
||||
login if params[:login]
|
||||
do_something_else
|
||||
end
|
||||
|
||||
def bad_handler3
|
||||
# BAD. Not detected: its the last statement in the method, so it doesn't
|
||||
# match the heuristic for an action.
|
||||
login if params[:login]
|
||||
end
|
||||
|
||||
def bad_handler4
|
||||
p = (params[:name] == "foo")
|
||||
# BAD
|
||||
if p
|
||||
verify!
|
||||
end
|
||||
end
|
||||
|
||||
def good_handler
|
||||
name = params[:name]
|
||||
# Call to a sensitive action, but the guard is not derived from user input.
|
||||
if should_auth_user?
|
||||
authenticate_user! name
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user