mirror of
https://github.com/github/codeql.git
synced 2026-02-20 00:43:44 +01:00
Merge remote-tracking branch 'origin/main' into parent_child
This commit is contained in:
@@ -9,6 +9,7 @@ import ast.Module
|
||||
import ast.Parameter
|
||||
import ast.Operation
|
||||
import ast.Pattern
|
||||
import ast.Scope
|
||||
import ast.Statement
|
||||
import ast.Variable
|
||||
private import ast.internal.AST
|
||||
@@ -17,11 +18,7 @@ private import ast.internal.AST
|
||||
* A node in the abstract syntax tree. This class is the base class for all Ruby
|
||||
* program elements.
|
||||
*/
|
||||
class AstNode extends @ast_node {
|
||||
AstNode::Range range;
|
||||
|
||||
AstNode() { range = this }
|
||||
|
||||
class AstNode extends TAstNode {
|
||||
/**
|
||||
* Gets the name of a primary CodeQL class to which this node belongs.
|
||||
*
|
||||
@@ -32,14 +29,22 @@ class AstNode extends @ast_node {
|
||||
string getAPrimaryQlClass() { result = "???" }
|
||||
|
||||
/** Gets a textual representation of this node. */
|
||||
final string toString() { result = range.toString() }
|
||||
cached
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the location of this node. */
|
||||
final Location getLocation() { result = range.getLocation() }
|
||||
Location getLocation() { result = toGenerated(this).getLocation() }
|
||||
|
||||
/** Gets a child node of this `AstNode`. */
|
||||
final AstNode getAChild() { range.child(_, result) }
|
||||
final AstNode getAChild() { result = this.getAChild(_) }
|
||||
|
||||
/** Gets the parent of this `AstNode`, if this node is not a root node. */
|
||||
final AstNode getParent() { result.getAChild() = this }
|
||||
|
||||
/**
|
||||
* Gets a child of this node, which can also be retrieved using a predicate
|
||||
* named `pred`.
|
||||
*/
|
||||
cached
|
||||
AstNode getAChild(string pred) { none() }
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
private import codeql_ruby.AST
|
||||
private import internal.Call
|
||||
private import internal.AST
|
||||
private import internal.TreeSitter
|
||||
|
||||
/**
|
||||
* A call.
|
||||
*/
|
||||
class Call extends Expr {
|
||||
override Call::Range range;
|
||||
|
||||
class Call extends Expr, TCall {
|
||||
override string getAPrimaryQlClass() { result = "Call" }
|
||||
|
||||
/**
|
||||
@@ -21,7 +20,7 @@ class Call extends Expr {
|
||||
* yield 0, bar: 1
|
||||
* ```
|
||||
*/
|
||||
final Expr getArgument(int n) { result = range.getArgument(n) }
|
||||
Expr getArgument(int n) { none() }
|
||||
|
||||
/**
|
||||
* Gets an argument of this method call.
|
||||
@@ -48,14 +47,27 @@ class Call extends Expr {
|
||||
* Gets the number of arguments of this method call.
|
||||
*/
|
||||
final int getNumberOfArguments() { result = count(this.getAnArgument()) }
|
||||
|
||||
override AstNode getAChild(string pred) { pred = "getArgument" and result = this.getArgument(_) }
|
||||
}
|
||||
|
||||
bindingset[s]
|
||||
private string getMethodName(MethodCall mc, string s) {
|
||||
(
|
||||
not mc instanceof LhsExpr
|
||||
or
|
||||
mc.getParent() instanceof AssignOperation
|
||||
) and
|
||||
result = s
|
||||
or
|
||||
mc instanceof LhsExpr and
|
||||
result = s + "="
|
||||
}
|
||||
|
||||
/**
|
||||
* A method call.
|
||||
*/
|
||||
class MethodCall extends Call {
|
||||
override MethodCall::Range range;
|
||||
|
||||
class MethodCall extends Call, TMethodCall {
|
||||
override string getAPrimaryQlClass() { result = "MethodCall" }
|
||||
|
||||
/**
|
||||
@@ -71,7 +83,7 @@ class MethodCall extends Call {
|
||||
* the call to `qux` is the `Expr` for `Baz`; for the call to `corge` there
|
||||
* is no result.
|
||||
*/
|
||||
final Expr getReceiver() { result = range.getReceiver() }
|
||||
Expr getReceiver() { none() }
|
||||
|
||||
/**
|
||||
* Gets the name of the method being called. For example, in:
|
||||
@@ -82,7 +94,7 @@ class MethodCall extends Call {
|
||||
*
|
||||
* the result is `"bar"`.
|
||||
*/
|
||||
final string getMethodName() { result = range.getMethodName() }
|
||||
string getMethodName() { none() }
|
||||
|
||||
/**
|
||||
* Gets the block of this method call, if any.
|
||||
@@ -90,7 +102,67 @@ class MethodCall extends Call {
|
||||
* foo.each { |x| puts x }
|
||||
* ```
|
||||
*/
|
||||
final Block getBlock() { result = range.getBlock() }
|
||||
Block getBlock() { none() }
|
||||
|
||||
override string toString() { result = "call to " + concat(this.getMethodName(), "/") }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = Call.super.getAChild(pred)
|
||||
or
|
||||
pred = "getReceiver" and result = this.getReceiver()
|
||||
or
|
||||
pred = "getBlock" and result = this.getBlock()
|
||||
}
|
||||
}
|
||||
|
||||
private class IdentifierMethodCall extends MethodCall, TIdentifierMethodCall {
|
||||
private Generated::Identifier g;
|
||||
|
||||
IdentifierMethodCall() { this = TIdentifierMethodCall(g) }
|
||||
|
||||
final override string getMethodName() { result = getMethodName(this, g.getValue()) }
|
||||
}
|
||||
|
||||
private class ScopeResolutionMethodCall extends MethodCall, TScopeResolutionMethodCall {
|
||||
private Generated::ScopeResolution g;
|
||||
private Generated::Identifier i;
|
||||
|
||||
ScopeResolutionMethodCall() { this = TScopeResolutionMethodCall(g, i) }
|
||||
|
||||
final override Expr getReceiver() { toGenerated(result) = g.getScope() }
|
||||
|
||||
final override string getMethodName() { result = getMethodName(this, i.getValue()) }
|
||||
}
|
||||
|
||||
private class RegularMethodCall extends MethodCall, TRegularMethodCall {
|
||||
private Generated::Call g;
|
||||
|
||||
RegularMethodCall() { this = TRegularMethodCall(g) }
|
||||
|
||||
final override Expr getReceiver() {
|
||||
toGenerated(result) = g.getReceiver()
|
||||
or
|
||||
not exists(g.getReceiver()) and
|
||||
toGenerated(result) = g.getMethod().(Generated::ScopeResolution).getScope()
|
||||
}
|
||||
|
||||
final override string getMethodName() {
|
||||
exists(string res | result = getMethodName(this, res) |
|
||||
res = "call" and g.getMethod() instanceof Generated::ArgumentList
|
||||
or
|
||||
res = g.getMethod().(Generated::Token).getValue()
|
||||
or
|
||||
res = g.getMethod().(Generated::ScopeResolution).getName().(Generated::Token).getValue()
|
||||
)
|
||||
}
|
||||
|
||||
final override Expr getArgument(int n) {
|
||||
toGenerated(result) = g.getArguments().getChild(n)
|
||||
or
|
||||
toGenerated(result) = g.getMethod().(Generated::ArgumentList).getChild(n)
|
||||
}
|
||||
|
||||
final override Block getBlock() { toGenerated(result) = g.getBlock() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,8 +173,6 @@ class MethodCall extends Call {
|
||||
* ```
|
||||
*/
|
||||
class SetterMethodCall extends MethodCall, LhsExpr {
|
||||
final override SetterMethodCall::Range range;
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "SetterMethodCall" }
|
||||
}
|
||||
|
||||
@@ -112,10 +182,20 @@ class SetterMethodCall extends MethodCall, LhsExpr {
|
||||
* a[0]
|
||||
* ```
|
||||
*/
|
||||
class ElementReference extends MethodCall, @element_reference {
|
||||
final override ElementReference::Range range;
|
||||
class ElementReference extends MethodCall, TElementReference {
|
||||
private Generated::ElementReference g;
|
||||
|
||||
ElementReference() { this = TElementReference(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "ElementReference" }
|
||||
|
||||
final override Expr getReceiver() { toGenerated(result) = g.getObject() }
|
||||
|
||||
final override string getMethodName() { result = getMethodName(this, "[]") }
|
||||
|
||||
final override Expr getArgument(int n) { toGenerated(result) = g.getChild(n) }
|
||||
|
||||
final override string toString() { result = "...[...]" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,10 +204,16 @@ class ElementReference extends MethodCall, @element_reference {
|
||||
* yield x, y
|
||||
* ```
|
||||
*/
|
||||
class YieldCall extends Call, @yield {
|
||||
final override YieldCall::Range range;
|
||||
class YieldCall extends Call, TYieldCall {
|
||||
private Generated::Yield g;
|
||||
|
||||
YieldCall() { this = TYieldCall(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "YieldCall" }
|
||||
|
||||
final override Expr getArgument(int n) { toGenerated(result) = g.getChild().getChild(n) }
|
||||
|
||||
final override string toString() { result = "yield ..." }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,20 +226,42 @@ class YieldCall extends Call, @yield {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class SuperCall extends MethodCall {
|
||||
final override SuperCall::Range range;
|
||||
|
||||
class SuperCall extends MethodCall, TSuperCall {
|
||||
final override string getAPrimaryQlClass() { result = "SuperCall" }
|
||||
}
|
||||
|
||||
private class TokenSuperCall extends SuperCall, TTokenSuperCall {
|
||||
private Generated::Super g;
|
||||
|
||||
TokenSuperCall() { this = TTokenSuperCall(g) }
|
||||
|
||||
final override string getMethodName() { result = getMethodName(this, g.getValue()) }
|
||||
}
|
||||
|
||||
private class RegularSuperCall extends SuperCall, TRegularSuperCall {
|
||||
private Generated::Call g;
|
||||
|
||||
RegularSuperCall() { this = TRegularSuperCall(g) }
|
||||
|
||||
final override string getMethodName() {
|
||||
result = getMethodName(this, g.getMethod().(Generated::Super).getValue())
|
||||
}
|
||||
|
||||
final override Expr getArgument(int n) { toGenerated(result) = g.getArguments().getChild(n) }
|
||||
|
||||
final override Block getBlock() { toGenerated(result) = g.getBlock() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A block argument in a method call.
|
||||
* ```rb
|
||||
* foo(&block)
|
||||
* ```
|
||||
*/
|
||||
class BlockArgument extends Expr, @block_argument {
|
||||
final override BlockArgument::Range range;
|
||||
class BlockArgument extends Expr, TBlockArgument {
|
||||
private Generated::BlockArgument g;
|
||||
|
||||
BlockArgument() { this = TBlockArgument(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "BlockArgument" }
|
||||
|
||||
@@ -164,7 +272,11 @@ class BlockArgument extends Expr, @block_argument {
|
||||
* foo(&bar)
|
||||
* ```
|
||||
*/
|
||||
final Expr getValue() { result = range.getValue() }
|
||||
final Expr getValue() { toGenerated(result) = g.getChild() }
|
||||
|
||||
final override string toString() { result = "&..." }
|
||||
|
||||
final override AstNode getAChild(string pred) { pred = "getValue" and result = this.getValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,8 +285,10 @@ class BlockArgument extends Expr, @block_argument {
|
||||
* foo(*args)
|
||||
* ```
|
||||
*/
|
||||
class SplatArgument extends Expr, @splat_argument {
|
||||
final override SplatArgument::Range range;
|
||||
class SplatArgument extends Expr, TSplatArgument {
|
||||
private Generated::SplatArgument g;
|
||||
|
||||
SplatArgument() { this = TSplatArgument(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "SplatArgument" }
|
||||
|
||||
@@ -185,7 +299,11 @@ class SplatArgument extends Expr, @splat_argument {
|
||||
* foo(*bar)
|
||||
* ```
|
||||
*/
|
||||
final Expr getValue() { result = range.getValue() }
|
||||
final Expr getValue() { toGenerated(result) = g.getChild() }
|
||||
|
||||
final override string toString() { result = "*..." }
|
||||
|
||||
final override AstNode getAChild(string pred) { pred = "getValue" and result = this.getValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,8 +312,10 @@ class SplatArgument extends Expr, @splat_argument {
|
||||
* foo(**options)
|
||||
* ```
|
||||
*/
|
||||
class HashSplatArgument extends Expr, @hash_splat_argument {
|
||||
final override HashSplatArgument::Range range;
|
||||
class HashSplatArgument extends Expr, THashSplatArgument {
|
||||
private Generated::HashSplatArgument g;
|
||||
|
||||
HashSplatArgument() { this = THashSplatArgument(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "HashSplatArgument" }
|
||||
|
||||
@@ -206,5 +326,9 @@ class HashSplatArgument extends Expr, @hash_splat_argument {
|
||||
* foo(**bar)
|
||||
* ```
|
||||
*/
|
||||
final Expr getValue() { result = range.getValue() }
|
||||
final Expr getValue() { toGenerated(result) = g.getChild() }
|
||||
|
||||
final override string toString() { result = "**..." }
|
||||
|
||||
final override AstNode getAChild(string pred) { pred = "getValue" and result = this.getValue() }
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
private import codeql_ruby.AST
|
||||
private import internal.Constant
|
||||
private import internal.AST
|
||||
private import internal.Variable
|
||||
private import internal.TreeSitter
|
||||
|
||||
/** An access to a constant. */
|
||||
class ConstantAccess extends Expr {
|
||||
override ConstantAccess::Range range;
|
||||
|
||||
class ConstantAccess extends Expr, TConstantAccess {
|
||||
/** Gets the name of the constant being accessed. */
|
||||
string getName() { result = range.getName() }
|
||||
string getName() { none() }
|
||||
|
||||
/**
|
||||
* Gets the expression used in the access's scope resolution operation, if
|
||||
@@ -24,7 +24,7 @@ class ConstantAccess extends Expr {
|
||||
* MESSAGE
|
||||
* ```
|
||||
*/
|
||||
Expr getScopeExpr() { result = range.getScopeExpr() }
|
||||
Expr getScopeExpr() { none() }
|
||||
|
||||
/**
|
||||
* Holds if the access uses the scope resolution operator to refer to the
|
||||
@@ -34,7 +34,32 @@ class ConstantAccess extends Expr {
|
||||
* ::MESSAGE
|
||||
* ```
|
||||
*/
|
||||
predicate hasGlobalScope() { range.hasGlobalScope() }
|
||||
predicate hasGlobalScope() { none() }
|
||||
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
override AstNode getAChild(string pred) { pred = "getScopeExpr" and result = this.getScopeExpr() }
|
||||
}
|
||||
|
||||
private class TokenConstantAccess extends ConstantAccess, TTokenConstantAccess {
|
||||
private Generated::Constant g;
|
||||
|
||||
TokenConstantAccess() { this = TTokenConstantAccess(g) }
|
||||
|
||||
final override string getName() { result = g.getValue() }
|
||||
}
|
||||
|
||||
private class ScopeResolutionConstantAccess extends ConstantAccess, TScopeResolutionConstantAccess {
|
||||
private Generated::ScopeResolution g;
|
||||
private Generated::Constant constant;
|
||||
|
||||
ScopeResolutionConstantAccess() { this = TScopeResolutionConstantAccess(g, constant) }
|
||||
|
||||
final override string getName() { result = constant.getValue() }
|
||||
|
||||
final override Expr getScopeExpr() { toGenerated(result) = g.getScope() }
|
||||
|
||||
final override predicate hasGlobalScope() { not exists(g.getScope()) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +79,12 @@ class ConstantAccess extends Expr {
|
||||
* ```
|
||||
*/
|
||||
class ConstantReadAccess extends ConstantAccess {
|
||||
final override ConstantReadAccess::Range range;
|
||||
ConstantReadAccess() {
|
||||
not this instanceof ConstantWriteAccess
|
||||
or
|
||||
// `X` in `X ||= 10` is considered both a read and a write
|
||||
this = any(AssignOperation a).getLeftOperand()
|
||||
}
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "ConstantReadAccess" }
|
||||
}
|
||||
@@ -76,7 +106,9 @@ class ConstantReadAccess extends ConstantAccess {
|
||||
* ```
|
||||
*/
|
||||
class ConstantWriteAccess extends ConstantAccess {
|
||||
override ConstantWriteAccess::Range range;
|
||||
ConstantWriteAccess() {
|
||||
explicitAssignmentNode(toGenerated(this), _) or this instanceof TNamespace
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConstantWriteAccess" }
|
||||
}
|
||||
@@ -89,8 +121,6 @@ class ConstantWriteAccess extends ConstantAccess {
|
||||
* MAX_SIZE = 100
|
||||
* ```
|
||||
*/
|
||||
class ConstantAssignment extends ConstantWriteAccess {
|
||||
override ConstantAssignment::Range range;
|
||||
|
||||
class ConstantAssignment extends ConstantWriteAccess, LhsExpr {
|
||||
override string getAPrimaryQlClass() { result = "ConstantAssignment" }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
private import codeql_ruby.AST
|
||||
private import internal.Control
|
||||
private import internal.AST
|
||||
private import internal.TreeSitter
|
||||
|
||||
/**
|
||||
* A control expression that can be any of the following:
|
||||
@@ -9,17 +10,13 @@ private import internal.Control
|
||||
* - `while`/`until` (including expression-modifier variants)
|
||||
* - `for`
|
||||
*/
|
||||
class ControlExpr extends Expr {
|
||||
override ControlExpr::Range range;
|
||||
}
|
||||
class ControlExpr extends Expr, TControlExpr { }
|
||||
|
||||
/**
|
||||
* A conditional expression: `if`/`unless` (including expression-modifier
|
||||
* variants), and ternary-if (`?:`) expressions.
|
||||
*/
|
||||
class ConditionalExpr extends ControlExpr {
|
||||
override ConditionalExpr::Range range;
|
||||
|
||||
class ConditionalExpr extends ControlExpr, TConditionalExpr {
|
||||
/**
|
||||
* Gets the condition expression. For example, the result is `foo` in the
|
||||
* following:
|
||||
@@ -29,13 +26,19 @@ class ConditionalExpr extends ControlExpr {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final Expr getCondition() { result = range.getCondition() }
|
||||
Expr getCondition() { none() }
|
||||
|
||||
/**
|
||||
* Gets the branch of this conditional expression that is taken when the
|
||||
* condition evaluates to `cond`, if any.
|
||||
*/
|
||||
Stmt getBranch(boolean cond) { result = range.getBranch(cond) }
|
||||
Stmt getBranch(boolean cond) { none() }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
pred = "getCondition" and result = this.getCondition()
|
||||
or
|
||||
pred = "getBranch" and result = this.getBranch(_)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,16 +51,14 @@ class ConditionalExpr extends ControlExpr {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class IfExpr extends ConditionalExpr {
|
||||
override IfExpr::Range range;
|
||||
|
||||
class IfExpr extends ConditionalExpr, TIfExpr {
|
||||
final override string getAPrimaryQlClass() { result = "IfExpr" }
|
||||
|
||||
/** Holds if this is an `elsif` expression. */
|
||||
final predicate isElsif() { this instanceof @elsif }
|
||||
predicate isElsif() { none() }
|
||||
|
||||
/** Gets the 'then' branch of this `if`/`elsif` expression. */
|
||||
final Stmt getThen() { result = range.getThen() }
|
||||
Stmt getThen() { none() }
|
||||
|
||||
/**
|
||||
* Gets the `elsif`/`else` branch of this `if`/`elsif` expression, if any. In
|
||||
@@ -90,7 +91,51 @@ class IfExpr extends ConditionalExpr {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final Stmt getElse() { result = range.getElse() }
|
||||
Stmt getElse() { none() }
|
||||
|
||||
final override Stmt getBranch(boolean cond) {
|
||||
cond = true and result = this.getThen()
|
||||
or
|
||||
cond = false and result = this.getElse()
|
||||
}
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = ConditionalExpr.super.getAChild(pred)
|
||||
or
|
||||
pred = "getThen" and result = this.getThen()
|
||||
or
|
||||
pred = "getElse" and result = this.getElse()
|
||||
}
|
||||
}
|
||||
|
||||
private class If extends IfExpr, TIf {
|
||||
private Generated::If g;
|
||||
|
||||
If() { this = TIf(g) }
|
||||
|
||||
final override Expr getCondition() { toGenerated(result) = g.getCondition() }
|
||||
|
||||
final override Stmt getThen() { toGenerated(result) = g.getConsequence() }
|
||||
|
||||
final override Stmt getElse() { toGenerated(result) = g.getAlternative() }
|
||||
|
||||
final override string toString() { result = "if ..." }
|
||||
}
|
||||
|
||||
private class Elsif extends IfExpr, TElsif {
|
||||
private Generated::Elsif g;
|
||||
|
||||
Elsif() { this = TElsif(g) }
|
||||
|
||||
final override predicate isElsif() { any() }
|
||||
|
||||
final override Expr getCondition() { toGenerated(result) = g.getCondition() }
|
||||
|
||||
final override Stmt getThen() { toGenerated(result) = g.getConsequence() }
|
||||
|
||||
final override Stmt getElse() { toGenerated(result) = g.getAlternative() }
|
||||
|
||||
final override string toString() { result = "elsif ..." }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,11 +146,15 @@ class IfExpr extends ConditionalExpr {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class UnlessExpr extends ConditionalExpr, @unless {
|
||||
final override UnlessExpr::Range range;
|
||||
class UnlessExpr extends ConditionalExpr, TUnlessExpr {
|
||||
private Generated::Unless g;
|
||||
|
||||
UnlessExpr() { this = TUnlessExpr(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "UnlessExpr" }
|
||||
|
||||
final override Expr getCondition() { toGenerated(result) = g.getCondition() }
|
||||
|
||||
/**
|
||||
* Gets the 'then' branch of this `unless` expression. In the following
|
||||
* example, the result is the `StmtSequence` containing `foo`.
|
||||
@@ -117,7 +166,7 @@ class UnlessExpr extends ConditionalExpr, @unless {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final Stmt getThen() { result = range.getThen() }
|
||||
final Stmt getThen() { toGenerated(result) = g.getConsequence() }
|
||||
|
||||
/**
|
||||
* Gets the 'else' branch of this `unless` expression. In the following
|
||||
@@ -130,7 +179,23 @@ class UnlessExpr extends ConditionalExpr, @unless {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final Stmt getElse() { result = range.getElse() }
|
||||
final Stmt getElse() { toGenerated(result) = g.getAlternative() }
|
||||
|
||||
final override Expr getBranch(boolean cond) {
|
||||
cond = false and result = getThen()
|
||||
or
|
||||
cond = true and result = getElse()
|
||||
}
|
||||
|
||||
final override string toString() { result = "unless ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = ConditionalExpr.super.getAChild(pred)
|
||||
or
|
||||
pred = "getThen" and result = this.getThen()
|
||||
or
|
||||
pred = "getElse" and result = this.getElse()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,11 +204,17 @@ class UnlessExpr extends ConditionalExpr, @unless {
|
||||
* foo if bar
|
||||
* ```
|
||||
*/
|
||||
class IfModifierExpr extends ConditionalExpr, @if_modifier {
|
||||
final override IfModifierExpr::Range range;
|
||||
class IfModifierExpr extends ConditionalExpr, TIfModifierExpr {
|
||||
private Generated::IfModifier g;
|
||||
|
||||
IfModifierExpr() { this = TIfModifierExpr(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "IfModifierExpr" }
|
||||
|
||||
final override Expr getCondition() { toGenerated(result) = g.getCondition() }
|
||||
|
||||
final override Stmt getBranch(boolean cond) { cond = true and result = this.getBody() }
|
||||
|
||||
/**
|
||||
* Gets the statement that is conditionally evaluated. In the following
|
||||
* example, the result is the `Expr` for `foo`.
|
||||
@@ -151,7 +222,15 @@ class IfModifierExpr extends ConditionalExpr, @if_modifier {
|
||||
* foo if bar
|
||||
* ```
|
||||
*/
|
||||
final Stmt getBody() { result = range.getBody() }
|
||||
final Stmt getBody() { toGenerated(result) = g.getBody() }
|
||||
|
||||
final override string toString() { result = "... if ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = ConditionalExpr.super.getAChild(pred)
|
||||
or
|
||||
pred = "getBody" and result = this.getBody()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,11 +239,17 @@ class IfModifierExpr extends ConditionalExpr, @if_modifier {
|
||||
* y /= x unless x == 0
|
||||
* ```
|
||||
*/
|
||||
class UnlessModifierExpr extends ConditionalExpr, @unless_modifier {
|
||||
final override UnlessModifierExpr::Range range;
|
||||
class UnlessModifierExpr extends ConditionalExpr, TUnlessModifierExpr {
|
||||
private Generated::UnlessModifier g;
|
||||
|
||||
UnlessModifierExpr() { this = TUnlessModifierExpr(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "UnlessModifierExpr" }
|
||||
|
||||
final override Expr getCondition() { toGenerated(result) = g.getCondition() }
|
||||
|
||||
final override Stmt getBranch(boolean cond) { cond = false and result = this.getBody() }
|
||||
|
||||
/**
|
||||
* Gets the statement that is conditionally evaluated. In the following
|
||||
* example, the result is the `Expr` for `foo`.
|
||||
@@ -172,7 +257,15 @@ class UnlessModifierExpr extends ConditionalExpr, @unless_modifier {
|
||||
* foo unless bar
|
||||
* ```
|
||||
*/
|
||||
final Stmt getBody() { result = range.getBody() }
|
||||
final Stmt getBody() { toGenerated(result) = g.getBody() }
|
||||
|
||||
final override string toString() { result = "... unless ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = ConditionalExpr.super.getAChild(pred)
|
||||
or
|
||||
pred = "getBody" and result = this.getBody()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,20 +274,42 @@ class UnlessModifierExpr extends ConditionalExpr, @unless_modifier {
|
||||
* (a > b) ? a : b
|
||||
* ```
|
||||
*/
|
||||
class TernaryIfExpr extends ConditionalExpr, @conditional {
|
||||
final override TernaryIfExpr::Range range;
|
||||
class TernaryIfExpr extends ConditionalExpr, TTernaryIfExpr {
|
||||
private Generated::Conditional g;
|
||||
|
||||
TernaryIfExpr() { this = TTernaryIfExpr(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "TernaryIfExpr" }
|
||||
|
||||
final override Expr getCondition() { toGenerated(result) = g.getCondition() }
|
||||
|
||||
/** Gets the 'then' branch of this ternary if expression. */
|
||||
final Stmt getThen() { result = range.getThen() }
|
||||
final Stmt getThen() { toGenerated(result) = g.getConsequence() }
|
||||
|
||||
/** Gets the 'else' branch of this ternary if expression. */
|
||||
final Stmt getElse() { result = range.getElse() }
|
||||
final Stmt getElse() { toGenerated(result) = g.getAlternative() }
|
||||
|
||||
final override Stmt getBranch(boolean cond) {
|
||||
cond = true and result = getThen()
|
||||
or
|
||||
cond = false and result = getElse()
|
||||
}
|
||||
|
||||
final override string toString() { result = "... ? ... : ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = ConditionalExpr.super.getAChild(pred)
|
||||
or
|
||||
pred = "getThen" and result = this.getThen()
|
||||
or
|
||||
pred = "getElse" and result = this.getElse()
|
||||
}
|
||||
}
|
||||
|
||||
class CaseExpr extends ControlExpr, @case__ {
|
||||
final override CaseExpr::Range range;
|
||||
class CaseExpr extends ControlExpr, TCaseExpr {
|
||||
private Generated::Case g;
|
||||
|
||||
CaseExpr() { this = TCaseExpr(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "CaseExpr" }
|
||||
|
||||
@@ -217,13 +332,13 @@ class CaseExpr extends ControlExpr, @case__ {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final Expr getValue() { result = range.getValue() }
|
||||
final Expr getValue() { toGenerated(result) = g.getValue() }
|
||||
|
||||
/**
|
||||
* Gets the `n`th branch of this case expression, either a `WhenExpr` or a
|
||||
* `StmtSequence`.
|
||||
*/
|
||||
final Expr getBranch(int n) { result = range.getBranch(n) }
|
||||
final Expr getBranch(int n) { toGenerated(result) = g.getChild(n) }
|
||||
|
||||
/**
|
||||
* Gets a branch of this case expression, either a `WhenExpr` or an
|
||||
@@ -241,6 +356,14 @@ class CaseExpr extends ControlExpr, @case__ {
|
||||
* Gets the number of branches of this case expression.
|
||||
*/
|
||||
final int getNumberOfBranches() { result = count(this.getBranch(_)) }
|
||||
|
||||
final override string toString() { result = "case ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
pred = "getValue" and result = this.getValue()
|
||||
or
|
||||
pred = "getBranch" and result = this.getBranch(_)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -251,13 +374,15 @@ class CaseExpr extends ControlExpr, @case__ {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class WhenExpr extends Expr, @when {
|
||||
final override WhenExpr::Range range;
|
||||
class WhenExpr extends Expr, TWhenExpr {
|
||||
private Generated::When g;
|
||||
|
||||
WhenExpr() { this = TWhenExpr(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "WhenExpr" }
|
||||
|
||||
/** Gets the body of this case-when expression. */
|
||||
final Stmt getBody() { result = range.getBody() }
|
||||
final Stmt getBody() { toGenerated(result) = g.getBody() }
|
||||
|
||||
/**
|
||||
* Gets the `n`th pattern (or condition) in this case-when expression. In the
|
||||
@@ -270,7 +395,7 @@ class WhenExpr extends Expr, @when {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final Expr getPattern(int n) { result = range.getPattern(n) }
|
||||
final Expr getPattern(int n) { toGenerated(result) = g.getPattern(n).getChild() }
|
||||
|
||||
/**
|
||||
* Gets a pattern (or condition) in this case-when expression.
|
||||
@@ -281,28 +406,43 @@ class WhenExpr extends Expr, @when {
|
||||
* Gets the number of patterns in this case-when expression.
|
||||
*/
|
||||
final int getNumberOfPatterns() { result = count(this.getPattern(_)) }
|
||||
|
||||
final override string toString() { result = "when ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
pred = "getBody" and result = this.getBody()
|
||||
or
|
||||
pred = "getPattern" and result = this.getPattern(_)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A loop. That is, a `for` loop, a `while` or `until` loop, or their
|
||||
* expression-modifier variants.
|
||||
*/
|
||||
class Loop extends ControlExpr {
|
||||
override Loop::Range range;
|
||||
|
||||
class Loop extends ControlExpr, TLoop {
|
||||
/** Gets the body of this loop. */
|
||||
Stmt getBody() { result = range.getBody() }
|
||||
Stmt getBody() { none() }
|
||||
|
||||
override AstNode getAChild(string pred) { pred = "getBody" and result = this.getBody() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A loop using a condition expression. That is, a `while` or `until` loop, or
|
||||
* their expression-modifier variants.
|
||||
*/
|
||||
class ConditionalLoop extends Loop {
|
||||
override ConditionalLoop::Range range;
|
||||
|
||||
class ConditionalLoop extends Loop, TConditionalLoop {
|
||||
/** Gets the condition expression of this loop. */
|
||||
final Expr getCondition() { result = range.getCondition() }
|
||||
Expr getCondition() { none() }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = Loop.super.getAChild(pred)
|
||||
or
|
||||
pred = "getCondition" and result = this.getCondition()
|
||||
}
|
||||
|
||||
/** Holds if the loop body is entered when the condition is `condValue`. */
|
||||
predicate entersLoopWhenConditionIs(boolean condValue) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,13 +454,25 @@ class ConditionalLoop extends Loop {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class WhileExpr extends ConditionalLoop, @while {
|
||||
final override WhileExpr::Range range;
|
||||
class WhileExpr extends ConditionalLoop, TWhileExpr {
|
||||
private Generated::While g;
|
||||
|
||||
WhileExpr() { this = TWhileExpr(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "WhileExpr" }
|
||||
|
||||
/** Gets the body of this `while` loop. */
|
||||
final override Stmt getBody() { result = range.getBody() }
|
||||
final override Stmt getBody() { toGenerated(result) = g.getBody() }
|
||||
|
||||
final override Expr getCondition() { toGenerated(result) = g.getCondition() }
|
||||
|
||||
/**
|
||||
* Holds if the loop body is entered when the condition is `condValue`. For
|
||||
* `while` loops, this holds when `condValue` is true.
|
||||
*/
|
||||
final override predicate entersLoopWhenConditionIs(boolean condValue) { condValue = true }
|
||||
|
||||
final override string toString() { result = "while ..." }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,13 +484,25 @@ class WhileExpr extends ConditionalLoop, @while {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class UntilExpr extends ConditionalLoop, @until {
|
||||
final override UntilExpr::Range range;
|
||||
class UntilExpr extends ConditionalLoop, TUntilExpr {
|
||||
private Generated::Until g;
|
||||
|
||||
UntilExpr() { this = TUntilExpr(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "UntilExpr" }
|
||||
|
||||
/** Gets the body of this `until` loop. */
|
||||
final override Stmt getBody() { result = range.getBody() }
|
||||
final override Stmt getBody() { toGenerated(result) = g.getBody() }
|
||||
|
||||
final override Expr getCondition() { toGenerated(result) = g.getCondition() }
|
||||
|
||||
/**
|
||||
* Holds if the loop body is entered when the condition is `condValue`. For
|
||||
* `until` loops, this holds when `condValue` is false.
|
||||
*/
|
||||
final override predicate entersLoopWhenConditionIs(boolean condValue) { condValue = false }
|
||||
|
||||
final override string toString() { result = "until ..." }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -347,10 +511,24 @@ class UntilExpr extends ConditionalLoop, @until {
|
||||
* foo while bar
|
||||
* ```
|
||||
*/
|
||||
class WhileModifierExpr extends ConditionalLoop, @while_modifier {
|
||||
final override WhileModifierExpr::Range range;
|
||||
class WhileModifierExpr extends ConditionalLoop, TWhileModifierExpr {
|
||||
private Generated::WhileModifier g;
|
||||
|
||||
WhileModifierExpr() { this = TWhileModifierExpr(g) }
|
||||
|
||||
final override Stmt getBody() { toGenerated(result) = g.getBody() }
|
||||
|
||||
final override Expr getCondition() { toGenerated(result) = g.getCondition() }
|
||||
|
||||
/**
|
||||
* Holds if the loop body is entered when the condition is `condValue`. For
|
||||
* `while`-modifier loops, this holds when `condValue` is true.
|
||||
*/
|
||||
final override predicate entersLoopWhenConditionIs(boolean condValue) { condValue = true }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "WhileModifierExpr" }
|
||||
|
||||
final override string toString() { result = "... while ..." }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,10 +537,24 @@ class WhileModifierExpr extends ConditionalLoop, @while_modifier {
|
||||
* foo until bar
|
||||
* ```
|
||||
*/
|
||||
class UntilModifierExpr extends ConditionalLoop, @until_modifier {
|
||||
final override UntilModifierExpr::Range range;
|
||||
class UntilModifierExpr extends ConditionalLoop, TUntilModifierExpr {
|
||||
private Generated::UntilModifier g;
|
||||
|
||||
UntilModifierExpr() { this = TUntilModifierExpr(g) }
|
||||
|
||||
final override Stmt getBody() { toGenerated(result) = g.getBody() }
|
||||
|
||||
final override Expr getCondition() { toGenerated(result) = g.getCondition() }
|
||||
|
||||
/**
|
||||
* Holds if the loop body is entered when the condition is `condValue`. For
|
||||
* `until`-modifier loops, this holds when `condValue` is false.
|
||||
*/
|
||||
final override predicate entersLoopWhenConditionIs(boolean condValue) { condValue = false }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "UntilModifierExpr" }
|
||||
|
||||
final override string toString() { result = "... until ..." }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,16 +565,18 @@ class UntilModifierExpr extends ConditionalLoop, @until_modifier {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class ForExpr extends Loop, @for {
|
||||
final override ForExpr::Range range;
|
||||
class ForExpr extends Loop, TForExpr {
|
||||
private Generated::For g;
|
||||
|
||||
ForExpr() { this = TForExpr(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "ForExpr" }
|
||||
|
||||
/** Gets the body of this `for` loop. */
|
||||
final override Stmt getBody() { result = range.getBody() }
|
||||
final override Stmt getBody() { toGenerated(result) = g.getBody() }
|
||||
|
||||
/** Gets the pattern representing the iteration argument. */
|
||||
final Pattern getPattern() { result = range.getPattern() }
|
||||
final Pattern getPattern() { toGenerated(result) = g.getPattern() }
|
||||
|
||||
/**
|
||||
* Gets the value being iterated over. In the following example, the result
|
||||
@@ -393,5 +587,15 @@ class ForExpr extends Loop, @for {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final Expr getValue() { result = range.getValue() }
|
||||
final Expr getValue() { toGenerated(result) = g.getValue().getChild() }
|
||||
|
||||
final override string toString() { result = "for ... in ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = Loop.super.getAChild(pred)
|
||||
or
|
||||
pred = "getPattern" and result = this.getPattern()
|
||||
or
|
||||
pred = "getValue" and result = this.getValue()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
private import codeql_ruby.AST
|
||||
private import internal.Expr
|
||||
private import internal.AST
|
||||
private import internal.TreeSitter
|
||||
|
||||
/**
|
||||
* An expression.
|
||||
*
|
||||
* This is the root QL class for all expressions.
|
||||
*/
|
||||
class Expr extends Stmt {
|
||||
override Expr::Range range;
|
||||
|
||||
Expr() { this = range }
|
||||
}
|
||||
class Expr extends Stmt, TExpr { }
|
||||
|
||||
/**
|
||||
* A reference to the current object. For example:
|
||||
@@ -18,10 +15,10 @@ class Expr extends Stmt {
|
||||
* - `self.method_name`
|
||||
* - `def self.method_name ... end`
|
||||
*/
|
||||
class Self extends Expr, @token_self {
|
||||
override Self::Range range;
|
||||
|
||||
class Self extends Expr, TSelf {
|
||||
final override string getAPrimaryQlClass() { result = "Self" }
|
||||
|
||||
final override string toString() { result = "self" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,32 +32,91 @@ class Self extends Expr, @token_self {
|
||||
* return 1, 2, *items, k: 5, **map
|
||||
* ```
|
||||
*/
|
||||
class ArgumentList extends Expr {
|
||||
override ArgumentList::Range range;
|
||||
class ArgumentList extends Expr, TArgumentList {
|
||||
private Generated::AstNode g;
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ArgumentList" }
|
||||
ArgumentList() { this = TArgumentList(g) }
|
||||
|
||||
/** Gets the `i`th element in this argument list. */
|
||||
Expr getElement(int i) {
|
||||
toGenerated(result) in [
|
||||
g.(Generated::ArgumentList).getChild(i), g.(Generated::RightAssignmentList).getChild(i)
|
||||
]
|
||||
}
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "ArgumentList" }
|
||||
|
||||
final override string toString() { result = "..., ..." }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
pred = "getElement" and result = this.getElement(_)
|
||||
}
|
||||
}
|
||||
|
||||
/** A sequence of expressions. */
|
||||
class StmtSequence extends Expr {
|
||||
override StmtSequence::Range range;
|
||||
|
||||
class StmtSequence extends Expr, TStmtSequence {
|
||||
override string getAPrimaryQlClass() { result = "StmtSequence" }
|
||||
|
||||
override string toString() {
|
||||
exists(int c | c = this.getNumberOfStatements() |
|
||||
c = 0 and result = ";"
|
||||
or
|
||||
c = 1 and result = this.getStmt(0).toString()
|
||||
or
|
||||
c > 1 and result = "...; ..."
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `n`th statement in this sequence. */
|
||||
final Stmt getStmt(int n) { result = range.getStmt(n) }
|
||||
Stmt getStmt(int n) { none() }
|
||||
|
||||
/** Gets a statement in this sequence. */
|
||||
final Stmt getAStmt() { result = this.getStmt(_) }
|
||||
|
||||
/** Gets the last expression in this sequence, if any. */
|
||||
final Expr getLastExpr() { result = this.getStmt(this.getNumberOfStatements() - 1) }
|
||||
/** Gets the last statement in this sequence, if any. */
|
||||
final Stmt getLastStmt() { result = this.getStmt(this.getNumberOfStatements() - 1) }
|
||||
|
||||
/** Gets the number of statements in this sequence. */
|
||||
final int getNumberOfStatements() { result = count(this.getAStmt()) }
|
||||
|
||||
/** Holds if this sequence has no statements. */
|
||||
final predicate isEmpty() { this.getNumberOfStatements() = 0 }
|
||||
|
||||
override AstNode getAChild(string pred) { pred = "getStmt" and result = this.getStmt(_) }
|
||||
}
|
||||
|
||||
private class Then extends StmtSequence, TThen {
|
||||
private Generated::Then g;
|
||||
|
||||
Then() { this = TThen(g) }
|
||||
|
||||
override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
|
||||
}
|
||||
|
||||
private class Else extends StmtSequence, TElse {
|
||||
private Generated::Else g;
|
||||
|
||||
Else() { this = TElse(g) }
|
||||
|
||||
override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
|
||||
}
|
||||
|
||||
private class Do extends StmtSequence, TDo {
|
||||
private Generated::Do g;
|
||||
|
||||
Do() { this = TDo(g) }
|
||||
|
||||
override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
|
||||
}
|
||||
|
||||
private class Ensure extends StmtSequence, TEnsure {
|
||||
private Generated::Ensure g;
|
||||
|
||||
Ensure() { this = TEnsure(g) }
|
||||
|
||||
override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
|
||||
|
||||
final override string toString() { result = "ensure ..." }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,22 +124,70 @@ class StmtSequence extends Expr {
|
||||
* or do-block. That is, any body that may also include rescue/ensure/else
|
||||
* statements.
|
||||
*/
|
||||
class BodyStatement extends StmtSequence {
|
||||
override BodyStatement::Range range;
|
||||
class BodyStmt extends StmtSequence, TBodyStmt {
|
||||
// Not defined by dispatch, as it should not be exposed
|
||||
private Generated::AstNode getChild(int i) {
|
||||
result = any(Generated::Method g | this = TMethod(g)).getChild(i)
|
||||
or
|
||||
result = any(Generated::SingletonMethod g | this = TSingletonMethod(g)).getChild(i)
|
||||
or
|
||||
exists(Generated::Lambda g | this = TLambda(g) |
|
||||
result = g.getBody().(Generated::DoBlock).getChild(i) or
|
||||
result = g.getBody().(Generated::Block).getChild(i)
|
||||
)
|
||||
or
|
||||
result = any(Generated::DoBlock g | this = TDoBlock(g)).getChild(i)
|
||||
or
|
||||
result = any(Generated::Program g | this = TToplevel(g)).getChild(i) and
|
||||
not result instanceof Generated::BeginBlock
|
||||
or
|
||||
result = any(Generated::Class g | this = TClass(g)).getChild(i)
|
||||
or
|
||||
result = any(Generated::SingletonClass g | this = TSingletonClass(g)).getChild(i)
|
||||
or
|
||||
result = any(Generated::Module g | this = TModule(g)).getChild(i)
|
||||
or
|
||||
result = any(Generated::Begin g | this = TBeginExpr(g)).getChild(i)
|
||||
}
|
||||
|
||||
final override Stmt getStmt(int n) {
|
||||
result =
|
||||
rank[n + 1](AstNode node, int i |
|
||||
toGenerated(node) = this.getChild(i) and
|
||||
not node instanceof Else and
|
||||
not node instanceof RescueClause and
|
||||
not node instanceof Ensure
|
||||
|
|
||||
node order by i
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `n`th rescue clause in this block. */
|
||||
final RescueClause getRescue(int n) { result = range.getRescue(n) }
|
||||
final RescueClause getRescue(int n) {
|
||||
result =
|
||||
rank[n + 1](RescueClause node, int i | toGenerated(node) = getChild(i) | node order by i)
|
||||
}
|
||||
|
||||
/** Gets a rescue clause in this block. */
|
||||
final RescueClause getARescue() { result = this.getRescue(_) }
|
||||
|
||||
/** Gets the `else` clause in this block, if any. */
|
||||
final StmtSequence getElse() { result = range.getElse() }
|
||||
final StmtSequence getElse() { result = unique(Else s | toGenerated(s) = getChild(_)) }
|
||||
|
||||
/** Gets the `ensure` clause in this block, if any. */
|
||||
final StmtSequence getEnsure() { result = range.getEnsure() }
|
||||
final StmtSequence getEnsure() { result = unique(Ensure s | toGenerated(s) = getChild(_)) }
|
||||
|
||||
final predicate hasEnsure() { exists(this.getEnsure()) }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = StmtSequence.super.getAChild(pred)
|
||||
or
|
||||
pred = "getRescue" and result = this.getRescue(_)
|
||||
or
|
||||
pred = "getElse" and result = this.getElse()
|
||||
or
|
||||
pred = "getEnsure" and result = this.getEnsure()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,10 +205,22 @@ class BodyStatement extends StmtSequence {
|
||||
* ()
|
||||
* ```
|
||||
*/
|
||||
class ParenthesizedExpr extends StmtSequence, @parenthesized_statements {
|
||||
final override ParenthesizedExpr::Range range;
|
||||
class ParenthesizedExpr extends StmtSequence, TParenthesizedExpr {
|
||||
private Generated::ParenthesizedStatements g;
|
||||
|
||||
ParenthesizedExpr() { this = TParenthesizedExpr(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "ParenthesizedExpr" }
|
||||
|
||||
final override string toString() {
|
||||
exists(int c | c = this.getNumberOfStatements() |
|
||||
c = 0 and result = "()"
|
||||
or
|
||||
c > 0 and result = "(" + StmtSequence.super.toString() + ")"
|
||||
)
|
||||
}
|
||||
|
||||
final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,8 +233,10 @@ class ParenthesizedExpr extends StmtSequence, @parenthesized_statements {
|
||||
* baz(qux: 1)
|
||||
* ```
|
||||
*/
|
||||
class Pair extends Expr, @pair {
|
||||
final override Pair::Range range;
|
||||
class Pair extends Expr, TPair {
|
||||
private Generated::Pair g;
|
||||
|
||||
Pair() { this = TPair(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "Pair" }
|
||||
|
||||
@@ -133,7 +251,7 @@ class Pair extends Expr, @pair {
|
||||
* { 'foo' => 123 }
|
||||
* ```
|
||||
*/
|
||||
final Expr getKey() { result = range.getKey() }
|
||||
final Expr getKey() { toGenerated(result) = g.getKey() }
|
||||
|
||||
/**
|
||||
* Gets the value expression of this pair. For example, the `InteralLiteral`
|
||||
@@ -142,7 +260,15 @@ class Pair extends Expr, @pair {
|
||||
* { 'foo' => 123 }
|
||||
* ```
|
||||
*/
|
||||
final Expr getValue() { result = range.getValue() }
|
||||
final Expr getValue() { toGenerated(result) = g.getValue() }
|
||||
|
||||
final override string toString() { result = "Pair" }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
pred = "getKey" and result = this.getKey()
|
||||
or
|
||||
pred = "getValue" and result = this.getValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,8 +280,10 @@ class Pair extends Expr, @pair {
|
||||
* puts msg
|
||||
* end
|
||||
*/
|
||||
class RescueClause extends Expr, @rescue {
|
||||
final override RescueClause::Range range;
|
||||
class RescueClause extends Expr, TRescueClause {
|
||||
private Generated::Rescue g;
|
||||
|
||||
RescueClause() { this = TRescueClause(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "RescueClause" }
|
||||
|
||||
@@ -169,7 +297,7 @@ class RescueClause extends Expr, @rescue {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final Expr getException(int n) { result = range.getException(n) }
|
||||
final Expr getException(int n) { toGenerated(result) = g.getExceptions().getChild(n) }
|
||||
|
||||
/**
|
||||
* Gets an exception to match, if any. For example `FirstError` or `SecondError` in:
|
||||
@@ -181,7 +309,7 @@ class RescueClause extends Expr, @rescue {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final Expr getAnException() { result = getException(_) }
|
||||
final Expr getAnException() { result = this.getException(_) }
|
||||
|
||||
/**
|
||||
* Gets the variable to which to assign the matched exception, if any.
|
||||
@@ -194,12 +322,22 @@ class RescueClause extends Expr, @rescue {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final LhsExpr getVariableExpr() { result = range.getVariableExpr() }
|
||||
final LhsExpr getVariableExpr() { toGenerated(result) = g.getVariable().getChild() }
|
||||
|
||||
/**
|
||||
* Gets the exception handler body.
|
||||
*/
|
||||
final StmtSequence getBody() { result = range.getBody() }
|
||||
final StmtSequence getBody() { toGenerated(result) = g.getBody() }
|
||||
|
||||
final override string toString() { result = "rescue ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
pred = "getException" and result = this.getException(_)
|
||||
or
|
||||
pred = "getVariableExpr" and result = this.getVariableExpr()
|
||||
or
|
||||
pred = "getBody" and result = this.getBody()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,8 +346,10 @@ class RescueClause extends Expr, @rescue {
|
||||
* contents = read_file rescue ""
|
||||
* ```
|
||||
*/
|
||||
class RescueModifierExpr extends Expr, @rescue_modifier {
|
||||
final override RescueModifierExpr::Range range;
|
||||
class RescueModifierExpr extends Expr, TRescueModifierExpr {
|
||||
private Generated::RescueModifier g;
|
||||
|
||||
RescueModifierExpr() { this = TRescueModifierExpr(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "RescueModifierExpr" }
|
||||
|
||||
@@ -219,7 +359,7 @@ class RescueModifierExpr extends Expr, @rescue_modifier {
|
||||
* body rescue handler
|
||||
* ```
|
||||
*/
|
||||
final Stmt getBody() { result = range.getBody() }
|
||||
final Stmt getBody() { toGenerated(result) = g.getBody() }
|
||||
|
||||
/**
|
||||
* Gets the exception handler of this `RescueModifierExpr`.
|
||||
@@ -227,7 +367,15 @@ class RescueModifierExpr extends Expr, @rescue_modifier {
|
||||
* body rescue handler
|
||||
* ```
|
||||
*/
|
||||
final Stmt getHandler() { result = range.getHandler() }
|
||||
final Stmt getHandler() { toGenerated(result) = g.getHandler() }
|
||||
|
||||
final override string toString() { result = "... rescue ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
pred = "getBody" and result = this.getBody()
|
||||
or
|
||||
pred = "getHandler" and result = this.getHandler()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,13 +385,15 @@ class RescueModifierExpr extends Expr, @rescue_modifier {
|
||||
* "foo" "bar" "baz"
|
||||
* ```
|
||||
*/
|
||||
class StringConcatenation extends Expr, @chained_string {
|
||||
final override StringConcatenation::Range range;
|
||||
class StringConcatenation extends Expr, TStringConcatenation {
|
||||
private Generated::ChainedString g;
|
||||
|
||||
StringConcatenation() { this = TStringConcatenation(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "StringConcatenation" }
|
||||
|
||||
/** Gets the `n`th string literal in this concatenation. */
|
||||
final StringLiteral getString(int n) { result = range.getString(n) }
|
||||
final StringLiteral getString(int n) { toGenerated(result) = g.getChild(n) }
|
||||
|
||||
/** Gets a string literal in this concatenation. */
|
||||
final StringLiteral getAString() { result = this.getString(_) }
|
||||
@@ -277,4 +427,8 @@ class StringConcatenation extends Expr, @chained_string {
|
||||
valueText order by i
|
||||
)
|
||||
}
|
||||
|
||||
final override string toString() { result = "\"...\" \"...\"" }
|
||||
|
||||
override AstNode getAChild(string pred) { pred = "getString" and result = this.getString(_) }
|
||||
}
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
private import codeql_ruby.AST
|
||||
private import internal.Literal
|
||||
private import internal.AST
|
||||
private import internal.TreeSitter
|
||||
|
||||
/**
|
||||
* A literal.
|
||||
*
|
||||
* This is the QL root class for all literals.
|
||||
*/
|
||||
class Literal extends Expr {
|
||||
override Literal::Range range;
|
||||
|
||||
class Literal extends Expr, TLiteral {
|
||||
/**
|
||||
* Gets the source text for this literal, if this is a simple literal.
|
||||
*
|
||||
* For complex literals, such as arrays, hashes, and strings with
|
||||
* interpolations, this predicate has no result.
|
||||
*/
|
||||
final string getValueText() { result = range.getValueText() }
|
||||
string getValueText() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,9 +30,7 @@ class Literal extends Expr {
|
||||
* 1i
|
||||
* ```
|
||||
*/
|
||||
class NumericLiteral extends Literal {
|
||||
override NumericLiteral::Range range;
|
||||
}
|
||||
class NumericLiteral extends Literal, TNumericLiteral { }
|
||||
|
||||
/**
|
||||
* An integer literal.
|
||||
@@ -43,8 +40,14 @@ class NumericLiteral extends Literal {
|
||||
* 0xff
|
||||
* ```
|
||||
*/
|
||||
class IntegerLiteral extends NumericLiteral, @token_integer {
|
||||
final override IntegerLiteral::Range range;
|
||||
class IntegerLiteral extends NumericLiteral, TIntegerLiteral {
|
||||
private Generated::Integer g;
|
||||
|
||||
IntegerLiteral() { this = TIntegerLiteral(g) }
|
||||
|
||||
final override string getValueText() { result = g.getValue() }
|
||||
|
||||
final override string toString() { result = this.getValueText() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "IntegerLiteral" }
|
||||
}
|
||||
@@ -57,8 +60,14 @@ class IntegerLiteral extends NumericLiteral, @token_integer {
|
||||
* 2.7e+5
|
||||
* ```
|
||||
*/
|
||||
class FloatLiteral extends NumericLiteral, @token_float {
|
||||
final override FloatLiteral::Range range;
|
||||
class FloatLiteral extends NumericLiteral, TFloatLiteral {
|
||||
private Generated::Float g;
|
||||
|
||||
FloatLiteral() { this = TFloatLiteral(g) }
|
||||
|
||||
final override string getValueText() { result = g.getValue() }
|
||||
|
||||
final override string toString() { result = this.getValueText() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "FloatLiteral" }
|
||||
}
|
||||
@@ -70,8 +79,14 @@ class FloatLiteral extends NumericLiteral, @token_float {
|
||||
* 123r
|
||||
* ```
|
||||
*/
|
||||
class RationalLiteral extends NumericLiteral, @rational {
|
||||
final override RationalLiteral::Range range;
|
||||
class RationalLiteral extends NumericLiteral, TRationalLiteral {
|
||||
private Generated::Rational g;
|
||||
|
||||
RationalLiteral() { this = TRationalLiteral(g) }
|
||||
|
||||
final override string getValueText() { result = g.getChild().(Generated::Token).getValue() + "r" }
|
||||
|
||||
final override string toString() { result = this.getValueText() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "RationalLiteral" }
|
||||
}
|
||||
@@ -83,15 +98,27 @@ class RationalLiteral extends NumericLiteral, @rational {
|
||||
* 1i
|
||||
* ```
|
||||
*/
|
||||
class ComplexLiteral extends NumericLiteral, @token_complex {
|
||||
final override ComplexLiteral::Range range;
|
||||
class ComplexLiteral extends NumericLiteral, TComplexLiteral {
|
||||
private Generated::Complex g;
|
||||
|
||||
ComplexLiteral() { this = TComplexLiteral(g) }
|
||||
|
||||
final override string getValueText() { result = g.getValue() }
|
||||
|
||||
final override string toString() { result = this.getValueText() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "ComplexLiteral" }
|
||||
}
|
||||
|
||||
/** A `nil` literal. */
|
||||
class NilLiteral extends Literal, @token_nil {
|
||||
final override NilLiteral::Range range;
|
||||
class NilLiteral extends Literal, TNilLiteral {
|
||||
private Generated::Nil g;
|
||||
|
||||
NilLiteral() { this = TNilLiteral(g) }
|
||||
|
||||
final override string getValueText() { result = g.getValue() }
|
||||
|
||||
final override string toString() { result = this.getValueText() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "NilLiteral" }
|
||||
}
|
||||
@@ -105,30 +132,48 @@ class NilLiteral extends Literal, @token_nil {
|
||||
* FALSE
|
||||
* ```
|
||||
*/
|
||||
class BooleanLiteral extends Literal, BooleanLiteral::DbUnion {
|
||||
final override BooleanLiteral::Range range;
|
||||
|
||||
class BooleanLiteral extends Literal, TBooleanLiteral {
|
||||
final override string getAPrimaryQlClass() { result = "BooleanLiteral" }
|
||||
|
||||
final override string toString() { result = this.getValueText() }
|
||||
|
||||
/** Holds if the Boolean literal is `true` or `TRUE`. */
|
||||
predicate isTrue() { range.isTrue() }
|
||||
predicate isTrue() { none() }
|
||||
|
||||
/** Holds if the Boolean literal is `false` or `FALSE`. */
|
||||
predicate isFalse() { range.isFalse() }
|
||||
predicate isFalse() { none() }
|
||||
}
|
||||
|
||||
private class TrueLiteral extends BooleanLiteral, TTrueLiteral {
|
||||
private Generated::True g;
|
||||
|
||||
TrueLiteral() { this = TTrueLiteral(g) }
|
||||
|
||||
final override string getValueText() { result = g.getValue() }
|
||||
|
||||
final override predicate isTrue() { any() }
|
||||
}
|
||||
|
||||
private class FalseLiteral extends BooleanLiteral, TFalseLiteral {
|
||||
private Generated::False g;
|
||||
|
||||
FalseLiteral() { this = TFalseLiteral(g) }
|
||||
|
||||
final override string getValueText() { result = g.getValue() }
|
||||
|
||||
final override predicate isFalse() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The base class for a component of a string: `StringTextComponent`,
|
||||
* `StringEscapeSequenceComponent`, or `StringInterpolationComponent`.
|
||||
*/
|
||||
class StringComponent extends AstNode {
|
||||
override StringComponent::Range range;
|
||||
|
||||
class StringComponent extends AstNode, TStringComponent {
|
||||
/**
|
||||
* Gets the source text for this string component. Has no result if this is
|
||||
* a `StringInterpolationComponent`.
|
||||
*/
|
||||
final string getValueText() { result = range.getValueText() }
|
||||
string getValueText() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,8 +188,14 @@ class StringComponent extends AstNode {
|
||||
* "foo#{ bar() } baz"
|
||||
* ```
|
||||
*/
|
||||
class StringTextComponent extends StringComponent, StringTextComponent::StringContentToken {
|
||||
final override StringTextComponent::Range range;
|
||||
class StringTextComponent extends StringComponent, TStringTextComponent {
|
||||
private Generated::Token g;
|
||||
|
||||
StringTextComponent() { this = TStringTextComponent(g) }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
|
||||
final override string getValueText() { result = g.getValue() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "StringTextComponent" }
|
||||
}
|
||||
@@ -152,8 +203,14 @@ class StringTextComponent extends StringComponent, StringTextComponent::StringCo
|
||||
/**
|
||||
* An escape sequence component of a string or string-like literal.
|
||||
*/
|
||||
class StringEscapeSequenceComponent extends StringComponent, @token_escape_sequence {
|
||||
final override StringEscapeSequenceComponent::Range range;
|
||||
class StringEscapeSequenceComponent extends StringComponent, TStringEscapeSequenceComponent {
|
||||
private Generated::EscapeSequence g;
|
||||
|
||||
StringEscapeSequenceComponent() { this = TStringEscapeSequenceComponent(g) }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
|
||||
final override string getValueText() { result = g.getValue() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "StringEscapeSequenceComponent" }
|
||||
}
|
||||
@@ -161,8 +218,17 @@ class StringEscapeSequenceComponent extends StringComponent, @token_escape_seque
|
||||
/**
|
||||
* An interpolation expression component of a string or string-like literal.
|
||||
*/
|
||||
class StringInterpolationComponent extends StringComponent, StmtSequence, @interpolation {
|
||||
final override StringInterpolationComponent::Range range;
|
||||
class StringInterpolationComponent extends StringComponent, StmtSequence,
|
||||
TStringInterpolationComponent {
|
||||
private Generated::Interpolation g;
|
||||
|
||||
StringInterpolationComponent() { this = TStringInterpolationComponent(g) }
|
||||
|
||||
final override string toString() { result = "#{...}" }
|
||||
|
||||
final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
|
||||
|
||||
final override string getValueText() { none() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "StringInterpolationComponent" }
|
||||
}
|
||||
@@ -170,9 +236,7 @@ class StringInterpolationComponent extends StringComponent, StmtSequence, @inter
|
||||
/**
|
||||
* A string, symbol, regex, or subshell literal.
|
||||
*/
|
||||
class StringlikeLiteral extends Literal {
|
||||
override StringlikeLiteral::Range range;
|
||||
|
||||
class StringlikeLiteral extends Literal, TStringlikeLiteral {
|
||||
/**
|
||||
* Gets the `n`th component of this string or string-like literal. The result
|
||||
* will be one of `StringTextComponent`, `StringInterpolationComponent`, and
|
||||
@@ -186,7 +250,7 @@ class StringlikeLiteral extends Literal {
|
||||
* "foo_#{ Time.now }"
|
||||
* ```
|
||||
*/
|
||||
final StringComponent getComponent(int n) { result = range.getComponent(n) }
|
||||
StringComponent getComponent(int n) { none() }
|
||||
|
||||
/**
|
||||
* Gets the number of components in this string or string-like literal.
|
||||
@@ -206,6 +270,91 @@ class StringlikeLiteral extends Literal {
|
||||
* ```
|
||||
*/
|
||||
final int getNumberOfComponents() { result = count(this.getComponent(_)) }
|
||||
|
||||
private string getStartDelimiter() {
|
||||
this instanceof TStringLiteral and
|
||||
result = "\""
|
||||
or
|
||||
this instanceof TRegexLiteral and
|
||||
result = "/"
|
||||
or
|
||||
this instanceof TSimpleSymbolLiteral and
|
||||
result = ":"
|
||||
or
|
||||
this instanceof TComplexSymbolLiteral and
|
||||
result = ":\""
|
||||
or
|
||||
this instanceof THashKeySymbolLiteral and
|
||||
result = ""
|
||||
or
|
||||
this instanceof TSubshellLiteral and
|
||||
result = "`"
|
||||
or
|
||||
this instanceof THereDoc and
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string getEndDelimiter() {
|
||||
this instanceof TStringLiteral and
|
||||
result = "\""
|
||||
or
|
||||
this instanceof TRegexLiteral and
|
||||
result = "/"
|
||||
or
|
||||
this instanceof TSimpleSymbolLiteral and
|
||||
result = ""
|
||||
or
|
||||
this instanceof TComplexSymbolLiteral and
|
||||
result = "\""
|
||||
or
|
||||
this instanceof THashKeySymbolLiteral and
|
||||
result = ""
|
||||
or
|
||||
this instanceof TSubshellLiteral and
|
||||
result = "`"
|
||||
or
|
||||
this instanceof THereDoc and
|
||||
result = ""
|
||||
}
|
||||
|
||||
override string getValueText() {
|
||||
// 0 components should result in the empty string
|
||||
// if there are any interpolations, there should be no result
|
||||
// otherwise, concatenate all the components
|
||||
forall(StringComponent c | c = this.getComponent(_) |
|
||||
not c instanceof StringInterpolationComponent
|
||||
) and
|
||||
result =
|
||||
concat(StringComponent c, int i | c = this.getComponent(i) | c.getValueText() order by i)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
exists(string full, string summary |
|
||||
full =
|
||||
concat(StringComponent c, int i, string s |
|
||||
c = this.getComponent(i) and
|
||||
(
|
||||
s = toGenerated(c).(Generated::Token).getValue()
|
||||
or
|
||||
not toGenerated(c) instanceof Generated::Token and
|
||||
s = "#{...}"
|
||||
)
|
||||
|
|
||||
s order by i
|
||||
) and
|
||||
(
|
||||
// summary should be 32 chars max (incl. ellipsis)
|
||||
full.length() > 32 and summary = full.substring(0, 29) + "..."
|
||||
or
|
||||
full.length() <= 32 and summary = full
|
||||
) and
|
||||
result = this.getStartDelimiter() + summary + this.getEndDelimiter()
|
||||
)
|
||||
}
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
pred = "getComponent" and result = this.getComponent(_)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,12 +365,26 @@ class StringlikeLiteral extends Literal {
|
||||
* "hello, #{name}"
|
||||
* ```
|
||||
*/
|
||||
class StringLiteral extends StringlikeLiteral {
|
||||
final override StringLiteral::Range range;
|
||||
|
||||
class StringLiteral extends StringlikeLiteral, TStringLiteral {
|
||||
final override string getAPrimaryQlClass() { result = "StringLiteral" }
|
||||
}
|
||||
|
||||
private class RegularStringLiteral extends StringLiteral, TRegularStringLiteral {
|
||||
private Generated::String g;
|
||||
|
||||
RegularStringLiteral() { this = TRegularStringLiteral(g) }
|
||||
|
||||
final override StringComponent getComponent(int n) { toGenerated(result) = g.getChild(n) }
|
||||
}
|
||||
|
||||
private class BareStringLiteral extends StringLiteral, TBareStringLiteral {
|
||||
private Generated::BareString g;
|
||||
|
||||
BareStringLiteral() { this = TBareStringLiteral(g) }
|
||||
|
||||
final override StringComponent getComponent(int n) { toGenerated(result) = g.getChild(n) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A regular expression literal.
|
||||
*
|
||||
@@ -229,11 +392,15 @@ class StringLiteral extends StringlikeLiteral {
|
||||
* /[a-z]+/
|
||||
* ```
|
||||
*/
|
||||
class RegexLiteral extends StringlikeLiteral, @regex {
|
||||
final override RegexLiteral::Range range;
|
||||
class RegexLiteral extends StringlikeLiteral, TRegexLiteral {
|
||||
private Generated::Regex g;
|
||||
|
||||
RegexLiteral() { this = TRegexLiteral(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "RegexLiteral" }
|
||||
|
||||
final override StringComponent getComponent(int i) { toGenerated(result) = g.getChild(i) }
|
||||
|
||||
/**
|
||||
* Gets the regex flags as a string.
|
||||
*
|
||||
@@ -242,7 +409,16 @@ class RegexLiteral extends StringlikeLiteral, @regex {
|
||||
* /foo/i # => "i"
|
||||
* /foo/imxo # => "imxo"
|
||||
*/
|
||||
final string getFlagString() { result = range.getFlagString() }
|
||||
final string getFlagString() {
|
||||
// For `/foo/i`, there should be an `/i` token in the database with `this`
|
||||
// as its parents. Strip the delimiter, which can vary.
|
||||
result =
|
||||
max(Generated::Token t |
|
||||
t.getParent() = g
|
||||
|
|
||||
t.getValue().suffix(1) order by t.getParentIndex()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the regex was specified using the `i` flag to indicate case
|
||||
@@ -264,16 +440,49 @@ class RegexLiteral extends StringlikeLiteral, @regex {
|
||||
* :"foo bar #{baz}"
|
||||
* ```
|
||||
*/
|
||||
class SymbolLiteral extends StringlikeLiteral {
|
||||
final override SymbolLiteral::Range range;
|
||||
|
||||
SymbolLiteral() {
|
||||
not any(UndefStmt u).getAMethodName() = this and
|
||||
not any(AliasStmt a).getNewName() = this and
|
||||
not any(AliasStmt a).getOldName() = this
|
||||
class SymbolLiteral extends StringlikeLiteral, TSymbolLiteral {
|
||||
final override string getAPrimaryQlClass() {
|
||||
not this instanceof MethodName and result = "SymbolLiteral"
|
||||
}
|
||||
}
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "SymbolLiteral" }
|
||||
private class SimpleSymbolLiteral extends SymbolLiteral, TSimpleSymbolLiteral {
|
||||
private Generated::SimpleSymbol g;
|
||||
|
||||
SimpleSymbolLiteral() { this = TSimpleSymbolLiteral(g) }
|
||||
|
||||
// Tree-sitter gives us value text including the colon, which we skip.
|
||||
final override string getValueText() { result = g.getValue().suffix(1) }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
}
|
||||
|
||||
private class ComplexSymbolLiteral extends SymbolLiteral, TComplexSymbolLiteral { }
|
||||
|
||||
private class DelimitedSymbolLiteral extends ComplexSymbolLiteral, TDelimitedSymbolLiteral {
|
||||
private Generated::DelimitedSymbol g;
|
||||
|
||||
DelimitedSymbolLiteral() { this = TDelimitedSymbolLiteral(g) }
|
||||
|
||||
final override StringComponent getComponent(int i) { toGenerated(result) = g.getChild(i) }
|
||||
}
|
||||
|
||||
private class BareSymbolLiteral extends ComplexSymbolLiteral, TBareSymbolLiteral {
|
||||
private Generated::BareSymbol g;
|
||||
|
||||
BareSymbolLiteral() { this = TBareSymbolLiteral(g) }
|
||||
|
||||
final override StringComponent getComponent(int i) { toGenerated(result) = g.getChild(i) }
|
||||
}
|
||||
|
||||
private class HashKeySymbolLiteral extends SymbolLiteral, THashKeySymbolLiteral {
|
||||
private Generated::HashKeySymbol g;
|
||||
|
||||
HashKeySymbolLiteral() { this = THashKeySymbolLiteral(g) }
|
||||
|
||||
final override string getValueText() { result = g.getValue() }
|
||||
|
||||
final override string toString() { result = ":" + this.getValueText() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,10 +493,14 @@ class SymbolLiteral extends StringlikeLiteral {
|
||||
* %x(/bin/sh foo.sh)
|
||||
* ```
|
||||
*/
|
||||
class SubshellLiteral extends StringlikeLiteral, @subshell {
|
||||
final override SubshellLiteral::Range range;
|
||||
class SubshellLiteral extends StringlikeLiteral, TSubshellLiteral {
|
||||
private Generated::Subshell g;
|
||||
|
||||
SubshellLiteral() { this = TSubshellLiteral(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "SubshellLiteral" }
|
||||
|
||||
final override StringComponent getComponent(int i) { toGenerated(result) = g.getChild(i) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,8 +511,14 @@ class SubshellLiteral extends StringlikeLiteral, @subshell {
|
||||
* ?\u{61}
|
||||
* ```
|
||||
*/
|
||||
class CharacterLiteral extends Literal, @token_character {
|
||||
final override CharacterLiteral::Range range;
|
||||
class CharacterLiteral extends Literal, TCharacterLiteral {
|
||||
private Generated::Character g;
|
||||
|
||||
CharacterLiteral() { this = TCharacterLiteral(g) }
|
||||
|
||||
final override string getValueText() { result = g.getValue() }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "CharacterLiteral" }
|
||||
}
|
||||
@@ -313,8 +532,10 @@ class CharacterLiteral extends Literal, @token_character {
|
||||
* SQL
|
||||
* ```
|
||||
*/
|
||||
class HereDoc extends StringlikeLiteral {
|
||||
final override HereDoc::Range range;
|
||||
class HereDoc extends StringlikeLiteral, THereDoc {
|
||||
private Generated::HeredocBeginning g;
|
||||
|
||||
HereDoc() { this = THereDoc(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "HereDoc" }
|
||||
|
||||
@@ -336,7 +557,13 @@ class HereDoc extends StringlikeLiteral {
|
||||
* <<`IDENTIFIER`
|
||||
* ```
|
||||
*/
|
||||
final string getQuoteStyle() { result = range.getQuoteStyle() }
|
||||
final string getQuoteStyle() {
|
||||
exists(string s |
|
||||
s = g.getValue() and
|
||||
s.charAt(s.length() - 1) = result and
|
||||
result = ["'", "`", "\""]
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the indentation modifier (`-` or `~`) of the here document identifier, if any.
|
||||
@@ -346,7 +573,36 @@ class HereDoc extends StringlikeLiteral {
|
||||
* <<IDENTIFIER
|
||||
* ```
|
||||
*/
|
||||
final string getIndentationModifier() { result = range.getIndentationModifier() }
|
||||
final string getIndentationModifier() {
|
||||
exists(string s |
|
||||
s = g.getValue() and
|
||||
s.charAt(2) = result and
|
||||
result = ["-", "~"]
|
||||
)
|
||||
}
|
||||
|
||||
private Generated::HeredocBody getBody() {
|
||||
exists(int i, File f |
|
||||
g =
|
||||
rank[i](Generated::HeredocBeginning b |
|
||||
f = b.getLocation().getFile()
|
||||
|
|
||||
b order by b.getLocation().getStartLine(), b.getLocation().getStartColumn()
|
||||
) and
|
||||
result =
|
||||
rank[i](Generated::HeredocBody b |
|
||||
f = b.getLocation().getFile()
|
||||
|
|
||||
b order by b.getLocation().getStartLine(), b.getLocation().getStartColumn()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override StringComponent getComponent(int n) {
|
||||
toGenerated(result) = this.getBody().getChild(n)
|
||||
}
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,19 +614,51 @@ class HereDoc extends StringlikeLiteral {
|
||||
* %i(foo bar)
|
||||
* ```
|
||||
*/
|
||||
class ArrayLiteral extends Literal {
|
||||
final override ArrayLiteral::Range range;
|
||||
|
||||
class ArrayLiteral extends Literal, TArrayLiteral {
|
||||
final override string getAPrimaryQlClass() { result = "ArrayLiteral" }
|
||||
|
||||
/** Gets the `n`th element in this array literal. */
|
||||
final Expr getElement(int n) { result = range.getElement(n) }
|
||||
Expr getElement(int n) { none() }
|
||||
|
||||
/** Gets an element in this array literal. */
|
||||
final Expr getAnElement() { result = range.getElement(_) }
|
||||
final Expr getAnElement() { result = this.getElement(_) }
|
||||
|
||||
/** Gets the number of elements in this array literal. */
|
||||
final int getNumberOfElements() { result = count(range.getElement(_)) }
|
||||
final int getNumberOfElements() { result = count(this.getAnElement()) }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
pred = "getElement" and result = this.getElement(_)
|
||||
}
|
||||
}
|
||||
|
||||
private class RegularArrayLiteral extends ArrayLiteral, TRegularArrayLiteral {
|
||||
private Generated::Array g;
|
||||
|
||||
RegularArrayLiteral() { this = TRegularArrayLiteral(g) }
|
||||
|
||||
final override Expr getElement(int i) { toGenerated(result) = g.getChild(i) }
|
||||
|
||||
final override string toString() { result = "[...]" }
|
||||
}
|
||||
|
||||
private class StringArrayLiteral extends ArrayLiteral, TStringArrayLiteral {
|
||||
private Generated::StringArray g;
|
||||
|
||||
StringArrayLiteral() { this = TStringArrayLiteral(g) }
|
||||
|
||||
final override Expr getElement(int i) { toGenerated(result) = g.getChild(i) }
|
||||
|
||||
final override string toString() { result = "%w(...)" }
|
||||
}
|
||||
|
||||
private class SymbolArrayLiteral extends ArrayLiteral, TSymbolArrayLiteral {
|
||||
private Generated::SymbolArray g;
|
||||
|
||||
SymbolArrayLiteral() { this = TSymbolArrayLiteral(g) }
|
||||
|
||||
final override Expr getElement(int i) { toGenerated(result) = g.getChild(i) }
|
||||
|
||||
final override string toString() { result = "%i(...)" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -380,8 +668,10 @@ class ArrayLiteral extends Literal {
|
||||
* { foo: 123, bar: 456 }
|
||||
* ```
|
||||
*/
|
||||
class HashLiteral extends Literal, @hash {
|
||||
final override HashLiteral::Range range;
|
||||
class HashLiteral extends Literal, THashLiteral {
|
||||
private Generated::Hash g;
|
||||
|
||||
HashLiteral() { this = THashLiteral(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "HashLiteral" }
|
||||
|
||||
@@ -395,16 +685,22 @@ class HashLiteral extends Literal, @hash {
|
||||
* { foo: 123, **bar }
|
||||
* ```
|
||||
*/
|
||||
final Expr getElement(int n) { result = range.getElement(n) }
|
||||
final Expr getElement(int n) { toGenerated(result) = g.getChild(n) }
|
||||
|
||||
/** Gets an element in this array literal. */
|
||||
final Expr getAnElement() { result = range.getElement(_) }
|
||||
final Expr getAnElement() { result = this.getElement(_) }
|
||||
|
||||
/** Gets a key-value `Pair` in this hash literal. */
|
||||
final Pair getAKeyValuePair() { result = this.getAnElement() }
|
||||
|
||||
/** Gets the number of elements in this hash literal. */
|
||||
final int getNumberOfElements() { result = count(range.getElement(_)) }
|
||||
final int getNumberOfElements() { result = count(this.getAnElement()) }
|
||||
|
||||
final override string toString() { result = "{...}" }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
pred = "getElement" and result = this.getElement(_)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -415,28 +711,38 @@ class HashLiteral extends Literal, @hash {
|
||||
* (1024...2048)
|
||||
* ```
|
||||
*/
|
||||
class RangeLiteral extends Literal, @range {
|
||||
final override RangeLiteral::Range range;
|
||||
class RangeLiteral extends Literal, TRangeLiteral {
|
||||
private Generated::Range g;
|
||||
|
||||
RangeLiteral() { this = TRangeLiteral(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "RangeLiteral" }
|
||||
|
||||
/** Gets the begin expression of this range, if any. */
|
||||
final Expr getBegin() { result = range.getBegin() }
|
||||
final Expr getBegin() { toGenerated(result) = g.getBegin() }
|
||||
|
||||
/** Gets the end expression of this range, if any. */
|
||||
final Expr getEnd() { result = range.getEnd() }
|
||||
final Expr getEnd() { toGenerated(result) = g.getEnd() }
|
||||
|
||||
/**
|
||||
* Holds if the range is inclusive of the end value, i.e. uses the `..`
|
||||
* operator.
|
||||
*/
|
||||
final predicate isInclusive() { range.isInclusive() }
|
||||
final predicate isInclusive() { g instanceof @range_dotdot }
|
||||
|
||||
/**
|
||||
* Holds if the range is exclusive of the end value, i.e. uses the `...`
|
||||
* operator.
|
||||
*/
|
||||
final predicate isExclusive() { range.isExclusive() }
|
||||
final predicate isExclusive() { g instanceof @range_dotdotdot }
|
||||
|
||||
final override string toString() { result = "_ " + g.getOperator() + " _" }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
pred = "getBegin" and result = this.getBegin()
|
||||
or
|
||||
pred = "getEnd" and result = this.getEnd()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -449,7 +755,21 @@ class RangeLiteral extends Literal, @range {
|
||||
* ```
|
||||
*/
|
||||
class MethodName extends Literal {
|
||||
final override MethodName::Range range;
|
||||
MethodName() { MethodName::range(toGenerated(this)) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "MethodName" }
|
||||
}
|
||||
|
||||
private class TokenMethodName extends MethodName, TTokenMethodName {
|
||||
private MethodName::Token g;
|
||||
|
||||
TokenMethodName() { this = TTokenMethodName(g) }
|
||||
|
||||
final override string getValueText() {
|
||||
result = g.(Generated::Token).getValue()
|
||||
or
|
||||
result = g.(Generated::Setter).getName().getValue() + "="
|
||||
}
|
||||
|
||||
final override string toString() { result = this.getValueText() }
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.controlflow.ControlFlowGraph
|
||||
private import internal.AST
|
||||
private import internal.Method
|
||||
private import internal.TreeSitter
|
||||
|
||||
/** A callable. */
|
||||
class Callable extends Expr, CfgScope {
|
||||
override Callable::Range range;
|
||||
|
||||
class Callable extends Expr, TCallable {
|
||||
/** Gets the number of parameters of this callable. */
|
||||
final int getNumberOfParameters() { result = count(this.getAParameter()) }
|
||||
|
||||
@@ -14,17 +12,37 @@ class Callable extends Expr, CfgScope {
|
||||
final Parameter getAParameter() { result = this.getParameter(_) }
|
||||
|
||||
/** Gets the `n`th parameter of this callable. */
|
||||
final Parameter getParameter(int n) { result = range.getParameter(n) }
|
||||
Parameter getParameter(int n) { none() }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
pred = "getParameter" and result = this.getParameter(_)
|
||||
}
|
||||
}
|
||||
|
||||
/** A method. */
|
||||
class Method extends Callable, BodyStatement, @method {
|
||||
final override Method::Range range;
|
||||
class MethodBase extends Callable, BodyStmt, Scope, TMethodBase {
|
||||
/** Gets the name of this method. */
|
||||
string getName() { none() }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = Callable.super.getAChild(pred)
|
||||
or
|
||||
result = BodyStmt.super.getAChild(pred)
|
||||
}
|
||||
}
|
||||
|
||||
/** A normal method. */
|
||||
class Method extends MethodBase, TMethod {
|
||||
private Generated::Method g;
|
||||
|
||||
Method() { this = TMethod(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "Method" }
|
||||
|
||||
/** Gets the name of this method. */
|
||||
final string getName() { result = range.getName() }
|
||||
final override string getName() {
|
||||
result = g.getName().(Generated::Token).getValue() or
|
||||
result = g.getName().(Generated::Setter).getName().getValue() + "="
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this is a setter method, as in the following example:
|
||||
@@ -36,20 +54,43 @@ class Method extends Callable, BodyStatement, @method {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final predicate isSetter() { range.isSetter() }
|
||||
final predicate isSetter() { g.getName() instanceof Generated::Setter }
|
||||
|
||||
final override Parameter getParameter(int n) {
|
||||
toGenerated(result) = g.getParameters().getChild(n)
|
||||
}
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
/** A singleton method. */
|
||||
class SingletonMethod extends Callable, BodyStatement, @singleton_method {
|
||||
final override SingletonMethod::Range range;
|
||||
class SingletonMethod extends MethodBase, TSingletonMethod {
|
||||
private Generated::SingletonMethod g;
|
||||
|
||||
SingletonMethod() { this = TSingletonMethod(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "SingletonMethod" }
|
||||
|
||||
/** Gets the object of this singleton method. */
|
||||
final Expr getObject() { result = range.getObject() }
|
||||
final Expr getObject() { toGenerated(result) = g.getObject() }
|
||||
|
||||
/** Gets the name of this method. */
|
||||
final string getName() { result = range.getName() }
|
||||
final override string getName() {
|
||||
result = g.getName().(Generated::Token).getValue()
|
||||
or
|
||||
result = g.getName().(Generated::Setter).getName().getValue() + "="
|
||||
}
|
||||
|
||||
final override Parameter getParameter(int n) {
|
||||
toGenerated(result) = g.getParameters().getChild(n)
|
||||
}
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = MethodBase.super.getAChild(pred)
|
||||
or
|
||||
pred = "getObject" and result = this.getObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,20 +99,52 @@ class SingletonMethod extends Callable, BodyStatement, @singleton_method {
|
||||
* -> (x) { x + 1 }
|
||||
* ```
|
||||
*/
|
||||
class Lambda extends Callable, BodyStatement, @lambda {
|
||||
final override Lambda::Range range;
|
||||
class Lambda extends Callable, BodyStmt, TLambda {
|
||||
private Generated::Lambda g;
|
||||
|
||||
Lambda() { this = TLambda(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "Lambda" }
|
||||
|
||||
final override Parameter getParameter(int n) {
|
||||
toGenerated(result) = g.getParameters().getChild(n)
|
||||
}
|
||||
|
||||
final override string toString() { result = "-> { ... }" }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = Callable.super.getAChild(pred)
|
||||
or
|
||||
result = BodyStmt.super.getAChild(pred)
|
||||
}
|
||||
}
|
||||
|
||||
/** A block. */
|
||||
class Block extends Callable, StmtSequence {
|
||||
override Block::Range range;
|
||||
class Block extends Callable, StmtSequence, Scope, TBlock {
|
||||
override AstNode getAChild(string pred) {
|
||||
result = Callable.super.getAChild(pred)
|
||||
or
|
||||
result = StmtSequence.super.getAChild(pred)
|
||||
}
|
||||
}
|
||||
|
||||
/** A block enclosed within `do` and `end`. */
|
||||
class DoBlock extends Block, BodyStatement, @do_block {
|
||||
final override DoBlock::Range range;
|
||||
class DoBlock extends Block, BodyStmt, TDoBlock {
|
||||
private Generated::DoBlock g;
|
||||
|
||||
DoBlock() { this = TDoBlock(g) }
|
||||
|
||||
final override Parameter getParameter(int n) {
|
||||
toGenerated(result) = g.getParameters().getChild(n)
|
||||
}
|
||||
|
||||
final override string toString() { result = "do ... end" }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = Block.super.getAChild(pred)
|
||||
or
|
||||
result = BodyStmt.super.getAChild(pred)
|
||||
}
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "DoBlock" }
|
||||
}
|
||||
@@ -82,8 +155,18 @@ class DoBlock extends Block, BodyStatement, @do_block {
|
||||
* names.each { |name| puts name }
|
||||
* ```
|
||||
*/
|
||||
class BraceBlock extends Block, @block {
|
||||
final override BraceBlock::Range range;
|
||||
class BraceBlock extends Block, TBraceBlock {
|
||||
private Generated::Block g;
|
||||
|
||||
BraceBlock() { this = TBraceBlock(g) }
|
||||
|
||||
final override Parameter getParameter(int n) {
|
||||
toGenerated(result) = g.getParameters().getChild(n)
|
||||
}
|
||||
|
||||
final override Stmt getStmt(int i) { toGenerated(result) = g.getChild(i) }
|
||||
|
||||
final override string toString() { result = "{ ... }" }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "BraceBlock" }
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.Constant
|
||||
private import internal.Module
|
||||
private import internal.AST
|
||||
private import internal.TreeSitter
|
||||
|
||||
/**
|
||||
* The base class for classes, singleton classes, and modules.
|
||||
*/
|
||||
class ModuleBase extends BodyStatement {
|
||||
override ModuleBase::Range range;
|
||||
|
||||
class ModuleBase extends BodyStmt, TModuleBase {
|
||||
/** Gets a method defined in this module/class. */
|
||||
Method getAMethod() { result = this.getAStmt() }
|
||||
MethodBase getAMethod() { result = this.getAStmt() }
|
||||
|
||||
/** Gets the method named `name` in this module/class, if any. */
|
||||
Method getMethod(string name) { result = this.getAMethod() and result.getName() = name }
|
||||
MethodBase getMethod(string name) { result = this.getAMethod() and result.getName() = name }
|
||||
|
||||
/** Gets a class defined in this module/class. */
|
||||
Class getAClass() { result = this.getAStmt() }
|
||||
@@ -37,20 +36,33 @@ class ModuleBase extends BodyStatement {
|
||||
* main
|
||||
* ```
|
||||
*/
|
||||
class Toplevel extends ModuleBase, @program {
|
||||
final override Toplevel::Range range;
|
||||
class Toplevel extends ModuleBase, TToplevel {
|
||||
private Generated::Program g;
|
||||
|
||||
Toplevel() { this = TToplevel(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "Toplevel" }
|
||||
|
||||
/**
|
||||
* Gets the `n`th `BEGIN` block.
|
||||
*/
|
||||
final BeginBlock getBeginBlock(int n) { result = range.getBeginBlock(n) }
|
||||
final BeginBlock getBeginBlock(int n) {
|
||||
toGenerated(result) =
|
||||
rank[n + 1](int i, Generated::BeginBlock b | b = g.getChild(i) | b order by i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a `BEGIN` block.
|
||||
*/
|
||||
final BeginBlock getABeginBlock() { result = getBeginBlock(_) }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = ModuleBase.super.getAChild(pred)
|
||||
or
|
||||
pred = "getBeginBlock" and result = this.getBeginBlock(_)
|
||||
}
|
||||
|
||||
final override string toString() { result = g.getLocation().getFile().getBaseName() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,9 +79,7 @@ class Toplevel extends ModuleBase, @program {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class Namespace extends ModuleBase, ConstantWriteAccess {
|
||||
override Namespace::Range range;
|
||||
|
||||
class Namespace extends ModuleBase, ConstantWriteAccess, TNamespace {
|
||||
override string getAPrimaryQlClass() { result = "Namespace" }
|
||||
|
||||
/**
|
||||
@@ -88,7 +98,7 @@ class Namespace extends ModuleBase, ConstantWriteAccess {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
override string getName() { result = range.getName() }
|
||||
override string getName() { none() }
|
||||
|
||||
/**
|
||||
* Gets the scope expression used in the module/class name's scope resolution
|
||||
@@ -109,7 +119,7 @@ class Namespace extends ModuleBase, ConstantWriteAccess {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
override Expr getScopeExpr() { result = range.getScopeExpr() }
|
||||
override Expr getScopeExpr() { none() }
|
||||
|
||||
/**
|
||||
* Holds if the module/class name uses the scope resolution operator to access the
|
||||
@@ -120,7 +130,14 @@ class Namespace extends ModuleBase, ConstantWriteAccess {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
override predicate hasGlobalScope() { range.hasGlobalScope() }
|
||||
override predicate hasGlobalScope() { none() }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = ModuleBase.super.getAChild(pred) or
|
||||
result = ConstantWriteAccess.super.getAChild(pred)
|
||||
}
|
||||
|
||||
final override string toString() { result = ConstantWriteAccess.super.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,8 +150,10 @@ class Namespace extends ModuleBase, ConstantWriteAccess {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class Class extends Namespace, @class {
|
||||
final override Class::Range range;
|
||||
class Class extends Namespace, TClass {
|
||||
private Generated::Class g;
|
||||
|
||||
Class() { this = TClass(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "Class" }
|
||||
|
||||
@@ -154,7 +173,29 @@ class Class extends Namespace, @class {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final Expr getSuperclassExpr() { result = range.getSuperclassExpr() }
|
||||
final Expr getSuperclassExpr() { toGenerated(result) = g.getSuperclass().getChild() }
|
||||
|
||||
final override string getName() {
|
||||
result = g.getName().(Generated::Token).getValue() or
|
||||
result = g.getName().(Generated::ScopeResolution).getName().(Generated::Token).getValue()
|
||||
}
|
||||
|
||||
final override Expr getScopeExpr() {
|
||||
toGenerated(result) = g.getName().(Generated::ScopeResolution).getScope()
|
||||
}
|
||||
|
||||
final override predicate hasGlobalScope() {
|
||||
exists(Generated::ScopeResolution sr |
|
||||
sr = g.getName() and
|
||||
not exists(sr.getScope())
|
||||
)
|
||||
}
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = Namespace.super.getAChild(pred)
|
||||
or
|
||||
pred = "getSuperclassExpr" and result = this.getSuperclassExpr()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,8 +209,10 @@ class Class extends Namespace, @class {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class SingletonClass extends ModuleBase, @singleton_class {
|
||||
final override SingletonClass::Range range;
|
||||
class SingletonClass extends ModuleBase, TSingletonClass {
|
||||
private Generated::SingletonClass g;
|
||||
|
||||
SingletonClass() { this = TSingletonClass(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "Class" }
|
||||
|
||||
@@ -182,7 +225,15 @@ class SingletonClass extends ModuleBase, @singleton_class {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final Expr getValue() { result = range.getValue() }
|
||||
final Expr getValue() { toGenerated(result) = g.getValue() }
|
||||
|
||||
final override string toString() { result = "class << ..." }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = ModuleBase.super.getAChild(pred)
|
||||
or
|
||||
pred = "getValue" and result = this.getValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -210,8 +261,26 @@ class SingletonClass extends ModuleBase, @singleton_class {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class Module extends Namespace, @module {
|
||||
final override Module::Range range;
|
||||
class Module extends Namespace, TModule {
|
||||
private Generated::Module g;
|
||||
|
||||
Module() { this = TModule(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "Module" }
|
||||
|
||||
final override string getName() {
|
||||
result = g.getName().(Generated::Token).getValue() or
|
||||
result = g.getName().(Generated::ScopeResolution).getName().(Generated::Token).getValue()
|
||||
}
|
||||
|
||||
final override Expr getScopeExpr() {
|
||||
toGenerated(result) = g.getName().(Generated::ScopeResolution).getScope()
|
||||
}
|
||||
|
||||
final override predicate hasGlobalScope() {
|
||||
exists(Generated::ScopeResolution sr |
|
||||
sr = g.getName() and
|
||||
not exists(sr.getScope())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,46 @@
|
||||
private import codeql_ruby.AST
|
||||
private import internal.Operation
|
||||
private import internal.AST
|
||||
private import internal.TreeSitter
|
||||
|
||||
/**
|
||||
* An operation.
|
||||
*
|
||||
* This is the QL root class for all operations.
|
||||
*/
|
||||
class Operation extends Expr {
|
||||
override Operation::Range range;
|
||||
|
||||
class Operation extends Expr, TOperation {
|
||||
/** Gets the operator of this operation. */
|
||||
final string getOperator() { result = range.getOperator() }
|
||||
string getOperator() { none() }
|
||||
|
||||
/** Gets an operand of this operation. */
|
||||
final Expr getAnOperand() { result = range.getAnOperand() }
|
||||
Expr getAnOperand() { none() }
|
||||
|
||||
override AstNode getAChild(string pred) { pred = "getAnOperand" and result = this.getAnOperand() }
|
||||
}
|
||||
|
||||
/** A unary operation. */
|
||||
class UnaryOperation extends Operation, @unary {
|
||||
override UnaryOperation::Range range;
|
||||
class UnaryOperation extends Operation, TUnaryOperation {
|
||||
private Generated::Unary g;
|
||||
|
||||
UnaryOperation() { g = toGenerated(this) }
|
||||
|
||||
/** Gets the operand of this unary operation. */
|
||||
final Expr getOperand() { result = range.getOperand() }
|
||||
final Expr getOperand() { toGenerated(result) = g.getOperand() }
|
||||
|
||||
final override string getOperator() { result = g.getOperator() }
|
||||
|
||||
final override Expr getAnOperand() { result = this.getOperand() }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = Operation.super.getAChild(pred)
|
||||
or
|
||||
pred = "getOperand" and result = this.getOperand()
|
||||
}
|
||||
|
||||
final override string toString() { result = this.getOperator() + " ..." }
|
||||
}
|
||||
|
||||
/** A unary logical operation. */
|
||||
class UnaryLogicalOperation extends UnaryOperation {
|
||||
override UnaryLogicalOperation::Range range;
|
||||
}
|
||||
class UnaryLogicalOperation extends UnaryOperation, TUnaryLogicalOperation { }
|
||||
|
||||
/**
|
||||
* A logical NOT operation, using either `!` or `not`.
|
||||
@@ -36,16 +49,12 @@ class UnaryLogicalOperation extends UnaryOperation {
|
||||
* not params.empty?
|
||||
* ```
|
||||
*/
|
||||
class NotExpr extends UnaryLogicalOperation, NotExpr::DbUnion {
|
||||
final override NotExpr::Range range;
|
||||
|
||||
class NotExpr extends UnaryLogicalOperation, TNotExpr {
|
||||
final override string getAPrimaryQlClass() { result = "NotExpr" }
|
||||
}
|
||||
|
||||
/** A unary arithmetic operation. */
|
||||
class UnaryArithmeticOperation extends UnaryOperation {
|
||||
override UnaryArithmeticOperation::Range range;
|
||||
}
|
||||
class UnaryArithmeticOperation extends UnaryOperation, TUnaryArithmeticOperation { }
|
||||
|
||||
/**
|
||||
* A unary plus expression.
|
||||
@@ -53,9 +62,7 @@ class UnaryArithmeticOperation extends UnaryOperation {
|
||||
* + a
|
||||
* ```
|
||||
*/
|
||||
class UnaryPlusExpr extends UnaryArithmeticOperation, @unary_plus {
|
||||
final override UnaryPlusExpr::Range range;
|
||||
|
||||
class UnaryPlusExpr extends UnaryArithmeticOperation, TUnaryPlusExpr {
|
||||
final override string getAPrimaryQlClass() { result = "UnaryPlusExpr" }
|
||||
}
|
||||
|
||||
@@ -65,16 +72,12 @@ class UnaryPlusExpr extends UnaryArithmeticOperation, @unary_plus {
|
||||
* - a
|
||||
* ```
|
||||
*/
|
||||
class UnaryMinusExpr extends UnaryArithmeticOperation, @unary_minus {
|
||||
final override UnaryMinusExpr::Range range;
|
||||
|
||||
class UnaryMinusExpr extends UnaryArithmeticOperation, TUnaryMinusExpr {
|
||||
final override string getAPrimaryQlClass() { result = "UnaryMinusExpr" }
|
||||
}
|
||||
|
||||
/** A unary bitwise operation. */
|
||||
class UnaryBitwiseOperation extends UnaryOperation {
|
||||
override UnaryBitwiseOperation::Range range;
|
||||
}
|
||||
class UnaryBitwiseOperation extends UnaryOperation, TUnaryBitwiseOperation { }
|
||||
|
||||
/**
|
||||
* A complement (bitwise NOT) expression.
|
||||
@@ -82,9 +85,7 @@ class UnaryBitwiseOperation extends UnaryOperation {
|
||||
* ~x
|
||||
* ```
|
||||
*/
|
||||
class ComplementExpr extends UnaryBitwiseOperation, @unary_tilde {
|
||||
final override ComplementExpr::Range range;
|
||||
|
||||
class ComplementExpr extends UnaryBitwiseOperation, TComplementExpr {
|
||||
final override string getAPrimaryQlClass() { result = "ComplementExpr" }
|
||||
}
|
||||
|
||||
@@ -94,29 +95,43 @@ class ComplementExpr extends UnaryBitwiseOperation, @unary_tilde {
|
||||
* defined? some_method
|
||||
* ```
|
||||
*/
|
||||
class DefinedExpr extends UnaryOperation, @unary_definedquestion {
|
||||
final override DefinedExpr::Range range;
|
||||
|
||||
class DefinedExpr extends UnaryOperation, TDefinedExpr {
|
||||
final override string getAPrimaryQlClass() { result = "DefinedExpr" }
|
||||
}
|
||||
|
||||
/** A binary operation. */
|
||||
class BinaryOperation extends Operation, @binary {
|
||||
override BinaryOperation::Range range;
|
||||
class BinaryOperation extends Operation, TBinaryOperation {
|
||||
private Generated::Binary g;
|
||||
|
||||
BinaryOperation() { g = toGenerated(this) }
|
||||
|
||||
final override string getOperator() { result = g.getOperator() }
|
||||
|
||||
final override Expr getAnOperand() {
|
||||
result = this.getLeftOperand() or result = this.getRightOperand()
|
||||
}
|
||||
|
||||
final override string toString() { result = "... " + this.getOperator() + " ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = Operation.super.getAChild(pred)
|
||||
or
|
||||
pred = "getLeftOperand" and result = this.getLeftOperand()
|
||||
or
|
||||
pred = "getRightOperand" and result = this.getRightOperand()
|
||||
}
|
||||
|
||||
/** Gets the left operand of this binary operation. */
|
||||
final Stmt getLeftOperand() { result = range.getLeftOperand() }
|
||||
final Stmt getLeftOperand() { toGenerated(result) = g.getLeft() }
|
||||
|
||||
/** Gets the right operand of this binary operation. */
|
||||
final Stmt getRightOperand() { result = range.getRightOperand() }
|
||||
final Stmt getRightOperand() { toGenerated(result) = g.getRight() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A binary arithmetic operation.
|
||||
*/
|
||||
class BinaryArithmeticOperation extends BinaryOperation {
|
||||
override BinaryArithmeticOperation::Range range;
|
||||
}
|
||||
class BinaryArithmeticOperation extends BinaryOperation, TBinaryArithmeticOperation { }
|
||||
|
||||
/**
|
||||
* An add expression.
|
||||
@@ -124,9 +139,7 @@ class BinaryArithmeticOperation extends BinaryOperation {
|
||||
* x + 1
|
||||
* ```
|
||||
*/
|
||||
class AddExpr extends BinaryArithmeticOperation, @binary_plus {
|
||||
final override AddExpr::Range range;
|
||||
|
||||
class AddExpr extends BinaryArithmeticOperation, TAddExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AddExpr" }
|
||||
}
|
||||
|
||||
@@ -136,9 +149,7 @@ class AddExpr extends BinaryArithmeticOperation, @binary_plus {
|
||||
* x - 3
|
||||
* ```
|
||||
*/
|
||||
class SubExpr extends BinaryArithmeticOperation, @binary_minus {
|
||||
final override SubExpr::Range range;
|
||||
|
||||
class SubExpr extends BinaryArithmeticOperation, TSubExpr {
|
||||
final override string getAPrimaryQlClass() { result = "SubExpr" }
|
||||
}
|
||||
|
||||
@@ -148,9 +159,7 @@ class SubExpr extends BinaryArithmeticOperation, @binary_minus {
|
||||
* x * 10
|
||||
* ```
|
||||
*/
|
||||
class MulExpr extends BinaryArithmeticOperation, @binary_star {
|
||||
final override MulExpr::Range range;
|
||||
|
||||
class MulExpr extends BinaryArithmeticOperation, TMulExpr {
|
||||
final override string getAPrimaryQlClass() { result = "MulExpr" }
|
||||
}
|
||||
|
||||
@@ -160,9 +169,7 @@ class MulExpr extends BinaryArithmeticOperation, @binary_star {
|
||||
* x / y
|
||||
* ```
|
||||
*/
|
||||
class DivExpr extends BinaryArithmeticOperation, @binary_slash {
|
||||
final override DivExpr::Range range;
|
||||
|
||||
class DivExpr extends BinaryArithmeticOperation, TDivExpr {
|
||||
final override string getAPrimaryQlClass() { result = "DivExpr" }
|
||||
}
|
||||
|
||||
@@ -172,9 +179,7 @@ class DivExpr extends BinaryArithmeticOperation, @binary_slash {
|
||||
* x % 2
|
||||
* ```
|
||||
*/
|
||||
class ModuloExpr extends BinaryArithmeticOperation, @binary_percent {
|
||||
final override ModuloExpr::Range range;
|
||||
|
||||
class ModuloExpr extends BinaryArithmeticOperation, TModuloExpr {
|
||||
final override string getAPrimaryQlClass() { result = "ModuloExpr" }
|
||||
}
|
||||
|
||||
@@ -184,18 +189,14 @@ class ModuloExpr extends BinaryArithmeticOperation, @binary_percent {
|
||||
* x ** 2
|
||||
* ```
|
||||
*/
|
||||
class ExponentExpr extends BinaryArithmeticOperation, @binary_starstar {
|
||||
final override ExponentExpr::Range range;
|
||||
|
||||
class ExponentExpr extends BinaryArithmeticOperation, TExponentExpr {
|
||||
final override string getAPrimaryQlClass() { result = "ExponentExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A binary logical operation.
|
||||
*/
|
||||
class BinaryLogicalOperation extends BinaryOperation {
|
||||
override BinaryLogicalOperation::Range range;
|
||||
}
|
||||
class BinaryLogicalOperation extends BinaryOperation, TBinaryLogicalOperation { }
|
||||
|
||||
/**
|
||||
* A logical AND operation, using either `and` or `&&`.
|
||||
@@ -204,9 +205,7 @@ class BinaryLogicalOperation extends BinaryOperation {
|
||||
* a && b
|
||||
* ```
|
||||
*/
|
||||
class LogicalAndExpr extends BinaryLogicalOperation, LogicalAndExpr::DbUnion {
|
||||
final override LogicalAndExpr::Range range;
|
||||
|
||||
class LogicalAndExpr extends BinaryLogicalOperation, TLogicalAndExpr {
|
||||
final override string getAPrimaryQlClass() { result = "LogicalAndExpr" }
|
||||
}
|
||||
|
||||
@@ -217,18 +216,14 @@ class LogicalAndExpr extends BinaryLogicalOperation, LogicalAndExpr::DbUnion {
|
||||
* a || b
|
||||
* ```
|
||||
*/
|
||||
class LogicalOrExpr extends BinaryLogicalOperation, LogicalOrExpr::DbUnion {
|
||||
final override LogicalOrExpr::Range range;
|
||||
|
||||
class LogicalOrExpr extends BinaryLogicalOperation, TLogicalOrExpr {
|
||||
final override string getAPrimaryQlClass() { result = "LogicalOrExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A binary bitwise operation.
|
||||
*/
|
||||
class BinaryBitwiseOperation extends BinaryOperation {
|
||||
override BinaryBitwiseOperation::Range range;
|
||||
}
|
||||
class BinaryBitwiseOperation extends BinaryOperation, TBinaryBitwiseOperation { }
|
||||
|
||||
/**
|
||||
* A left-shift operation.
|
||||
@@ -236,9 +231,7 @@ class BinaryBitwiseOperation extends BinaryOperation {
|
||||
* x << n
|
||||
* ```
|
||||
*/
|
||||
class LShiftExpr extends BinaryBitwiseOperation, @binary_langlelangle {
|
||||
final override LShiftExpr::Range range;
|
||||
|
||||
class LShiftExpr extends BinaryBitwiseOperation, TLShiftExpr {
|
||||
final override string getAPrimaryQlClass() { result = "LShiftExpr" }
|
||||
}
|
||||
|
||||
@@ -248,9 +241,7 @@ class LShiftExpr extends BinaryBitwiseOperation, @binary_langlelangle {
|
||||
* x >> n
|
||||
* ```
|
||||
*/
|
||||
class RShiftExpr extends BinaryBitwiseOperation, @binary_ranglerangle {
|
||||
final override RShiftExpr::Range range;
|
||||
|
||||
class RShiftExpr extends BinaryBitwiseOperation, TRShiftExpr {
|
||||
final override string getAPrimaryQlClass() { result = "RShiftExpr" }
|
||||
}
|
||||
|
||||
@@ -260,9 +251,7 @@ class RShiftExpr extends BinaryBitwiseOperation, @binary_ranglerangle {
|
||||
* x & 0xff
|
||||
* ```
|
||||
*/
|
||||
class BitwiseAndExpr extends BinaryBitwiseOperation, @binary_ampersand {
|
||||
final override BitwiseAndExpr::Range range;
|
||||
|
||||
class BitwiseAndExpr extends BinaryBitwiseOperation, TBitwiseAndExpr {
|
||||
final override string getAPrimaryQlClass() { result = "BitwiseAndExpr" }
|
||||
}
|
||||
|
||||
@@ -272,9 +261,7 @@ class BitwiseAndExpr extends BinaryBitwiseOperation, @binary_ampersand {
|
||||
* x | 0x01
|
||||
* ```
|
||||
*/
|
||||
class BitwiseOrExpr extends BinaryBitwiseOperation, @binary_pipe {
|
||||
final override BitwiseOrExpr::Range range;
|
||||
|
||||
class BitwiseOrExpr extends BinaryBitwiseOperation, TBitwiseOrExpr {
|
||||
final override string getAPrimaryQlClass() { result = "BitwiseOrExpr" }
|
||||
}
|
||||
|
||||
@@ -284,9 +271,7 @@ class BitwiseOrExpr extends BinaryBitwiseOperation, @binary_pipe {
|
||||
* x ^ y
|
||||
* ```
|
||||
*/
|
||||
class BitwiseXorExpr extends BinaryBitwiseOperation, @binary_caret {
|
||||
final override BitwiseXorExpr::Range range;
|
||||
|
||||
class BitwiseXorExpr extends BinaryBitwiseOperation, TBitwiseXorExpr {
|
||||
final override string getAPrimaryQlClass() { result = "BitwiseXorExpr" }
|
||||
}
|
||||
|
||||
@@ -294,16 +279,12 @@ class BitwiseXorExpr extends BinaryBitwiseOperation, @binary_caret {
|
||||
* A comparison operation. That is, either an equality operation or a
|
||||
* relational operation.
|
||||
*/
|
||||
class ComparisonOperation extends BinaryOperation {
|
||||
override ComparisonOperation::Range range;
|
||||
}
|
||||
class ComparisonOperation extends BinaryOperation, TComparisonOperation { }
|
||||
|
||||
/**
|
||||
* An equality operation.
|
||||
*/
|
||||
class EqualityOperation extends ComparisonOperation {
|
||||
override EqualityOperation::Range range;
|
||||
}
|
||||
class EqualityOperation extends ComparisonOperation, TEqualityOperation { }
|
||||
|
||||
/**
|
||||
* An equals expression.
|
||||
@@ -311,9 +292,7 @@ class EqualityOperation extends ComparisonOperation {
|
||||
* x == y
|
||||
* ```
|
||||
*/
|
||||
class EqExpr extends EqualityOperation, @binary_equalequal {
|
||||
final override EqExpr::Range range;
|
||||
|
||||
class EqExpr extends EqualityOperation, TEqExpr {
|
||||
final override string getAPrimaryQlClass() { result = "EqExpr" }
|
||||
}
|
||||
|
||||
@@ -323,9 +302,7 @@ class EqExpr extends EqualityOperation, @binary_equalequal {
|
||||
* x != y
|
||||
* ```
|
||||
*/
|
||||
class NEExpr extends EqualityOperation, @binary_bangequal {
|
||||
final override NEExpr::Range range;
|
||||
|
||||
class NEExpr extends EqualityOperation, TNEExpr {
|
||||
final override string getAPrimaryQlClass() { result = "NEExpr" }
|
||||
}
|
||||
|
||||
@@ -335,21 +312,27 @@ class NEExpr extends EqualityOperation, @binary_bangequal {
|
||||
* String === "foo"
|
||||
* ```
|
||||
*/
|
||||
class CaseEqExpr extends EqualityOperation, @binary_equalequalequal {
|
||||
final override CaseEqExpr::Range range;
|
||||
|
||||
class CaseEqExpr extends EqualityOperation, TCaseEqExpr {
|
||||
final override string getAPrimaryQlClass() { result = "CaseEqExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A relational operation, that is, one of `<=`, `<`, `>`, or `>=`.
|
||||
*/
|
||||
class RelationalOperation extends ComparisonOperation {
|
||||
override RelationalOperation::Range range;
|
||||
class RelationalOperation extends ComparisonOperation, TRelationalOperation {
|
||||
/** Gets the greater operand. */
|
||||
Expr getGreaterOperand() { none() }
|
||||
|
||||
final Expr getGreaterOperand() { result = range.getGreaterOperand() }
|
||||
/** Gets the lesser operand. */
|
||||
Expr getLesserOperand() { none() }
|
||||
|
||||
final Expr getLesserOperand() { result = range.getLesserOperand() }
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = ComparisonOperation.super.getAChild(pred)
|
||||
or
|
||||
pred = "getGreaterOperand" and result = this.getGreaterOperand()
|
||||
or
|
||||
pred = "getLesserOperand" and result = this.getLesserOperand()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,10 +341,12 @@ class RelationalOperation extends ComparisonOperation {
|
||||
* x > 0
|
||||
* ```
|
||||
*/
|
||||
class GTExpr extends RelationalOperation, @binary_rangle {
|
||||
final override GTExpr::Range range;
|
||||
|
||||
class GTExpr extends RelationalOperation, TGTExpr {
|
||||
final override string getAPrimaryQlClass() { result = "GTExpr" }
|
||||
|
||||
final override Expr getGreaterOperand() { result = this.getLeftOperand() }
|
||||
|
||||
final override Expr getLesserOperand() { result = this.getRightOperand() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -370,10 +355,12 @@ class GTExpr extends RelationalOperation, @binary_rangle {
|
||||
* x >= 0
|
||||
* ```
|
||||
*/
|
||||
class GEExpr extends RelationalOperation, @binary_rangleequal {
|
||||
final override GEExpr::Range range;
|
||||
|
||||
class GEExpr extends RelationalOperation, TGEExpr {
|
||||
final override string getAPrimaryQlClass() { result = "GEExpr" }
|
||||
|
||||
final override Expr getGreaterOperand() { result = this.getLeftOperand() }
|
||||
|
||||
final override Expr getLesserOperand() { result = this.getRightOperand() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -382,10 +369,12 @@ class GEExpr extends RelationalOperation, @binary_rangleequal {
|
||||
* x < 10
|
||||
* ```
|
||||
*/
|
||||
class LTExpr extends RelationalOperation, @binary_langle {
|
||||
final override LTExpr::Range range;
|
||||
|
||||
class LTExpr extends RelationalOperation, TLTExpr {
|
||||
final override string getAPrimaryQlClass() { result = "LTExpr" }
|
||||
|
||||
final override Expr getGreaterOperand() { result = this.getRightOperand() }
|
||||
|
||||
final override Expr getLesserOperand() { result = this.getLeftOperand() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -394,10 +383,12 @@ class LTExpr extends RelationalOperation, @binary_langle {
|
||||
* x <= 10
|
||||
* ```
|
||||
*/
|
||||
class LEExpr extends RelationalOperation, @binary_langleequal {
|
||||
final override LEExpr::Range range;
|
||||
|
||||
class LEExpr extends RelationalOperation, TLEExpr {
|
||||
final override string getAPrimaryQlClass() { result = "LEExpr" }
|
||||
|
||||
final override Expr getGreaterOperand() { result = this.getRightOperand() }
|
||||
|
||||
final override Expr getLesserOperand() { result = this.getLeftOperand() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -406,9 +397,7 @@ class LEExpr extends RelationalOperation, @binary_langleequal {
|
||||
* a <=> b
|
||||
* ```
|
||||
*/
|
||||
class SpaceshipExpr extends BinaryOperation, @binary_langleequalrangle {
|
||||
final override SpaceshipExpr::Range range;
|
||||
|
||||
class SpaceshipExpr extends BinaryOperation, TSpaceshipExpr {
|
||||
final override string getAPrimaryQlClass() { result = "SpaceshipExpr" }
|
||||
}
|
||||
|
||||
@@ -418,9 +407,7 @@ class SpaceshipExpr extends BinaryOperation, @binary_langleequalrangle {
|
||||
* input =~ /\d/
|
||||
* ```
|
||||
*/
|
||||
class RegexMatchExpr extends BinaryOperation, @binary_equaltilde {
|
||||
final override RegexMatchExpr::Range range;
|
||||
|
||||
class RegexMatchExpr extends BinaryOperation, TRegexMatchExpr {
|
||||
final override string getAPrimaryQlClass() { result = "RegexMatchExpr" }
|
||||
}
|
||||
|
||||
@@ -430,9 +417,7 @@ class RegexMatchExpr extends BinaryOperation, @binary_equaltilde {
|
||||
* input !~ /\d/
|
||||
* ```
|
||||
*/
|
||||
class NoRegexMatchExpr extends BinaryOperation, @binary_bangtilde {
|
||||
final override NoRegexMatchExpr::Range range;
|
||||
|
||||
class NoRegexMatchExpr extends BinaryOperation, TNoRegexMatchExpr {
|
||||
final override string getAPrimaryQlClass() { result = "NoRegexMatchExpr" }
|
||||
}
|
||||
|
||||
@@ -441,14 +426,26 @@ class NoRegexMatchExpr extends BinaryOperation, @binary_bangtilde {
|
||||
*
|
||||
* This is a QL base class for all assignments.
|
||||
*/
|
||||
class Assignment extends Operation {
|
||||
override Assignment::Range range;
|
||||
|
||||
class Assignment extends Operation, TAssignment {
|
||||
/** Gets the left hand side of this assignment. */
|
||||
Pattern getLeftOperand() { result = range.getLeftOperand() }
|
||||
Pattern getLeftOperand() { none() }
|
||||
|
||||
/** Gets the right hand side of this assignment. */
|
||||
final Expr getRightOperand() { result = range.getRightOperand() }
|
||||
Expr getRightOperand() { none() }
|
||||
|
||||
final override Expr getAnOperand() {
|
||||
result = this.getLeftOperand() or result = this.getRightOperand()
|
||||
}
|
||||
|
||||
final override string toString() { result = "... " + this.getOperator() + " ..." }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = Operation.super.getAChild(pred)
|
||||
or
|
||||
pred = "getLeftOperand" and result = getLeftOperand()
|
||||
or
|
||||
pred = "getRightOperand" and result = getRightOperand()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -457,8 +454,16 @@ class Assignment extends Operation {
|
||||
* x = 123
|
||||
* ```
|
||||
*/
|
||||
class AssignExpr extends Assignment {
|
||||
override AssignExpr::Range range;
|
||||
class AssignExpr extends Assignment, TAssignExpr {
|
||||
private Generated::Assignment g;
|
||||
|
||||
AssignExpr() { this = TAssignExpr(g) }
|
||||
|
||||
final override Pattern getLeftOperand() { toGenerated(result) = g.getLeft() }
|
||||
|
||||
final override Expr getRightOperand() { toGenerated(result) = g.getRight() }
|
||||
|
||||
final override string getOperator() { result = "=" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AssignExpr" }
|
||||
}
|
||||
@@ -466,16 +471,22 @@ class AssignExpr extends Assignment {
|
||||
/**
|
||||
* A binary assignment operation other than `=`.
|
||||
*/
|
||||
class AssignOperation extends Assignment {
|
||||
override AssignOperation::Range range;
|
||||
class AssignOperation extends Assignment, TAssignOperation {
|
||||
private Generated::OperatorAssignment g;
|
||||
|
||||
AssignOperation() { g = toGenerated(this) }
|
||||
|
||||
final override string getOperator() { result = g.getOperator() }
|
||||
|
||||
final override LhsExpr getLeftOperand() { toGenerated(result) = g.getLeft() }
|
||||
|
||||
final override Expr getRightOperand() { toGenerated(result) = g.getRight() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An arithmetic assignment operation: `+=`, `-=`, `*=`, `/=`, `**=`, and `%=`.
|
||||
*/
|
||||
class AssignArithmeticOperation extends AssignOperation {
|
||||
override AssignArithmeticOperation::Range range;
|
||||
}
|
||||
class AssignArithmeticOperation extends AssignOperation, TAssignArithmeticOperation { }
|
||||
|
||||
/**
|
||||
* A `+=` assignment expression.
|
||||
@@ -483,9 +494,7 @@ class AssignArithmeticOperation extends AssignOperation {
|
||||
* x += 1
|
||||
* ```
|
||||
*/
|
||||
class AssignAddExpr extends AssignArithmeticOperation, @operator_assignment_plusequal {
|
||||
final override AssignAddExpr::Range range;
|
||||
|
||||
class AssignAddExpr extends AssignArithmeticOperation, TAssignAddExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AssignAddExpr" }
|
||||
}
|
||||
|
||||
@@ -495,9 +504,7 @@ class AssignAddExpr extends AssignArithmeticOperation, @operator_assignment_plus
|
||||
* x -= 3
|
||||
* ```
|
||||
*/
|
||||
class AssignSubExpr extends AssignArithmeticOperation, @operator_assignment_minusequal {
|
||||
final override AssignSubExpr::Range range;
|
||||
|
||||
class AssignSubExpr extends AssignArithmeticOperation, TAssignSubExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AssignSubExpr" }
|
||||
}
|
||||
|
||||
@@ -507,9 +514,7 @@ class AssignSubExpr extends AssignArithmeticOperation, @operator_assignment_minu
|
||||
* x *= 10
|
||||
* ```
|
||||
*/
|
||||
class AssignMulExpr extends AssignArithmeticOperation, @operator_assignment_starequal {
|
||||
final override AssignMulExpr::Range range;
|
||||
|
||||
class AssignMulExpr extends AssignArithmeticOperation, TAssignMulExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AssignMulExpr" }
|
||||
}
|
||||
|
||||
@@ -519,9 +524,7 @@ class AssignMulExpr extends AssignArithmeticOperation, @operator_assignment_star
|
||||
* x /= y
|
||||
* ```
|
||||
*/
|
||||
class AssignDivExpr extends AssignArithmeticOperation, @operator_assignment_slashequal {
|
||||
final override AssignDivExpr::Range range;
|
||||
|
||||
class AssignDivExpr extends AssignArithmeticOperation, TAssignDivExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AssignDivExpr" }
|
||||
}
|
||||
|
||||
@@ -531,9 +534,7 @@ class AssignDivExpr extends AssignArithmeticOperation, @operator_assignment_slas
|
||||
* x %= 4
|
||||
* ```
|
||||
*/
|
||||
class AssignModuloExpr extends AssignArithmeticOperation, @operator_assignment_percentequal {
|
||||
final override AssignModuloExpr::Range range;
|
||||
|
||||
class AssignModuloExpr extends AssignArithmeticOperation, TAssignModuloExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AssignModuloExpr" }
|
||||
}
|
||||
|
||||
@@ -543,20 +544,14 @@ class AssignModuloExpr extends AssignArithmeticOperation, @operator_assignment_p
|
||||
* x **= 2
|
||||
* ```
|
||||
*/
|
||||
class AssignExponentExpr extends AssignArithmeticOperation, @operator_assignment_starstarequal {
|
||||
final override AssignExponentExpr::Range range;
|
||||
|
||||
class AssignExponentExpr extends AssignArithmeticOperation, TAssignExponentExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AssignExponentExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A logical assignment operation: `&&=` and `||=`.
|
||||
*/
|
||||
class AssignLogicalOperation extends AssignOperation {
|
||||
override AssignLogicalOperation::Range range;
|
||||
|
||||
final override LhsExpr getLeftOperand() { result = super.getLeftOperand() }
|
||||
}
|
||||
class AssignLogicalOperation extends AssignOperation, TAssignLogicalOperation { }
|
||||
|
||||
/**
|
||||
* A logical AND assignment operation.
|
||||
@@ -564,10 +559,7 @@ class AssignLogicalOperation extends AssignOperation {
|
||||
* x &&= y.even?
|
||||
* ```
|
||||
*/
|
||||
class AssignLogicalAndExpr extends AssignLogicalOperation,
|
||||
@operator_assignment_ampersandampersandequal {
|
||||
final override AssignLogicalAndExpr::Range range;
|
||||
|
||||
class AssignLogicalAndExpr extends AssignLogicalOperation, TAssignLogicalAndExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AssignLogicalAndExpr" }
|
||||
}
|
||||
|
||||
@@ -577,18 +569,14 @@ class AssignLogicalAndExpr extends AssignLogicalOperation,
|
||||
* x ||= y
|
||||
* ```
|
||||
*/
|
||||
class AssignLogicalOrExpr extends AssignLogicalOperation, @operator_assignment_pipepipeequal {
|
||||
final override AssignLogicalOrExpr::Range range;
|
||||
|
||||
class AssignLogicalOrExpr extends AssignLogicalOperation, TAssignLogicalOrExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AssignLogicalOrExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A bitwise assignment operation: `<<=`, `>>=`, `&=`, `|=` and `^=`.
|
||||
*/
|
||||
class AssignBitwiseOperation extends AssignOperation {
|
||||
override AssignBitwiseOperation::Range range;
|
||||
}
|
||||
class AssignBitwiseOperation extends AssignOperation, TAssignBitwiseOperation { }
|
||||
|
||||
/**
|
||||
* A left-shift assignment operation.
|
||||
@@ -596,9 +584,7 @@ class AssignBitwiseOperation extends AssignOperation {
|
||||
* x <<= 3
|
||||
* ```
|
||||
*/
|
||||
class AssignLShiftExpr extends AssignBitwiseOperation, @operator_assignment_langlelangleequal {
|
||||
final override AssignLShiftExpr::Range range;
|
||||
|
||||
class AssignLShiftExpr extends AssignBitwiseOperation, TAssignLShiftExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AssignLShiftExpr" }
|
||||
}
|
||||
|
||||
@@ -608,9 +594,7 @@ class AssignLShiftExpr extends AssignBitwiseOperation, @operator_assignment_lang
|
||||
* x >>= 3
|
||||
* ```
|
||||
*/
|
||||
class AssignRShiftExpr extends AssignBitwiseOperation, @operator_assignment_ranglerangleequal {
|
||||
final override AssignRShiftExpr::Range range;
|
||||
|
||||
class AssignRShiftExpr extends AssignBitwiseOperation, TAssignRShiftExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AssignRShiftExpr" }
|
||||
}
|
||||
|
||||
@@ -620,9 +604,7 @@ class AssignRShiftExpr extends AssignBitwiseOperation, @operator_assignment_rang
|
||||
* x &= 0xff
|
||||
* ```
|
||||
*/
|
||||
class AssignBitwiseAndExpr extends AssignBitwiseOperation, @operator_assignment_ampersandequal {
|
||||
final override AssignBitwiseAndExpr::Range range;
|
||||
|
||||
class AssignBitwiseAndExpr extends AssignBitwiseOperation, TAssignBitwiseAndExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AssignBitwiseAndExpr" }
|
||||
}
|
||||
|
||||
@@ -632,9 +614,7 @@ class AssignBitwiseAndExpr extends AssignBitwiseOperation, @operator_assignment_
|
||||
* x |= 0x01
|
||||
* ```
|
||||
*/
|
||||
class AssignBitwiseOrExpr extends AssignBitwiseOperation, @operator_assignment_pipeequal {
|
||||
final override AssignBitwiseOrExpr::Range range;
|
||||
|
||||
class AssignBitwiseOrExpr extends AssignBitwiseOperation, TAssignBitwiseOrExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AssignBitwiseOrExpr" }
|
||||
}
|
||||
|
||||
@@ -644,8 +624,6 @@ class AssignBitwiseOrExpr extends AssignBitwiseOperation, @operator_assignment_p
|
||||
* x ^= y
|
||||
* ```
|
||||
*/
|
||||
class AssignBitwiseXorExpr extends AssignBitwiseOperation, @operator_assignment_caretequal {
|
||||
final override AssignBitwiseXorExpr::Range range;
|
||||
|
||||
class AssignBitwiseXorExpr extends AssignBitwiseOperation, TAssignBitwiseXorExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AssignBitwiseXorExpr" }
|
||||
}
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
private import codeql_ruby.AST
|
||||
private import internal.Pattern
|
||||
private import internal.AST
|
||||
private import internal.Variable
|
||||
private import internal.Parameter
|
||||
private import internal.TreeSitter
|
||||
|
||||
/** A parameter. */
|
||||
class Parameter extends AstNode {
|
||||
override Parameter::Range range;
|
||||
|
||||
class Parameter extends AstNode, TParameter {
|
||||
/** Gets the callable that this parameter belongs to. */
|
||||
final Callable getCallable() { result.getAParameter() = this }
|
||||
|
||||
/** Gets the zero-based position of this parameter. */
|
||||
final int getPosition() { result = range.getPosition() }
|
||||
final int getPosition() { this = any(Callable c).getParameter(result) }
|
||||
|
||||
/** Gets a variable introduced by this parameter. */
|
||||
LocalVariable getAVariable() { result = range.getAVariable() }
|
||||
LocalVariable getAVariable() { none() }
|
||||
|
||||
/** Gets the variable named `name` introduced by this parameter. */
|
||||
final LocalVariable getVariable(string name) {
|
||||
@@ -28,44 +27,61 @@ class Parameter extends AstNode {
|
||||
*
|
||||
* This includes both simple parameters and tuple parameters.
|
||||
*/
|
||||
class PatternParameter extends Parameter, Pattern {
|
||||
override PatternParameter::Range range;
|
||||
|
||||
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 {
|
||||
override TuplePatternParameter::Range range;
|
||||
class TuplePatternParameter extends PatternParameter, TuplePattern, TTuplePatternParameter {
|
||||
final override LocalVariable getAVariable() { result = TuplePattern.super.getAVariable() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "TuplePatternParameter" }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = PatternParameter.super.getAChild(pred) or
|
||||
result = TuplePattern.super.getAChild(pred)
|
||||
}
|
||||
}
|
||||
|
||||
/** A named parameter. */
|
||||
class NamedParameter extends Parameter {
|
||||
override NamedParameter::Range range;
|
||||
|
||||
class NamedParameter extends Parameter, TNamedParameter {
|
||||
/** Gets the name of this parameter. */
|
||||
final string getName() { result = range.getName() }
|
||||
string getName() { none() }
|
||||
|
||||
/** Gets the variable introduced by this parameter. */
|
||||
LocalVariable getVariable() { result = range.getVariable() }
|
||||
LocalVariable getVariable() { none() }
|
||||
|
||||
override LocalVariable getAVariable() { result = this.getVariable() }
|
||||
|
||||
/** Gets an access to this parameter. */
|
||||
final VariableAccess getAnAccess() { result = this.getVariable().getAnAccess() }
|
||||
|
||||
/** Gets the access that defines the underlying local variable. */
|
||||
final VariableAccess getDefiningAccess() { result = this.getVariable().getDefiningAccess() }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = Parameter.super.getAChild(pred)
|
||||
or
|
||||
pred = "getDefiningAccess" and
|
||||
result = this.getDefiningAccess()
|
||||
}
|
||||
}
|
||||
|
||||
/** A simple (normal) parameter. */
|
||||
class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern {
|
||||
override SimpleParameter::Range range;
|
||||
class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern, TSimpleParameter {
|
||||
private Generated::Identifier g;
|
||||
|
||||
final override LocalVariable getVariable() { result = range.getVariable() }
|
||||
SimpleParameter() { this = TSimpleParameter(g) }
|
||||
|
||||
final override LocalVariable getAVariable() { result = range.getAVariable() }
|
||||
final override string getName() { result = g.getValue() }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g) }
|
||||
|
||||
final override LocalVariable getAVariable() { result = this.getVariable() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "SimpleParameter" }
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,10 +92,16 @@ class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class BlockParameter extends @block_parameter, NamedParameter {
|
||||
final override BlockParameter::Range range;
|
||||
class BlockParameter extends NamedParameter, TBlockParameter {
|
||||
private Generated::BlockParameter g;
|
||||
|
||||
final override LocalVariable getVariable() { result = range.getVariable() }
|
||||
BlockParameter() { this = TBlockParameter(g) }
|
||||
|
||||
final override string getName() { result = g.getName().getValue() }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
|
||||
|
||||
final override string toString() { result = "&" + this.getName() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "BlockParameter" }
|
||||
}
|
||||
@@ -93,10 +115,18 @@ class BlockParameter extends @block_parameter, NamedParameter {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class HashSplatParameter extends @hash_splat_parameter, NamedParameter {
|
||||
final override HashSplatParameter::Range range;
|
||||
class HashSplatParameter extends NamedParameter, THashSplatParameter {
|
||||
private Generated::HashSplatParameter g;
|
||||
|
||||
HashSplatParameter() { this = THashSplatParameter(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "HashSplatParameter" }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
|
||||
|
||||
final override string toString() { result = "**" + this.getName() }
|
||||
|
||||
final override string getName() { result = g.getName().getValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,23 +140,39 @@ class HashSplatParameter extends @hash_splat_parameter, NamedParameter {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class KeywordParameter extends @keyword_parameter, NamedParameter {
|
||||
final override KeywordParameter::Range range;
|
||||
class KeywordParameter extends NamedParameter, TKeywordParameter {
|
||||
private Generated::KeywordParameter g;
|
||||
|
||||
KeywordParameter() { this = TKeywordParameter(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "KeywordParameter" }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
|
||||
|
||||
/**
|
||||
* Gets the default value, i.e. the value assigned to the parameter when one
|
||||
* is not provided by the caller. If the parameter is mandatory and does not
|
||||
* have a default value, this predicate has no result.
|
||||
*/
|
||||
final Expr getDefaultValue() { result = range.getDefaultValue() }
|
||||
final Expr getDefaultValue() { toGenerated(result) = g.getValue() }
|
||||
|
||||
/**
|
||||
* Holds if the parameter is optional. That is, there is a default value that
|
||||
* is used when the caller omits this parameter.
|
||||
*/
|
||||
final predicate isOptional() { exists(this.getDefaultValue()) }
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
|
||||
final override string getName() { result = g.getName().getValue() }
|
||||
|
||||
final override Location getLocation() { result = g.getName().getLocation() }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = NamedParameter.super.getAChild(pred)
|
||||
or
|
||||
pred = "getDefaultValue" and result = this.getDefaultValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,8 +184,10 @@ class KeywordParameter extends @keyword_parameter, NamedParameter {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class OptionalParameter extends @optional_parameter, NamedParameter {
|
||||
final override OptionalParameter::Range range;
|
||||
class OptionalParameter extends NamedParameter, TOptionalParameter {
|
||||
private Generated::OptionalParameter g;
|
||||
|
||||
OptionalParameter() { this = TOptionalParameter(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "OptionalParameter" }
|
||||
|
||||
@@ -147,7 +195,21 @@ class OptionalParameter extends @optional_parameter, NamedParameter {
|
||||
* Gets the default value, i.e. the value assigned to the parameter when one
|
||||
* is not provided by the caller.
|
||||
*/
|
||||
final Expr getDefaultValue() { result = range.getDefaultValue() }
|
||||
final Expr getDefaultValue() { toGenerated(result) = g.getValue() }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
|
||||
final override string getName() { result = g.getName().getValue() }
|
||||
|
||||
final override Location getLocation() { result = g.getName().getLocation() }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = NamedParameter.super.getAChild(pred)
|
||||
or
|
||||
pred = "getDefaultValue" and result = this.getDefaultValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,8 +220,16 @@ class OptionalParameter extends @optional_parameter, NamedParameter {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class SplatParameter extends @splat_parameter, NamedParameter {
|
||||
final override SplatParameter::Range range;
|
||||
class SplatParameter extends NamedParameter, TSplatParameter {
|
||||
private Generated::SplatParameter g;
|
||||
|
||||
SplatParameter() { this = TSplatParameter(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "SplatParameter" }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
|
||||
|
||||
final override string toString() { result = "*" + this.getName() }
|
||||
|
||||
final override string getName() { result = g.getName().getValue() }
|
||||
}
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql.Locations
|
||||
private import internal.Pattern
|
||||
private import internal.AST
|
||||
private import internal.TreeSitter
|
||||
private import internal.Variable
|
||||
|
||||
/** A pattern. */
|
||||
class Pattern extends AstNode {
|
||||
override Pattern::Range range;
|
||||
|
||||
Pattern() { range = this }
|
||||
Pattern() {
|
||||
explicitAssignmentNode(toGenerated(this), _) or
|
||||
implicitAssignmentNode(toGenerated(this)) or
|
||||
implicitParameterAssignmentNode(toGenerated(this), _)
|
||||
}
|
||||
|
||||
/** Gets a variable used in (or introduced by) this pattern. */
|
||||
Variable getAVariable() { result = range.getAVariable() }
|
||||
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
|
||||
@@ -29,17 +36,14 @@ class Pattern extends AstNode {
|
||||
* rescue E => var
|
||||
* ```
|
||||
*/
|
||||
class LhsExpr extends Pattern, Expr {
|
||||
override LhsExpr::Range range;
|
||||
class LhsExpr extends Pattern, LhsExpr_, Expr {
|
||||
override Variable getAVariable() { result = this.(VariableAccess).getVariable() }
|
||||
}
|
||||
|
||||
private class TVariablePattern = TVariableAccess or TSimpleParameter;
|
||||
|
||||
/** A simple variable pattern. */
|
||||
class VariablePattern extends Pattern, VariablePattern::VariableToken {
|
||||
override VariablePattern::Range range;
|
||||
|
||||
/** Gets the variable used in (or introduced by) this pattern. */
|
||||
Variable getVariable() { access(this, result) }
|
||||
}
|
||||
class VariablePattern extends Pattern, LhsExpr, TVariablePattern { }
|
||||
|
||||
/**
|
||||
* A tuple pattern.
|
||||
@@ -51,13 +55,32 @@ class VariablePattern extends Pattern, VariablePattern::VariableToken {
|
||||
* a, b, *rest, c, d = value
|
||||
* ```
|
||||
*/
|
||||
class TuplePattern extends Pattern {
|
||||
override TuplePattern::Range range;
|
||||
|
||||
class TuplePattern extends Pattern, TTuplePattern {
|
||||
override string getAPrimaryQlClass() { result = "TuplePattern" }
|
||||
|
||||
private Generated::AstNode getChild(int i) {
|
||||
result = toGenerated(this).(Generated::DestructuredParameter).getChild(i)
|
||||
or
|
||||
result = toGenerated(this).(Generated::DestructuredLeftAssignment).getChild(i)
|
||||
or
|
||||
toGenerated(this) =
|
||||
any(Generated::LeftAssignmentList lal |
|
||||
if
|
||||
strictcount(int j | exists(lal.getChild(j))) = 1 and
|
||||
lal.getChild(0) instanceof Generated::DestructuredLeftAssignment
|
||||
then result = lal.getChild(0).(Generated::DestructuredLeftAssignment).getChild(i)
|
||||
else result = lal.getChild(i)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `i`th pattern in this tuple pattern. */
|
||||
final Pattern getElement(int i) { result = range.getElement(i) }
|
||||
final Pattern getElement(int i) {
|
||||
exists(Generated::AstNode c | c = this.getChild(i) |
|
||||
toGenerated(result) = c.(Generated::RestAssignment).getChild()
|
||||
or
|
||||
toGenerated(result) = c
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a sub pattern in this tuple pattern. */
|
||||
final Pattern getAnElement() { result = this.getElement(_) }
|
||||
@@ -69,5 +92,13 @@ class TuplePattern extends Pattern {
|
||||
* a, b, *rest, c, d = value
|
||||
* ```
|
||||
*/
|
||||
final int getRestIndex() { result = range.getRestIndex() }
|
||||
final int getRestIndex() {
|
||||
result = unique(int i | getChild(i) instanceof Generated::RestAssignment)
|
||||
}
|
||||
|
||||
override Variable getAVariable() { result = this.getElement(_).getAVariable() }
|
||||
|
||||
override string toString() { result = "(..., ...)" }
|
||||
|
||||
override AstNode getAChild(string pred) { pred = "getElement" and result = getElement(_) }
|
||||
}
|
||||
|
||||
28
ql/src/codeql_ruby/ast/Scope.qll
Normal file
28
ql/src/codeql_ruby/ast/Scope.qll
Normal file
@@ -0,0 +1,28 @@
|
||||
private import codeql_ruby.AST
|
||||
private import internal.AST
|
||||
private import internal.Scope
|
||||
private import internal.TreeSitter
|
||||
|
||||
class Scope extends AstNode, TScopeType {
|
||||
private Scope::Range range;
|
||||
|
||||
Scope() { range = toGenerated(this) }
|
||||
|
||||
/** Gets the enclosing module, if any. */
|
||||
ModuleBase getEnclosingModule() { toGenerated(result) = range.getEnclosingModule() }
|
||||
|
||||
/** Gets the enclosing method, if any. */
|
||||
MethodBase getEnclosingMethod() { toGenerated(result) = range.getEnclosingMethod() }
|
||||
|
||||
/** Gets the scope in which this scope is nested, if any. */
|
||||
Scope getOuterScope() { toGenerated(result) = range.getOuterScope() }
|
||||
|
||||
/** Gets a variable that is declared in this scope. */
|
||||
final Variable getAVariable() { result.getDeclaringScope() = this }
|
||||
|
||||
/** Gets the variable declared in this scope with the given name, if any. */
|
||||
final Variable getVariable(string name) {
|
||||
result = this.getAVariable() and
|
||||
result.getName() = name
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.CFG
|
||||
private import internal.Expr
|
||||
private import internal.Statement
|
||||
private import internal.AST
|
||||
private import internal.TreeSitter
|
||||
private import internal.Variable
|
||||
private import codeql_ruby.controlflow.internal.ControlFlowGraphImpl
|
||||
|
||||
@@ -10,18 +10,13 @@ private import codeql_ruby.controlflow.internal.ControlFlowGraphImpl
|
||||
*
|
||||
* This is the root QL class for all statements.
|
||||
*/
|
||||
class Stmt extends AstNode {
|
||||
override Stmt::Range range;
|
||||
|
||||
class Stmt extends AstNode, TStmt {
|
||||
/** Gets a control-flow node for this statement, if any. */
|
||||
CfgNodes::AstCfgNode getAControlFlowNode() { result.getNode() = this }
|
||||
|
||||
/** Gets the control-flow scope of this statement, if any. */
|
||||
CfgScope getCfgScope() { result = getCfgScope(this) }
|
||||
|
||||
/** Gets the variable scope that this statement belongs to. */
|
||||
VariableScope getVariableScope() { result = enclosingScope(this) }
|
||||
|
||||
/** Gets the enclosing callable, if any. */
|
||||
Callable getEnclosingCallable() { result = this.getCfgScope() }
|
||||
}
|
||||
@@ -29,10 +24,10 @@ class Stmt extends AstNode {
|
||||
/**
|
||||
* An empty statement (`;`).
|
||||
*/
|
||||
class EmptyStmt extends Stmt, @token_empty_statement {
|
||||
final override EmptyStmt::Range range;
|
||||
|
||||
class EmptyStmt extends Stmt, TEmptyStmt {
|
||||
final override string getAPrimaryQlClass() { result = "EmptyStmt" }
|
||||
|
||||
final override string toString() { result = ";" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,10 +38,10 @@ class EmptyStmt extends Stmt, @token_empty_statement {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class BeginExpr extends BodyStatement, @begin {
|
||||
final override Begin::Range range;
|
||||
|
||||
class BeginExpr extends BodyStmt, TBeginExpr {
|
||||
final override string getAPrimaryQlClass() { result = "BeginExpr" }
|
||||
|
||||
final override string toString() { result = "begin ... " }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,10 +50,16 @@ class BeginExpr extends BodyStatement, @begin {
|
||||
* BEGIN { puts "starting ..." }
|
||||
* ```
|
||||
*/
|
||||
class BeginBlock extends StmtSequence, @begin_block {
|
||||
final override BeginBlock::Range range;
|
||||
class BeginBlock extends StmtSequence, TBeginBlock {
|
||||
private Generated::BeginBlock g;
|
||||
|
||||
BeginBlock() { this = TBeginBlock(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "BeginBlock" }
|
||||
|
||||
final override string toString() { result = "BEGIN { ... }" }
|
||||
|
||||
final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,10 +68,16 @@ class BeginBlock extends StmtSequence, @begin_block {
|
||||
* END { puts "shutting down" }
|
||||
* ```
|
||||
*/
|
||||
class EndBlock extends StmtSequence, @end_block {
|
||||
final override EndBlock::Range range;
|
||||
class EndBlock extends StmtSequence, TEndBlock {
|
||||
private Generated::EndBlock g;
|
||||
|
||||
EndBlock() { this = TEndBlock(g) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "EndBlock" }
|
||||
|
||||
final override string toString() { result = "END { ... }" }
|
||||
|
||||
final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,16 +88,24 @@ class EndBlock extends StmtSequence, @end_block {
|
||||
* - undef :"method_#{ name }"
|
||||
* ```
|
||||
*/
|
||||
class UndefStmt extends Stmt, @undef {
|
||||
final override UndefStmt::Range range;
|
||||
class UndefStmt extends Stmt, TUndefStmt {
|
||||
private Generated::Undef g;
|
||||
|
||||
UndefStmt() { this = TUndefStmt(g) }
|
||||
|
||||
/** Gets the `n`th method name to undefine. */
|
||||
final MethodName getMethodName(int n) { result = range.getMethodName(n) }
|
||||
final MethodName getMethodName(int n) { toGenerated(result) = g.getChild(n) }
|
||||
|
||||
/** Gets a method name to undefine. */
|
||||
final MethodName getAMethodName() { result = getMethodName(_) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "UndefStmt" }
|
||||
|
||||
final override string toString() { result = "undef ..." }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
pred = "getMethodName" and result = this.getMethodName(_)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,16 +116,26 @@ class UndefStmt extends Stmt, @undef {
|
||||
* - alias bar :"method_#{ name }"
|
||||
* ```
|
||||
*/
|
||||
class AliasStmt extends Stmt, @alias {
|
||||
final override AliasStmt::Range range;
|
||||
class AliasStmt extends Stmt, TAliasStmt {
|
||||
private Generated::Alias g;
|
||||
|
||||
AliasStmt() { this = TAliasStmt(g) }
|
||||
|
||||
/** Gets the new method name. */
|
||||
final MethodName getNewName() { result = range.getNewName() }
|
||||
final MethodName getNewName() { toGenerated(result) = g.getName() }
|
||||
|
||||
/** Gets the original method name. */
|
||||
final MethodName getOldName() { result = range.getOldName() }
|
||||
final MethodName getOldName() { toGenerated(result) = g.getAlias() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "AliasStmt" }
|
||||
|
||||
final override string toString() { result = "alias ..." }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
pred = "getNewName" and result = this.getNewName()
|
||||
or
|
||||
pred = "getOldName" and result = this.getOldName()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,11 +150,30 @@ class AliasStmt extends Stmt, @alias {
|
||||
* next value
|
||||
* ```
|
||||
*/
|
||||
class ReturningStmt extends Stmt {
|
||||
override ReturningStmt::Range range;
|
||||
class ReturningStmt extends Stmt, TReturningStmt {
|
||||
private Generated::ArgumentList getArgumentList() {
|
||||
result = any(Generated::Return g | this = TReturnStmt(g)).getChild()
|
||||
or
|
||||
result = any(Generated::Break g | this = TBreakStmt(g)).getChild()
|
||||
or
|
||||
result = any(Generated::Next g | this = TNextStmt(g)).getChild()
|
||||
}
|
||||
|
||||
/** Gets the returned value, if any. */
|
||||
final Expr getValue() { result = range.getValue() }
|
||||
final Expr getValue() {
|
||||
toGenerated(result) =
|
||||
any(Generated::AstNode res |
|
||||
exists(Generated::ArgumentList a, int c |
|
||||
a = this.getArgumentList() and c = count(a.getChild(_))
|
||||
|
|
||||
res = a.getChild(0) and c = 1
|
||||
or
|
||||
res = a and c > 1
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override AstNode getAChild(string pred) { pred = "getValue" and result = this.getValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,10 +183,10 @@ class ReturningStmt extends Stmt {
|
||||
* return value
|
||||
* ```
|
||||
*/
|
||||
class ReturnStmt extends ReturningStmt, @return {
|
||||
final override ReturnStmt::Range range;
|
||||
|
||||
class ReturnStmt extends ReturningStmt, TReturnStmt {
|
||||
final override string getAPrimaryQlClass() { result = "ReturnStmt" }
|
||||
|
||||
final override string toString() { result = "return" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,10 +196,10 @@ class ReturnStmt extends ReturningStmt, @return {
|
||||
* break value
|
||||
* ```
|
||||
*/
|
||||
class BreakStmt extends ReturningStmt, @break {
|
||||
final override BreakStmt::Range range;
|
||||
|
||||
class BreakStmt extends ReturningStmt, TBreakStmt {
|
||||
final override string getAPrimaryQlClass() { result = "BreakStmt" }
|
||||
|
||||
final override string toString() { result = "break" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,10 +209,10 @@ class BreakStmt extends ReturningStmt, @break {
|
||||
* next value
|
||||
* ```
|
||||
*/
|
||||
class NextStmt extends ReturningStmt, @next {
|
||||
final override NextStmt::Range range;
|
||||
|
||||
class NextStmt extends ReturningStmt, TNextStmt {
|
||||
final override string getAPrimaryQlClass() { result = "NextStmt" }
|
||||
|
||||
final override string toString() { result = "next" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,10 +221,10 @@ class NextStmt extends ReturningStmt, @next {
|
||||
* redo
|
||||
* ```
|
||||
*/
|
||||
class RedoStmt extends Stmt, @redo {
|
||||
final override RedoStmt::Range range;
|
||||
|
||||
class RedoStmt extends Stmt, TRedoStmt {
|
||||
final override string getAPrimaryQlClass() { result = "RedoStmt" }
|
||||
|
||||
final override string toString() { result = "redo" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,8 +233,8 @@ class RedoStmt extends Stmt, @redo {
|
||||
* retry
|
||||
* ```
|
||||
*/
|
||||
class RetryStmt extends Stmt, @retry {
|
||||
final override RetryStmt::Range range;
|
||||
|
||||
class RetryStmt extends Stmt, TRetryStmt {
|
||||
final override string getAPrimaryQlClass() { result = "RetryStmt" }
|
||||
|
||||
final override string toString() { result = "retry" }
|
||||
}
|
||||
|
||||
@@ -2,36 +2,10 @@
|
||||
|
||||
private import codeql_ruby.AST
|
||||
private import codeql.Locations
|
||||
private import internal.AST
|
||||
private import internal.TreeSitter
|
||||
private import internal.Variable
|
||||
|
||||
/** A scope in which variables can be declared. */
|
||||
class VariableScope extends TScope {
|
||||
VariableScope::Range range;
|
||||
|
||||
VariableScope() { range = this }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = range.toString() }
|
||||
|
||||
/** Gets the program element this scope is associated with, if any. */
|
||||
final AstNode getScopeElement() { result = range.getScopeElement() }
|
||||
|
||||
/** Gets the location of the program element this scope is associated with. */
|
||||
final Location getLocation() { result = getScopeElement().getLocation() }
|
||||
|
||||
/** Gets a variable that is declared in this scope. */
|
||||
final Variable getAVariable() { result.getDeclaringScope() = this }
|
||||
|
||||
/** Gets the variable with the given name that is declared in this scope. */
|
||||
final Variable getVariable(string name) {
|
||||
result = this.getAVariable() and
|
||||
result.getName() = name
|
||||
}
|
||||
|
||||
/** Gets the scope in which this scope is nested, if any. */
|
||||
VariableScope getOuterScope() { result = enclosingScope(this.getScopeElement()) }
|
||||
}
|
||||
|
||||
/** A variable declared in a scope. */
|
||||
class Variable extends TVariable {
|
||||
Variable::Range range;
|
||||
@@ -48,7 +22,7 @@ class Variable extends TVariable {
|
||||
final Location getLocation() { result = range.getLocation() }
|
||||
|
||||
/** Gets the scope this variable is declared in. */
|
||||
final VariableScope getDeclaringScope() { result = range.getDeclaringScope() }
|
||||
final Scope getDeclaringScope() { toGenerated(result) = range.getDeclaringScope() }
|
||||
|
||||
/** Gets an access to this variable. */
|
||||
VariableAccess getAnAccess() { result.getVariable() = this }
|
||||
@@ -105,11 +79,9 @@ class ClassVariable extends Variable, TClassVariable {
|
||||
}
|
||||
|
||||
/** An access to a variable. */
|
||||
class VariableAccess extends Expr {
|
||||
override VariableAccess::Range range;
|
||||
|
||||
class VariableAccess extends Expr, TVariableAccess {
|
||||
/** Gets the variable this identifier refers to. */
|
||||
Variable getVariable() { result = range.getVariable() }
|
||||
Variable getVariable() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this access is a write access belonging to the explicit
|
||||
@@ -121,7 +93,9 @@ class VariableAccess extends Expr {
|
||||
*
|
||||
* both `a` and `b` are write accesses belonging to the same assignment.
|
||||
*/
|
||||
predicate isExplicitWrite(AstNode assignment) { range.isExplicitWrite(assignment) }
|
||||
predicate isExplicitWrite(AstNode assignment) {
|
||||
explicitWriteAccess(toGenerated(this), toGenerated(assignment))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this access is a write access belonging to an implicit assignment.
|
||||
@@ -138,7 +112,7 @@ class VariableAccess extends Expr {
|
||||
* the access to `elements` in the parameter list is an implicit assignment,
|
||||
* as is the first access to `e`.
|
||||
*/
|
||||
predicate isImplicitWrite() { range.isImplicitWrite() }
|
||||
predicate isImplicitWrite() { implicitWriteAccess(toGenerated(this)) }
|
||||
}
|
||||
|
||||
/** An access to a variable where the value is updated. */
|
||||
@@ -160,14 +134,15 @@ class VariableReadAccess extends VariableAccess {
|
||||
}
|
||||
|
||||
/** An access to a local variable. */
|
||||
class LocalVariableAccess extends VariableAccess, LocalVariableAccess::LocalVariableRange {
|
||||
final override LocalVariableAccess::Range range;
|
||||
class LocalVariableAccess extends VariableAccess, TLocalVariableAccess {
|
||||
private Generated::Identifier g;
|
||||
private LocalVariable v;
|
||||
|
||||
final override LocalVariable getVariable() { result = range.getVariable() }
|
||||
LocalVariableAccess() { this = TLocalVariableAccess(g, v) }
|
||||
|
||||
final override string getAPrimaryQlClass() {
|
||||
not this instanceof NamedParameter and result = "LocalVariableAccess"
|
||||
}
|
||||
final override LocalVariable getVariable() { result = v }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "LocalVariableAccess" }
|
||||
|
||||
/**
|
||||
* Holds if this access is a captured variable access. For example in
|
||||
@@ -185,6 +160,8 @@ class LocalVariableAccess extends VariableAccess, LocalVariableAccess::LocalVari
|
||||
* the access to `x` in the second `puts x` is not.
|
||||
*/
|
||||
final predicate isCapturedAccess() { isCapturedAccess(this) }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
}
|
||||
|
||||
/** An access to a local variable where the value is updated. */
|
||||
@@ -194,12 +171,17 @@ class LocalVariableWriteAccess extends LocalVariableAccess, VariableWriteAccess
|
||||
class LocalVariableReadAccess extends LocalVariableAccess, VariableReadAccess { }
|
||||
|
||||
/** An access to a global variable. */
|
||||
class GlobalVariableAccess extends VariableAccess, @token_global_variable {
|
||||
final override GlobalVariableAccess::Range range;
|
||||
class GlobalVariableAccess extends VariableAccess, TGlobalVariableAccess {
|
||||
private Generated::GlobalVariable g;
|
||||
private GlobalVariable v;
|
||||
|
||||
final override GlobalVariable getVariable() { result = range.getVariable() }
|
||||
GlobalVariableAccess() { this = TGlobalVariableAccess(g, v) }
|
||||
|
||||
final override GlobalVariable getVariable() { result = v }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "GlobalVariableAccess" }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
}
|
||||
|
||||
/** An access to a global variable where the value is updated. */
|
||||
@@ -209,19 +191,29 @@ class GlobalVariableWriteAccess extends GlobalVariableAccess, VariableWriteAcces
|
||||
class GlobalVariableReadAccess extends GlobalVariableAccess, VariableReadAccess { }
|
||||
|
||||
/** An access to an instance variable. */
|
||||
class InstanceVariableAccess extends VariableAccess, @token_instance_variable {
|
||||
final override InstanceVariableAccess::Range range;
|
||||
class InstanceVariableAccess extends VariableAccess, TInstanceVariableAccess {
|
||||
private Generated::InstanceVariable g;
|
||||
private InstanceVariable v;
|
||||
|
||||
final override InstanceVariable getVariable() { result = range.getVariable() }
|
||||
InstanceVariableAccess() { this = TInstanceVariableAccess(g, v) }
|
||||
|
||||
final override InstanceVariable getVariable() { result = v }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "InstanceVariableAccess" }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
}
|
||||
|
||||
/** An access to a class variable. */
|
||||
class ClassVariableAccess extends VariableAccess, @token_class_variable {
|
||||
final override ClassVariableAccess::Range range;
|
||||
class ClassVariableAccess extends VariableAccess, TClassVariableAccess {
|
||||
private Generated::ClassVariable g;
|
||||
private ClassVariable v;
|
||||
|
||||
final override ClassVariable getVariable() { result = range.getVariable() }
|
||||
ClassVariableAccess() { this = TClassVariableAccess(g, v) }
|
||||
|
||||
final override ClassVariable getVariable() { result = v }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "ClassVariableAccess" }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
}
|
||||
|
||||
@@ -1,17 +1,502 @@
|
||||
import codeql.Locations
|
||||
private import TreeSitter
|
||||
private import codeql_ruby.ast.internal.Parameter
|
||||
private import codeql_ruby.ast.internal.Variable
|
||||
private import codeql_ruby.AST as AST
|
||||
|
||||
module AstNode {
|
||||
abstract class Range extends @ast_node {
|
||||
Generated::AstNode generated;
|
||||
module MethodName {
|
||||
predicate range(Generated::UnderscoreMethodName g) {
|
||||
exists(Generated::Undef u | u.getChild(_) = g)
|
||||
or
|
||||
exists(Generated::Alias a | a.getName() = g or a.getAlias() = g)
|
||||
}
|
||||
|
||||
Range() { this = generated }
|
||||
class Token =
|
||||
@setter or @token_class_variable or @token_constant or @token_global_variable or
|
||||
@token_identifier or @token_instance_variable or @token_operator;
|
||||
}
|
||||
|
||||
cached
|
||||
abstract string toString();
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
newtype TAstNode =
|
||||
TAddExpr(Generated::Binary g) { g instanceof @binary_plus } or
|
||||
TAliasStmt(Generated::Alias g) or
|
||||
TArgumentList(Generated::AstNode g) {
|
||||
(
|
||||
g.getParent() instanceof Generated::Break or
|
||||
g.getParent() instanceof Generated::Return or
|
||||
g.getParent() instanceof Generated::Next or
|
||||
g.getParent() instanceof Generated::Assignment or
|
||||
g.getParent() instanceof Generated::OperatorAssignment
|
||||
) and
|
||||
(
|
||||
strictcount(g.(Generated::ArgumentList).getChild(_)) > 1
|
||||
or
|
||||
g instanceof Generated::RightAssignmentList
|
||||
)
|
||||
} or
|
||||
TAssignAddExpr(Generated::OperatorAssignment g) { g instanceof @operator_assignment_plusequal } or
|
||||
TAssignBitwiseAndExpr(Generated::OperatorAssignment g) {
|
||||
g instanceof @operator_assignment_ampersandequal
|
||||
} or
|
||||
TAssignBitwiseOrExpr(Generated::OperatorAssignment g) {
|
||||
g instanceof @operator_assignment_pipeequal
|
||||
} or
|
||||
TAssignBitwiseXorExpr(Generated::OperatorAssignment g) {
|
||||
g instanceof @operator_assignment_caretequal
|
||||
} or
|
||||
TAssignDivExpr(Generated::OperatorAssignment g) { g instanceof @operator_assignment_slashequal } or
|
||||
TAssignExponentExpr(Generated::OperatorAssignment g) {
|
||||
g instanceof @operator_assignment_starstarequal
|
||||
} or
|
||||
TAssignExpr(Generated::Assignment g) or
|
||||
TAssignLShiftExpr(Generated::OperatorAssignment g) {
|
||||
g instanceof @operator_assignment_langlelangleequal
|
||||
} or
|
||||
TAssignLogicalAndExpr(Generated::OperatorAssignment g) {
|
||||
g instanceof @operator_assignment_ampersandampersandequal
|
||||
} or
|
||||
TAssignLogicalOrExpr(Generated::OperatorAssignment g) {
|
||||
g instanceof @operator_assignment_pipepipeequal
|
||||
} or
|
||||
TAssignModuloExpr(Generated::OperatorAssignment g) {
|
||||
g instanceof @operator_assignment_percentequal
|
||||
} or
|
||||
TAssignMulExpr(Generated::OperatorAssignment g) { g instanceof @operator_assignment_starequal } or
|
||||
TAssignRShiftExpr(Generated::OperatorAssignment g) {
|
||||
g instanceof @operator_assignment_ranglerangleequal
|
||||
} or
|
||||
TAssignSubExpr(Generated::OperatorAssignment g) { g instanceof @operator_assignment_minusequal } or
|
||||
TBareStringLiteral(Generated::BareString g) or
|
||||
TBareSymbolLiteral(Generated::BareSymbol g) or
|
||||
TBeginBlock(Generated::BeginBlock g) or
|
||||
TBeginExpr(Generated::Begin g) or
|
||||
TBitwiseAndExpr(Generated::Binary g) { g instanceof @binary_ampersand } or
|
||||
TBitwiseOrExpr(Generated::Binary g) { g instanceof @binary_pipe } or
|
||||
TBitwiseXorExpr(Generated::Binary g) { g instanceof @binary_caret } or
|
||||
TBlockArgument(Generated::BlockArgument g) or
|
||||
TBlockParameter(Generated::BlockParameter g) or
|
||||
TBraceBlock(Generated::Block g) { not g.getParent() instanceof Generated::Lambda } or
|
||||
TBreakStmt(Generated::Break g) or
|
||||
TCaseEqExpr(Generated::Binary g) { g instanceof @binary_equalequalequal } or
|
||||
TCaseExpr(Generated::Case g) or
|
||||
TCharacterLiteral(Generated::Character g) or
|
||||
TClass(Generated::Class g) or
|
||||
TClassVariableAccess(Generated::ClassVariable g, AST::ClassVariable v) {
|
||||
ClassVariableAccess::range(g, v)
|
||||
} or
|
||||
TComplementExpr(Generated::Unary g) { g instanceof @unary_tilde } or
|
||||
TComplexLiteral(Generated::Complex g) or
|
||||
TDefinedExpr(Generated::Unary g) { g instanceof @unary_definedquestion } or
|
||||
TDelimitedSymbolLiteral(Generated::DelimitedSymbol g) or
|
||||
TDestructuredLeftAssignment(Generated::DestructuredLeftAssignment g) {
|
||||
not strictcount(int i | exists(g.getParent().(Generated::LeftAssignmentList).getChild(i))) = 1
|
||||
} or
|
||||
TDivExpr(Generated::Binary g) { g instanceof @binary_slash } or
|
||||
TDo(Generated::Do g) or
|
||||
TDoBlock(Generated::DoBlock g) { not g.getParent() instanceof Generated::Lambda } or
|
||||
TElementReference(Generated::ElementReference g) or
|
||||
TElse(Generated::Else g) or
|
||||
TElsif(Generated::Elsif g) or
|
||||
TEmptyStmt(Generated::EmptyStatement g) or
|
||||
TEndBlock(Generated::EndBlock g) or
|
||||
TEnsure(Generated::Ensure g) or
|
||||
TEqExpr(Generated::Binary g) { g instanceof @binary_equalequal } or
|
||||
TExponentExpr(Generated::Binary g) { g instanceof @binary_starstar } or
|
||||
TFalseLiteral(Generated::False g) or
|
||||
TFloatLiteral(Generated::Float g) { not any(Generated::Rational r).getChild() = g } or
|
||||
TForExpr(Generated::For g) or
|
||||
TForIn(Generated::In g) or // TODO REMOVE
|
||||
TGEExpr(Generated::Binary g) { g instanceof @binary_rangleequal } or
|
||||
TGTExpr(Generated::Binary g) { g instanceof @binary_rangle } or
|
||||
TGlobalVariableAccess(Generated::GlobalVariable g, AST::GlobalVariable v) {
|
||||
GlobalVariableAccess::range(g, v)
|
||||
} or
|
||||
THashKeySymbolLiteral(Generated::HashKeySymbol g) or
|
||||
THashLiteral(Generated::Hash g) or
|
||||
THashSplatArgument(Generated::HashSplatArgument g) or
|
||||
THashSplatParameter(Generated::HashSplatParameter g) or
|
||||
THereDoc(Generated::HeredocBeginning g) or
|
||||
TIdentifierMethodCall(Generated::Identifier g) { vcall(g) and not access(g, _) } or
|
||||
TIf(Generated::If g) or
|
||||
TIfModifierExpr(Generated::IfModifier g) or
|
||||
TInstanceVariableAccess(Generated::InstanceVariable g, AST::InstanceVariable v) {
|
||||
InstanceVariableAccess::range(g, v)
|
||||
} or
|
||||
TIntegerLiteral(Generated::Integer g) { not any(Generated::Rational r).getChild() = g } or
|
||||
TKeywordParameter(Generated::KeywordParameter g) or
|
||||
TLEExpr(Generated::Binary g) { g instanceof @binary_langleequal } or
|
||||
TLShiftExpr(Generated::Binary g) { g instanceof @binary_langlelangle } or
|
||||
TLTExpr(Generated::Binary g) { g instanceof @binary_langle } or
|
||||
TLambda(Generated::Lambda g) or
|
||||
TLeftAssignmentList(Generated::LeftAssignmentList g) or
|
||||
TLocalVariableAccess(Generated::Identifier g, AST::LocalVariable v) {
|
||||
LocalVariableAccess::range(g, v)
|
||||
} or
|
||||
TLogicalAndExpr(Generated::Binary g) {
|
||||
g instanceof @binary_and or g instanceof @binary_ampersandampersand
|
||||
} or
|
||||
TLogicalOrExpr(Generated::Binary g) { g instanceof @binary_or or g instanceof @binary_pipepipe } or
|
||||
TMethod(Generated::Method g) or
|
||||
TModule(Generated::Module g) or
|
||||
TModuloExpr(Generated::Binary g) { g instanceof @binary_percent } or
|
||||
TMulExpr(Generated::Binary g) { g instanceof @binary_star } or
|
||||
TNEExpr(Generated::Binary g) { g instanceof @binary_bangequal } or
|
||||
TNextStmt(Generated::Next g) or
|
||||
TNilLiteral(Generated::Nil g) or
|
||||
TNoRegexMatchExpr(Generated::Binary g) { g instanceof @binary_bangtilde } or
|
||||
TNotExpr(Generated::Unary g) { g instanceof @unary_bang or g instanceof @unary_not } or
|
||||
TOptionalParameter(Generated::OptionalParameter g) or
|
||||
TPair(Generated::Pair g) or
|
||||
TParenthesizedExpr(Generated::ParenthesizedStatements g) or
|
||||
TRShiftExpr(Generated::Binary g) { g instanceof @binary_ranglerangle } or
|
||||
TRangeLiteral(Generated::Range g) or
|
||||
TRationalLiteral(Generated::Rational g) or
|
||||
TRedoStmt(Generated::Redo g) or
|
||||
TRegexLiteral(Generated::Regex g) or
|
||||
TRegexMatchExpr(Generated::Binary g) { g instanceof @binary_equaltilde } or
|
||||
TRegularArrayLiteral(Generated::Array g) or
|
||||
TRegularMethodCall(Generated::Call g) { not g.getMethod() instanceof Generated::Super } or
|
||||
TRegularStringLiteral(Generated::String g) or
|
||||
TRegularSuperCall(Generated::Call g) { g.getMethod() instanceof Generated::Super } or
|
||||
TRescueClause(Generated::Rescue g) or
|
||||
TRescueModifierExpr(Generated::RescueModifier g) or
|
||||
TRetryStmt(Generated::Retry g) or
|
||||
TReturnStmt(Generated::Return g) or
|
||||
TScopeResolutionConstantAccess(Generated::ScopeResolution g, Generated::Constant constant) {
|
||||
constant = g.getName() and
|
||||
(
|
||||
// A tree-sitter `scope_resolution` node with a `constant` name field is a
|
||||
// read of that constant in any context where an identifier would be a
|
||||
// vcall.
|
||||
vcall(g)
|
||||
or
|
||||
explicitAssignmentNode(g, _)
|
||||
)
|
||||
} or
|
||||
TScopeResolutionMethodCall(Generated::ScopeResolution g, Generated::Identifier i) {
|
||||
i = g.getName() and
|
||||
not exists(Generated::Call c | c.getMethod() = g)
|
||||
} or
|
||||
TSelf(Generated::Self g) or
|
||||
TSimpleParameter(Generated::Identifier g) { g instanceof Parameter::Range } or
|
||||
TSimpleSymbolLiteral(Generated::SimpleSymbol g) or
|
||||
TSingletonClass(Generated::SingletonClass g) or
|
||||
TSingletonMethod(Generated::SingletonMethod g) or
|
||||
TSpaceshipExpr(Generated::Binary g) { g instanceof @binary_langleequalrangle } or
|
||||
TSplatArgument(Generated::SplatArgument g) or
|
||||
TSplatParameter(Generated::SplatParameter g) or
|
||||
TStringArrayLiteral(Generated::StringArray g) or
|
||||
TStringConcatenation(Generated::ChainedString g) or
|
||||
TStringEscapeSequenceComponent(Generated::EscapeSequence g) or
|
||||
TStringInterpolationComponent(Generated::Interpolation g) or
|
||||
TStringTextComponent(Generated::Token g) {
|
||||
g instanceof Generated::StringContent or g instanceof Generated::HeredocContent
|
||||
} or
|
||||
TSubExpr(Generated::Binary g) { g instanceof @binary_minus } or
|
||||
TSubshellLiteral(Generated::Subshell g) or
|
||||
TSymbolArrayLiteral(Generated::SymbolArray g) or
|
||||
TTernaryIfExpr(Generated::Conditional g) or
|
||||
TThen(Generated::Then g) or
|
||||
TTokenConstantAccess(Generated::Constant g) {
|
||||
// A tree-sitter `constant` token is a read of that constant in any context
|
||||
// where an identifier would be a vcall.
|
||||
vcall(g)
|
||||
or
|
||||
explicitAssignmentNode(g, _)
|
||||
} or
|
||||
TTokenMethodName(MethodName::Token g) { MethodName::range(g) } or
|
||||
TTokenSuperCall(Generated::Super g) { vcall(g) } or
|
||||
TToplevel(Generated::Program g) { g.getLocation().getFile().getExtension() != "erb" } or
|
||||
TTrueLiteral(Generated::True g) or
|
||||
TTuplePatternParameter(Generated::DestructuredParameter g) or
|
||||
TUnaryMinusExpr(Generated::Unary g) { g instanceof @unary_minus } or
|
||||
TUnaryPlusExpr(Generated::Unary g) { g instanceof @unary_plus } or
|
||||
TUndefStmt(Generated::Undef g) or
|
||||
TUnlessExpr(Generated::Unless g) or
|
||||
TUnlessModifierExpr(Generated::UnlessModifier g) or
|
||||
TUntilExpr(Generated::Until g) or
|
||||
TUntilModifierExpr(Generated::UntilModifier g) or
|
||||
TWhenExpr(Generated::When g) or
|
||||
TWhileExpr(Generated::While g) or
|
||||
TWhileModifierExpr(Generated::WhileModifier g) or
|
||||
TYieldCall(Generated::Yield g)
|
||||
|
||||
Location getLocation() { result = generated.getLocation() }
|
||||
|
||||
predicate child(string label, AstNode::Range child) { none() }
|
||||
/** Gets the underlying TreeSitter entity for a given AST node. */
|
||||
cached
|
||||
Generated::AstNode toGenerated(AST::AstNode n) {
|
||||
n = TAddExpr(result) or
|
||||
n = TAliasStmt(result) or
|
||||
n = TArgumentList(result) or
|
||||
n = TAssignAddExpr(result) or
|
||||
n = TAssignBitwiseAndExpr(result) or
|
||||
n = TAssignBitwiseOrExpr(result) or
|
||||
n = TAssignBitwiseXorExpr(result) or
|
||||
n = TAssignDivExpr(result) or
|
||||
n = TAssignExponentExpr(result) or
|
||||
n = TAssignExpr(result) or
|
||||
n = TAssignLShiftExpr(result) or
|
||||
n = TAssignLogicalAndExpr(result) or
|
||||
n = TAssignLogicalOrExpr(result) or
|
||||
n = TAssignModuloExpr(result) or
|
||||
n = TAssignMulExpr(result) or
|
||||
n = TAssignRShiftExpr(result) or
|
||||
n = TAssignSubExpr(result) or
|
||||
n = TBareStringLiteral(result) or
|
||||
n = TBareSymbolLiteral(result) or
|
||||
n = TBeginBlock(result) or
|
||||
n = TBeginExpr(result) or
|
||||
n = TBitwiseAndExpr(result) or
|
||||
n = TBitwiseOrExpr(result) or
|
||||
n = TBitwiseXorExpr(result) or
|
||||
n = TBlockArgument(result) or
|
||||
n = TBlockParameter(result) or
|
||||
n = TBraceBlock(result) or
|
||||
n = TBreakStmt(result) or
|
||||
n = TCaseEqExpr(result) or
|
||||
n = TCaseExpr(result) or
|
||||
n = TCharacterLiteral(result) or
|
||||
n = TClass(result) or
|
||||
n = TClassVariableAccess(result, _) or
|
||||
n = TComplementExpr(result) or
|
||||
n = TComplexLiteral(result) or
|
||||
n = TDefinedExpr(result) or
|
||||
n = TDelimitedSymbolLiteral(result) or
|
||||
n = TDestructuredLeftAssignment(result) or
|
||||
n = TDivExpr(result) or
|
||||
n = TDo(result) or
|
||||
n = TDoBlock(result) or
|
||||
n = TElementReference(result) or
|
||||
n = TElse(result) or
|
||||
n = TElsif(result) or
|
||||
n = TEmptyStmt(result) or
|
||||
n = TEndBlock(result) or
|
||||
n = TEnsure(result) or
|
||||
n = TEqExpr(result) or
|
||||
n = TExponentExpr(result) or
|
||||
n = TFalseLiteral(result) or
|
||||
n = TFloatLiteral(result) or
|
||||
n = TForExpr(result) or
|
||||
n = TForIn(result) or // TODO REMOVE
|
||||
n = TGEExpr(result) or
|
||||
n = TGTExpr(result) or
|
||||
n = TGlobalVariableAccess(result, _) or
|
||||
n = THashKeySymbolLiteral(result) or
|
||||
n = THashLiteral(result) or
|
||||
n = THashSplatArgument(result) or
|
||||
n = THashSplatParameter(result) or
|
||||
n = THereDoc(result) or
|
||||
n = TIdentifierMethodCall(result) or
|
||||
n = TIf(result) or
|
||||
n = TIfModifierExpr(result) or
|
||||
n = TInstanceVariableAccess(result, _) or
|
||||
n = TIntegerLiteral(result) or
|
||||
n = TKeywordParameter(result) or
|
||||
n = TLEExpr(result) or
|
||||
n = TLShiftExpr(result) or
|
||||
n = TLTExpr(result) or
|
||||
n = TLambda(result) or
|
||||
n = TLeftAssignmentList(result) or
|
||||
n = TLocalVariableAccess(result, _) or
|
||||
n = TLogicalAndExpr(result) or
|
||||
n = TLogicalOrExpr(result) or
|
||||
n = TMethod(result) or
|
||||
n = TModule(result) or
|
||||
n = TModuloExpr(result) or
|
||||
n = TMulExpr(result) or
|
||||
n = TNEExpr(result) or
|
||||
n = TNextStmt(result) or
|
||||
n = TNilLiteral(result) or
|
||||
n = TNoRegexMatchExpr(result) or
|
||||
n = TNotExpr(result) or
|
||||
n = TOptionalParameter(result) or
|
||||
n = TPair(result) or
|
||||
n = TParenthesizedExpr(result) or
|
||||
n = TRShiftExpr(result) or
|
||||
n = TRangeLiteral(result) or
|
||||
n = TRationalLiteral(result) or
|
||||
n = TRedoStmt(result) or
|
||||
n = TRegexLiteral(result) or
|
||||
n = TRegexMatchExpr(result) or
|
||||
n = TRegularArrayLiteral(result) or
|
||||
n = TRegularMethodCall(result) or
|
||||
n = TRegularStringLiteral(result) or
|
||||
n = TRegularSuperCall(result) or
|
||||
n = TRescueClause(result) or
|
||||
n = TRescueModifierExpr(result) or
|
||||
n = TRetryStmt(result) or
|
||||
n = TReturnStmt(result) or
|
||||
n = TScopeResolutionConstantAccess(result, _) or
|
||||
n = TScopeResolutionMethodCall(result, _) or
|
||||
n = TSelf(result) or
|
||||
n = TSimpleParameter(result) or
|
||||
n = TSimpleSymbolLiteral(result) or
|
||||
n = TSingletonClass(result) or
|
||||
n = TSingletonMethod(result) or
|
||||
n = TSpaceshipExpr(result) or
|
||||
n = TSplatArgument(result) or
|
||||
n = TSplatParameter(result) or
|
||||
n = TStringArrayLiteral(result) or
|
||||
n = TStringConcatenation(result) or
|
||||
n = TStringEscapeSequenceComponent(result) or
|
||||
n = TStringInterpolationComponent(result) or
|
||||
n = TStringTextComponent(result) or
|
||||
n = TSubExpr(result) or
|
||||
n = TSubshellLiteral(result) or
|
||||
n = TSymbolArrayLiteral(result) or
|
||||
n = TTernaryIfExpr(result) or
|
||||
n = TThen(result) or
|
||||
n = TTokenConstantAccess(result) or
|
||||
n = TTokenMethodName(result) or
|
||||
n = TTokenSuperCall(result) or
|
||||
n = TToplevel(result) or
|
||||
n = TTrueLiteral(result) or
|
||||
n = TTuplePatternParameter(result) or
|
||||
n = TUnaryMinusExpr(result) or
|
||||
n = TUnaryPlusExpr(result) or
|
||||
n = TUndefStmt(result) or
|
||||
n = TUnlessExpr(result) or
|
||||
n = TUnlessModifierExpr(result) or
|
||||
n = TUntilExpr(result) or
|
||||
n = TUntilModifierExpr(result) or
|
||||
n = TWhenExpr(result) or
|
||||
n = TWhileExpr(result) or
|
||||
n = TWhileModifierExpr(result) or
|
||||
n = TYieldCall(result)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
TAstNode fromGenerated(Generated::AstNode n) { n = toGenerated(result) }
|
||||
|
||||
class TCall = TMethodCall or TYieldCall;
|
||||
|
||||
class TMethodCall =
|
||||
TIdentifierMethodCall or TScopeResolutionMethodCall or TRegularMethodCall or TElementReference or
|
||||
TSuperCall;
|
||||
|
||||
class TSuperCall = TTokenSuperCall or TRegularSuperCall;
|
||||
|
||||
class TConstantAccess = TTokenConstantAccess or TScopeResolutionConstantAccess or TNamespace;
|
||||
|
||||
class TControlExpr = TConditionalExpr or TCaseExpr or TLoop;
|
||||
|
||||
class TConditionalExpr =
|
||||
TIfExpr or TUnlessExpr or TIfModifierExpr or TUnlessModifierExpr or TTernaryIfExpr;
|
||||
|
||||
class TIfExpr = TIf or TElsif;
|
||||
|
||||
class TConditionalLoop = TWhileExpr or TUntilExpr or TWhileModifierExpr or TUntilModifierExpr;
|
||||
|
||||
class TLoop = TConditionalLoop or TForExpr;
|
||||
|
||||
class TExpr =
|
||||
TSelf or TArgumentList or TRescueClause or TRescueModifierExpr or TPair or TStringConcatenation or
|
||||
TCall or TBlockArgument or TSplatArgument or THashSplatArgument or TConstantAccess or
|
||||
TControlExpr or TWhenExpr or TLiteral or TCallable or TVariableAccess or TStmtSequence or
|
||||
TOperation or TSimpleParameter;
|
||||
|
||||
class TStmtSequence =
|
||||
TBeginBlock or TEndBlock or TThen or TElse or TDo or TEnsure or TStringInterpolationComponent or
|
||||
TBlock or TBodyStmt or TParenthesizedExpr;
|
||||
|
||||
class TBodyStmt = TBeginExpr or TModuleBase or TMethod or TLambda or TDoBlock or TSingletonMethod;
|
||||
|
||||
class TLiteral =
|
||||
TNumericLiteral or TNilLiteral or TBooleanLiteral or TStringlikeLiteral or TCharacterLiteral or
|
||||
TArrayLiteral or THashLiteral or TRangeLiteral or TTokenMethodName;
|
||||
|
||||
class TNumericLiteral = TIntegerLiteral or TFloatLiteral or TRationalLiteral or TComplexLiteral;
|
||||
|
||||
class TBooleanLiteral = TTrueLiteral or TFalseLiteral;
|
||||
|
||||
class TStringComponent =
|
||||
TStringTextComponent or TStringEscapeSequenceComponent or TStringInterpolationComponent;
|
||||
|
||||
class TStringlikeLiteral =
|
||||
TStringLiteral or TRegexLiteral or TSymbolLiteral or TSubshellLiteral or THereDoc;
|
||||
|
||||
class TStringLiteral = TRegularStringLiteral or TBareStringLiteral;
|
||||
|
||||
class TSymbolLiteral = TSimpleSymbolLiteral or TComplexSymbolLiteral or THashKeySymbolLiteral;
|
||||
|
||||
class TComplexSymbolLiteral = TDelimitedSymbolLiteral or TBareSymbolLiteral;
|
||||
|
||||
class TArrayLiteral = TRegularArrayLiteral or TStringArrayLiteral or TSymbolArrayLiteral;
|
||||
|
||||
class TCallable = TMethodBase or TLambda or TBlock;
|
||||
|
||||
class TMethodBase = TMethod or TSingletonMethod;
|
||||
|
||||
class TBlock = TDoBlock or TBraceBlock;
|
||||
|
||||
class TModuleBase = TToplevel or TNamespace or TSingletonClass;
|
||||
|
||||
class TNamespace = TClass or TModule;
|
||||
|
||||
class TOperation = TUnaryOperation or TBinaryOperation or TAssignment;
|
||||
|
||||
class TUnaryOperation =
|
||||
TUnaryLogicalOperation or TUnaryArithmeticOperation or TUnaryBitwiseOperation or TDefinedExpr;
|
||||
|
||||
class TUnaryLogicalOperation = TNotExpr;
|
||||
|
||||
class TUnaryArithmeticOperation = TUnaryPlusExpr or TUnaryMinusExpr;
|
||||
|
||||
class TUnaryBitwiseOperation = TComplementExpr;
|
||||
|
||||
class TBinaryOperation =
|
||||
TBinaryArithmeticOperation or TBinaryLogicalOperation or TBinaryBitwiseOperation or
|
||||
TComparisonOperation or TSpaceshipExpr or TRegexMatchExpr or TNoRegexMatchExpr;
|
||||
|
||||
class TBinaryArithmeticOperation =
|
||||
TAddExpr or TSubExpr or TMulExpr or TDivExpr or TModuloExpr or TExponentExpr;
|
||||
|
||||
class TBinaryLogicalOperation = TLogicalAndExpr or TLogicalOrExpr;
|
||||
|
||||
class TBinaryBitwiseOperation =
|
||||
TLShiftExpr or TRShiftExpr or TBitwiseAndExpr or TBitwiseOrExpr or TBitwiseXorExpr;
|
||||
|
||||
class TComparisonOperation = TEqualityOperation or TRelationalOperation;
|
||||
|
||||
class TEqualityOperation = TEqExpr or TNEExpr or TCaseEqExpr;
|
||||
|
||||
class TRelationalOperation = TGTExpr or TGEExpr or TLTExpr or TLEExpr;
|
||||
|
||||
class TAssignment = TAssignExpr or TAssignOperation;
|
||||
|
||||
class TAssignOperation =
|
||||
TAssignArithmeticOperation or TAssignLogicalOperation or TAssignBitwiseOperation;
|
||||
|
||||
class TAssignArithmeticOperation =
|
||||
TAssignAddExpr or TAssignSubExpr or TAssignMulExpr or TAssignDivExpr or TAssignModuloExpr or
|
||||
TAssignExponentExpr;
|
||||
|
||||
class TAssignLogicalOperation = TAssignLogicalAndExpr or TAssignLogicalOrExpr;
|
||||
|
||||
class TAssignBitwiseOperation =
|
||||
TAssignLShiftExpr or TAssignRShiftExpr or TAssignBitwiseAndExpr or TAssignBitwiseOrExpr or
|
||||
TAssignBitwiseXorExpr;
|
||||
|
||||
class TStmt =
|
||||
TEmptyStmt or TBodyStmt or TStmtSequence or TUndefStmt or TAliasStmt or TReturningStmt or
|
||||
TRedoStmt or TRetryStmt or TExpr;
|
||||
|
||||
class TReturningStmt = TReturnStmt or TBreakStmt or TNextStmt;
|
||||
|
||||
class TParameter =
|
||||
TPatternParameter or TBlockParameter or THashSplatParameter or TKeywordParameter or
|
||||
TOptionalParameter or TSplatParameter;
|
||||
|
||||
class TPatternParameter = TSimpleParameter or TTuplePatternParameter;
|
||||
|
||||
class TNamedParameter =
|
||||
TSimpleParameter or TBlockParameter or THashSplatParameter or TKeywordParameter or
|
||||
TOptionalParameter or TSplatParameter;
|
||||
|
||||
class TTuplePattern = TTuplePatternParameter or TDestructuredLeftAssignment or TLeftAssignmentList;
|
||||
|
||||
class TVariableAccess =
|
||||
TLocalVariableAccess or TGlobalVariableAccess or TInstanceVariableAccess or TClassVariableAccess;
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Expr
|
||||
private import codeql_ruby.ast.internal.Pattern
|
||||
private import codeql_ruby.ast.internal.TreeSitter
|
||||
private import codeql_ruby.ast.internal.Variable
|
||||
|
||||
module Call {
|
||||
abstract class Range extends Expr::Range {
|
||||
abstract Expr getArgument(int n);
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getArgument" and child = getArgument(_)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module MethodCall {
|
||||
class Range extends Call::Range {
|
||||
MethodCallRange::Range range;
|
||||
|
||||
Range() { this = range }
|
||||
|
||||
final Block getBlock() { result = range.getBlock() }
|
||||
|
||||
final Expr getReceiver() { result = range.getReceiver() }
|
||||
|
||||
final override Expr getArgument(int n) { result = range.getArgument(n) }
|
||||
|
||||
abstract string getMethodName();
|
||||
|
||||
override string toString() {
|
||||
result = range.toString()
|
||||
or
|
||||
not exists(range.toString()) and result = "call to " + concat(this.getMethodName(), "/")
|
||||
}
|
||||
|
||||
final override predicate child(string label, AstNode::Range child) {
|
||||
super.child(label, child)
|
||||
or
|
||||
label = "getReceiver" and child = getReceiver()
|
||||
or
|
||||
label = "getBlock" and child = getBlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module MethodCallRange {
|
||||
abstract class Range extends @ast_node {
|
||||
Generated::AstNode generated;
|
||||
|
||||
Range() { this = generated }
|
||||
|
||||
abstract Block getBlock();
|
||||
|
||||
abstract Expr getReceiver();
|
||||
|
||||
abstract string getMethod();
|
||||
|
||||
abstract Expr getArgument(int n);
|
||||
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
private class IdentifierCallRange extends MethodCallRange::Range, @token_identifier {
|
||||
final override Generated::Identifier generated;
|
||||
|
||||
IdentifierCallRange() { vcall(this) and not access(this, _) }
|
||||
|
||||
final override Expr getReceiver() { none() }
|
||||
|
||||
final override string getMethod() { result = generated.getValue() }
|
||||
|
||||
final override Expr getArgument(int n) { none() }
|
||||
|
||||
final override Block getBlock() { none() }
|
||||
}
|
||||
|
||||
private class ScopeResolutionIdentifierCallRange extends MethodCallRange::Range, @scope_resolution {
|
||||
final override Generated::ScopeResolution generated;
|
||||
Generated::Identifier identifier;
|
||||
|
||||
ScopeResolutionIdentifierCallRange() {
|
||||
identifier = generated.getName() and
|
||||
not exists(Generated::Call c | c.getMethod() = this)
|
||||
}
|
||||
|
||||
final override Expr getReceiver() { result = generated.getScope() }
|
||||
|
||||
final override string getMethod() { result = identifier.getValue() }
|
||||
|
||||
final override Expr getArgument(int n) { none() }
|
||||
|
||||
final override Block getBlock() { none() }
|
||||
}
|
||||
|
||||
private class RegularCallRange extends MethodCallRange::Range, @call {
|
||||
final override Generated::Call generated;
|
||||
|
||||
final override Expr getReceiver() {
|
||||
result = generated.getReceiver()
|
||||
or
|
||||
not exists(generated.getReceiver()) and
|
||||
result = generated.getMethod().(Generated::ScopeResolution).getScope()
|
||||
}
|
||||
|
||||
final override string getMethod() {
|
||||
result = "call" and generated.getMethod() instanceof Generated::ArgumentList
|
||||
or
|
||||
result = generated.getMethod().(Generated::Token).getValue()
|
||||
or
|
||||
result =
|
||||
generated.getMethod().(Generated::ScopeResolution).getName().(Generated::Token).getValue()
|
||||
}
|
||||
|
||||
final override Expr getArgument(int n) {
|
||||
result = generated.getArguments().getChild(n)
|
||||
or
|
||||
not exists(generated.getArguments()) and
|
||||
result = generated.getMethod().(Generated::ArgumentList).getChild(n)
|
||||
}
|
||||
|
||||
final override Block getBlock() { result = generated.getBlock() }
|
||||
}
|
||||
}
|
||||
|
||||
module ElementReferenceRange {
|
||||
class Range extends MethodCallRange::Range, @element_reference {
|
||||
final override Generated::ElementReference generated;
|
||||
|
||||
final override Expr getReceiver() { result = generated.getObject() }
|
||||
|
||||
final override string getMethod() { result = "[]" }
|
||||
|
||||
final override string toString() { result = "...[...]" }
|
||||
|
||||
final override Expr getArgument(int n) { result = generated.getChild(n) }
|
||||
|
||||
final override Block getBlock() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
module NormalMethodCall {
|
||||
class Range extends MethodCall::Range {
|
||||
Range() {
|
||||
not this instanceof LhsExpr::Range or
|
||||
generated.getParent() instanceof AssignOperation
|
||||
}
|
||||
|
||||
final override string getMethodName() { result = range.getMethod() }
|
||||
}
|
||||
}
|
||||
|
||||
module SetterMethodCall {
|
||||
class Range extends MethodCall::Range, LhsExpr::Range {
|
||||
final override string getMethodName() { result = range.getMethod() + "=" }
|
||||
|
||||
final override string toString() { result = MethodCall::Range.super.toString() }
|
||||
}
|
||||
}
|
||||
|
||||
module ElementReference {
|
||||
class Range extends MethodCall::Range {
|
||||
override ElementReferenceRange::Range range;
|
||||
|
||||
final override string getMethodName() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
module SuperCall {
|
||||
class Range extends NormalMethodCall::Range {
|
||||
override SuperCallRange::Range range;
|
||||
}
|
||||
}
|
||||
|
||||
module YieldCall {
|
||||
class Range extends Call::Range, @yield {
|
||||
final override Generated::Yield generated;
|
||||
|
||||
final override Expr getArgument(int n) { result = generated.getChild().getChild(n) }
|
||||
|
||||
final override string toString() { result = "yield ..." }
|
||||
}
|
||||
}
|
||||
|
||||
module SuperCallRange {
|
||||
abstract class Range extends MethodCallRange::Range { }
|
||||
|
||||
private class SuperTokenCallRange extends SuperCallRange::Range, @token_super {
|
||||
final override Generated::Super generated;
|
||||
|
||||
// N.B. `super` tokens can never be accesses, so any vcall with `super` must
|
||||
// be a call.
|
||||
SuperTokenCallRange() { vcall(this) }
|
||||
|
||||
final override Expr getReceiver() { none() }
|
||||
|
||||
final override string getMethod() { result = generated.getValue() }
|
||||
|
||||
final override Expr getArgument(int n) { none() }
|
||||
|
||||
final override Block getBlock() { none() }
|
||||
}
|
||||
|
||||
private class RegularSuperCallRange extends SuperCallRange::Range, @call {
|
||||
final override Generated::Call generated;
|
||||
|
||||
RegularSuperCallRange() { generated.getMethod() instanceof Generated::Super }
|
||||
|
||||
final override Expr getReceiver() { none() }
|
||||
|
||||
final override string getMethod() {
|
||||
result = generated.getMethod().(Generated::Super).getValue()
|
||||
}
|
||||
|
||||
final override Expr getArgument(int n) { result = generated.getArguments().getChild(n) }
|
||||
|
||||
final override Block getBlock() { result = generated.getBlock() }
|
||||
}
|
||||
}
|
||||
|
||||
module BlockArgument {
|
||||
class Range extends Expr::Range, @block_argument {
|
||||
final override Generated::BlockArgument generated;
|
||||
|
||||
final Expr getValue() { result = generated.getChild() }
|
||||
|
||||
final override string toString() { result = "&..." }
|
||||
|
||||
final override predicate child(string label, AstNode::Range child) {
|
||||
label = "getValue" and child = getValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module SplatArgument {
|
||||
class Range extends Expr::Range, @splat_argument {
|
||||
final override Generated::SplatArgument generated;
|
||||
|
||||
final Expr getValue() { result = generated.getChild() }
|
||||
|
||||
final override string toString() { result = "*..." }
|
||||
|
||||
final override predicate child(string label, AstNode::Range child) {
|
||||
label = "getValue" and child = getValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module HashSplatArgument {
|
||||
class Range extends Expr::Range, @hash_splat_argument {
|
||||
final override Generated::HashSplatArgument generated;
|
||||
|
||||
final Expr getValue() { result = generated.getChild() }
|
||||
|
||||
final override string toString() { result = "**..." }
|
||||
|
||||
final override predicate child(string label, AstNode::Range child) {
|
||||
label = "getValue" and child = getValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Expr
|
||||
private import codeql_ruby.ast.internal.Pattern
|
||||
private import codeql_ruby.ast.internal.TreeSitter
|
||||
private import codeql_ruby.ast.internal.Variable
|
||||
|
||||
module ConstantAccess {
|
||||
abstract class Range extends Expr::Range {
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
abstract string getName();
|
||||
|
||||
abstract Expr::Range getScopeExpr();
|
||||
|
||||
abstract predicate hasGlobalScope();
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getScopeExpr" and child = getScopeExpr()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module ConstantReadAccess {
|
||||
abstract class Range extends ConstantAccess::Range { }
|
||||
|
||||
private class TokenConstantReadAccessRange extends ConstantReadAccess::Range, @token_constant {
|
||||
final override Generated::Constant generated;
|
||||
|
||||
// A tree-sitter `constant` token is a read of that constant in any context
|
||||
// where an identifier would be a vcall.
|
||||
TokenConstantReadAccessRange() { vcall(this) }
|
||||
|
||||
final override string getName() { result = generated.getValue() }
|
||||
|
||||
final override Expr::Range getScopeExpr() { none() }
|
||||
|
||||
final override predicate hasGlobalScope() { none() }
|
||||
}
|
||||
|
||||
private class ScopeResolutionReadAccessRange extends ConstantReadAccess::Range, @scope_resolution {
|
||||
final override Generated::ScopeResolution generated;
|
||||
Generated::Constant constant;
|
||||
|
||||
// A tree-sitter `scope_resolution` node with a `constant` name field is a
|
||||
// read of that constant in any context where an identifier would be a
|
||||
// vcall.
|
||||
ScopeResolutionReadAccessRange() {
|
||||
constant = generated.getName() and
|
||||
vcall(this)
|
||||
}
|
||||
|
||||
final override string getName() { result = constant.getValue() }
|
||||
|
||||
final override Expr::Range getScopeExpr() { result = generated.getScope() }
|
||||
|
||||
final override predicate hasGlobalScope() { not exists(generated.getScope()) }
|
||||
}
|
||||
}
|
||||
|
||||
module ConstantWriteAccess {
|
||||
abstract class Range extends ConstantAccess::Range { }
|
||||
}
|
||||
|
||||
module ConstantAssignment {
|
||||
abstract class Range extends ConstantWriteAccess::Range, LhsExpr::Range {
|
||||
Range() { explicitAssignmentNode(this, _) }
|
||||
|
||||
override string toString() { result = ConstantWriteAccess::Range.super.toString() }
|
||||
}
|
||||
|
||||
private class TokenConstantAssignmentRange extends ConstantAssignment::Range, @token_constant {
|
||||
final override Generated::Constant generated;
|
||||
|
||||
final override string getName() { result = generated.getValue() }
|
||||
|
||||
final override Expr::Range getScopeExpr() { none() }
|
||||
|
||||
final override predicate hasGlobalScope() { none() }
|
||||
}
|
||||
|
||||
private class ScopeResolutionAssignmentRange extends ConstantAssignment::Range, @scope_resolution {
|
||||
final override Generated::ScopeResolution generated;
|
||||
Generated::Constant constant;
|
||||
|
||||
ScopeResolutionAssignmentRange() { constant = generated.getName() }
|
||||
|
||||
final override string getName() { result = constant.getValue() }
|
||||
|
||||
final override Expr::Range getScopeExpr() { result = generated.getScope() }
|
||||
|
||||
final override predicate hasGlobalScope() { not exists(generated.getScope()) }
|
||||
}
|
||||
}
|
||||
@@ -1,299 +0,0 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Expr
|
||||
private import codeql_ruby.ast.internal.Pattern
|
||||
private import codeql_ruby.ast.internal.TreeSitter
|
||||
|
||||
module ControlExpr {
|
||||
abstract class Range extends Expr::Range { }
|
||||
}
|
||||
|
||||
module ConditionalExpr {
|
||||
abstract class Range extends ControlExpr::Range {
|
||||
abstract Expr getCondition();
|
||||
|
||||
abstract Stmt getBranch(boolean cond);
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getCondition" and child = getCondition()
|
||||
or
|
||||
label = "getBranch" and child = getBranch(_)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module IfExpr {
|
||||
abstract class Range extends ConditionalExpr::Range {
|
||||
abstract Stmt getThen();
|
||||
|
||||
abstract Stmt getElse();
|
||||
|
||||
final override string toString() {
|
||||
if this instanceof @elsif then result = "elsif ..." else result = "if ..."
|
||||
}
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
super.child(label, child)
|
||||
or
|
||||
label = "getThen" and child = getThen()
|
||||
or
|
||||
label = "getElse" and child = getElse()
|
||||
}
|
||||
}
|
||||
|
||||
private class IfRange extends IfExpr::Range, @if {
|
||||
final override Generated::If generated;
|
||||
|
||||
final override Expr getCondition() { result = generated.getCondition() }
|
||||
|
||||
final override Stmt getThen() { result = generated.getConsequence() }
|
||||
|
||||
final override Stmt getElse() { result = generated.getAlternative() }
|
||||
|
||||
final override Stmt getBranch(boolean cond) {
|
||||
cond = true and result = getThen()
|
||||
or
|
||||
cond = false and result = getElse()
|
||||
}
|
||||
}
|
||||
|
||||
private class ElsifRange extends IfExpr::Range, @elsif {
|
||||
final override Generated::Elsif generated;
|
||||
|
||||
final override Expr getCondition() { result = generated.getCondition() }
|
||||
|
||||
final override Stmt getThen() { result = generated.getConsequence() }
|
||||
|
||||
final override Stmt getElse() { result = generated.getAlternative() }
|
||||
|
||||
final override Expr getBranch(boolean cond) {
|
||||
cond = true and result = getThen()
|
||||
or
|
||||
cond = false and result = getElse()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module UnlessExpr {
|
||||
class Range extends ConditionalExpr::Range, @unless {
|
||||
final override Generated::Unless generated;
|
||||
|
||||
final override Expr getCondition() { result = generated.getCondition() }
|
||||
|
||||
final Stmt getThen() { result = generated.getConsequence() }
|
||||
|
||||
final Stmt getElse() { result = generated.getAlternative() }
|
||||
|
||||
final override Expr getBranch(boolean cond) {
|
||||
cond = false and result = getThen()
|
||||
or
|
||||
cond = true and result = getElse()
|
||||
}
|
||||
|
||||
final override string toString() { result = "unless ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
ConditionalExpr::Range.super.child(label, child)
|
||||
or
|
||||
label = "getThen" and child = getThen()
|
||||
or
|
||||
label = "getElse" and child = getElse()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module IfModifierExpr {
|
||||
class Range extends ConditionalExpr::Range, @if_modifier {
|
||||
final override Generated::IfModifier generated;
|
||||
|
||||
final override Expr getCondition() { result = generated.getCondition() }
|
||||
|
||||
final Stmt getBody() { result = generated.getBody() }
|
||||
|
||||
final override Stmt getBranch(boolean cond) { cond = true and result = getBody() }
|
||||
|
||||
final override string toString() { result = "... if ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
ConditionalExpr::Range.super.child(label, child)
|
||||
or
|
||||
label = "getBody" and child = getBody()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module UnlessModifierExpr {
|
||||
class Range extends ConditionalExpr::Range, @unless_modifier {
|
||||
final override Generated::UnlessModifier generated;
|
||||
|
||||
final override Expr getCondition() { result = generated.getCondition() }
|
||||
|
||||
final Stmt getBody() { result = generated.getBody() }
|
||||
|
||||
final override Stmt getBranch(boolean cond) { cond = false and result = getBody() }
|
||||
|
||||
final override string toString() { result = "... unless ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
ConditionalExpr::Range.super.child(label, child)
|
||||
or
|
||||
label = "getBody" and child = getBody()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module TernaryIfExpr {
|
||||
class Range extends ConditionalExpr::Range, @conditional {
|
||||
final override Generated::Conditional generated;
|
||||
|
||||
final override Expr getCondition() { result = generated.getCondition() }
|
||||
|
||||
final Stmt getThen() { result = generated.getConsequence() }
|
||||
|
||||
final Stmt getElse() { result = generated.getAlternative() }
|
||||
|
||||
final override Stmt getBranch(boolean cond) {
|
||||
cond = true and result = getThen()
|
||||
or
|
||||
cond = false and result = getElse()
|
||||
}
|
||||
|
||||
final override string toString() { result = "... ? ... : ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
ConditionalExpr::Range.super.child(label, child)
|
||||
or
|
||||
label = "getThen" and child = getThen()
|
||||
or
|
||||
label = "getElse" and child = getElse()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module CaseExpr {
|
||||
class Range extends ControlExpr::Range, @case__ {
|
||||
final override Generated::Case generated;
|
||||
|
||||
final Expr getValue() { result = generated.getValue() }
|
||||
|
||||
final Expr getBranch(int n) { result = generated.getChild(n) }
|
||||
|
||||
final override string toString() { result = "case ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getValue" and child = getValue()
|
||||
or
|
||||
label = "getBranch" and child = getBranch(_)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module WhenExpr {
|
||||
class Range extends Expr::Range, @when {
|
||||
final override Generated::When generated;
|
||||
|
||||
final Stmt getBody() { result = generated.getBody() }
|
||||
|
||||
final Expr getPattern(int n) { result = generated.getPattern(n).getChild() }
|
||||
|
||||
final override string toString() { result = "when ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getBody" and child = getBody()
|
||||
or
|
||||
label = "getPattern" and child = getPattern(_)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module Loop {
|
||||
abstract class Range extends ControlExpr::Range {
|
||||
abstract Stmt getBody();
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getBody" and child = getBody()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module ConditionalLoop {
|
||||
abstract class Range extends Loop::Range {
|
||||
abstract Expr getCondition();
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
super.child(label, child)
|
||||
or
|
||||
label = "getCondition" and child = getCondition()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module WhileExpr {
|
||||
class Range extends ConditionalLoop::Range, @while {
|
||||
final override Generated::While generated;
|
||||
|
||||
final override Stmt getBody() { result = generated.getBody() }
|
||||
|
||||
final override Expr getCondition() { result = generated.getCondition() }
|
||||
|
||||
final override string toString() { result = "while ..." }
|
||||
}
|
||||
}
|
||||
|
||||
module UntilExpr {
|
||||
class Range extends ConditionalLoop::Range, @until {
|
||||
final override Generated::Until generated;
|
||||
|
||||
final override Stmt getBody() { result = generated.getBody() }
|
||||
|
||||
final override Expr getCondition() { result = generated.getCondition() }
|
||||
|
||||
final override string toString() { result = "until ..." }
|
||||
}
|
||||
}
|
||||
|
||||
module WhileModifierExpr {
|
||||
class Range extends ConditionalLoop::Range, @while_modifier {
|
||||
final override Generated::WhileModifier generated;
|
||||
|
||||
final override Stmt getBody() { result = generated.getBody() }
|
||||
|
||||
final override Expr getCondition() { result = generated.getCondition() }
|
||||
|
||||
final override string toString() { result = "... while ..." }
|
||||
}
|
||||
}
|
||||
|
||||
module UntilModifierExpr {
|
||||
class Range extends ConditionalLoop::Range, @until_modifier {
|
||||
final override Generated::UntilModifier generated;
|
||||
|
||||
final override Stmt getBody() { result = generated.getBody() }
|
||||
|
||||
final override Expr getCondition() { result = generated.getCondition() }
|
||||
|
||||
final override string toString() { result = "... until ..." }
|
||||
}
|
||||
}
|
||||
|
||||
module ForExpr {
|
||||
class Range extends Loop::Range, @for {
|
||||
final override Generated::For generated;
|
||||
|
||||
final override StmtSequence getBody() { result = generated.getBody() }
|
||||
|
||||
final Pattern getPattern() { result = generated.getPattern() }
|
||||
|
||||
final Expr getValue() { result = generated.getValue().getChild() }
|
||||
|
||||
final override string toString() { result = "for ... in ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
Loop::Range.super.child(label, child)
|
||||
or
|
||||
label = "getPattern" and child = getPattern()
|
||||
or
|
||||
label = "getValue" and child = getValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Literal
|
||||
private import codeql_ruby.ast.internal.Statement
|
||||
private import codeql_ruby.ast.internal.TreeSitter
|
||||
|
||||
module Expr {
|
||||
abstract class Range extends Stmt::Range { }
|
||||
}
|
||||
|
||||
module Self {
|
||||
class Range extends Expr::Range, @token_self {
|
||||
final override Generated::Self generated;
|
||||
|
||||
final override string toString() { result = "self" }
|
||||
}
|
||||
}
|
||||
|
||||
module ArgumentList {
|
||||
private class ValidParent = @break or @return or @next or @assignment or @operator_assignment;
|
||||
|
||||
abstract class Range extends Expr::Range {
|
||||
Range() { generated.getParent() instanceof ValidParent }
|
||||
|
||||
abstract Expr getElement(int i);
|
||||
|
||||
final override string toString() { result = "..., ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getElement" and child = getElement(_)
|
||||
}
|
||||
}
|
||||
|
||||
private class ArgArgumentList extends ArgumentList::Range, @argument_list {
|
||||
final override Generated::ArgumentList generated;
|
||||
|
||||
ArgArgumentList() { strictcount(generated.getChild(_)) > 1 }
|
||||
|
||||
final override Expr getElement(int i) { result = generated.getChild(i) }
|
||||
}
|
||||
|
||||
private class AssignmentList extends ArgumentList::Range, @right_assignment_list {
|
||||
final override Generated::RightAssignmentList generated;
|
||||
|
||||
final override Expr getElement(int i) { result = generated.getChild(i) }
|
||||
}
|
||||
}
|
||||
|
||||
module StmtSequence {
|
||||
abstract class Range extends Expr::Range {
|
||||
abstract Stmt getStmt(int n);
|
||||
|
||||
int getNumberOfStatements() { result = count(this.getStmt(_)) }
|
||||
|
||||
override string toString() {
|
||||
exists(int c | c = this.getNumberOfStatements() |
|
||||
c = 0 and result = ";"
|
||||
or
|
||||
c = 1 and result = this.getStmt(0).toString()
|
||||
or
|
||||
c > 1 and result = "...; ..."
|
||||
)
|
||||
}
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getStmt" and child = getStmt(_)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module BodyStatement {
|
||||
abstract class Range extends StmtSequence::Range {
|
||||
final override Stmt getStmt(int n) {
|
||||
result =
|
||||
rank[n + 1](Generated::AstNode node, int i |
|
||||
node = getChild(i) and
|
||||
not node instanceof Generated::Else and
|
||||
not node instanceof Generated::Rescue and
|
||||
not node instanceof Generated::Ensure
|
||||
|
|
||||
node order by i
|
||||
)
|
||||
}
|
||||
|
||||
final RescueClause getRescue(int n) {
|
||||
result = rank[n + 1](Generated::Rescue node, int i | node = getChild(i) | node order by i)
|
||||
}
|
||||
|
||||
final StmtSequence getElse() { result = unique(Generated::Else s | s = getChild(_)) }
|
||||
|
||||
final StmtSequence getEnsure() { result = unique(Generated::Ensure s | s = getChild(_)) }
|
||||
|
||||
abstract Generated::AstNode getChild(int i);
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
StmtSequence::Range.super.child(label, child)
|
||||
or
|
||||
label = "getRescue" and child = getRescue(_)
|
||||
or
|
||||
label = "getElse" and child = getElse()
|
||||
or
|
||||
label = "getEnsure" and child = getEnsure()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module ParenthesizedExpr {
|
||||
class Range extends StmtSequence::Range, @parenthesized_statements {
|
||||
final override Generated::ParenthesizedStatements generated;
|
||||
|
||||
final override Stmt getStmt(int n) { result = generated.getChild(n) }
|
||||
|
||||
final override string toString() {
|
||||
exists(int c | c = this.getNumberOfStatements() |
|
||||
c = 0 and result = "()"
|
||||
or
|
||||
c > 0 and result = "(" + StmtSequence::Range.super.toString() + ")"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module ThenExpr {
|
||||
class Range extends StmtSequence::Range, @then {
|
||||
final override Generated::Then generated;
|
||||
|
||||
final override Stmt getStmt(int n) { result = generated.getChild(n) }
|
||||
}
|
||||
}
|
||||
|
||||
module ElseExpr {
|
||||
class Range extends StmtSequence::Range, @else {
|
||||
final override Generated::Else generated;
|
||||
|
||||
final override Stmt getStmt(int n) { result = generated.getChild(n) }
|
||||
}
|
||||
}
|
||||
|
||||
module DoExpr {
|
||||
class Range extends StmtSequence::Range, @do {
|
||||
final override Generated::Do generated;
|
||||
|
||||
final override Stmt getStmt(int n) { result = generated.getChild(n) }
|
||||
}
|
||||
}
|
||||
|
||||
module Ensure {
|
||||
class Range extends StmtSequence::Range, @ensure {
|
||||
final override Generated::Ensure generated;
|
||||
|
||||
final override Stmt getStmt(int n) { result = generated.getChild(n) }
|
||||
|
||||
final override string toString() { result = "ensure ..." }
|
||||
}
|
||||
}
|
||||
|
||||
module RescueClause {
|
||||
class Range extends Expr::Range, @rescue {
|
||||
final override Generated::Rescue generated;
|
||||
|
||||
final Expr getException(int n) { result = generated.getExceptions().getChild(n) }
|
||||
|
||||
final LhsExpr getVariableExpr() { result = generated.getVariable().getChild() }
|
||||
|
||||
final StmtSequence getBody() { result = generated.getBody() }
|
||||
|
||||
final override string toString() { result = "rescue ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getException" and child = getException(_)
|
||||
or
|
||||
label = "getVariableExpr" and child = getVariableExpr()
|
||||
or
|
||||
label = "getBody" and child = getBody()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module RescueModifierExpr {
|
||||
class Range extends Expr::Range, @rescue_modifier {
|
||||
final override Generated::RescueModifier generated;
|
||||
|
||||
final Stmt getBody() { result = generated.getBody() }
|
||||
|
||||
final Stmt getHandler() { result = generated.getHandler() }
|
||||
|
||||
final override string toString() { result = "... rescue ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getBody" and child = getBody()
|
||||
or
|
||||
label = "getHandler" and child = getHandler()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module Pair {
|
||||
class Range extends Expr::Range, @pair {
|
||||
final override Generated::Pair generated;
|
||||
|
||||
final Expr getKey() { result = generated.getKey() }
|
||||
|
||||
final Expr getValue() { result = generated.getValue() }
|
||||
|
||||
final override string toString() { result = "Pair" }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getKey" and child = getKey()
|
||||
or
|
||||
label = "getValue" and child = getValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module StringConcatenation {
|
||||
class Range extends Expr::Range, @chained_string {
|
||||
final override Generated::ChainedString generated;
|
||||
|
||||
final StringLiteral::Range getString(int i) { result = generated.getChild(i) }
|
||||
|
||||
final override string toString() { result = "\"...\" \"...\"" }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getString" and child = getString(_)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,446 +0,0 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Expr
|
||||
private import codeql_ruby.ast.internal.TreeSitter
|
||||
|
||||
module Literal {
|
||||
abstract class Range extends Expr::Range {
|
||||
abstract string getValueText();
|
||||
|
||||
override string toString() { result = this.getValueText() }
|
||||
}
|
||||
}
|
||||
|
||||
module NumericLiteral {
|
||||
abstract class Range extends Literal::Range { }
|
||||
}
|
||||
|
||||
module IntegerLiteral {
|
||||
class Range extends NumericLiteral::Range, @token_integer {
|
||||
final override Generated::Integer generated;
|
||||
|
||||
Range() { not any(Generated::Rational r).getChild() = this }
|
||||
|
||||
final override string getValueText() { result = generated.getValue() }
|
||||
|
||||
final override string toString() { result = this.getValueText() }
|
||||
}
|
||||
}
|
||||
|
||||
module FloatLiteral {
|
||||
class Range extends NumericLiteral::Range, @token_float {
|
||||
final override Generated::Float generated;
|
||||
|
||||
Range() { not any(Generated::Rational r).getChild() = this }
|
||||
|
||||
final override string getValueText() { result = generated.getValue() }
|
||||
|
||||
final override string toString() { result = this.getValueText() }
|
||||
}
|
||||
}
|
||||
|
||||
module RationalLiteral {
|
||||
class Range extends NumericLiteral::Range, @rational {
|
||||
final override Generated::Rational generated;
|
||||
|
||||
final override string getValueText() {
|
||||
result = generated.getChild().(Generated::Token).getValue() + "r"
|
||||
}
|
||||
|
||||
final override string toString() { result = this.getValueText() }
|
||||
}
|
||||
}
|
||||
|
||||
module ComplexLiteral {
|
||||
class Range extends NumericLiteral::Range, @token_complex {
|
||||
final override Generated::Complex generated;
|
||||
|
||||
final override string getValueText() { result = generated.getValue() }
|
||||
|
||||
final override string toString() { result = this.getValueText() }
|
||||
}
|
||||
}
|
||||
|
||||
module NilLiteral {
|
||||
class Range extends Literal::Range, @token_nil {
|
||||
final override Generated::Nil generated;
|
||||
|
||||
final override string getValueText() { result = generated.getValue() }
|
||||
|
||||
final override string toString() { result = this.getValueText() }
|
||||
}
|
||||
}
|
||||
|
||||
module BooleanLiteral {
|
||||
class DbUnion = @token_true or @token_false;
|
||||
|
||||
class Range extends Literal::Range, DbUnion {
|
||||
final override Generated::Token generated;
|
||||
|
||||
final override string getValueText() { result = generated.getValue() }
|
||||
|
||||
final override string toString() { result = this.getValueText() }
|
||||
|
||||
predicate isTrue() { this instanceof @token_true }
|
||||
|
||||
predicate isFalse() { this instanceof @token_false }
|
||||
}
|
||||
}
|
||||
|
||||
module StringComponent {
|
||||
abstract class Range extends AstNode::Range {
|
||||
abstract string getValueText();
|
||||
}
|
||||
}
|
||||
|
||||
module StringTextComponent {
|
||||
class StringContentToken = @token_string_content or @token_heredoc_content;
|
||||
|
||||
class Range extends StringComponent::Range, StringContentToken {
|
||||
final override Generated::Token generated;
|
||||
|
||||
final override string toString() { result = generated.getValue() }
|
||||
|
||||
final override string getValueText() { result = generated.getValue() }
|
||||
}
|
||||
}
|
||||
|
||||
module StringEscapeSequenceComponent {
|
||||
class Range extends StringComponent::Range, @token_escape_sequence {
|
||||
final override Generated::EscapeSequence generated;
|
||||
|
||||
final override string toString() { result = generated.getValue() }
|
||||
|
||||
final override string getValueText() { result = generated.getValue() }
|
||||
}
|
||||
}
|
||||
|
||||
module StringInterpolationComponent {
|
||||
class Range extends StringComponent::Range, StmtSequence::Range, @interpolation {
|
||||
final override Generated::Interpolation generated;
|
||||
|
||||
final override string toString() { result = "#{...}" }
|
||||
|
||||
final override Stmt getStmt(int n) { result = generated.getChild(n) }
|
||||
|
||||
final override string getValueText() { none() }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
StmtSequence::Range.super.child(label, child)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module StringlikeLiteral {
|
||||
abstract class Range extends Literal::Range {
|
||||
abstract StringComponent::Range getComponent(int i);
|
||||
|
||||
string getStartDelimiter() { result = "" }
|
||||
|
||||
string getEndDelimiter() { result = "" }
|
||||
|
||||
final predicate isSimple() { count(this.getComponent(_)) <= 1 }
|
||||
|
||||
override string getValueText() {
|
||||
// 0 components should result in the empty string
|
||||
// if there are any interpolations, there should be no result
|
||||
// otherwise, concatenate all the components
|
||||
forall(StringComponent c | c = this.getComponent(_) |
|
||||
not c instanceof StringInterpolationComponent::Range
|
||||
) and
|
||||
result =
|
||||
concat(StringComponent::Range c, int i |
|
||||
c = this.getComponent(i)
|
||||
|
|
||||
c.getValueText() order by i
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
exists(string full, string summary |
|
||||
full =
|
||||
concat(StringComponent::Range c, int i, string s |
|
||||
c = this.getComponent(i) and
|
||||
if c instanceof Generated::Token
|
||||
then s = c.(Generated::Token).getValue()
|
||||
else s = "#{...}"
|
||||
|
|
||||
s order by i
|
||||
) and
|
||||
(
|
||||
// summary should be 32 chars max (incl. ellipsis)
|
||||
full.length() > 32 and summary = full.substring(0, 29) + "..."
|
||||
or
|
||||
full.length() <= 32 and summary = full
|
||||
) and
|
||||
result = this.getStartDelimiter() + summary + this.getEndDelimiter()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getComponent" and child = getComponent(_)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module StringLiteral {
|
||||
abstract class Range extends StringlikeLiteral::Range {
|
||||
final override string getStartDelimiter() { result = "\"" }
|
||||
|
||||
final override string getEndDelimiter() { result = "\"" }
|
||||
}
|
||||
|
||||
private class RegularStringRange extends StringLiteral::Range, @string__ {
|
||||
final override Generated::String generated;
|
||||
|
||||
final override StringComponent::Range getComponent(int i) { result = generated.getChild(i) }
|
||||
}
|
||||
|
||||
private class BareStringRange extends StringLiteral::Range, @bare_string {
|
||||
final override Generated::BareString generated;
|
||||
|
||||
final override StringComponent::Range getComponent(int i) { result = generated.getChild(i) }
|
||||
}
|
||||
}
|
||||
|
||||
module RegexLiteral {
|
||||
class Range extends StringlikeLiteral::Range, @regex {
|
||||
final override Generated::Regex generated;
|
||||
|
||||
final override StringComponent::Range getComponent(int i) { result = generated.getChild(i) }
|
||||
|
||||
final override string getStartDelimiter() { result = "/" }
|
||||
|
||||
final override string getEndDelimiter() { result = "/" }
|
||||
|
||||
final string getFlagString() {
|
||||
// For `/foo/i`, there should be an `/i` token in the database with `this`
|
||||
// as its parents. Strip the delimiter, which can vary.
|
||||
result =
|
||||
max(Generated::Token t |
|
||||
t.getParent() = this
|
||||
|
|
||||
t.getValue().suffix(1) order by t.getParentIndex()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module SymbolLiteral {
|
||||
abstract class Range extends StringlikeLiteral::Range { }
|
||||
|
||||
class SimpleSymbolRange extends SymbolLiteral::Range {
|
||||
final override Generated::SimpleSymbol generated;
|
||||
|
||||
final override StringComponent::Range getComponent(int i) { none() }
|
||||
|
||||
final override string getStartDelimiter() { result = ":" }
|
||||
|
||||
// Tree-sitter gives us value text including the colon, which we skip.
|
||||
final override string getValueText() { result = generated.getValue().suffix(1) }
|
||||
|
||||
final override string toString() { result = generated.getValue() }
|
||||
}
|
||||
|
||||
abstract private class ComplexSymbolRange extends SymbolLiteral::Range {
|
||||
final override string getStartDelimiter() { result = ":\"" }
|
||||
|
||||
final override string getEndDelimiter() { result = "\"" }
|
||||
}
|
||||
|
||||
class DelimitedSymbolRange extends ComplexSymbolRange, @delimited_symbol {
|
||||
final override Generated::DelimitedSymbol generated;
|
||||
|
||||
final override StringComponent::Range getComponent(int i) { result = generated.getChild(i) }
|
||||
}
|
||||
|
||||
class BareSymbolRange extends ComplexSymbolRange, @bare_symbol {
|
||||
final override Generated::BareSymbol generated;
|
||||
|
||||
final override StringComponent::Range getComponent(int i) { result = generated.getChild(i) }
|
||||
}
|
||||
|
||||
class HashKeySymbolRange extends SymbolLiteral::Range, @token_hash_key_symbol {
|
||||
final override Generated::HashKeySymbol generated;
|
||||
|
||||
final override StringComponent::Range getComponent(int i) { none() }
|
||||
|
||||
final override string getValueText() { result = generated.getValue() }
|
||||
|
||||
final override string toString() { result = ":" + this.getValueText() }
|
||||
}
|
||||
}
|
||||
|
||||
module SubshellLiteral {
|
||||
class Range extends StringlikeLiteral::Range, @subshell {
|
||||
final override Generated::Subshell generated;
|
||||
|
||||
final override StringComponent::Range getComponent(int i) { result = generated.getChild(i) }
|
||||
|
||||
final override string getStartDelimiter() { result = "`" }
|
||||
|
||||
final override string getEndDelimiter() { result = "`" }
|
||||
}
|
||||
}
|
||||
|
||||
module CharacterLiteral {
|
||||
class Range extends Literal::Range, @token_character {
|
||||
final override Generated::Character generated;
|
||||
|
||||
final override string getValueText() { result = generated.getValue() }
|
||||
|
||||
final override string toString() { result = generated.getValue() }
|
||||
}
|
||||
}
|
||||
|
||||
module HereDoc {
|
||||
private Generated::HeredocBody heredoc(Generated::HeredocBeginning start) {
|
||||
exists(int i, File f |
|
||||
start =
|
||||
rank[i](Generated::HeredocBeginning b |
|
||||
f = b.getLocation().getFile()
|
||||
|
|
||||
b order by b.getLocation().getStartLine(), b.getLocation().getStartColumn()
|
||||
) and
|
||||
result =
|
||||
rank[i](Generated::HeredocBody b |
|
||||
f = b.getLocation().getFile()
|
||||
|
|
||||
b order by b.getLocation().getStartLine(), b.getLocation().getStartColumn()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class Range extends StringlikeLiteral::Range, @token_heredoc_beginning {
|
||||
final override Generated::HeredocBeginning generated;
|
||||
private Generated::HeredocBody body;
|
||||
|
||||
Range() { body = heredoc(this) }
|
||||
|
||||
final override StringComponent::Range getComponent(int n) { result = body.getChild(n) }
|
||||
|
||||
final string getQuoteStyle() {
|
||||
exists(string s |
|
||||
s = generated.getValue() and
|
||||
s.charAt(s.length() - 1) = result and
|
||||
result = ["'", "`", "\""]
|
||||
)
|
||||
}
|
||||
|
||||
final string getIndentationModifier() {
|
||||
exists(string s |
|
||||
s = generated.getValue() and
|
||||
s.charAt(2) = result and
|
||||
result = ["-", "~"]
|
||||
)
|
||||
}
|
||||
|
||||
final override string toString() { result = generated.getValue() }
|
||||
}
|
||||
}
|
||||
|
||||
module ArrayLiteral {
|
||||
abstract class Range extends Literal::Range {
|
||||
final override string getValueText() { none() }
|
||||
|
||||
abstract Expr getElement(int i);
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getElement" and child = getElement(_)
|
||||
}
|
||||
}
|
||||
|
||||
private class RegularArrayRange extends ArrayLiteral::Range, @array {
|
||||
final override Generated::Array generated;
|
||||
|
||||
final override Expr getElement(int i) { result = generated.getChild(i) }
|
||||
|
||||
final override string toString() { result = "[...]" }
|
||||
}
|
||||
|
||||
private class StringArrayRange extends ArrayLiteral::Range, @string_array {
|
||||
final override Generated::StringArray generated;
|
||||
|
||||
final override Expr getElement(int i) { result = generated.getChild(i) }
|
||||
|
||||
final override string toString() { result = "%w(...)" }
|
||||
}
|
||||
|
||||
private class SymbolArrayRange extends ArrayLiteral::Range, @symbol_array {
|
||||
final override Generated::SymbolArray generated;
|
||||
|
||||
final override Expr getElement(int i) { result = generated.getChild(i) }
|
||||
|
||||
final override string toString() { result = "%i(...)" }
|
||||
}
|
||||
}
|
||||
|
||||
module HashLiteral {
|
||||
class Range extends Literal::Range, @hash {
|
||||
final override Generated::Hash generated;
|
||||
|
||||
final override string getValueText() { none() }
|
||||
|
||||
final Expr getElement(int i) { result = generated.getChild(i) }
|
||||
|
||||
final override string toString() { result = "{...}" }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getElement" and child = getElement(_)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module RangeLiteral {
|
||||
class Range extends Literal::Range, @range {
|
||||
final override Generated::Range generated;
|
||||
|
||||
final override string getValueText() { none() }
|
||||
|
||||
final override string toString() { result = "_ " + generated.getOperator() + " _" }
|
||||
|
||||
final Expr getBegin() { result = generated.getBegin() }
|
||||
|
||||
final Expr getEnd() { result = generated.getEnd() }
|
||||
|
||||
final predicate isInclusive() { this instanceof @range_dotdot }
|
||||
|
||||
final predicate isExclusive() { this instanceof @range_dotdotdot }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getBegin" and child = getBegin()
|
||||
or
|
||||
label = "getEnd" and child = getEnd()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module MethodName {
|
||||
private class TokenTypes =
|
||||
@setter or @token_class_variable or @token_constant or @token_global_variable or
|
||||
@token_identifier or @token_instance_variable or @token_operator;
|
||||
|
||||
abstract class Range extends Literal::Range, @underscore_method_name {
|
||||
Range() {
|
||||
exists(Generated::Undef u | u.getChild(_) = generated)
|
||||
or
|
||||
exists(Generated::Alias a | a.getName() = generated or a.getAlias() = generated)
|
||||
}
|
||||
}
|
||||
|
||||
private class TokenMethodName extends MethodName::Range, TokenTypes {
|
||||
final override Generated::UnderscoreMethodName generated;
|
||||
|
||||
final override string getValueText() {
|
||||
result = generated.(Generated::Token).getValue()
|
||||
or
|
||||
result = generated.(Generated::Setter).getName().getValue() + "="
|
||||
}
|
||||
}
|
||||
|
||||
private class SimpleSymbolMethodName extends MethodName::Range, SymbolLiteral::SimpleSymbolRange,
|
||||
@token_simple_symbol { }
|
||||
|
||||
private class DelimitedSymbolMethodName extends MethodName::Range,
|
||||
SymbolLiteral::DelimitedSymbolRange, @delimited_symbol { }
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Expr
|
||||
private import codeql_ruby.ast.internal.Parameter
|
||||
private import TreeSitter
|
||||
|
||||
module Callable {
|
||||
abstract class Range extends Expr::Range {
|
||||
abstract Parameter::Range getParameter(int n);
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getParameter" and child = getParameter(_)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module Method {
|
||||
class Range extends Callable::Range, BodyStatement::Range, @method {
|
||||
final override Generated::Method generated;
|
||||
|
||||
override Parameter::Range getParameter(int n) { result = generated.getParameters().getChild(n) }
|
||||
|
||||
string getName() {
|
||||
result = generated.getName().(Generated::Token).getValue() or
|
||||
result = generated.getName().(Generated::Setter).getName().getValue() + "="
|
||||
}
|
||||
|
||||
final predicate isSetter() { generated.getName() instanceof Generated::Setter }
|
||||
|
||||
final override Generated::AstNode getChild(int i) { result = generated.getChild(i) }
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
Callable::Range.super.child(label, child) or BodyStatement::Range.super.child(label, child)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module SingletonMethod {
|
||||
class Range extends Callable::Range, BodyStatement::Range, @singleton_method {
|
||||
final override Generated::SingletonMethod generated;
|
||||
|
||||
override Parameter::Range getParameter(int n) { result = generated.getParameters().getChild(n) }
|
||||
|
||||
string getName() {
|
||||
result = generated.getName().(Generated::Token).getValue() or
|
||||
result = generated.getName().(SymbolLiteral).getValueText() or
|
||||
result = generated.getName().(Generated::Setter).getName().getValue() + "="
|
||||
}
|
||||
|
||||
final Generated::AstNode getObject() { result = generated.getObject() }
|
||||
|
||||
final override Generated::AstNode getChild(int i) { result = generated.getChild(i) }
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
Callable::Range.super.child(label, child)
|
||||
or
|
||||
BodyStatement::Range.super.child(label, child)
|
||||
or
|
||||
label = "getObject" and child = getObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module Lambda {
|
||||
class Range extends Callable::Range, BodyStatement::Range, @lambda {
|
||||
final override Generated::Lambda generated;
|
||||
|
||||
final override Parameter::Range getParameter(int n) {
|
||||
result = generated.getParameters().getChild(n)
|
||||
}
|
||||
|
||||
final override Generated::AstNode getChild(int i) {
|
||||
result = generated.getBody().(Generated::DoBlock).getChild(i) or
|
||||
result = generated.getBody().(Generated::Block).getChild(i)
|
||||
}
|
||||
|
||||
final override string toString() { result = "-> { ... }" }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
Callable::Range.super.child(label, child)
|
||||
or
|
||||
BodyStatement::Range.super.child(label, child)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module Block {
|
||||
abstract class Range extends Callable::Range, StmtSequence::Range {
|
||||
Range() { not generated.getParent() instanceof Generated::Lambda }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
Callable::Range.super.child(label, child)
|
||||
or
|
||||
StmtSequence::Range.super.child(label, child)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module DoBlock {
|
||||
class Range extends Block::Range, BodyStatement::Range, @do_block {
|
||||
final override Generated::DoBlock generated;
|
||||
|
||||
final override Generated::AstNode getChild(int i) { result = generated.getChild(i) }
|
||||
|
||||
final override Parameter::Range getParameter(int n) {
|
||||
result = generated.getParameters().getChild(n)
|
||||
}
|
||||
|
||||
final override string toString() { result = "do ... end" }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
Block::Range.super.child(label, child)
|
||||
or
|
||||
BodyStatement::Range.super.child(label, child)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module BraceBlock {
|
||||
class Range extends Block::Range, @block {
|
||||
final override Generated::Block generated;
|
||||
|
||||
final override Parameter::Range getParameter(int n) {
|
||||
result = generated.getParameters().getChild(n)
|
||||
}
|
||||
|
||||
final override Stmt getStmt(int i) { result = generated.getChild(i) }
|
||||
|
||||
final override string toString() { result = "{ ... }" }
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Constant
|
||||
private import codeql_ruby.ast.internal.Expr
|
||||
private import codeql_ruby.ast.internal.TreeSitter
|
||||
|
||||
module ModuleBase {
|
||||
abstract class Range extends BodyStatement::Range { }
|
||||
}
|
||||
|
||||
module Namespace {
|
||||
abstract class Range extends ModuleBase::Range, ConstantWriteAccess::Range {
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
ModuleBase::Range.super.child(label, child) or
|
||||
ConstantWriteAccess::Range.super.child(label, child)
|
||||
}
|
||||
|
||||
override string toString() { result = ModuleBase::Range.super.toString() }
|
||||
}
|
||||
}
|
||||
|
||||
module Toplevel {
|
||||
class Range extends ModuleBase::Range, @program {
|
||||
final override Generated::Program generated;
|
||||
|
||||
Range() { generated.getLocation().getFile().getExtension() != "erb" }
|
||||
|
||||
final override Generated::AstNode getChild(int i) {
|
||||
result = generated.getChild(i) and
|
||||
not result instanceof Generated::BeginBlock
|
||||
}
|
||||
|
||||
final StmtSequence getBeginBlock(int n) {
|
||||
result = rank[n](int i, Generated::BeginBlock b | b = generated.getChild(i) | b order by i)
|
||||
}
|
||||
|
||||
final override string toString() { result = generated.getLocation().getFile().getBaseName() }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
ModuleBase::Range.super.child(label, child)
|
||||
or
|
||||
label = "getBeginBlock" and child = getBeginBlock(_)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module Class {
|
||||
class Range extends Namespace::Range, @class {
|
||||
final override Generated::Class generated;
|
||||
|
||||
final override Generated::AstNode getChild(int i) { result = generated.getChild(i) }
|
||||
|
||||
final override string getName() {
|
||||
result = generated.getName().(Generated::Token).getValue() or
|
||||
result =
|
||||
generated.getName().(Generated::ScopeResolution).getName().(Generated::Token).getValue()
|
||||
}
|
||||
|
||||
final override Expr::Range getScopeExpr() {
|
||||
result = generated.getName().(Generated::ScopeResolution).getScope()
|
||||
}
|
||||
|
||||
final override predicate hasGlobalScope() {
|
||||
exists(Generated::ScopeResolution sr |
|
||||
sr = generated.getName() and
|
||||
not exists(sr.getScope())
|
||||
)
|
||||
}
|
||||
|
||||
final Expr getSuperclassExpr() { result = generated.getSuperclass().getChild() }
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
Namespace::Range.super.child(label, child)
|
||||
or
|
||||
label = "getSuperclassExpr" and child = getSuperclassExpr()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module SingletonClass {
|
||||
class Range extends ModuleBase::Range, @singleton_class {
|
||||
final override Generated::SingletonClass generated;
|
||||
|
||||
final override Generated::AstNode getChild(int i) { result = generated.getChild(i) }
|
||||
|
||||
final Expr getValue() { result = generated.getValue() }
|
||||
|
||||
final override string toString() { result = "class << ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
ModuleBase::Range.super.child(label, child)
|
||||
or
|
||||
label = "getValue" and child = getValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module Module {
|
||||
class Range extends Namespace::Range, @module {
|
||||
final override Generated::Module generated;
|
||||
|
||||
final override Generated::AstNode getChild(int i) { result = generated.getChild(i) }
|
||||
|
||||
final override string getName() {
|
||||
result = generated.getName().(Generated::Token).getValue() or
|
||||
result =
|
||||
generated.getName().(Generated::ScopeResolution).getName().(Generated::Token).getValue()
|
||||
}
|
||||
|
||||
final override Expr::Range getScopeExpr() {
|
||||
result = generated.getName().(Generated::ScopeResolution).getScope()
|
||||
}
|
||||
|
||||
final override predicate hasGlobalScope() {
|
||||
exists(Generated::ScopeResolution sr |
|
||||
sr = generated.getName() and
|
||||
not exists(sr.getScope())
|
||||
)
|
||||
}
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
Namespace::Range.super.child(label, child)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,355 +0,0 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.TreeSitter
|
||||
private import codeql_ruby.ast.internal.Expr
|
||||
|
||||
module Operation {
|
||||
abstract class Range extends Expr::Range {
|
||||
abstract string getOperator();
|
||||
|
||||
abstract Stmt getAnOperand();
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getAnOperand" and child = getAnOperand()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module UnaryOperation {
|
||||
abstract class Range extends Operation::Range, @unary {
|
||||
final override Generated::Unary generated;
|
||||
|
||||
final override string getOperator() { result = generated.getOperator() }
|
||||
|
||||
Expr getOperand() { result = generated.getOperand() }
|
||||
|
||||
final override Expr getAnOperand() { result = this.getOperand() }
|
||||
|
||||
override string toString() { result = this.getOperator() + " ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
Operation::Range.super.child(label, child)
|
||||
or
|
||||
label = "getOperand" and child = getOperand()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module UnaryLogicalOperation {
|
||||
abstract class Range extends UnaryOperation::Range { }
|
||||
}
|
||||
|
||||
module UnaryArithmeticOperation {
|
||||
abstract class Range extends UnaryOperation::Range { }
|
||||
}
|
||||
|
||||
module UnaryBitwiseOperation {
|
||||
abstract class Range extends UnaryOperation::Range { }
|
||||
}
|
||||
|
||||
module NotExpr {
|
||||
class DbUnion = @unary_bang or @unary_not;
|
||||
|
||||
class Range extends UnaryLogicalOperation::Range, DbUnion { }
|
||||
}
|
||||
|
||||
module UnaryPlusExpr {
|
||||
class Range extends UnaryArithmeticOperation::Range, @unary_plus { }
|
||||
}
|
||||
|
||||
module UnaryMinusExpr {
|
||||
class Range extends UnaryArithmeticOperation::Range, @unary_minus { }
|
||||
}
|
||||
|
||||
module ComplementExpr {
|
||||
class Range extends UnaryBitwiseOperation::Range, @unary_tilde { }
|
||||
}
|
||||
|
||||
module DefinedExpr {
|
||||
class Range extends UnaryOperation::Range, @unary_definedquestion { }
|
||||
}
|
||||
|
||||
module BinaryOperation {
|
||||
abstract class Range extends Operation::Range, @binary {
|
||||
final override Generated::Binary generated;
|
||||
|
||||
final override string getOperator() { result = generated.getOperator() }
|
||||
|
||||
final Expr getLeftOperand() { result = generated.getLeft() }
|
||||
|
||||
final Stmt getRightOperand() { result = generated.getRight() }
|
||||
|
||||
final override Stmt getAnOperand() {
|
||||
result = this.getLeftOperand() or result = this.getRightOperand()
|
||||
}
|
||||
|
||||
override string toString() { result = "... " + this.getOperator() + " ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
Operation::Range.super.child(label, child)
|
||||
or
|
||||
label = "getLeftOperand" and child = getLeftOperand()
|
||||
or
|
||||
label = "getRightOperand" and child = getRightOperand()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module BinaryArithmeticOperation {
|
||||
abstract class Range extends BinaryOperation::Range { }
|
||||
}
|
||||
|
||||
module BinaryLogicalOperation {
|
||||
abstract class Range extends BinaryOperation::Range { }
|
||||
}
|
||||
|
||||
module BinaryBitwiseOperation {
|
||||
abstract class Range extends BinaryOperation::Range { }
|
||||
}
|
||||
|
||||
module ComparisonOperation {
|
||||
abstract class Range extends BinaryOperation::Range, @binary { }
|
||||
}
|
||||
|
||||
module AddExpr {
|
||||
class Range extends BinaryArithmeticOperation::Range, @binary_plus { }
|
||||
}
|
||||
|
||||
module SubExpr {
|
||||
class Range extends BinaryArithmeticOperation::Range, @binary_minus { }
|
||||
}
|
||||
|
||||
module MulExpr {
|
||||
class Range extends BinaryArithmeticOperation::Range, @binary_star { }
|
||||
}
|
||||
|
||||
module DivExpr {
|
||||
class Range extends BinaryArithmeticOperation::Range, @binary_slash { }
|
||||
}
|
||||
|
||||
module ModuloExpr {
|
||||
class Range extends BinaryArithmeticOperation::Range, @binary_percent { }
|
||||
}
|
||||
|
||||
module ExponentExpr {
|
||||
class Range extends BinaryArithmeticOperation::Range, @binary_starstar { }
|
||||
}
|
||||
|
||||
module LogicalAndExpr {
|
||||
class DbUnion = @binary_and or @binary_ampersandampersand;
|
||||
|
||||
class Range extends BinaryLogicalOperation::Range, DbUnion { }
|
||||
}
|
||||
|
||||
module LogicalOrExpr {
|
||||
class DbUnion = @binary_or or @binary_pipepipe;
|
||||
|
||||
class Range extends BinaryLogicalOperation::Range, DbUnion { }
|
||||
}
|
||||
|
||||
module LShiftExpr {
|
||||
class Range extends BinaryBitwiseOperation::Range, @binary_langlelangle { }
|
||||
}
|
||||
|
||||
module RShiftExpr {
|
||||
class Range extends BinaryBitwiseOperation::Range, @binary_ranglerangle { }
|
||||
}
|
||||
|
||||
module BitwiseAndExpr {
|
||||
class Range extends BinaryBitwiseOperation::Range, @binary_ampersand { }
|
||||
}
|
||||
|
||||
module BitwiseOrExpr {
|
||||
class Range extends BinaryBitwiseOperation::Range, @binary_pipe { }
|
||||
}
|
||||
|
||||
module BitwiseXorExpr {
|
||||
class Range extends BinaryBitwiseOperation::Range, @binary_caret { }
|
||||
}
|
||||
|
||||
module EqualityOperation {
|
||||
abstract class Range extends ComparisonOperation::Range { }
|
||||
}
|
||||
|
||||
module EqExpr {
|
||||
class Range extends EqualityOperation::Range, @binary_equalequal { }
|
||||
}
|
||||
|
||||
module NEExpr {
|
||||
class Range extends EqualityOperation::Range, @binary_bangequal { }
|
||||
}
|
||||
|
||||
module CaseEqExpr {
|
||||
class Range extends EqualityOperation::Range, @binary_equalequalequal { }
|
||||
}
|
||||
|
||||
module RelationalOperation {
|
||||
abstract class Range extends ComparisonOperation::Range {
|
||||
abstract Expr getGreaterOperand();
|
||||
|
||||
abstract Expr getLesserOperand();
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
ComparisonOperation::Range.super.child(label, child)
|
||||
or
|
||||
label = "getGreaterOperand" and child = getGreaterOperand()
|
||||
or
|
||||
label = "getLesserOperand" and child = getLesserOperand()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module GTExpr {
|
||||
class Range extends RelationalOperation::Range, @binary_rangle {
|
||||
final override Expr getGreaterOperand() { result = this.getLeftOperand() }
|
||||
|
||||
final override Expr getLesserOperand() { result = this.getRightOperand() }
|
||||
}
|
||||
}
|
||||
|
||||
module GEExpr {
|
||||
class Range extends RelationalOperation::Range, @binary_rangleequal {
|
||||
final override Expr getGreaterOperand() { result = this.getLeftOperand() }
|
||||
|
||||
final override Expr getLesserOperand() { result = this.getRightOperand() }
|
||||
}
|
||||
}
|
||||
|
||||
module LTExpr {
|
||||
class Range extends RelationalOperation::Range, @binary_langle {
|
||||
final override Expr getGreaterOperand() { result = this.getRightOperand() }
|
||||
|
||||
final override Expr getLesserOperand() { result = this.getLeftOperand() }
|
||||
}
|
||||
}
|
||||
|
||||
module LEExpr {
|
||||
class Range extends RelationalOperation::Range, @binary_langleequal {
|
||||
final override Expr getGreaterOperand() { result = this.getRightOperand() }
|
||||
|
||||
final override Expr getLesserOperand() { result = this.getLeftOperand() }
|
||||
}
|
||||
}
|
||||
|
||||
module SpaceshipExpr {
|
||||
class Range extends BinaryOperation::Range, @binary_langleequalrangle { }
|
||||
}
|
||||
|
||||
module RegexMatchExpr {
|
||||
class Range extends BinaryOperation::Range, @binary_equaltilde { }
|
||||
}
|
||||
|
||||
module NoRegexMatchExpr {
|
||||
class Range extends BinaryOperation::Range, @binary_bangtilde { }
|
||||
}
|
||||
|
||||
module Assignment {
|
||||
abstract class Range extends Operation::Range {
|
||||
abstract Pattern getLeftOperand();
|
||||
|
||||
abstract Expr getRightOperand();
|
||||
|
||||
final override Expr getAnOperand() {
|
||||
result = this.getLeftOperand() or result = this.getRightOperand()
|
||||
}
|
||||
|
||||
override string toString() { result = "... " + this.getOperator() + " ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
Operation::Range.super.child(label, child)
|
||||
or
|
||||
label = "getLeftOperand" and child = getLeftOperand()
|
||||
or
|
||||
label = "getRightOperand" and child = getRightOperand()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module AssignExpr {
|
||||
class Range extends Assignment::Range, @assignment {
|
||||
final override Generated::Assignment generated;
|
||||
|
||||
final override Pattern getLeftOperand() { result = generated.getLeft() }
|
||||
|
||||
final override Expr getRightOperand() { result = generated.getRight() }
|
||||
|
||||
final override string getOperator() { result = "=" }
|
||||
}
|
||||
}
|
||||
|
||||
module AssignOperation {
|
||||
abstract class Range extends Assignment::Range, @operator_assignment {
|
||||
final override Generated::OperatorAssignment generated;
|
||||
|
||||
final override string getOperator() { result = generated.getOperator() }
|
||||
|
||||
final override LhsExpr getLeftOperand() { result = generated.getLeft() }
|
||||
|
||||
final override Expr getRightOperand() { result = generated.getRight() }
|
||||
}
|
||||
}
|
||||
|
||||
module AssignArithmeticOperation {
|
||||
abstract class Range extends AssignOperation::Range { }
|
||||
}
|
||||
|
||||
module AssignLogicalOperation {
|
||||
abstract class Range extends AssignOperation::Range { }
|
||||
}
|
||||
|
||||
module AssignBitwiseOperation {
|
||||
abstract class Range extends AssignOperation::Range { }
|
||||
}
|
||||
|
||||
module AssignAddExpr {
|
||||
class Range extends AssignArithmeticOperation::Range, @operator_assignment_plusequal { }
|
||||
}
|
||||
|
||||
module AssignSubExpr {
|
||||
class Range extends AssignArithmeticOperation::Range, @operator_assignment_minusequal { }
|
||||
}
|
||||
|
||||
module AssignMulExpr {
|
||||
class Range extends AssignArithmeticOperation::Range, @operator_assignment_starequal { }
|
||||
}
|
||||
|
||||
module AssignDivExpr {
|
||||
class Range extends AssignArithmeticOperation::Range, @operator_assignment_slashequal { }
|
||||
}
|
||||
|
||||
module AssignExponentExpr {
|
||||
class Range extends AssignArithmeticOperation::Range, @operator_assignment_starstarequal { }
|
||||
}
|
||||
|
||||
module AssignModuloExpr {
|
||||
class Range extends AssignArithmeticOperation::Range, @operator_assignment_percentequal { }
|
||||
}
|
||||
|
||||
module AssignLogicalAndExpr {
|
||||
class Range extends AssignLogicalOperation::Range, @operator_assignment_ampersandampersandequal {
|
||||
}
|
||||
}
|
||||
|
||||
module AssignLogicalOrExpr {
|
||||
class Range extends AssignLogicalOperation::Range, @operator_assignment_pipepipeequal { }
|
||||
}
|
||||
|
||||
module AssignLShiftExpr {
|
||||
class Range extends AssignBitwiseOperation::Range, @operator_assignment_langlelangleequal { }
|
||||
}
|
||||
|
||||
module AssignRShiftExpr {
|
||||
class Range extends AssignBitwiseOperation::Range, @operator_assignment_ranglerangleequal { }
|
||||
}
|
||||
|
||||
module AssignBitwiseAndExpr {
|
||||
class Range extends AssignBitwiseOperation::Range, @operator_assignment_ampersandequal { }
|
||||
}
|
||||
|
||||
module AssignBitwiseOrExpr {
|
||||
class Range extends AssignBitwiseOperation::Range, @operator_assignment_pipeequal { }
|
||||
}
|
||||
|
||||
module AssignBitwiseXorExpr {
|
||||
class Range extends AssignBitwiseOperation::Range, @operator_assignment_caretequal { }
|
||||
}
|
||||
@@ -1,14 +1,9 @@
|
||||
private import codeql_ruby.AST
|
||||
private import AST
|
||||
private import TreeSitter
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Expr
|
||||
private import codeql_ruby.ast.internal.Variable
|
||||
private import codeql_ruby.ast.internal.Method
|
||||
private import codeql_ruby.ast.internal.Pattern
|
||||
private import codeql.Locations
|
||||
|
||||
module Parameter {
|
||||
class Range extends AstNode::Range {
|
||||
class Range extends Generated::AstNode {
|
||||
private int pos;
|
||||
|
||||
Range() {
|
||||
@@ -19,143 +14,6 @@ module Parameter {
|
||||
this = any(Generated::LambdaParameters lp).getChild(pos)
|
||||
}
|
||||
|
||||
final int getPosition() { result = pos }
|
||||
|
||||
LocalVariable getAVariable() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
module NamedParameter {
|
||||
abstract class Range extends Parameter::Range {
|
||||
abstract string getName();
|
||||
|
||||
abstract LocalVariable getVariable();
|
||||
|
||||
override LocalVariable getAVariable() { result = this.getVariable() }
|
||||
}
|
||||
}
|
||||
|
||||
module SimpleParameter {
|
||||
class Range extends NamedParameter::Range, PatternParameter::Range, VariablePattern::Range {
|
||||
final override string getName() { result = this.getVariableName() }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, this) }
|
||||
|
||||
final override LocalVariable getAVariable() { result = this.getVariable() }
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
}
|
||||
}
|
||||
|
||||
module PatternParameter {
|
||||
class Range extends Parameter::Range, Pattern::Range {
|
||||
override LocalVariable getAVariable() { result = this.(Pattern::Range).getAVariable() }
|
||||
|
||||
override string toString() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
module TuplePatternParameter {
|
||||
class Range extends PatternParameter::Range, TuplePattern::Range {
|
||||
override LocalVariable getAVariable() { result = TuplePattern::Range.super.getAVariable() }
|
||||
|
||||
override string toString() { result = TuplePattern::Range.super.toString() }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
PatternParameter::Range.super.child(label, child) or
|
||||
TuplePattern::Range.super.child(label, child)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module BlockParameter {
|
||||
class Range extends NamedParameter::Range, @block_parameter {
|
||||
final override Generated::BlockParameter generated;
|
||||
|
||||
final override string getName() { result = generated.getName().getValue() }
|
||||
|
||||
final override LocalVariable getVariable() {
|
||||
result = TLocalVariable(_, _, generated.getName())
|
||||
}
|
||||
|
||||
final override string toString() { result = "&" + this.getName() }
|
||||
}
|
||||
}
|
||||
|
||||
module HashSplatParameter {
|
||||
class Range extends NamedParameter::Range, @hash_splat_parameter {
|
||||
final override Generated::HashSplatParameter generated;
|
||||
|
||||
final override LocalVariable getVariable() {
|
||||
result = TLocalVariable(_, _, generated.getName())
|
||||
}
|
||||
|
||||
final override string toString() { result = "**" + this.getName() }
|
||||
|
||||
final override string getName() { result = generated.getName().getValue() }
|
||||
}
|
||||
}
|
||||
|
||||
module KeywordParameter {
|
||||
class Range extends NamedParameter::Range, @keyword_parameter {
|
||||
final override Generated::KeywordParameter generated;
|
||||
|
||||
final override LocalVariable getVariable() {
|
||||
result = TLocalVariable(_, _, generated.getName())
|
||||
}
|
||||
|
||||
final Expr::Range getDefaultValue() { result = generated.getValue() }
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
|
||||
final override string getName() { result = generated.getName().getValue() }
|
||||
|
||||
final override Location getLocation() { result = generated.getName().getLocation() }
|
||||
|
||||
final override predicate child(string label, AstNode::Range child) {
|
||||
NamedParameter::Range.super.child(label, child)
|
||||
or
|
||||
label = "getDefaultValue" and child = getDefaultValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module OptionalParameter {
|
||||
class Range extends NamedParameter::Range, @optional_parameter {
|
||||
final override Generated::OptionalParameter generated;
|
||||
|
||||
final override LocalVariable getVariable() {
|
||||
result = TLocalVariable(_, _, generated.getName())
|
||||
}
|
||||
|
||||
final Expr::Range getDefaultValue() { result = generated.getValue() }
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
|
||||
final override string getName() { result = generated.getName().getValue() }
|
||||
|
||||
final override Location getLocation() { result = generated.getName().getLocation() }
|
||||
|
||||
final override predicate child(string label, AstNode::Range child) {
|
||||
NamedParameter::Range.super.child(label, child)
|
||||
or
|
||||
label = "getDefaultValue" and child = getDefaultValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module SplatParameter {
|
||||
class Range extends NamedParameter::Range, @splat_parameter {
|
||||
final override Generated::SplatParameter generated;
|
||||
|
||||
final override LocalVariable getVariable() {
|
||||
result = TLocalVariable(_, _, generated.getName())
|
||||
}
|
||||
|
||||
final override string toString() { result = "*" + this.getName() }
|
||||
|
||||
final override string getName() { result = generated.getName().getValue() }
|
||||
int getPosition() { result = pos }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
private import codeql_ruby.AST
|
||||
private import TreeSitter
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Expr
|
||||
private import codeql_ruby.ast.internal.Variable
|
||||
private import codeql_ruby.ast.internal.Method
|
||||
private import codeql.Locations
|
||||
|
||||
/**
|
||||
* Holds if `n` is in the left-hand-side of an explicit assignment `assignment`.
|
||||
*/
|
||||
predicate explicitAssignmentNode(Generated::AstNode n, Generated::AstNode assignment) {
|
||||
n = assignment.(Generated::Assignment).getLeft()
|
||||
or
|
||||
n = assignment.(Generated::OperatorAssignment).getLeft()
|
||||
or
|
||||
exists(Generated::AstNode parent |
|
||||
parent = n.getParent() and
|
||||
explicitAssignmentNode(parent, assignment)
|
||||
|
|
||||
parent instanceof Generated::DestructuredLeftAssignment
|
||||
or
|
||||
parent instanceof Generated::LeftAssignmentList
|
||||
or
|
||||
parent instanceof Generated::RestAssignment
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `n` is inside an implicit assignment. */
|
||||
predicate implicitAssignmentNode(Generated::AstNode n) {
|
||||
n = any(Generated::ExceptionVariable ev).getChild()
|
||||
or
|
||||
n = any(Generated::For for).getPattern()
|
||||
or
|
||||
implicitAssignmentNode(n.getParent())
|
||||
}
|
||||
|
||||
/** Holds if `n` is inside a parameter. */
|
||||
predicate implicitParameterAssignmentNode(Generated::AstNode n, Callable::Range c) {
|
||||
n = c.getParameter(_)
|
||||
or
|
||||
implicitParameterAssignmentNode(n.getParent().(Generated::DestructuredParameter), c)
|
||||
}
|
||||
|
||||
module Pattern {
|
||||
abstract class Range extends AstNode::Range {
|
||||
cached
|
||||
Range() {
|
||||
explicitAssignmentNode(this, _)
|
||||
or
|
||||
implicitAssignmentNode(this)
|
||||
or
|
||||
implicitParameterAssignmentNode(this, _)
|
||||
}
|
||||
|
||||
Variable getAVariable() { none() }
|
||||
|
||||
override string toString() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
module LhsExpr {
|
||||
abstract class Range extends Pattern::Range, Expr::Range { }
|
||||
}
|
||||
|
||||
module VariablePattern {
|
||||
class VariableToken =
|
||||
@token_identifier or @token_instance_variable or @token_class_variable or @token_global_variable;
|
||||
|
||||
class Range extends LhsExpr::Range, VariableToken {
|
||||
override Generated::Token generated;
|
||||
|
||||
string getVariableName() { result = generated.getValue() }
|
||||
|
||||
override Variable getAVariable() { access(this, result) }
|
||||
|
||||
override string toString() { result = this.getVariableName() }
|
||||
}
|
||||
}
|
||||
|
||||
module TuplePattern {
|
||||
private class Range_ =
|
||||
@destructured_parameter or @destructured_left_assignment or @left_assignment_list;
|
||||
|
||||
class Range extends Pattern::Range, Range_ {
|
||||
Pattern::Range getElement(int i) {
|
||||
exists(Generated::AstNode c | c = getChild(i) |
|
||||
result = c.(Generated::RestAssignment).getChild()
|
||||
or
|
||||
not c instanceof Generated::RestAssignment and result = c
|
||||
)
|
||||
}
|
||||
|
||||
private Generated::AstNode getChild(int i) {
|
||||
result = this.(Generated::DestructuredParameter).getChild(i)
|
||||
or
|
||||
result = this.(Generated::DestructuredLeftAssignment).getChild(i)
|
||||
or
|
||||
result = this.(Generated::LeftAssignmentList).getChild(i)
|
||||
}
|
||||
|
||||
int getRestIndex() { result = unique(int i | getChild(i) instanceof Generated::RestAssignment) }
|
||||
|
||||
override Variable getAVariable() { result = this.getElement(_).getAVariable() }
|
||||
|
||||
override string toString() { result = "(..., ...)" }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getElement" and child = getElement(_)
|
||||
}
|
||||
}
|
||||
}
|
||||
85
ql/src/codeql_ruby/ast/internal/Scope.qll
Normal file
85
ql/src/codeql_ruby/ast/internal/Scope.qll
Normal file
@@ -0,0 +1,85 @@
|
||||
private import TreeSitter
|
||||
private import codeql_ruby.ast.Scope
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Parameter
|
||||
|
||||
class TScopeType = TMethodBase or TModuleLike or TBlockLike;
|
||||
|
||||
private class TBlockLike = TDoBlock or TLambda or TBlock or TEndBlock;
|
||||
|
||||
private class TModuleLike = TToplevel or TModule or TClass or TSingletonClass;
|
||||
|
||||
module Scope {
|
||||
class TypeRange = Callable::TypeRange or ModuleBase::TypeRange or @end_block;
|
||||
|
||||
class Range extends Generated::AstNode, TypeRange {
|
||||
Range() { not this = any(Generated::Lambda l).getBody() }
|
||||
|
||||
ModuleBase::Range getEnclosingModule() {
|
||||
result = this
|
||||
or
|
||||
not this instanceof ModuleBase::Range and result = this.getOuterScope().getEnclosingModule()
|
||||
}
|
||||
|
||||
MethodBase::Range getEnclosingMethod() {
|
||||
result = this
|
||||
or
|
||||
not this instanceof MethodBase::Range and
|
||||
not this instanceof ModuleBase::Range and
|
||||
result = this.getOuterScope().getEnclosingMethod()
|
||||
}
|
||||
|
||||
Range getOuterScope() { result = scopeOf(this) }
|
||||
}
|
||||
}
|
||||
|
||||
module MethodBase {
|
||||
class TypeRange = @method or @singleton_method;
|
||||
|
||||
class Range extends Scope::Range, TypeRange { }
|
||||
}
|
||||
|
||||
module Callable {
|
||||
class TypeRange = MethodBase::TypeRange or @do_block or @lambda or @block;
|
||||
|
||||
class Range extends Scope::Range, TypeRange {
|
||||
Parameter::Range getParameter(int i) {
|
||||
result = this.(Generated::Method).getParameters().getChild(i) or
|
||||
result = this.(Generated::SingletonMethod).getParameters().getChild(i) or
|
||||
result = this.(Generated::DoBlock).getParameters().getChild(i) or
|
||||
result = this.(Generated::Lambda).getParameters().getChild(i) or
|
||||
result = this.(Generated::Block).getParameters().getChild(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module ModuleBase {
|
||||
class TypeRange = @program or @module or @class or @singleton_class;
|
||||
|
||||
class Range extends Scope::Range, TypeRange { }
|
||||
}
|
||||
|
||||
private Generated::AstNode parentOf(Generated::AstNode n) {
|
||||
exists(Generated::AstNode parent | parent = n.getParent() |
|
||||
if
|
||||
n =
|
||||
[
|
||||
parent.(Generated::Module).getName(), parent.(Generated::Class).getName(),
|
||||
parent.(Generated::Class).getSuperclass(), parent.(Generated::SingletonClass).getValue(),
|
||||
parent.(Generated::Method).getName(), parent.(Generated::SingletonMethod).getName(),
|
||||
parent.(Generated::SingletonMethod).getObject()
|
||||
]
|
||||
then result = parent.getParent()
|
||||
else result = parent
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the enclosing scope of a node */
|
||||
cached
|
||||
Scope::Range scopeOf(Generated::AstNode n) {
|
||||
exists(Generated::AstNode p | p = parentOf(n) |
|
||||
p = result
|
||||
or
|
||||
not p instanceof Scope::Range and result = scopeOf(p)
|
||||
)
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Expr
|
||||
private import codeql_ruby.ast.internal.TreeSitter
|
||||
|
||||
module Stmt {
|
||||
abstract class Range extends AstNode::Range { }
|
||||
}
|
||||
|
||||
module EmptyStmt {
|
||||
class Range extends Stmt::Range, @token_empty_statement {
|
||||
final override Generated::EmptyStatement generated;
|
||||
|
||||
final override string toString() { result = ";" }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) { none() }
|
||||
}
|
||||
}
|
||||
|
||||
module Begin {
|
||||
class Range extends BodyStatement::Range, @begin {
|
||||
final override Generated::Begin generated;
|
||||
|
||||
final override Generated::AstNode getChild(int n) { result = generated.getChild(n) }
|
||||
|
||||
final override string toString() { result = "begin ... " }
|
||||
}
|
||||
}
|
||||
|
||||
module BeginBlock {
|
||||
class Range extends StmtSequence::Range, @begin_block {
|
||||
final override Generated::BeginBlock generated;
|
||||
|
||||
final override Stmt getStmt(int n) { result = generated.getChild(n) }
|
||||
|
||||
final override string toString() { result = "BEGIN { ... }" }
|
||||
}
|
||||
}
|
||||
|
||||
module EndBlock {
|
||||
class Range extends StmtSequence::Range, @end_block {
|
||||
final override Generated::EndBlock generated;
|
||||
|
||||
final override Stmt getStmt(int n) { result = generated.getChild(n) }
|
||||
|
||||
final override string toString() { result = "END { ... }" }
|
||||
}
|
||||
}
|
||||
|
||||
module UndefStmt {
|
||||
class Range extends Stmt::Range, @undef {
|
||||
final override Generated::Undef generated;
|
||||
|
||||
final MethodName getMethodName(int n) { result = generated.getChild(n) }
|
||||
|
||||
final override string toString() { result = "undef ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getMethodName" and child = getMethodName(_)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module AliasStmt {
|
||||
class Range extends Stmt::Range, @alias {
|
||||
final override Generated::Alias generated;
|
||||
|
||||
final MethodName getNewName() { result = generated.getName() }
|
||||
|
||||
final MethodName getOldName() { result = generated.getAlias() }
|
||||
|
||||
final override string toString() { result = "alias ..." }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getNewName" and child = getNewName()
|
||||
or
|
||||
label = "getOldName" and child = getOldName()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module ReturningStmt {
|
||||
abstract class Range extends Stmt::Range {
|
||||
abstract Generated::ArgumentList getArgumentList();
|
||||
|
||||
final Expr getValue() {
|
||||
exists(Generated::ArgumentList a, int c |
|
||||
a = this.getArgumentList() and c = count(a.getChild(_))
|
||||
|
|
||||
result = a.getChild(0) and c = 1
|
||||
or
|
||||
result = a and c > 1
|
||||
)
|
||||
}
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
label = "getValue" and child = getValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module ReturnStmt {
|
||||
class Range extends ReturningStmt::Range, @return {
|
||||
final override Generated::Return generated;
|
||||
|
||||
final override string toString() { result = "return" }
|
||||
|
||||
final override Generated::ArgumentList getArgumentList() { result = generated.getChild() }
|
||||
}
|
||||
}
|
||||
|
||||
module BreakStmt {
|
||||
class Range extends ReturningStmt::Range, @break {
|
||||
final override Generated::Break generated;
|
||||
|
||||
final override string toString() { result = "break" }
|
||||
|
||||
final override Generated::ArgumentList getArgumentList() { result = generated.getChild() }
|
||||
}
|
||||
}
|
||||
|
||||
module NextStmt {
|
||||
class Range extends ReturningStmt::Range, @next {
|
||||
final override Generated::Next generated;
|
||||
|
||||
final override string toString() { result = "next" }
|
||||
|
||||
final override Generated::ArgumentList getArgumentList() { result = generated.getChild() }
|
||||
}
|
||||
}
|
||||
|
||||
module RedoStmt {
|
||||
class Range extends Stmt::Range, @redo {
|
||||
final override Generated::Redo generated;
|
||||
|
||||
final override string toString() { result = "redo" }
|
||||
}
|
||||
}
|
||||
|
||||
module RetryStmt {
|
||||
class Range extends Stmt::Range, @retry {
|
||||
final override Generated::Retry generated;
|
||||
|
||||
final override string toString() { result = "retry" }
|
||||
}
|
||||
}
|
||||
@@ -2,83 +2,74 @@ private import TreeSitter
|
||||
private import codeql.Locations
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Expr
|
||||
private import codeql_ruby.ast.internal.Method
|
||||
private import codeql_ruby.ast.internal.Module
|
||||
private import codeql_ruby.ast.internal.Pattern
|
||||
private import codeql_ruby.ast.internal.Parameter
|
||||
private import codeql_ruby.ast.internal.Scope
|
||||
|
||||
Generated::AstNode parentOf(Generated::AstNode n) {
|
||||
exists(Generated::AstNode parent | parent = n.getParent() |
|
||||
if
|
||||
n =
|
||||
[
|
||||
parent.(Generated::Module).getName(), parent.(Generated::Class).getName(),
|
||||
parent.(Generated::Class).getSuperclass(), parent.(Generated::SingletonClass).getValue(),
|
||||
parent.(Generated::Method).getName(), parent.(Generated::SingletonMethod).getName(),
|
||||
parent.(Generated::SingletonMethod).getObject()
|
||||
]
|
||||
then result = parent.getParent()
|
||||
else result = parent
|
||||
/**
|
||||
* Holds if `n` is in the left-hand-side of an explicit assignment `assignment`.
|
||||
*/
|
||||
predicate explicitAssignmentNode(Generated::AstNode n, Generated::AstNode assignment) {
|
||||
n = assignment.(Generated::Assignment).getLeft()
|
||||
or
|
||||
n = assignment.(Generated::OperatorAssignment).getLeft()
|
||||
or
|
||||
exists(Generated::AstNode parent |
|
||||
parent = n.getParent() and
|
||||
explicitAssignmentNode(parent, assignment)
|
||||
|
|
||||
parent instanceof Generated::DestructuredLeftAssignment
|
||||
or
|
||||
parent instanceof Generated::LeftAssignmentList
|
||||
or
|
||||
parent instanceof Generated::RestAssignment
|
||||
)
|
||||
}
|
||||
|
||||
private Generated::AstNode parentOfNoScope(Generated::AstNode n) {
|
||||
result = parentOf(n) and
|
||||
not n = any(VariableScope::Range s).getScopeElement()
|
||||
/** Holds if `n` is inside an implicit assignment. */
|
||||
predicate implicitAssignmentNode(Generated::AstNode n) {
|
||||
n = any(Generated::ExceptionVariable ev).getChild()
|
||||
or
|
||||
n = any(Generated::For for).getPattern()
|
||||
or
|
||||
implicitAssignmentNode(n.getParent())
|
||||
}
|
||||
|
||||
/** Holds if `n` is inside a parameter. */
|
||||
predicate implicitParameterAssignmentNode(Generated::AstNode n, Callable::Range c) {
|
||||
n = c.getParameter(_)
|
||||
or
|
||||
implicitParameterAssignmentNode(n.getParent().(Generated::DestructuredParameter), c)
|
||||
}
|
||||
|
||||
private predicate instanceVariableAccess(
|
||||
Generated::InstanceVariable var, string name, VariableScope scope, boolean instance
|
||||
Generated::InstanceVariable var, string name, Scope::Range scope, boolean instance
|
||||
) {
|
||||
name = var.getValue() and
|
||||
scope = enclosingModuleOrClass(var) and
|
||||
if hasEnclosingMethod(var) then instance = true else instance = false
|
||||
}
|
||||
|
||||
private predicate classVariableAccess(Generated::ClassVariable var, string name, VariableScope scope) {
|
||||
private predicate classVariableAccess(Generated::ClassVariable var, string name, Scope::Range scope) {
|
||||
name = var.getValue() and
|
||||
scope = enclosingModuleOrClass(var)
|
||||
}
|
||||
|
||||
predicate hasEnclosingMethod(Generated::AstNode node) {
|
||||
exists(Callable::Range method |
|
||||
parentCallableScope*(enclosingScope(node)) = TCallableScope(method)
|
||||
|
|
||||
method instanceof Method::Range or
|
||||
method instanceof SingletonMethod::Range
|
||||
)
|
||||
private predicate hasEnclosingMethod(Generated::AstNode node) {
|
||||
exists(Scope::Range s | scopeOf(node) = s and exists(s.getEnclosingMethod()))
|
||||
}
|
||||
|
||||
private TCallableScope parentCallableScope(TCallableScope scope) {
|
||||
exists(Callable::Range c |
|
||||
scope = TCallableScope(c) and
|
||||
not c instanceof Method::Range and
|
||||
not c instanceof SingletonMethod::Range
|
||||
|
|
||||
result = scope.(VariableScope::Range).getOuterScope()
|
||||
)
|
||||
private ModuleBase::Range enclosingModuleOrClass(Generated::AstNode node) {
|
||||
exists(Scope::Range s | scopeOf(node) = s and result = s.getEnclosingModule())
|
||||
}
|
||||
|
||||
private VariableScope::Range parentScope(VariableScope::Range scope) {
|
||||
not scope instanceof ModuleOrClassScope and
|
||||
result = scope.getOuterScope()
|
||||
}
|
||||
|
||||
private ModuleOrClassScope enclosingModuleOrClass(Generated::AstNode node) {
|
||||
result = parentScope*(enclosingScope(node))
|
||||
}
|
||||
|
||||
private predicate parameterAssignment(
|
||||
CallableScope::Range scope, string name, Generated::Identifier i
|
||||
) {
|
||||
implicitParameterAssignmentNode(i, scope.getScopeElement()) and
|
||||
private predicate parameterAssignment(Callable::Range scope, string name, Generated::Identifier i) {
|
||||
implicitParameterAssignmentNode(i, scope) and
|
||||
name = i.getValue()
|
||||
}
|
||||
|
||||
/** Holds if `scope` defines `name` in its parameter declaration at `i`. */
|
||||
private predicate scopeDefinesParameterVariable(
|
||||
CallableScope::Range scope, string name, Generated::Identifier i
|
||||
Callable::Range scope, string name, Generated::Identifier i
|
||||
) {
|
||||
// In case of overlapping parameter names (e.g. `_`), only the first
|
||||
// parameter will give rise to a variable
|
||||
@@ -90,8 +81,8 @@ private predicate scopeDefinesParameterVariable(
|
||||
)
|
||||
or
|
||||
exists(Parameter::Range p |
|
||||
p = scope.getScopeElement().(Callable::Range).getParameter(_) and
|
||||
name = p.(NamedParameter::Range).getName()
|
||||
p = scope.getParameter(_) and
|
||||
name = i.getValue()
|
||||
|
|
||||
i = p.(Generated::BlockParameter).getName() or
|
||||
i = p.(Generated::HashSplatParameter).getName() or
|
||||
@@ -102,10 +93,10 @@ private predicate scopeDefinesParameterVariable(
|
||||
}
|
||||
|
||||
/** Holds if `name` is assigned in `scope` at `i`. */
|
||||
private predicate scopeAssigns(VariableScope scope, string name, Generated::Identifier i) {
|
||||
private predicate scopeAssigns(Scope::Range scope, string name, Generated::Identifier i) {
|
||||
(explicitAssignmentNode(i, _) or implicitAssignmentNode(i)) and
|
||||
name = i.getValue() and
|
||||
scope = enclosingScope(i)
|
||||
scope = scopeOf(i)
|
||||
}
|
||||
|
||||
/** Holds if location `one` starts strictly before location `two` */
|
||||
@@ -116,45 +107,12 @@ private predicate strictlyBefore(Location one, Location two) {
|
||||
one.getStartLine() = two.getStartLine() and one.getStartColumn() < two.getStartColumn()
|
||||
}
|
||||
|
||||
private Generated::AstNode getNodeForIdentifier(Generated::Identifier id) {
|
||||
exists(Generated::AstNode parent | parent = id.getParent() |
|
||||
if
|
||||
parent instanceof Generated::BlockParameter
|
||||
or
|
||||
parent instanceof Generated::SplatParameter
|
||||
or
|
||||
parent instanceof Generated::HashSplatParameter
|
||||
or
|
||||
parent instanceof Generated::KeywordParameter
|
||||
or
|
||||
parent instanceof Generated::OptionalParameter
|
||||
then result = parent
|
||||
else result = id
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/** Gets the enclosing scope for `node`. */
|
||||
cached
|
||||
VariableScope::Range enclosingScope(Generated::AstNode node) {
|
||||
result.getScopeElement() = parentOfNoScope*(parentOf(node))
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TScope =
|
||||
TGlobalScope() or
|
||||
TTopLevelScope(Generated::Program node) or
|
||||
TModuleScope(Generated::Module node) or
|
||||
TClassScope(Generated::AstNode cls) {
|
||||
cls instanceof Generated::Class or cls instanceof Generated::SingletonClass
|
||||
} or
|
||||
TCallableScope(Callable::Range c)
|
||||
|
||||
cached
|
||||
newtype TVariable =
|
||||
TGlobalVariable(string name) { name = any(Generated::GlobalVariable var).getValue() } or
|
||||
TClassVariable(VariableScope scope, string name, Generated::AstNode decl) {
|
||||
TClassVariable(Scope::Range scope, string name, Generated::AstNode decl) {
|
||||
decl =
|
||||
min(Generated::ClassVariable other |
|
||||
classVariableAccess(other, name, scope)
|
||||
@@ -162,7 +120,7 @@ private module Cached {
|
||||
other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn()
|
||||
)
|
||||
} or
|
||||
TInstanceVariable(VariableScope scope, string name, boolean instance, Generated::AstNode decl) {
|
||||
TInstanceVariable(Scope::Range scope, string name, boolean instance, Generated::AstNode decl) {
|
||||
decl =
|
||||
min(Generated::InstanceVariable other |
|
||||
instanceVariableAccess(other, name, scope, instance)
|
||||
@@ -170,7 +128,7 @@ private module Cached {
|
||||
other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn()
|
||||
)
|
||||
} or
|
||||
TLocalVariable(VariableScope::Range scope, string name, Generated::Identifier i) {
|
||||
TLocalVariable(Scope::Range scope, string name, Generated::Identifier i) {
|
||||
scopeDefinesParameterVariable(scope, name, i)
|
||||
or
|
||||
i =
|
||||
@@ -180,7 +138,7 @@ private module Cached {
|
||||
other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn()
|
||||
) and
|
||||
not scopeDefinesParameterVariable(scope, name, _) and
|
||||
not scope.inherits(name, _)
|
||||
not inherits(scope, name, _)
|
||||
}
|
||||
|
||||
// Db types that can be vcalls
|
||||
@@ -330,10 +288,12 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate access(Generated::Identifier access, Variable variable) {
|
||||
exists(string name | name = access.getValue() |
|
||||
variable.getDeclaringScope() = enclosingScope(access) and
|
||||
predicate access(Generated::Identifier access, Variable::Range variable) {
|
||||
exists(string name |
|
||||
variable.getName() = name and
|
||||
name = access.getValue()
|
||||
|
|
||||
variable.getDeclaringScope() = scopeOf(access) and
|
||||
not strictlyBefore(access.getLocation(), variable.getLocation()) and
|
||||
// In case of overlapping parameter names, later parameters should not
|
||||
// be considered accesses to the first parameter
|
||||
@@ -341,15 +301,20 @@ private module Cached {
|
||||
then scopeDefinesParameterVariable(_, _, access)
|
||||
else any()
|
||||
or
|
||||
exists(VariableScope declScope |
|
||||
variable = declScope.getVariable(name) and
|
||||
enclosingScope(access).inherits(name, declScope)
|
||||
exists(Scope::Range declScope |
|
||||
variable.getDeclaringScope() = declScope and
|
||||
inherits(scopeOf(access), name, declScope)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private class Access extends Generated::Token {
|
||||
Access() { access(this, _) or this instanceof Generated::GlobalVariable }
|
||||
Access() {
|
||||
access(this, _) or
|
||||
this instanceof Generated::GlobalVariable or
|
||||
this instanceof Generated::InstanceVariable or
|
||||
this instanceof Generated::ClassVariable
|
||||
}
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -365,13 +330,13 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate isCapturedAccess(LocalVariableAccess::Range access) {
|
||||
access.getVariable().getDeclaringScope() != enclosingScope(access)
|
||||
predicate isCapturedAccess(LocalVariableAccess access) {
|
||||
toGenerated(access.getVariable().getDeclaringScope()) != scopeOf(toGenerated(access))
|
||||
}
|
||||
|
||||
cached
|
||||
predicate instanceVariableAccess(Generated::InstanceVariable var, InstanceVariable v) {
|
||||
exists(string name, VariableScope scope, boolean instance |
|
||||
exists(string name, Scope::Range scope, boolean instance |
|
||||
v = TInstanceVariable(scope, name, instance, _) and
|
||||
instanceVariableAccess(var, name, scope, instance)
|
||||
)
|
||||
@@ -379,7 +344,7 @@ private module Cached {
|
||||
|
||||
cached
|
||||
predicate classVariableAccess(Generated::ClassVariable var, ClassVariable variable) {
|
||||
exists(VariableScope scope, string name |
|
||||
exists(Scope::Range scope, string name |
|
||||
variable = TClassVariable(scope, name, _) and
|
||||
classVariableAccess(var, name, scope)
|
||||
)
|
||||
@@ -388,125 +353,23 @@ private module Cached {
|
||||
|
||||
import Cached
|
||||
|
||||
module VariableScope {
|
||||
abstract class Range extends TScope {
|
||||
abstract string toString();
|
||||
|
||||
abstract Generated::AstNode getScopeElement();
|
||||
|
||||
abstract predicate isCapturing();
|
||||
|
||||
VariableScope::Range getOuterScope() { result = enclosingScope(this.getScopeElement()) }
|
||||
|
||||
/** Holds if this scope inherits `name` from an outer scope `outer`. */
|
||||
predicate inherits(string name, VariableScope::Range outer) {
|
||||
this.isCapturing() and
|
||||
not scopeDefinesParameterVariable(this, name, _) and
|
||||
(
|
||||
outer = this.getOuterScope() and
|
||||
(
|
||||
scopeDefinesParameterVariable(outer, name, _)
|
||||
or
|
||||
exists(Generated::Identifier i |
|
||||
scopeAssigns(outer, name, i) and
|
||||
strictlyBefore(i.getLocation(), this.getLocation())
|
||||
)
|
||||
)
|
||||
or
|
||||
this.getOuterScope().inherits(name, outer)
|
||||
/** Holds if this scope inherits `name` from an outer scope `outer`. */
|
||||
private predicate inherits(Scope::Range scope, string name, Scope::Range outer) {
|
||||
(scope instanceof Generated::Block or scope instanceof Generated::DoBlock) and
|
||||
not scopeDefinesParameterVariable(scope, name, _) and
|
||||
(
|
||||
outer = scope.getOuterScope() and
|
||||
(
|
||||
scopeDefinesParameterVariable(outer, name, _)
|
||||
or
|
||||
exists(Generated::Identifier i |
|
||||
scopeAssigns(outer, name, i) and
|
||||
strictlyBefore(i.getLocation(), scope.getLocation())
|
||||
)
|
||||
}
|
||||
|
||||
final Location getLocation() { result = getScopeElement().getLocation() }
|
||||
}
|
||||
}
|
||||
|
||||
module GlobalScope {
|
||||
class Range extends VariableScope::Range, TGlobalScope {
|
||||
override string toString() { result = "global scope" }
|
||||
|
||||
override Generated::AstNode getScopeElement() { none() }
|
||||
|
||||
override predicate isCapturing() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
module TopLevelScope {
|
||||
class Range extends VariableScope::Range, TTopLevelScope {
|
||||
Generated::Program program;
|
||||
|
||||
Range() { TTopLevelScope(program) = this }
|
||||
|
||||
override string toString() {
|
||||
result = "top-level scope for " + program.getLocation().getFile().getBaseName()
|
||||
}
|
||||
|
||||
override Generated::AstNode getScopeElement() { result = program }
|
||||
|
||||
override predicate isCapturing() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
module ModuleScope {
|
||||
class Range extends VariableScope::Range, TModuleScope {
|
||||
Generated::Module mdl;
|
||||
|
||||
Range() { TModuleScope(mdl) = this }
|
||||
|
||||
override string toString() { result = "module scope for " + mdl.(Module::Range).getName() }
|
||||
|
||||
override Generated::AstNode getScopeElement() { result = mdl }
|
||||
|
||||
override predicate isCapturing() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
module ClassScope {
|
||||
class Range extends VariableScope::Range, TClassScope {
|
||||
Generated::AstNode cls;
|
||||
|
||||
Range() { TClassScope(cls) = this }
|
||||
|
||||
override string toString() {
|
||||
result = "class scope for " + cls.(Class::Range).getName()
|
||||
or
|
||||
cls instanceof Generated::SingletonClass and result = "class scope"
|
||||
}
|
||||
|
||||
override Generated::AstNode getScopeElement() { result = cls }
|
||||
|
||||
override predicate isCapturing() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
module CallableScope {
|
||||
class Range extends VariableScope::Range, TCallableScope {
|
||||
private Generated::AstNode c;
|
||||
|
||||
Range() { this = TCallableScope(c) }
|
||||
|
||||
override string toString() {
|
||||
result = "method scope for " + c.(SingletonMethod).getName()
|
||||
or
|
||||
result = "method scope for " + c.(Method).getName()
|
||||
or
|
||||
c instanceof Lambda and
|
||||
result = "lambda scope"
|
||||
or
|
||||
c instanceof Block and
|
||||
result = "block scope"
|
||||
}
|
||||
|
||||
override Generated::AstNode getScopeElement() { TCallableScope(result) = this }
|
||||
|
||||
override predicate isCapturing() {
|
||||
c instanceof Generated::Lambda
|
||||
or
|
||||
c instanceof Generated::Block
|
||||
or
|
||||
c instanceof Generated::DoBlock
|
||||
}
|
||||
}
|
||||
)
|
||||
or
|
||||
inherits(scope.getOuterScope(), name, outer)
|
||||
)
|
||||
}
|
||||
|
||||
module Variable {
|
||||
@@ -517,13 +380,13 @@ module Variable {
|
||||
|
||||
abstract Location getLocation();
|
||||
|
||||
abstract VariableScope getDeclaringScope();
|
||||
abstract Scope::Range getDeclaringScope();
|
||||
}
|
||||
}
|
||||
|
||||
module LocalVariable {
|
||||
class Range extends Variable::Range, TLocalVariable {
|
||||
private VariableScope scope;
|
||||
private Scope::Range scope;
|
||||
private string name;
|
||||
private Generated::Identifier i;
|
||||
|
||||
@@ -533,9 +396,9 @@ module LocalVariable {
|
||||
|
||||
final override Location getLocation() { result = i.getLocation() }
|
||||
|
||||
final override VariableScope getDeclaringScope() { result = scope }
|
||||
final override Scope::Range getDeclaringScope() { result = scope }
|
||||
|
||||
final VariableAccess getDefiningAccess() { result = getNodeForIdentifier(i) }
|
||||
final VariableAccess getDefiningAccess() { toGenerated(result) = i }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,15 +412,13 @@ module GlobalVariable {
|
||||
|
||||
final override Location getLocation() { none() }
|
||||
|
||||
final override VariableScope getDeclaringScope() { result = TGlobalScope() }
|
||||
final override Scope::Range getDeclaringScope() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
private class ModuleOrClassScope = TClassScope or TModuleScope or TTopLevelScope;
|
||||
|
||||
module InstanceVariable {
|
||||
class Range extends Variable::Range, TInstanceVariable {
|
||||
private ModuleOrClassScope scope;
|
||||
private ModuleBase::Range scope;
|
||||
private boolean instance;
|
||||
private string name;
|
||||
private Generated::AstNode decl;
|
||||
@@ -570,13 +431,13 @@ module InstanceVariable {
|
||||
|
||||
final override Location getLocation() { result = decl.getLocation() }
|
||||
|
||||
final override VariableScope getDeclaringScope() { result = scope }
|
||||
final override Scope::Range getDeclaringScope() { result = scope }
|
||||
}
|
||||
}
|
||||
|
||||
module ClassVariable {
|
||||
class Range extends Variable::Range, TClassVariable {
|
||||
private ModuleOrClassScope scope;
|
||||
private ModuleBase::Range scope;
|
||||
private string name;
|
||||
private Generated::AstNode decl;
|
||||
|
||||
@@ -586,90 +447,33 @@ module ClassVariable {
|
||||
|
||||
final override Location getLocation() { result = decl.getLocation() }
|
||||
|
||||
final override VariableScope getDeclaringScope() { result = scope }
|
||||
}
|
||||
}
|
||||
|
||||
module VariableAccess {
|
||||
abstract class Range extends Expr::Range {
|
||||
abstract Variable getVariable();
|
||||
|
||||
final predicate isExplicitWrite(AstNode assignment) {
|
||||
exists(Generated::Identifier i | this = getNodeForIdentifier(i) |
|
||||
explicitWriteAccess(i, assignment)
|
||||
)
|
||||
or
|
||||
not this = getNodeForIdentifier(_) and explicitWriteAccess(this, assignment)
|
||||
}
|
||||
|
||||
final predicate isImplicitWrite() {
|
||||
exists(Generated::Identifier i | this = getNodeForIdentifier(i) | implicitWriteAccess(i))
|
||||
or
|
||||
not this = getNodeForIdentifier(_) and implicitWriteAccess(this)
|
||||
}
|
||||
final override Scope::Range getDeclaringScope() { result = scope }
|
||||
}
|
||||
}
|
||||
|
||||
module LocalVariableAccess {
|
||||
class LocalVariableRange =
|
||||
@token_identifier or @splat_parameter or @keyword_parameter or @optional_parameter or
|
||||
@hash_splat_parameter or @block_parameter;
|
||||
|
||||
class Range extends VariableAccess::Range, LocalVariableRange {
|
||||
LocalVariable variable;
|
||||
|
||||
Range() {
|
||||
exists(Generated::Identifier id |
|
||||
this = getNodeForIdentifier(id) and
|
||||
access(id, variable) and
|
||||
(
|
||||
explicitWriteAccess(id, _)
|
||||
or
|
||||
implicitWriteAccess(id)
|
||||
or
|
||||
vcall(id)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = generated.(Generated::Identifier).getValue() }
|
||||
|
||||
final override LocalVariable getVariable() { result = variable }
|
||||
predicate range(Generated::Identifier id, LocalVariable v) {
|
||||
access(id, v) and
|
||||
(
|
||||
explicitWriteAccess(id, _)
|
||||
or
|
||||
implicitWriteAccess(id)
|
||||
or
|
||||
vcall(id)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module GlobalVariableAccess {
|
||||
class Range extends VariableAccess::Range, @token_global_variable {
|
||||
GlobalVariable variable;
|
||||
|
||||
Range() { this.(Generated::GlobalVariable).getValue() = variable.getName() }
|
||||
|
||||
final override GlobalVariable getVariable() { result = variable }
|
||||
|
||||
override string toString() { result = generated.(Generated::GlobalVariable).getValue() }
|
||||
}
|
||||
predicate range(Generated::GlobalVariable n, GlobalVariable v) { n.getValue() = v.getName() }
|
||||
}
|
||||
|
||||
module InstanceVariableAccess {
|
||||
class Range extends VariableAccess::Range, @token_instance_variable {
|
||||
InstanceVariable variable;
|
||||
|
||||
Range() { instanceVariableAccess(this, variable) }
|
||||
|
||||
final override InstanceVariable getVariable() { result = variable }
|
||||
|
||||
override string toString() { result = generated.(Generated::InstanceVariable).getValue() }
|
||||
predicate range(Generated::InstanceVariable n, InstanceVariable v) {
|
||||
instanceVariableAccess(n, v)
|
||||
}
|
||||
}
|
||||
|
||||
module ClassVariableAccess {
|
||||
class Range extends VariableAccess::Range, @token_class_variable {
|
||||
ClassVariable variable;
|
||||
|
||||
Range() { classVariableAccess(this, variable) }
|
||||
|
||||
final override ClassVariable getVariable() { result = variable }
|
||||
|
||||
override string toString() { result = generated.(Generated::ClassVariable).getValue() }
|
||||
}
|
||||
predicate range(Generated::ClassVariable n, ClassVariable v) { classVariableAccess(n, v) }
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
private import codeql.Locations
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.TreeSitter
|
||||
private import codeql_ruby.controlflow.ControlFlowGraph
|
||||
private import internal.ControlFlowGraphImpl
|
||||
private import CfgNodes
|
||||
@@ -351,14 +353,14 @@ class ExitBasicBlock extends BasicBlock {
|
||||
}
|
||||
|
||||
private module JoinBlockPredecessors {
|
||||
private predicate id(AstNode x, AstNode y) { x = y }
|
||||
private predicate id(Generated::AstNode x, Generated::AstNode y) { x = y }
|
||||
|
||||
private predicate idOf(AstNode x, int y) = equivalenceRelation(id/2)(x, y)
|
||||
private predicate idOf(Generated::AstNode x, int y) = equivalenceRelation(id/2)(x, y)
|
||||
|
||||
int getId(JoinBlockPredecessor jbp) {
|
||||
idOf(jbp.getFirstNode().(AstCfgNode).getNode(), result)
|
||||
idOf(toGenerated(jbp.getFirstNode().(AstCfgNode).getNode()), result)
|
||||
or
|
||||
idOf(jbp.(EntryBasicBlock).getScope(), result)
|
||||
idOf(toGenerated(jbp.(EntryBasicBlock).getScope()), result)
|
||||
}
|
||||
|
||||
string getSplitString(JoinBlockPredecessor jbp) {
|
||||
|
||||
@@ -62,11 +62,11 @@ class ExitNode extends CfgNode, TExitNode {
|
||||
* (dead) code or not important for control flow, and multiple when there are different
|
||||
* splits for the AST node.
|
||||
*/
|
||||
class AstCfgNode extends CfgNode, TAstNode {
|
||||
class AstCfgNode extends CfgNode, TAstCfgNode {
|
||||
private Splits splits;
|
||||
private AstNode n;
|
||||
|
||||
AstCfgNode() { this = TAstNode(n, splits) }
|
||||
AstCfgNode() { this = TAstCfgNode(n, splits) }
|
||||
|
||||
final override AstNode getNode() { result = n }
|
||||
|
||||
@@ -131,7 +131,7 @@ abstract private class ExprChildMapping extends Expr {
|
||||
|
||||
pragma[noinline]
|
||||
private BasicBlock getABasicBlockInScope() {
|
||||
result.getANode() = TAstNode(this.getAChildStar(), _)
|
||||
result.getANode() = TAstCfgNode(this.getAChildStar(), _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -283,7 +283,7 @@ module ExprNodes {
|
||||
}
|
||||
|
||||
private class StmtSequenceChildMapping extends ExprChildMapping, StmtSequence {
|
||||
override predicate relevantChild(Expr e) { e = this.getLastExpr() }
|
||||
override predicate relevantChild(Expr e) { e = this.getLastStmt() }
|
||||
}
|
||||
|
||||
/** A control-flow node that wraps a `StmtSequence` AST expression. */
|
||||
@@ -292,8 +292,8 @@ module ExprNodes {
|
||||
|
||||
final override StmtSequence getExpr() { result = ExprCfgNode.super.getExpr() }
|
||||
|
||||
/** Gets the last expression in this sequence, if any. */
|
||||
final ExprCfgNode getLastExpr() { e.hasCfgChild(e.getLastExpr(), this, result) }
|
||||
/** Gets the last statement in this sequence, if any. */
|
||||
final ExprCfgNode getLastStmt() { e.hasCfgChild(e.getLastStmt(), this, result) }
|
||||
}
|
||||
|
||||
private class ForExprChildMapping extends ExprChildMapping, ForExpr {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/** Provides classes representing the control flow graph. */
|
||||
|
||||
private import codeql.Locations
|
||||
private import codeql_ruby.AST as AST
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.controlflow.BasicBlocks
|
||||
private import SuccessorTypes
|
||||
private import internal.ControlFlowGraphImpl
|
||||
@@ -9,12 +9,12 @@ private import internal.Splitting
|
||||
private import internal.Completion
|
||||
|
||||
/** An AST node with an associated control-flow graph. */
|
||||
class CfgScope extends AST::AstNode {
|
||||
class CfgScope extends Scope {
|
||||
CfgScope() { this instanceof CfgScope::Range_ }
|
||||
|
||||
/** Gets the CFG scope that this scope is nested under, if any. */
|
||||
final CfgScope getOuterCfgScope() {
|
||||
exists(AST::AstNode parent |
|
||||
exists(AstNode parent |
|
||||
parent = this.getParent() and
|
||||
result = getCfgScope(parent)
|
||||
)
|
||||
@@ -34,7 +34,7 @@ class CfgNode extends TCfgNode {
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the AST node that this node corresponds to, if any. */
|
||||
AST::AstNode getNode() { none() }
|
||||
AstNode getNode() { none() }
|
||||
|
||||
/** Gets the location of this control flow node. */
|
||||
Location getLocation() { none() }
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
/**
|
||||
* Provides various helper classes for AST nodes. The definitions in this file
|
||||
* will likely be part of the hand-written user-facing AST layer.
|
||||
*/
|
||||
|
||||
private import codeql_ruby.ast.internal.TreeSitter::Generated
|
||||
private import codeql_ruby.controlflow.internal.Completion
|
||||
|
||||
class LogicalNotAstNode extends Unary {
|
||||
AstNode operand;
|
||||
|
||||
LogicalNotAstNode() {
|
||||
this.getOperator().toString() in ["!", "not"] and
|
||||
operand = this.getOperand()
|
||||
}
|
||||
}
|
||||
|
||||
class LogicalAndAstNode extends Binary {
|
||||
AstNode left;
|
||||
AstNode right;
|
||||
|
||||
LogicalAndAstNode() {
|
||||
this.getOperator().toString() in ["&&", "and"] and
|
||||
left = this.getLeft() and
|
||||
right = this.getRight()
|
||||
}
|
||||
|
||||
AstNode getAnOperand() { result in [left, right] }
|
||||
}
|
||||
|
||||
class LogicalOrAstNode extends Binary {
|
||||
AstNode left;
|
||||
AstNode right;
|
||||
|
||||
LogicalOrAstNode() {
|
||||
this.getOperator().toString() in ["||", "or"] and
|
||||
left = this.getLeft() and
|
||||
right = this.getRight()
|
||||
}
|
||||
|
||||
AstNode getAnOperand() { result in [left, right] }
|
||||
}
|
||||
|
||||
private class If_or_elisif =
|
||||
@if or @elsif or @conditional or @if_modifier or @unless or @unless_modifier;
|
||||
|
||||
class IfElsifAstNode extends AstNode, If_or_elisif {
|
||||
AstNode getConditionNode() { none() }
|
||||
|
||||
AstNode getBranch(boolean b) { none() }
|
||||
}
|
||||
|
||||
private class IfAstNode extends IfElsifAstNode, If {
|
||||
override AstNode getConditionNode() { result = this.getCondition() }
|
||||
|
||||
override AstNode getBranch(boolean b) {
|
||||
b = true and result = this.getConsequence()
|
||||
or
|
||||
b = false and result = this.getAlternative()
|
||||
}
|
||||
}
|
||||
|
||||
private class ElsifAstNode extends IfElsifAstNode, Elsif {
|
||||
override AstNode getConditionNode() { result = this.getCondition() }
|
||||
|
||||
override AstNode getBranch(boolean b) {
|
||||
b = true and result = this.getConsequence()
|
||||
or
|
||||
b = false and result = this.getAlternative()
|
||||
}
|
||||
}
|
||||
|
||||
private class ConditionalAstNode extends IfElsifAstNode, Conditional {
|
||||
override AstNode getConditionNode() { result = this.getCondition() }
|
||||
|
||||
override AstNode getBranch(boolean b) {
|
||||
b = true and result = this.getConsequence()
|
||||
or
|
||||
b = false and result = this.getAlternative()
|
||||
}
|
||||
}
|
||||
|
||||
private class IfModifierAstNode extends IfElsifAstNode, IfModifier {
|
||||
override AstNode getConditionNode() { result = this.getCondition() }
|
||||
|
||||
override AstNode getBranch(boolean b) { b = true and result = this.getBody() }
|
||||
}
|
||||
|
||||
private class UnlessAstNode extends IfElsifAstNode, Unless {
|
||||
override AstNode getConditionNode() { result = this.getCondition() }
|
||||
|
||||
override AstNode getBranch(boolean b) {
|
||||
b = false and result = this.getConsequence()
|
||||
or
|
||||
b = true and result = this.getAlternative()
|
||||
}
|
||||
}
|
||||
|
||||
private class UnlessModifierAstNode extends IfElsifAstNode, UnlessModifier {
|
||||
override AstNode getConditionNode() { result = this.getCondition() }
|
||||
|
||||
override AstNode getBranch(boolean b) { b = false and result = this.getBody() }
|
||||
}
|
||||
|
||||
private class CondLoop = @while or @while_modifier or @until or @until_modifier;
|
||||
|
||||
class ConditionalLoopAstNode extends AstNode, CondLoop {
|
||||
AstNode getConditionNode() { none() }
|
||||
|
||||
AstNode getBodyNode() { none() }
|
||||
|
||||
predicate continueLoop(BooleanCompletion c) { c instanceof TrueCompletion }
|
||||
|
||||
final predicate endLoop(BooleanCompletion c) { continueLoop(c.getDual()) }
|
||||
}
|
||||
|
||||
private class WhileLoop extends ConditionalLoopAstNode, While {
|
||||
override UnderscoreStatement getConditionNode() { result = this.getCondition() }
|
||||
|
||||
override Do getBodyNode() { result = this.getBody() }
|
||||
}
|
||||
|
||||
private class WhileModifierLoop extends ConditionalLoopAstNode, WhileModifier {
|
||||
override AstNode getConditionNode() { result = this.getCondition() }
|
||||
|
||||
override UnderscoreStatement getBodyNode() { result = this.getBody() }
|
||||
}
|
||||
|
||||
private class UntilLoop extends ConditionalLoopAstNode, Until {
|
||||
override UnderscoreStatement getConditionNode() { result = this.getCondition() }
|
||||
|
||||
override Do getBodyNode() { result = this.getBody() }
|
||||
|
||||
override predicate continueLoop(BooleanCompletion c) { c instanceof FalseCompletion }
|
||||
}
|
||||
|
||||
private class UntilModifierLoop extends ConditionalLoopAstNode, UntilModifier {
|
||||
override AstNode getConditionNode() { result = this.getCondition() }
|
||||
|
||||
override UnderscoreStatement getBodyNode() { result = this.getBody() }
|
||||
|
||||
override predicate continueLoop(BooleanCompletion c) { c instanceof FalseCompletion }
|
||||
}
|
||||
|
||||
class ParenthesizedStatement extends ParenthesizedStatements {
|
||||
ParenthesizedStatement() { strictcount(int i | exists(this.getChild(i))) = 1 }
|
||||
|
||||
AstNode getChild() { result = this.getChild(0) }
|
||||
}
|
||||
@@ -14,7 +14,7 @@ query predicate nodes(CfgNode n, string attr, string val) {
|
||||
p
|
||||
order by
|
||||
p.getLocation().getFile().getBaseName(), p.getLocation().getFile().getAbsolutePath(),
|
||||
p.getLocation().getStartLine()
|
||||
p.getLocation().getStartLine(), p.getLocation().getStartColumn()
|
||||
)
|
||||
).toString()
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.controlflow.ControlFlowGraph
|
||||
private import ControlFlowGraphImpl
|
||||
private import NonReturning
|
||||
@@ -48,12 +49,12 @@ private predicate nestedEnsureCompletion(Completion outer, int nestLevel) {
|
||||
or
|
||||
outer = TExitCompletion()
|
||||
) and
|
||||
nestLevel = any(Trees::RescueEnsureBlockTree t).nestLevel()
|
||||
nestLevel = any(Trees::BodyStmtTree t).getNestLevel()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate completionIsValidForStmt(AstNode n, Completion c) {
|
||||
n instanceof InRange and
|
||||
n = TForIn(_) and
|
||||
c instanceof EmptinessCompletion
|
||||
or
|
||||
n instanceof BreakStmt and
|
||||
@@ -175,7 +176,7 @@ private predicate inBooleanContext(AstNode n) {
|
||||
or
|
||||
n = any(NotExpr parent | inBooleanContext(parent)).getOperand()
|
||||
or
|
||||
n = any(StmtSequence parent | inBooleanContext(parent)).getLastExpr()
|
||||
n = any(StmtSequence parent | inBooleanContext(parent)).getLastStmt()
|
||||
or
|
||||
exists(CaseExpr c, WhenExpr w |
|
||||
not exists(c.getValue()) and
|
||||
@@ -205,7 +206,7 @@ private predicate inMatchingContext(AstNode n) {
|
||||
w.getPattern(_) = n
|
||||
)
|
||||
or
|
||||
n = any(Trees::DefaultValueParameterTree t | t.hasDefaultValue())
|
||||
n.(Trees::DefaultValueParameterTree).hasDefaultValue()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,13 +16,13 @@ private module Cached {
|
||||
cached
|
||||
newtype TSplitKind =
|
||||
TConditionalCompletionSplitKind() or
|
||||
TEnsureSplitKind(int nestLevel) { nestLevel = any(Trees::RescueEnsureBlockTree t).nestLevel() }
|
||||
TEnsureSplitKind(int nestLevel) { nestLevel = any(Trees::BodyStmtTree t).getNestLevel() }
|
||||
|
||||
cached
|
||||
newtype TSplit =
|
||||
TConditionalCompletionSplit(ConditionalCompletion c) or
|
||||
TEnsureSplit(EnsureSplitting::EnsureSplitType type, int nestLevel) {
|
||||
nestLevel = any(Trees::RescueEnsureBlockTree t).nestLevel()
|
||||
nestLevel = any(Trees::BodyStmtTree t).getNestLevel()
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -226,7 +226,7 @@ private module ConditionalCompletionSplitting {
|
||||
last(succ.(LogicalOrExpr).getAnOperand(), pred, c) and
|
||||
completion = c
|
||||
or
|
||||
last(succ.(ParenthesizedExpr).getLastExpr(), pred, c) and
|
||||
last(succ.(StmtSequence).getLastStmt(), pred, c) and
|
||||
completion = c
|
||||
or
|
||||
last(succ.(ConditionalExpr).getBranch(_), pred, c) and
|
||||
@@ -277,12 +277,11 @@ module EnsureSplitting {
|
||||
|
||||
/** A node that belongs to an `ensure` block. */
|
||||
private class EnsureNode extends AstNode {
|
||||
private Trees::RescueEnsureBlockTree block;
|
||||
private Trees::BodyStmtTree block;
|
||||
|
||||
EnsureNode() { this = block.getAnEnsureDescendant() }
|
||||
|
||||
/** Gets the immediate block that this node belongs to. */
|
||||
Trees::RescueEnsureBlockTree getBlock() { result = block }
|
||||
int getNestLevel() { result = block.getNestLevel() }
|
||||
|
||||
/** Holds if this node is the entry node in the `ensure` block it belongs to. */
|
||||
predicate isEntryNode() { first(block.getEnsure(), this) }
|
||||
@@ -355,7 +354,7 @@ module EnsureSplitting {
|
||||
pragma[noinline]
|
||||
private predicate hasEntry0(AstNode pred, EnsureNode succ, int nestLevel, Completion c) {
|
||||
succ.isEntryNode() and
|
||||
nestLevel = succ.getBlock().nestLevel() and
|
||||
nestLevel = succ.getNestLevel() and
|
||||
succ(pred, succ, c)
|
||||
}
|
||||
|
||||
@@ -378,11 +377,9 @@ module EnsureSplitting {
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate exit0(
|
||||
AstNode pred, Trees::RescueEnsureBlockTree block, int nestLevel, Completion c
|
||||
) {
|
||||
private predicate exit0(AstNode pred, Trees::BodyStmtTree block, int nestLevel, Completion c) {
|
||||
this.appliesToPredecessor(pred) and
|
||||
nestLevel = block.nestLevel() and
|
||||
nestLevel = block.getNestLevel() and
|
||||
block.lastInner(pred, c)
|
||||
}
|
||||
|
||||
@@ -391,9 +388,7 @@ module EnsureSplitting {
|
||||
* `inherited` indicates whether `c` is an inherited completion from the
|
||||
* body.
|
||||
*/
|
||||
private predicate exit(
|
||||
Trees::RescueEnsureBlockTree block, AstNode pred, Completion c, boolean inherited
|
||||
) {
|
||||
private predicate exit(Trees::BodyStmtTree block, AstNode pred, Completion c, boolean inherited) {
|
||||
exists(EnsureSplitType type |
|
||||
exit0(pred, block, this.getNestLevel(), c) and
|
||||
type = this.getType()
|
||||
@@ -477,10 +472,10 @@ module EnsureSplitting {
|
||||
if en.isEntryNode()
|
||||
then
|
||||
// entering a nested `ensure` block
|
||||
en.getBlock().nestLevel() > this.getNestLevel()
|
||||
en.getNestLevel() > this.getNestLevel()
|
||||
else
|
||||
// staying in the same (possibly nested) `ensure` block as `pred`
|
||||
en.getBlock().nestLevel() >= this.getNestLevel()
|
||||
en.getNestLevel() >= this.getNestLevel()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ private module Cached {
|
||||
or
|
||||
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::AssignExprCfgNode).getRhs()
|
||||
or
|
||||
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::StmtSequenceCfgNode).getLastExpr()
|
||||
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::StmtSequenceCfgNode).getLastStmt()
|
||||
or
|
||||
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::ConditionalExprCfgNode).getBranch(_)
|
||||
or
|
||||
|
||||
@@ -6,7 +6,7 @@ private import CfgNodes::ExprNodes
|
||||
|
||||
/** Holds if `v` is uninitialized at index `i` in entry block `bb`. */
|
||||
predicate uninitializedWrite(EntryBasicBlock bb, int i, LocalVariable v) {
|
||||
v.getDeclaringScope().getScopeElement() = bb.getScope() and
|
||||
v.getDeclaringScope() = bb.getScope() and
|
||||
i = -1
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ private predicate capturedExitRead(AnnotatedExitBasicBlock bb, int i, LocalVaria
|
||||
i = bb.length()
|
||||
}
|
||||
|
||||
private CfgScope getCaptureOuterCfgScope(Callable scope) {
|
||||
private CfgScope getCaptureOuterCfgScope(CfgScope scope) {
|
||||
result = scope.getOuterCfgScope() and
|
||||
(
|
||||
scope instanceof Block
|
||||
|
||||
@@ -27,6 +27,19 @@ class PrintAstNode extends AstNode {
|
||||
string getProperty(string key) {
|
||||
key = "semmle.label" and
|
||||
result = "[" + concat(this.getAPrimaryQlClass(), ", ") + "] " + this.toString()
|
||||
or
|
||||
key = "semmle.order" and
|
||||
result =
|
||||
any(int i |
|
||||
this =
|
||||
rank[i](AstNode p |
|
||||
|
|
||||
p
|
||||
order by
|
||||
p.getLocation().getFile().getBaseName(), p.getLocation().getFile().getAbsolutePath(),
|
||||
p.getLocation().getStartLine(), p.getLocation().getStartColumn()
|
||||
)
|
||||
).toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,7 +52,7 @@ class PrintAstNode extends AstNode {
|
||||
/**
|
||||
* Gets the child node that is accessed using the predicate `edgeName`.
|
||||
*/
|
||||
PrintAstNode getChild(string edgeName) { range.child(edgeName, result) }
|
||||
PrintAstNode getChild(string edgeName) { result = this.getAChild(edgeName) }
|
||||
}
|
||||
|
||||
private predicate shouldPrintNode(AstNode n) {
|
||||
@@ -62,9 +75,14 @@ query predicate nodes(PrintAstNode node, string key, string value) {
|
||||
query predicate edges(PrintAstNode source, PrintAstNode target, string key, string value) {
|
||||
source.shouldPrint() and
|
||||
target.shouldPrint() and
|
||||
key = "semmle.label" and
|
||||
target = source.getAChild() and
|
||||
value = concat(string name | source.getChild(name) = target | name, "/")
|
||||
(
|
||||
key = "semmle.label" and
|
||||
value = concat(string name | source.getChild(name) = target | name, "/")
|
||||
or
|
||||
key = "semmle.order" and
|
||||
value = target.getProperty("semmle.order")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
65
ql/src/queries/performance/UseDetect.ql
Normal file
65
ql/src/queries/performance/UseDetect.ql
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @name Use detect
|
||||
* @description Use 'detect' instead of 'select' followed by 'first' or 'last'.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @id rb/use-detect
|
||||
* @tags performance rubocop
|
||||
* @precision high
|
||||
*
|
||||
* This is an implementation of Rubocop rule
|
||||
* https://github.com/rubocop/rubocop-performance/blob/master/lib/rubocop/cop/performance/detect.rb
|
||||
*/
|
||||
|
||||
import ruby
|
||||
import codeql_ruby.dataflow.SSA
|
||||
|
||||
/** A call that extracts the first or last element of a list. */
|
||||
class EndCall extends MethodCall {
|
||||
string detect;
|
||||
|
||||
EndCall() {
|
||||
detect = "detect" and
|
||||
(
|
||||
this.getMethodName() = "first" and
|
||||
this.getNumberOfArguments() = 0
|
||||
or
|
||||
this.getNumberOfArguments() = 1 and
|
||||
this.getArgument(0).(IntegerLiteral).getValueText() = "0"
|
||||
)
|
||||
or
|
||||
detect = "reverse_detect" and
|
||||
(
|
||||
this.getMethodName() = "last" and
|
||||
this.getNumberOfArguments() = 0
|
||||
or
|
||||
this.getNumberOfArguments() = 1 and
|
||||
this.getArgument(0).(UnaryMinusExpr).getOperand().(IntegerLiteral).getValueText() = "1"
|
||||
)
|
||||
}
|
||||
|
||||
string detectCall() { result = detect }
|
||||
}
|
||||
|
||||
Expr getUniqueRead(Expr e) {
|
||||
exists(AssignExpr ae |
|
||||
e = ae.getRightOperand() and
|
||||
forex(Ssa::WriteDefinition def | def.getWriteAccess() = ae.getLeftOperand() |
|
||||
strictcount(def.getARead()) = 1 and
|
||||
not def = any(Ssa::PhiNode phi).getAnInput() and
|
||||
def.getARead() = result.getAControlFlowNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class SelectBlock extends MethodCall {
|
||||
SelectBlock() {
|
||||
this.getMethodName() in ["select", "filter", "find_all"] and
|
||||
exists(this.getBlock())
|
||||
}
|
||||
}
|
||||
|
||||
from EndCall call, SelectBlock selectBlock
|
||||
where getUniqueRead*(selectBlock) = call.getReceiver()
|
||||
select call, "Replace this call and $@ with '" + call.detectCall() + "'.", selectBlock,
|
||||
"'select' call"
|
||||
@@ -13,12 +13,14 @@ calls/calls.rb:
|
||||
# 17| getStmt: [MethodCall] call to foo
|
||||
# 17| getBlock: [BraceBlock] { ... }
|
||||
# 17| getParameter: [SimpleParameter] x
|
||||
# 17| getDefiningAccess: [LocalVariableAccess] x
|
||||
# 17| getStmt: [AddExpr] ... + ...
|
||||
# 17| getAnOperand/getLeftOperand: [LocalVariableAccess] x
|
||||
# 17| getAnOperand/getRightOperand: [IntegerLiteral] 1
|
||||
# 20| getStmt: [MethodCall] call to foo
|
||||
# 20| getBlock: [DoBlock] do ... end
|
||||
# 20| getParameter: [SimpleParameter] x
|
||||
# 20| getDefiningAccess: [LocalVariableAccess] x
|
||||
# 21| getStmt: [AddExpr] ... + ...
|
||||
# 21| getAnOperand/getLeftOperand: [LocalVariableAccess] x
|
||||
# 21| getAnOperand/getRightOperand: [IntegerLiteral] 1
|
||||
@@ -28,6 +30,7 @@ calls/calls.rb:
|
||||
# 25| getComponent: [StringTextComponent] foo
|
||||
# 25| getBlock: [DoBlock] do ... end
|
||||
# 25| getParameter: [SimpleParameter] x
|
||||
# 25| getDefiningAccess: [LocalVariableAccess] x
|
||||
# 26| getStmt: [AddExpr] ... + ...
|
||||
# 26| getAnOperand/getLeftOperand: [LocalVariableAccess] x
|
||||
# 26| getAnOperand/getRightOperand: [IntegerLiteral] 1
|
||||
@@ -153,16 +156,20 @@ calls/calls.rb:
|
||||
# 144| getReceiver: [ConstantReadAccess] X
|
||||
# 148| getStmt: [Method] method_with_keyword_param
|
||||
# 148| getParameter: [KeywordParameter] keyword
|
||||
# 148| getDefiningAccess: [LocalVariableAccess] keyword
|
||||
# 148| getDefaultValue: [MethodCall] call to foo
|
||||
# 150| getStmt: [Method] method_with_keyword_param2
|
||||
# 150| getParameter: [KeywordParameter] keyword
|
||||
# 150| getDefiningAccess: [LocalVariableAccess] keyword
|
||||
# 150| getDefaultValue: [MethodCall] call to foo
|
||||
# 150| getReceiver: [ConstantReadAccess] X
|
||||
# 154| getStmt: [Method] method_with_optional_param
|
||||
# 154| getParameter: [OptionalParameter] param
|
||||
# 154| getDefiningAccess: [LocalVariableAccess] param
|
||||
# 154| getDefaultValue: [MethodCall] call to foo
|
||||
# 156| getStmt: [Method] method_with_optional_param2
|
||||
# 156| getParameter: [OptionalParameter] param
|
||||
# 156| getDefiningAccess: [LocalVariableAccess] param
|
||||
# 156| getDefaultValue: [MethodCall] call to foo
|
||||
# 156| getReceiver: [ConstantReadAccess] X
|
||||
# 160| getStmt: [Module] SomeModule
|
||||
@@ -383,12 +390,14 @@ calls/calls.rb:
|
||||
# 290| getStmt: [SuperCall] call to super
|
||||
# 290| getBlock: [BraceBlock] { ... }
|
||||
# 290| getParameter: [SimpleParameter] x
|
||||
# 290| getDefiningAccess: [LocalVariableAccess] x
|
||||
# 290| getStmt: [AddExpr] ... + ...
|
||||
# 290| getAnOperand/getLeftOperand: [LocalVariableAccess] x
|
||||
# 290| getAnOperand/getRightOperand: [IntegerLiteral] 1
|
||||
# 291| getStmt: [SuperCall] call to super
|
||||
# 291| getBlock: [DoBlock] do ... end
|
||||
# 291| getParameter: [SimpleParameter] x
|
||||
# 291| getDefiningAccess: [LocalVariableAccess] x
|
||||
# 291| getStmt: [MulExpr] ... * ...
|
||||
# 291| getAnOperand/getLeftOperand: [LocalVariableAccess] x
|
||||
# 291| getAnOperand/getRightOperand: [IntegerLiteral] 2
|
||||
@@ -397,6 +406,7 @@ calls/calls.rb:
|
||||
# 292| getArgument: [IntegerLiteral] 5
|
||||
# 292| getBlock: [BraceBlock] { ... }
|
||||
# 292| getParameter: [SimpleParameter] x
|
||||
# 292| getDefiningAccess: [LocalVariableAccess] x
|
||||
# 292| getStmt: [AddExpr] ... + ...
|
||||
# 292| getAnOperand/getLeftOperand: [LocalVariableAccess] x
|
||||
# 292| getAnOperand/getRightOperand: [IntegerLiteral] 100
|
||||
@@ -405,6 +415,7 @@ calls/calls.rb:
|
||||
# 293| getArgument: [IntegerLiteral] 7
|
||||
# 293| getBlock: [DoBlock] do ... end
|
||||
# 293| getParameter: [SimpleParameter] x
|
||||
# 293| getDefiningAccess: [LocalVariableAccess] x
|
||||
# 293| getStmt: [AddExpr] ... + ...
|
||||
# 293| getAnOperand/getLeftOperand: [LocalVariableAccess] x
|
||||
# 293| getAnOperand/getRightOperand: [IntegerLiteral] 200
|
||||
@@ -689,6 +700,7 @@ constants/constants.rb:
|
||||
# 19| getReceiver: [ConstantReadAccess] Names
|
||||
# 19| getBlock: [DoBlock] do ... end
|
||||
# 19| getParameter: [SimpleParameter] name
|
||||
# 19| getDefiningAccess: [LocalVariableAccess] name
|
||||
# 20| getStmt: [MethodCall] call to puts
|
||||
# 20| getArgument: [StringLiteral] "#{...} #{...}"
|
||||
# 20| getComponent: [StringInterpolationComponent] #{...}
|
||||
@@ -1173,9 +1185,8 @@ control/loops.rb:
|
||||
# 24| getAnOperand/getRightOperand: [LocalVariableAccess] value
|
||||
# 28| getStmt: [ForExpr] for ... in ...
|
||||
# 28| getPattern: [TuplePattern] (..., ...)
|
||||
# 28| getElement: [TuplePattern] (..., ...)
|
||||
# 28| getElement: [LocalVariableAccess] key
|
||||
# 28| getElement: [LocalVariableAccess] value
|
||||
# 28| getElement: [LocalVariableAccess] key
|
||||
# 28| getElement: [LocalVariableAccess] value
|
||||
# 28| <in>: [???] In
|
||||
# 28| getValue: [HashLiteral] {...}
|
||||
# 28| getElement: [Pair] Pair
|
||||
@@ -1528,8 +1539,11 @@ params/params.rb:
|
||||
# 1| [Toplevel] params.rb
|
||||
# 4| getStmt: [Method] identifier_method_params
|
||||
# 4| getParameter: [SimpleParameter] foo
|
||||
# 4| getDefiningAccess: [LocalVariableAccess] foo
|
||||
# 4| getParameter: [SimpleParameter] bar
|
||||
# 4| getDefiningAccess: [LocalVariableAccess] bar
|
||||
# 4| getParameter: [SimpleParameter] baz
|
||||
# 4| getDefiningAccess: [LocalVariableAccess] baz
|
||||
# 8| getStmt: [AssignExpr] ... = ...
|
||||
# 8| getAnOperand/getLeftOperand: [LocalVariableAccess] hash
|
||||
# 8| getAnOperand/getRightOperand: [HashLiteral] {...}
|
||||
@@ -1537,7 +1551,9 @@ params/params.rb:
|
||||
# 9| getReceiver: [LocalVariableAccess] hash
|
||||
# 9| getBlock: [DoBlock] do ... end
|
||||
# 9| getParameter: [SimpleParameter] key
|
||||
# 9| getDefiningAccess: [LocalVariableAccess] key
|
||||
# 9| getParameter: [SimpleParameter] value
|
||||
# 9| getDefiningAccess: [LocalVariableAccess] value
|
||||
# 10| getStmt: [MethodCall] call to puts
|
||||
# 10| getArgument: [StringLiteral] "#{...} -> #{...}"
|
||||
# 10| getComponent: [StringInterpolationComponent] #{...}
|
||||
@@ -1549,7 +1565,9 @@ params/params.rb:
|
||||
# 14| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
|
||||
# 14| getAnOperand/getRightOperand: [Lambda] -> { ... }
|
||||
# 14| getParameter: [SimpleParameter] foo
|
||||
# 14| getDefiningAccess: [LocalVariableAccess] foo
|
||||
# 14| getParameter: [SimpleParameter] bar
|
||||
# 14| getDefiningAccess: [LocalVariableAccess] bar
|
||||
# 14| getStmt: [AddExpr] ... + ...
|
||||
# 14| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
|
||||
# 14| getAnOperand/getRightOperand: [LocalVariableAccess] bar
|
||||
@@ -1589,24 +1607,36 @@ params/params.rb:
|
||||
# 26| getAnOperand/getRightOperand: [LocalVariableAccess] fourth
|
||||
# 30| getStmt: [Method] method_with_splat
|
||||
# 30| getParameter: [SimpleParameter] wibble
|
||||
# 30| getDefiningAccess: [LocalVariableAccess] wibble
|
||||
# 30| getParameter: [SplatParameter] *splat
|
||||
# 30| getDefiningAccess: [LocalVariableAccess] splat
|
||||
# 30| getParameter: [HashSplatParameter] **double_splat
|
||||
# 30| getDefiningAccess: [LocalVariableAccess] double_splat
|
||||
# 34| getStmt: [MethodCall] call to each
|
||||
# 34| getReceiver: [LocalVariableAccess] array
|
||||
# 34| getBlock: [DoBlock] do ... end
|
||||
# 34| getParameter: [SimpleParameter] val
|
||||
# 34| getDefiningAccess: [LocalVariableAccess] val
|
||||
# 34| getParameter: [SplatParameter] *splat
|
||||
# 34| getDefiningAccess: [LocalVariableAccess] splat
|
||||
# 34| getParameter: [HashSplatParameter] **double_splat
|
||||
# 34| getDefiningAccess: [LocalVariableAccess] double_splat
|
||||
# 38| getStmt: [AssignExpr] ... = ...
|
||||
# 38| getAnOperand/getLeftOperand: [LocalVariableAccess] lambda_with_splats
|
||||
# 38| getAnOperand/getRightOperand: [Lambda] -> { ... }
|
||||
# 38| getParameter: [SimpleParameter] x
|
||||
# 38| getDefiningAccess: [LocalVariableAccess] x
|
||||
# 38| getParameter: [SplatParameter] *blah
|
||||
# 38| getDefiningAccess: [LocalVariableAccess] blah
|
||||
# 38| getParameter: [HashSplatParameter] **wibble
|
||||
# 38| getDefiningAccess: [LocalVariableAccess] wibble
|
||||
# 41| getStmt: [Method] method_with_keyword_params
|
||||
# 41| getParameter: [SimpleParameter] x
|
||||
# 41| getDefiningAccess: [LocalVariableAccess] x
|
||||
# 41| getParameter: [KeywordParameter] foo
|
||||
# 41| getDefiningAccess: [LocalVariableAccess] foo
|
||||
# 41| getParameter: [KeywordParameter] bar
|
||||
# 41| getDefiningAccess: [LocalVariableAccess] bar
|
||||
# 41| getDefaultValue: [IntegerLiteral] 7
|
||||
# 42| getStmt: [AddExpr] ... + ...
|
||||
# 42| getAnOperand/getLeftOperand: [AddExpr] ... + ...
|
||||
@@ -1615,6 +1645,7 @@ params/params.rb:
|
||||
# 42| getAnOperand/getRightOperand: [LocalVariableAccess] bar
|
||||
# 46| getStmt: [Method] use_block_with_keyword
|
||||
# 46| getParameter: [BlockParameter] &block
|
||||
# 46| getDefiningAccess: [LocalVariableAccess] block
|
||||
# 47| getStmt: [MethodCall] call to puts
|
||||
# 47| getArgument: [MethodCall] call to call
|
||||
# 47| getReceiver: [LocalVariableAccess] block
|
||||
@@ -1627,7 +1658,9 @@ params/params.rb:
|
||||
# 49| getStmt: [MethodCall] call to use_block_with_keyword
|
||||
# 49| getBlock: [DoBlock] do ... end
|
||||
# 49| getParameter: [KeywordParameter] xx
|
||||
# 49| getDefiningAccess: [LocalVariableAccess] xx
|
||||
# 49| getParameter: [KeywordParameter] yy
|
||||
# 49| getDefiningAccess: [LocalVariableAccess] yy
|
||||
# 49| getDefaultValue: [IntegerLiteral] 100
|
||||
# 50| getStmt: [AddExpr] ... + ...
|
||||
# 50| getAnOperand/getLeftOperand: [LocalVariableAccess] xx
|
||||
@@ -1636,8 +1669,11 @@ params/params.rb:
|
||||
# 53| getAnOperand/getLeftOperand: [LocalVariableAccess] lambda_with_keyword_params
|
||||
# 53| getAnOperand/getRightOperand: [Lambda] -> { ... }
|
||||
# 53| getParameter: [SimpleParameter] x
|
||||
# 53| getDefiningAccess: [LocalVariableAccess] x
|
||||
# 53| getParameter: [KeywordParameter] y
|
||||
# 53| getDefiningAccess: [LocalVariableAccess] y
|
||||
# 53| getParameter: [KeywordParameter] z
|
||||
# 53| getDefiningAccess: [LocalVariableAccess] z
|
||||
# 53| getDefaultValue: [IntegerLiteral] 3
|
||||
# 54| getStmt: [AddExpr] ... + ...
|
||||
# 54| getAnOperand/getLeftOperand: [AddExpr] ... + ...
|
||||
@@ -1646,12 +1682,16 @@ params/params.rb:
|
||||
# 54| getAnOperand/getRightOperand: [LocalVariableAccess] z
|
||||
# 58| getStmt: [Method] method_with_optional_params
|
||||
# 58| getParameter: [SimpleParameter] val1
|
||||
# 58| getDefiningAccess: [LocalVariableAccess] val1
|
||||
# 58| getParameter: [OptionalParameter] val2
|
||||
# 58| getDefiningAccess: [LocalVariableAccess] val2
|
||||
# 58| getDefaultValue: [IntegerLiteral] 0
|
||||
# 58| getParameter: [OptionalParameter] val3
|
||||
# 58| getDefiningAccess: [LocalVariableAccess] val3
|
||||
# 58| getDefaultValue: [IntegerLiteral] 100
|
||||
# 62| getStmt: [Method] use_block_with_optional
|
||||
# 62| getParameter: [BlockParameter] &block
|
||||
# 62| getDefiningAccess: [LocalVariableAccess] block
|
||||
# 63| getStmt: [MethodCall] call to call
|
||||
# 63| getReceiver: [LocalVariableAccess] block
|
||||
# 63| getArgument: [StringLiteral] "Zeus"
|
||||
@@ -1659,7 +1699,9 @@ params/params.rb:
|
||||
# 65| getStmt: [MethodCall] call to use_block_with_optional
|
||||
# 65| getBlock: [DoBlock] do ... end
|
||||
# 65| getParameter: [SimpleParameter] name
|
||||
# 65| getDefiningAccess: [LocalVariableAccess] name
|
||||
# 65| getParameter: [OptionalParameter] age
|
||||
# 65| getDefiningAccess: [LocalVariableAccess] age
|
||||
# 65| getDefaultValue: [IntegerLiteral] 99
|
||||
# 66| getStmt: [MethodCall] call to puts
|
||||
# 66| getArgument: [StringLiteral] "#{...} is #{...} years old"
|
||||
@@ -1673,9 +1715,12 @@ params/params.rb:
|
||||
# 70| getAnOperand/getLeftOperand: [LocalVariableAccess] lambda_with_optional_params
|
||||
# 70| getAnOperand/getRightOperand: [Lambda] -> { ... }
|
||||
# 70| getParameter: [SimpleParameter] a
|
||||
# 70| getDefiningAccess: [LocalVariableAccess] a
|
||||
# 70| getParameter: [OptionalParameter] b
|
||||
# 70| getDefiningAccess: [LocalVariableAccess] b
|
||||
# 70| getDefaultValue: [IntegerLiteral] 1000
|
||||
# 70| getParameter: [OptionalParameter] c
|
||||
# 70| getDefiningAccess: [LocalVariableAccess] c
|
||||
# 70| getDefaultValue: [IntegerLiteral] 20
|
||||
# 70| getStmt: [AddExpr] ... + ...
|
||||
# 70| getAnOperand/getLeftOperand: [AddExpr] ... + ...
|
||||
|
||||
@@ -3,22 +3,3 @@
|
||||
*/
|
||||
|
||||
import codeql_ruby.printAst
|
||||
|
||||
class OrderedAstNode extends PrintAstNode {
|
||||
override string getProperty(string key) {
|
||||
result = super.getProperty(key)
|
||||
or
|
||||
key = "semmle.order" and
|
||||
result =
|
||||
any(int i |
|
||||
this =
|
||||
rank[i](AstNode p |
|
||||
|
|
||||
p
|
||||
order by
|
||||
p.getLocation().getFile().getBaseName(), p.getLocation().getFile().getAbsolutePath(),
|
||||
p.getLocation().getStartLine()
|
||||
)
|
||||
).toString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import ruby
|
||||
import codeql_ruby.ast.internal.TreeSitter
|
||||
|
||||
private string getMethodName(Call c) {
|
||||
result = c.(MethodCall).getMethodName()
|
||||
|
||||
@@ -29,7 +29,8 @@ forExprs
|
||||
forExprsTuplePatterns
|
||||
| loops.rb:22:1:25:3 | for ... in ... | loops.rb:22:5:22:14 | (..., ...) | 0 | loops.rb:22:5:22:7 | key |
|
||||
| loops.rb:22:1:25:3 | for ... in ... | loops.rb:22:5:22:14 | (..., ...) | 1 | loops.rb:22:10:22:14 | value |
|
||||
| loops.rb:28:1:32:3 | for ... in ... | loops.rb:28:5:28:16 | (..., ...) | 0 | loops.rb:28:5:28:16 | (..., ...) |
|
||||
| loops.rb:28:1:32:3 | for ... in ... | loops.rb:28:5:28:16 | (..., ...) | 0 | loops.rb:28:6:28:8 | key |
|
||||
| loops.rb:28:1:32:3 | for ... in ... | loops.rb:28:5:28:16 | (..., ...) | 1 | loops.rb:28:11:28:15 | value |
|
||||
whileExprs
|
||||
| loops.rb:35:1:39:3 | while ... | loops.rb:35:7:35:11 | ... < ... | loops.rb:35:12:39:3 | ...; ... | 0 | loops.rb:36:3:36:8 | ... += ... |
|
||||
| loops.rb:35:1:39:3 | while ... | loops.rb:35:7:35:11 | ... < ... | loops.rb:35:12:39:3 | ...; ... | 1 | loops.rb:37:3:37:8 | ... += ... |
|
||||
|
||||
@@ -3,6 +3,6 @@ toplevel
|
||||
| modules.rb:1:1:61:3 | modules.rb | Toplevel |
|
||||
| toplevel.rb:1:1:5:23 | toplevel.rb | Toplevel |
|
||||
beginBlocks
|
||||
| toplevel.rb:1:1:5:23 | toplevel.rb | 1 | toplevel.rb:5:1:5:22 | BEGIN { ... } |
|
||||
| toplevel.rb:1:1:5:23 | toplevel.rb | 0 | toplevel.rb:5:1:5:22 | BEGIN { ... } |
|
||||
endBlocks
|
||||
| toplevel.rb:1:1:5:23 | toplevel.rb | toplevel.rb:3:1:3:18 | END { ... } |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -130,6 +130,9 @@ module M
|
||||
Constant = 5
|
||||
end
|
||||
|
||||
class EmptyClass; end
|
||||
module EmptyModule; end
|
||||
|
||||
1/0 rescue puts "div by zero"
|
||||
|
||||
(*init, last) = 1, 2, 3
|
||||
|
||||
@@ -13,11 +13,11 @@ definition
|
||||
| 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:17:7:22 | client | parameters.rb:7:17:7:22 | client |
|
||||
| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas |
|
||||
| parameters.rb:15:15:15:19 | **map | parameters.rb:15:17:15:19 | map |
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas |
|
||||
| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map |
|
||||
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key |
|
||||
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value |
|
||||
| parameters.rb:21:16:21:21 | &block | parameters.rb:21:17:21:21 | block |
|
||||
| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block |
|
||||
| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name |
|
||||
| parameters.rb:25:33:25:36 | size | parameters.rb:25:33:25:36 | size |
|
||||
| parameters.rb:30:15:30:19 | first | parameters.rb:30:15:30:19 | first |
|
||||
@@ -100,12 +100,12 @@ read
|
||||
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y |
|
||||
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:9:25:9:30 | client |
|
||||
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:11:41:11:46 | client |
|
||||
| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas |
|
||||
| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:11:14:11:19 | pizzas |
|
||||
| parameters.rb:15:15:15:19 | **map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map |
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas |
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:11:14:11:19 | pizzas |
|
||||
| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map |
|
||||
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key |
|
||||
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value |
|
||||
| parameters.rb:21:16:21:21 | &block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block |
|
||||
| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block |
|
||||
| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:40:25:43 | name |
|
||||
| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:26:8:26:11 | name |
|
||||
| parameters.rb:25:33:25:36 | size | parameters.rb:25:33:25:36 | size | parameters.rb:27:8:27:11 | size |
|
||||
@@ -181,11 +181,11 @@ firstRead
|
||||
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y |
|
||||
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:9:25:9:30 | client |
|
||||
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:11:41:11:46 | client |
|
||||
| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas |
|
||||
| parameters.rb:15:15:15:19 | **map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map |
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas |
|
||||
| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map |
|
||||
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key |
|
||||
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value |
|
||||
| parameters.rb:21:16:21:21 | &block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block |
|
||||
| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block |
|
||||
| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:40:25:43 | name |
|
||||
| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:26:8:26:11 | name |
|
||||
| parameters.rb:25:33:25:36 | size | parameters.rb:25:33:25:36 | size | parameters.rb:27:8:27:11 | size |
|
||||
@@ -250,12 +250,12 @@ lastRead
|
||||
| parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y |
|
||||
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:9:25:9:30 | client |
|
||||
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:11:41:11:46 | client |
|
||||
| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas |
|
||||
| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:11:14:11:19 | pizzas |
|
||||
| parameters.rb:15:15:15:19 | **map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map |
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas |
|
||||
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:11:14:11:19 | pizzas |
|
||||
| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map |
|
||||
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key |
|
||||
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value |
|
||||
| parameters.rb:21:16:21:21 | &block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block |
|
||||
| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block |
|
||||
| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:26:8:26:11 | name |
|
||||
| parameters.rb:25:33:25:36 | size | parameters.rb:25:33:25:36 | size | parameters.rb:27:8:27:11 | size |
|
||||
| parameters.rb:30:15:30:19 | first | parameters.rb:30:15:30:19 | first | parameters.rb:31:11:31:15 | first |
|
||||
@@ -306,7 +306,7 @@ lastRead
|
||||
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
|
||||
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 |
|
||||
| parameters.rb:7:25: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: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: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 |
|
||||
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | scopes.rb:11:4:11:4 | a |
|
||||
| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:28:8:28:8 | x | scopes.rb:31:10:31:10 | x |
|
||||
|
||||
@@ -1,182 +1,193 @@
|
||||
variableAccess
|
||||
| class_variables.rb:1:1:1:3 | @@x | class_variables.rb:1:1:1:3 | @@x | class_variables.rb:1:1:29:4 | top-level scope for class_variables.rb |
|
||||
| class_variables.rb:3:3:3:5 | @@x | class_variables.rb:1:1:1:3 | @@x | class_variables.rb:1:1:29:4 | top-level scope for class_variables.rb |
|
||||
| class_variables.rb:6:4:6:6 | @@x | class_variables.rb:1:1:1:3 | @@x | class_variables.rb:1:1:29:4 | top-level scope for class_variables.rb |
|
||||
| class_variables.rb:11:7:11:9 | @@x | class_variables.rb:11:7:11:9 | @@x | class_variables.rb:9:1:16:3 | class scope for X |
|
||||
| class_variables.rb:14:6:14:8 | @@x | class_variables.rb:11:7:11:9 | @@x | class_variables.rb:9:1:16:3 | class scope for X |
|
||||
| class_variables.rb:19:3:19:5 | @@x | class_variables.rb:19:3:19:5 | @@x | class_variables.rb:18:1:20:3 | class scope for Y |
|
||||
| class_variables.rb:23:3:23:5 | @@x | class_variables.rb:23:3:23:5 | @@x | class_variables.rb:22:1:24:3 | module scope for M |
|
||||
| class_variables.rb:28:5:28:7 | @@x | class_variables.rb:28:5:28:7 | @@x | class_variables.rb:26:1:29:3 | module scope for N |
|
||||
| instance_variables.rb:1:1:1:4 | @top | instance_variables.rb:1:1:1:4 | @top | instance_variables.rb:1:1:44:4 | top-level scope for instance_variables.rb |
|
||||
| instance_variables.rb:4:3:4:6 | @foo | instance_variables.rb:4:3:4:6 | @foo | instance_variables.rb:1:1:44:4 | top-level scope for instance_variables.rb |
|
||||
| instance_variables.rb:8:8:8:11 | @foo | instance_variables.rb:4:3:4:6 | @foo | instance_variables.rb:1:1:44:4 | top-level scope for instance_variables.rb |
|
||||
| instance_variables.rb:11:6:11:9 | @top | instance_variables.rb:1:1:1:4 | @top | instance_variables.rb:1:1:44:4 | top-level scope for instance_variables.rb |
|
||||
| instance_variables.rb:14:3:14:4 | @x | instance_variables.rb:14:3:14:4 | @x | instance_variables.rb:13:1:18:3 | class scope for X |
|
||||
| instance_variables.rb:16:5:16:6 | @y | instance_variables.rb:16:5:16:6 | @y | instance_variables.rb:13:1:18:3 | class scope for X |
|
||||
| instance_variables.rb:21:2:21:3 | @m | instance_variables.rb:21:2:21:3 | @m | instance_variables.rb:20:1:25:3 | module scope for M |
|
||||
| instance_variables.rb:23:4:23:5 | @n | instance_variables.rb:23:4:23:5 | @n | instance_variables.rb:20:1:25:3 | module scope for M |
|
||||
| instance_variables.rb:28:3:28:4 | @x | instance_variables.rb:28:3:28:4 | @x | instance_variables.rb:1:1:44:4 | top-level scope for instance_variables.rb |
|
||||
| instance_variables.rb:32:12:32:13 | @x | instance_variables.rb:32:12:32:13 | @x | instance_variables.rb:1:1:44:4 | top-level scope for instance_variables.rb |
|
||||
| instance_variables.rb:36:3:36:4 | @x | instance_variables.rb:36:3:36:4 | @x | instance_variables.rb:35:1:44:4 | class scope for C |
|
||||
| instance_variables.rb:39:6:39:7 | @x | instance_variables.rb:39:6:39:7 | @x | instance_variables.rb:35:1:44:4 | class scope for C |
|
||||
| instance_variables.rb:42:6:42:7 | @x | instance_variables.rb:39:6:39:7 | @x | instance_variables.rb:35:1:44:4 | class scope for C |
|
||||
| nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:4:1:39:3 | class scope for C |
|
||||
| nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:6:3:37:5 | module scope for M |
|
||||
| nested_scopes.rb:9:7:9:7 | a | nested_scopes.rb:9:7:9:7 | a | nested_scopes.rb:8:5:35:7 | module scope for N |
|
||||
| nested_scopes.rb:11:9:11:9 | a | nested_scopes.rb:11:9:11:9 | a | nested_scopes.rb:10:7:26:9 | class scope for D |
|
||||
| nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:12:9:21:11 | method scope for show_a |
|
||||
| nested_scopes.rb:14:16:14:16 | a | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:12:9:21:11 | method scope for show_a |
|
||||
| nested_scopes.rb:15:11:15:11 | a | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:12:9:21:11 | method scope for show_a |
|
||||
| nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:19:20:13 | block scope |
|
||||
| nested_scopes.rb:16:13:16:13 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:19:20:13 | block scope |
|
||||
| nested_scopes.rb:16:26:16:26 | x | nested_scopes.rb:16:26:16:26 | x | nested_scopes.rb:16:21:19:15 | block scope |
|
||||
| nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | block scope |
|
||||
| nested_scopes.rb:17:15:17:15 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | block scope |
|
||||
| nested_scopes.rb:18:15:18:15 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | block scope |
|
||||
| nested_scopes.rb:18:26:18:26 | x | nested_scopes.rb:18:26:18:26 | x | nested_scopes.rb:18:23:18:36 | block scope |
|
||||
| nested_scopes.rb:18:34:18:34 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | block scope |
|
||||
| nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:9:24:11 | method scope for show_a2 |
|
||||
| nested_scopes.rb:23:16:23:16 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:9:24:11 | method scope for show_a2 |
|
||||
| nested_scopes.rb:25:14:25:14 | a | nested_scopes.rb:11:9:11:9 | a | nested_scopes.rb:10:7:26:9 | class scope for D |
|
||||
| nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:30:7:33:9 | class scope |
|
||||
| nested_scopes.rb:32:16:32:16 | a | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:30:7:33:9 | class scope |
|
||||
| nested_scopes.rb:34:12:34:12 | a | nested_scopes.rb:9:7:9:7 | a | nested_scopes.rb:8:5:35:7 | module scope for N |
|
||||
| nested_scopes.rb:36:10:36:10 | a | nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:6:3:37:5 | module scope for M |
|
||||
| nested_scopes.rb:38:8:38:8 | a | nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:4:1:39:3 | class scope for C |
|
||||
| nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:1:1:42:1 | top-level scope for nested_scopes.rb |
|
||||
| nested_scopes.rb:41:1:41:1 | d | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:1:1:42:1 | top-level scope for nested_scopes.rb |
|
||||
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:1:9:5:3 | block scope |
|
||||
| parameters.rb:1:18:1:18 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | block scope |
|
||||
| parameters.rb:2:4:2:4 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | block scope |
|
||||
| parameters.rb:3:9:3:9 | x | parameters.rb:1:14:1:14 | x | parameters.rb:1:9:5:3 | block scope |
|
||||
| parameters.rb:4:9:4:9 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | block scope |
|
||||
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | method scope for order_pizza |
|
||||
| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | method scope for order_pizza |
|
||||
| parameters.rb:8:6:8:11 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | method scope for order_pizza |
|
||||
| parameters.rb:9:25:9:30 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | method scope for order_pizza |
|
||||
| parameters.rb:11:14:11:19 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | method scope for order_pizza |
|
||||
| parameters.rb:11:41:11:46 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | method scope for order_pizza |
|
||||
| parameters.rb:15:15:15:19 | **map | parameters.rb:15:17:15:19 | map | parameters.rb:15:1:19:3 | method scope for print_map |
|
||||
| parameters.rb:16:3:16:5 | map | parameters.rb:15:17:15:19 | map | parameters.rb:15:1:19:3 | method scope for print_map |
|
||||
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:16:12:18:5 | block scope |
|
||||
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:16:12:18:5 | block scope |
|
||||
| parameters.rb:17:13:17:15 | key | parameters.rb:16:16:16:18 | key | parameters.rb:16:12:18:5 | block scope |
|
||||
| parameters.rb:17:22:17:26 | value | parameters.rb:16:21:16:25 | value | parameters.rb:16:12:18:5 | block scope |
|
||||
| parameters.rb:21:16:21:21 | &block | parameters.rb:21:17:21:21 | block | parameters.rb:21:1:23:3 | method scope for call_block |
|
||||
| parameters.rb:22:3:22:7 | block | parameters.rb:21:17:21:21 | block | parameters.rb:21:1:23:3 | method scope for call_block |
|
||||
| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:1:28:3 | method scope for opt_param |
|
||||
| parameters.rb:25:33:25:36 | size | parameters.rb:25:33:25:36 | size | parameters.rb:25:1:28:3 | method scope for opt_param |
|
||||
| parameters.rb:25:40:25:43 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:1:28:3 | method scope for opt_param |
|
||||
| parameters.rb:26:8:26:11 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:1:28:3 | method scope for opt_param |
|
||||
| parameters.rb:27:8:27:11 | size | parameters.rb:25:33:25:36 | size | parameters.rb:25:1:28:3 | method scope for opt_param |
|
||||
| parameters.rb:30:15:30:19 | first | parameters.rb:30:15:30:19 | first | parameters.rb:30:1:32:3 | method scope for key_param |
|
||||
| parameters.rb:30:24:30:29 | middle | parameters.rb:30:24:30:29 | middle | parameters.rb:30:1:32:3 | method scope for key_param |
|
||||
| parameters.rb:30:36:30:39 | last | parameters.rb:30:36:30:39 | last | parameters.rb:30:1:32:3 | method scope for key_param |
|
||||
| parameters.rb:31:11:31:15 | first | parameters.rb:30:15:30:19 | first | parameters.rb:30:1:32:3 | method scope for key_param |
|
||||
| parameters.rb:31:20:31:25 | middle | parameters.rb:30:24:30:29 | middle | parameters.rb:30:1:32:3 | method scope for key_param |
|
||||
| parameters.rb:31:30:31:33 | last | parameters.rb:30:36:30:39 | last | parameters.rb:30:1:32:3 | method scope for key_param |
|
||||
| parameters.rb:34:1:34:1 | b | parameters.rb:34:1:34:1 | b | parameters.rb:1:1:58:1 | top-level scope for parameters.rb |
|
||||
| parameters.rb:35:11:35:11 | a | parameters.rb:35:11:35:11 | a | parameters.rb:35:1:38:3 | method scope for multi |
|
||||
| parameters.rb:35:16:35:16 | b | parameters.rb:35:16:35:16 | b | parameters.rb:35:1:38:3 | method scope for multi |
|
||||
| parameters.rb:37:11:37:11 | a | parameters.rb:35:11:35:11 | a | parameters.rb:35:1:38:3 | method scope for multi |
|
||||
| parameters.rb:37:16:37:16 | b | parameters.rb:35:16:35:16 | b | parameters.rb:35:1:38:3 | method scope for multi |
|
||||
| parameters.rb:40:12:40:12 | d | parameters.rb:40:12:40:12 | d | parameters.rb:40:1:43:3 | method scope for multi2 |
|
||||
| parameters.rb:40:15:40:15 | e | parameters.rb:40:15:40:15 | e | parameters.rb:40:1:43:3 | method scope for multi2 |
|
||||
| parameters.rb:42:11:42:11 | d | parameters.rb:40:12:40:12 | d | parameters.rb:40:1:43:3 | method scope for multi2 |
|
||||
| parameters.rb:42:16:42:16 | e | parameters.rb:40:15:40:15 | e | parameters.rb:40:1:43:3 | method scope for multi2 |
|
||||
| parameters.rb:45:20:45:20 | _ | parameters.rb:45:20:45:20 | _ | parameters.rb:45:1:47:3 | method scope for dup_underscore |
|
||||
| parameters.rb:46:8:46:8 | _ | parameters.rb:45:20:45:20 | _ | parameters.rb:45:1:47:3 | method scope for dup_underscore |
|
||||
| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:49:1:51:3 | method scope for tuples |
|
||||
| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:49:1:51:3 | method scope for tuples |
|
||||
| parameters.rb:50:11:50:11 | a | parameters.rb:49:13:49:13 | a | parameters.rb:49:1:51:3 | method scope for tuples |
|
||||
| parameters.rb:50:16:50:16 | b | parameters.rb:49:15:49:15 | b | parameters.rb:49:1:51:3 | method scope for tuples |
|
||||
| parameters.rb:53:1:53:1 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | top-level scope for parameters.rb |
|
||||
| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:54:9:57:3 | block scope |
|
||||
| parameters.rb:54:19:54:19 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | top-level scope for parameters.rb |
|
||||
| parameters.rb:55:9:55:9 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | top-level scope for parameters.rb |
|
||||
| parameters.rb:56:9:56:9 | y | parameters.rb:54:14:54:14 | y | parameters.rb:54:9:57:3 | block scope |
|
||||
| scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x | scopes.rb:2:9:6:3 | block scope |
|
||||
| scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:4 | a | scopes.rb:2:9:6:3 | block scope |
|
||||
| scopes.rb:5:9:5:9 | a | scopes.rb:4:4:4:4 | a | scopes.rb:2:9:6:3 | block scope |
|
||||
| scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:8:6:8:6 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x | scopes.rb:9:9:18:3 | block scope |
|
||||
| scopes.rb:10:9:10:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:12:9:12:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:13:7:13:7 | b | scopes.rb:13:7:13:7 | b | scopes.rb:9:9:18:3 | block scope |
|
||||
| scopes.rb:13:11:13:11 | c | scopes.rb:13:11:13:11 | c | scopes.rb:9:9:18:3 | block scope |
|
||||
| scopes.rb:13:14:13:14 | d | scopes.rb:13:14:13:14 | d | scopes.rb:9:9:18:3 | block scope |
|
||||
| scopes.rb:14:9:14:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:15:9:15:9 | b | scopes.rb:13:7:13:7 | b | scopes.rb:9:9:18:3 | block scope |
|
||||
| scopes.rb:16:9:16:9 | c | scopes.rb:13:11:13:11 | c | scopes.rb:9:9:18:3 | block scope |
|
||||
| scopes.rb:17:9:17:9 | d | scopes.rb:13:14:13:14 | d | scopes.rb:9:9:18:3 | block scope |
|
||||
| scopes.rb:21:1:21:7 | $global | file://:0:0:0:0 | $global | file://:0:0:0:0 | global scope |
|
||||
| scopes.rb:24:1:24:6 | script | scopes.rb:24:1:24:6 | script | scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:24:10:24:11 | $0 | file://:0:0:0:0 | $0 | file://:0:0:0:0 | global scope |
|
||||
| scopes.rb:27:1:27:1 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:28:8:28:8 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:29:3:29:3 | x | scopes.rb:29:3:29:3 | x | scopes.rb:28:1:30:3 | module scope for B |
|
||||
| scopes.rb:31:10:31:10 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:32:3:32:3 | x | scopes.rb:32:3:32:3 | x | scopes.rb:31:1:33:3 | class scope |
|
||||
| scopes.rb:34:7:34:7 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:34:14:34:14 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:35:3:35:3 | x | scopes.rb:35:3:35:3 | x | scopes.rb:34:1:36:3 | class scope for C |
|
||||
| scopes.rb:37:5:37:5 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:38:3:38:3 | x | scopes.rb:38:3:38:3 | x | scopes.rb:37:1:39:3 | method scope for foo |
|
||||
| ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | ssa.rb:1:1:16:3 | method scope for m |
|
||||
| ssa.rb:2:3:2:3 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | method scope for m |
|
||||
| ssa.rb:3:8:3:8 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | method scope for m |
|
||||
| ssa.rb:4:8:4:8 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | method scope for m |
|
||||
| ssa.rb:5:6:5:6 | b | ssa.rb:1:7:1:7 | b | ssa.rb:1:1:16:3 | method scope for m |
|
||||
| ssa.rb:6:5:6:5 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | method scope for m |
|
||||
| ssa.rb:7:10:7:10 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | method scope for m |
|
||||
| ssa.rb:8:10:8:10 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | method scope for m |
|
||||
| ssa.rb:10:5:10:5 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | method scope for m |
|
||||
| ssa.rb:11:10:11:10 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | method scope for m |
|
||||
| ssa.rb:12:10:12:10 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | method scope for m |
|
||||
| ssa.rb:15:8:15:8 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | method scope for m |
|
||||
| ssa.rb:18:8:18:8 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | method scope for m1 |
|
||||
| ssa.rb:19:9:19:9 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | method scope for m1 |
|
||||
| ssa.rb:20:10:20:10 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | method scope for m1 |
|
||||
| ssa.rb:21:5:21:5 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | method scope for m1 |
|
||||
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:25:1:30:3 | method scope for m2 |
|
||||
| ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:25:1:30:3 | method scope for m2 |
|
||||
| ssa.rb:26:15:26:22 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:25:1:30:3 | method scope for m2 |
|
||||
| ssa.rb:27:10:27:13 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:25:1:30:3 | method scope for m2 |
|
||||
| ssa.rb:29:8:29:11 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:25:1:30:3 | method scope for m2 |
|
||||
| ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | ssa.rb:33:16:35:5 | block scope |
|
||||
| ssa.rb:34:10:34:10 | x | ssa.rb:33:20:33:20 | x | ssa.rb:33:16:35:5 | block scope |
|
||||
| ssa.rb:40:3:40:4 | m3 | ssa.rb:40:3:40:4 | m3 | ssa.rb:38:1:42:3 | method scope for m4 |
|
||||
| ssa.rb:41:8:41:9 | m3 | ssa.rb:40:3:40:4 | m3 | ssa.rb:38:1:42:3 | method scope for m4 |
|
||||
| ssa.rb:44:8:44:8 | b | ssa.rb:44:8:44:8 | b | ssa.rb:44:1:47:3 | method scope for m5 |
|
||||
| ssa.rb:45:3:45:3 | x | ssa.rb:45:3:45:3 | x | ssa.rb:44:1:47:3 | method scope for m5 |
|
||||
| ssa.rb:45:12:45:12 | b | ssa.rb:44:8:44:8 | b | ssa.rb:44:1:47:3 | method scope for m5 |
|
||||
| ssa.rb:46:8:46:8 | x | ssa.rb:45:3:45:3 | x | ssa.rb:44:1:47:3 | method scope for m5 |
|
||||
| ssa.rb:49:9:49:9 | x | ssa.rb:49:9:49:9 | x | ssa.rb:49:1:51:3 | method scope for m6 |
|
||||
| ssa.rb:49:14:49:14 | y | ssa.rb:49:14:49:14 | y | ssa.rb:49:1:51:3 | method scope for m6 |
|
||||
| ssa.rb:50:8:50:8 | y | ssa.rb:49:14:49:14 | y | ssa.rb:49:1:51:3 | method scope for m6 |
|
||||
| ssa.rb:53:8:53:10 | foo | ssa.rb:53:8:53:10 | foo | ssa.rb:53:1:56:3 | method scope for m7 |
|
||||
| ssa.rb:54:3:54:3 | x | ssa.rb:54:3:54:3 | x | ssa.rb:53:1:56:3 | method scope for m7 |
|
||||
| ssa.rb:54:7:54:9 | foo | ssa.rb:53:8:53:10 | foo | ssa.rb:53:1:56:3 | method scope for m7 |
|
||||
| ssa.rb:55:8:55:8 | x | ssa.rb:54:3:54:3 | x | ssa.rb:53:1:56:3 | method scope for m7 |
|
||||
| ssa.rb:59:3:59:3 | x | ssa.rb:59:3:59:3 | x | ssa.rb:58:1:62:3 | method scope for m8 |
|
||||
| ssa.rb:60:3:60:3 | x | ssa.rb:59:3:59:3 | x | ssa.rb:58:1:62:3 | method scope for m8 |
|
||||
| ssa.rb:61:8:61:8 | x | ssa.rb:59:3:59:3 | x | ssa.rb:58:1:62:3 | method scope for m8 |
|
||||
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:64:1:72:3 | method scope for m9 |
|
||||
| ssa.rb:65:3:65:10 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | method scope for m9 |
|
||||
| ssa.rb:66:3:66:3 | a | ssa.rb:64:8:64:8 | a | ssa.rb:64:1:72:3 | method scope for m9 |
|
||||
| ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:66:11:70:5 | block scope |
|
||||
| ssa.rb:67:10:67:10 | a | ssa.rb:66:15:66:15 | a | ssa.rb:66:11:70:5 | block scope |
|
||||
| ssa.rb:68:10:68:17 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | method scope for m9 |
|
||||
| ssa.rb:69:5:69:12 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | method scope for m9 |
|
||||
| ssa.rb:71:8:71:15 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | method scope for m9 |
|
||||
| ssa.rb:75:3:75:10 | captured | ssa.rb:75:3:75:10 | captured | ssa.rb:74:1:79:3 | method scope for m10 |
|
||||
| ssa.rb:77:15:77:22 | captured | ssa.rb:75:3:75:10 | captured | ssa.rb:74:1:79:3 | method scope for m10 |
|
||||
| ssa.rb:82:3:82:10 | captured | ssa.rb:82:3:82:10 | captured | ssa.rb:81:1:88:3 | method scope for m11 |
|
||||
| ssa.rb:85:15:85:22 | captured | ssa.rb:82:3:82:10 | captured | ssa.rb:81:1:88:3 | method scope for m11 |
|
||||
| class_variables.rb:1:1:1:3 | @@x | class_variables.rb:1:1:1:3 | @@x | class_variables.rb:1:1:29:4 | class_variables.rb |
|
||||
| class_variables.rb:3:3:3:5 | @@x | class_variables.rb:1:1:1:3 | @@x | class_variables.rb:1:1:29:4 | class_variables.rb |
|
||||
| class_variables.rb:6:4:6:6 | @@x | class_variables.rb:1:1:1:3 | @@x | class_variables.rb:1:1:29:4 | class_variables.rb |
|
||||
| class_variables.rb:11:7:11:9 | @@x | class_variables.rb:11:7:11:9 | @@x | class_variables.rb:9:1:16:3 | X |
|
||||
| class_variables.rb:14:6:14:8 | @@x | class_variables.rb:11:7:11:9 | @@x | class_variables.rb:9:1:16:3 | X |
|
||||
| class_variables.rb:19:3:19:5 | @@x | class_variables.rb:19:3:19:5 | @@x | class_variables.rb:18:1:20:3 | Y |
|
||||
| class_variables.rb:23:3:23:5 | @@x | class_variables.rb:23:3:23:5 | @@x | class_variables.rb:22:1:24:3 | M |
|
||||
| class_variables.rb:28:5:28:7 | @@x | class_variables.rb:28:5:28:7 | @@x | class_variables.rb:26:1:29:3 | N |
|
||||
| instance_variables.rb:1:1:1:4 | @top | instance_variables.rb:1:1:1:4 | @top | instance_variables.rb:1:1:44:4 | instance_variables.rb |
|
||||
| instance_variables.rb:4:3:4:6 | @foo | instance_variables.rb:4:3:4:6 | @foo | instance_variables.rb:1:1:44:4 | instance_variables.rb |
|
||||
| instance_variables.rb:8:8:8:11 | @foo | instance_variables.rb:4:3:4:6 | @foo | instance_variables.rb:1:1:44:4 | instance_variables.rb |
|
||||
| instance_variables.rb:11:6:11:9 | @top | instance_variables.rb:1:1:1:4 | @top | instance_variables.rb:1:1:44:4 | instance_variables.rb |
|
||||
| instance_variables.rb:14:3:14:4 | @x | instance_variables.rb:14:3:14:4 | @x | instance_variables.rb:13:1:18:3 | X |
|
||||
| instance_variables.rb:16:5:16:6 | @y | instance_variables.rb:16:5:16:6 | @y | instance_variables.rb:13:1:18:3 | X |
|
||||
| instance_variables.rb:21:2:21:3 | @m | instance_variables.rb:21:2:21:3 | @m | instance_variables.rb:20:1:25:3 | M |
|
||||
| instance_variables.rb:23:4:23:5 | @n | instance_variables.rb:23:4:23:5 | @n | instance_variables.rb:20:1:25:3 | M |
|
||||
| instance_variables.rb:28:3:28:4 | @x | instance_variables.rb:28:3:28:4 | @x | instance_variables.rb:1:1:44:4 | instance_variables.rb |
|
||||
| instance_variables.rb:32:12:32:13 | @x | instance_variables.rb:32:12:32:13 | @x | instance_variables.rb:1:1:44:4 | instance_variables.rb |
|
||||
| instance_variables.rb:36:3:36:4 | @x | instance_variables.rb:36:3:36:4 | @x | instance_variables.rb:35:1:44:4 | C |
|
||||
| instance_variables.rb:39:6:39:7 | @x | instance_variables.rb:39:6:39:7 | @x | instance_variables.rb:35:1:44:4 | C |
|
||||
| instance_variables.rb:42:6:42:7 | @x | instance_variables.rb:39:6:39:7 | @x | instance_variables.rb:35:1:44:4 | C |
|
||||
| nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:4:1:39:3 | C |
|
||||
| nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:6:3:37:5 | M |
|
||||
| nested_scopes.rb:9:7:9:7 | a | nested_scopes.rb:9:7:9:7 | a | nested_scopes.rb:8:5:35:7 | N |
|
||||
| nested_scopes.rb:11:9:11:9 | a | nested_scopes.rb:11:9:11:9 | a | nested_scopes.rb:10:7:26:9 | D |
|
||||
| nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:12:9:21:11 | show_a |
|
||||
| nested_scopes.rb:14:16:14:16 | a | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:12:9:21:11 | show_a |
|
||||
| nested_scopes.rb:15:11:15:11 | a | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:12:9:21:11 | show_a |
|
||||
| nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:19:20:13 | do ... end |
|
||||
| nested_scopes.rb:16:13:16:13 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:19:20:13 | do ... end |
|
||||
| nested_scopes.rb:16:26:16:26 | x | nested_scopes.rb:16:26:16:26 | x | nested_scopes.rb:16:21:19:15 | do ... end |
|
||||
| nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | do ... end |
|
||||
| nested_scopes.rb:17:15:17:15 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | do ... end |
|
||||
| nested_scopes.rb:18:15:18:15 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | do ... end |
|
||||
| nested_scopes.rb:18:26:18:26 | x | nested_scopes.rb:18:26:18:26 | x | nested_scopes.rb:18:23:18:36 | { ... } |
|
||||
| nested_scopes.rb:18:34:18:34 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | do ... end |
|
||||
| nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:9:24:11 | show_a2 |
|
||||
| nested_scopes.rb:23:16:23:16 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:9:24:11 | show_a2 |
|
||||
| nested_scopes.rb:25:14:25:14 | a | nested_scopes.rb:11:9:11:9 | a | nested_scopes.rb:10:7:26:9 | D |
|
||||
| nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:30:7:33:9 | class << ... |
|
||||
| nested_scopes.rb:32:16:32:16 | a | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:30:7:33:9 | class << ... |
|
||||
| nested_scopes.rb:34:12:34:12 | a | nested_scopes.rb:9:7:9:7 | a | nested_scopes.rb:8:5:35:7 | N |
|
||||
| nested_scopes.rb:36:10:36:10 | a | nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:6:3:37:5 | M |
|
||||
| nested_scopes.rb:38:8:38:8 | a | nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:4:1:39:3 | C |
|
||||
| nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:1:1:42:1 | nested_scopes.rb |
|
||||
| nested_scopes.rb:41:1:41:1 | d | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:1:1:42:1 | nested_scopes.rb |
|
||||
| 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:9:3:9 | x | parameters.rb:1:14:1:14 | x | parameters.rb:1:9:5:3 | do ... end |
|
||||
| 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 |
|
||||
| parameters.rb:8:6:8:11 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | order_pizza |
|
||||
| parameters.rb:9:25:9:30 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | order_pizza |
|
||||
| parameters.rb:11:14:11:19 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | order_pizza |
|
||||
| parameters.rb:11:41:11:46 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | order_pizza |
|
||||
| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:15:1:19:3 | print_map |
|
||||
| parameters.rb:16:3:16:5 | map | parameters.rb:15:17:15:19 | map | parameters.rb:15:1:19:3 | print_map |
|
||||
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:16:12:18:5 | do ... end |
|
||||
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:16:12:18:5 | do ... end |
|
||||
| parameters.rb:17:13:17:15 | key | parameters.rb:16:16:16:18 | key | parameters.rb:16:12:18:5 | do ... end |
|
||||
| parameters.rb:17:22:17:26 | value | parameters.rb:16:21:16:25 | value | parameters.rb:16:12:18:5 | do ... end |
|
||||
| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:21:1:23:3 | call_block |
|
||||
| parameters.rb:22:3:22:7 | block | parameters.rb:21:17:21:21 | block | parameters.rb:21:1:23:3 | call_block |
|
||||
| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:1:28:3 | opt_param |
|
||||
| parameters.rb:25:33:25:36 | size | parameters.rb:25:33:25:36 | size | parameters.rb:25:1:28:3 | opt_param |
|
||||
| parameters.rb:25:40:25:43 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:1:28:3 | opt_param |
|
||||
| parameters.rb:26:8:26:11 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:1:28:3 | opt_param |
|
||||
| parameters.rb:27:8:27:11 | size | parameters.rb:25:33:25:36 | size | parameters.rb:25:1:28:3 | opt_param |
|
||||
| parameters.rb:30:15:30:19 | first | parameters.rb:30:15:30:19 | first | parameters.rb:30:1:32:3 | key_param |
|
||||
| parameters.rb:30:24:30:29 | middle | parameters.rb:30:24:30:29 | middle | parameters.rb:30:1:32:3 | key_param |
|
||||
| parameters.rb:30:36:30:39 | last | parameters.rb:30:36:30:39 | last | parameters.rb:30:1:32:3 | key_param |
|
||||
| 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: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:11:37:11 | a | parameters.rb:35:11:35:11 | a | parameters.rb:35:1:38:3 | multi |
|
||||
| parameters.rb:37:16:37:16 | b | parameters.rb:35:16:35:16 | b | parameters.rb:35:1:38:3 | multi |
|
||||
| parameters.rb:40:12:40:12 | d | parameters.rb:40:12:40:12 | d | parameters.rb:40:1:43:3 | multi2 |
|
||||
| parameters.rb:40:15:40:15 | e | parameters.rb:40:15:40:15 | e | parameters.rb:40:1:43:3 | multi2 |
|
||||
| parameters.rb:42:11:42:11 | d | parameters.rb:40:12:40:12 | d | parameters.rb:40:1:43:3 | multi2 |
|
||||
| parameters.rb:42:16:42:16 | e | parameters.rb:40:15:40:15 | e | parameters.rb:40:1:43:3 | multi2 |
|
||||
| parameters.rb:45:20:45:20 | _ | parameters.rb:45:20:45:20 | _ | parameters.rb:45:1:47:3 | dup_underscore |
|
||||
| parameters.rb:46:8:46:8 | _ | parameters.rb:45:20:45:20 | _ | parameters.rb:45:1:47:3 | dup_underscore |
|
||||
| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:49:1:51:3 | tuples |
|
||||
| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | 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: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:9:55:9 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58: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 |
|
||||
| scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x | scopes.rb:2:9:6:3 | do ... end |
|
||||
| scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:4 | a | scopes.rb:2:9:6:3 | do ... end |
|
||||
| scopes.rb:5:9:5:9 | a | scopes.rb:4:4:4:4 | a | scopes.rb:2:9:6:3 | do ... end |
|
||||
| scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:8:6:8:6 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x | scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:10:9:10:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:12:9:12:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:13:7:13:7 | b | scopes.rb:13:7:13:7 | b | scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:13:11:13:11 | c | scopes.rb:13:11:13:11 | c | scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:13:14:13:14 | d | scopes.rb:13:14:13:14 | d | scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:14:9:14:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:15:9:15:9 | b | scopes.rb:13:7:13:7 | b | scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:16:9:16:9 | c | scopes.rb:13:11:13:11 | c | scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:17:9:17:9 | d | scopes.rb:13:14:13:14 | d | scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:24:1:24:6 | script | scopes.rb:24:1:24:6 | script | scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:27:1:27:1 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:28:8:28:8 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:29:3:29:3 | x | scopes.rb:29:3:29:3 | x | scopes.rb:28:1:30:3 | B |
|
||||
| scopes.rb:31:10:31:10 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:32:3:32:3 | x | scopes.rb:32:3:32:3 | x | scopes.rb:31:1:33:3 | class << ... |
|
||||
| scopes.rb:34:7:34:7 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:34:14:34:14 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:35:3:35:3 | x | scopes.rb:35:3:35:3 | x | scopes.rb:34:1:36:3 | C |
|
||||
| scopes.rb:37:5:37:5 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:38:3:38:3 | x | scopes.rb:38:3:38:3 | x | scopes.rb:37:1:39:3 | foo |
|
||||
| ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:2:3:2:3 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:3:8:3:8 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:4:8:4:8 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:5:6:5:6 | b | ssa.rb:1:7:1:7 | b | ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:6:5:6:5 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:7:10:7:10 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:8:10:8:10 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:10:5:10:5 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:11:10:11:10 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:12:10:12:10 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:15:8:15:8 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:18:8:18:8 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | m1 |
|
||||
| ssa.rb:19:9:19:9 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | m1 |
|
||||
| ssa.rb:20:10:20:10 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | m1 |
|
||||
| ssa.rb:21:5:21:5 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | m1 |
|
||||
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:25:1:30:3 | m2 |
|
||||
| ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:25:1:30:3 | m2 |
|
||||
| ssa.rb:26:15:26:22 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:25:1:30:3 | m2 |
|
||||
| ssa.rb:27:10:27:13 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:25:1:30:3 | m2 |
|
||||
| ssa.rb:29:8:29:11 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:25:1:30:3 | m2 |
|
||||
| ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | ssa.rb:33:16:35:5 | do ... end |
|
||||
| ssa.rb:34:10:34:10 | x | ssa.rb:33:20:33:20 | x | ssa.rb:33:16:35:5 | do ... end |
|
||||
| ssa.rb:40:3:40:4 | m3 | ssa.rb:40:3:40:4 | m3 | ssa.rb:38:1:42:3 | m4 |
|
||||
| ssa.rb:41:8:41:9 | m3 | ssa.rb:40:3:40:4 | m3 | ssa.rb:38:1:42:3 | m4 |
|
||||
| ssa.rb:44:8:44:8 | b | ssa.rb:44:8:44:8 | b | ssa.rb:44:1:47:3 | m5 |
|
||||
| ssa.rb:45:3:45:3 | x | ssa.rb:45:3:45:3 | x | ssa.rb:44:1:47:3 | m5 |
|
||||
| ssa.rb:45:12:45:12 | b | ssa.rb:44:8:44:8 | b | ssa.rb:44:1:47:3 | m5 |
|
||||
| ssa.rb:46:8:46:8 | x | ssa.rb:45:3:45:3 | x | ssa.rb:44:1:47:3 | m5 |
|
||||
| ssa.rb:49:9:49:9 | x | ssa.rb:49:9:49:9 | x | ssa.rb:49:1:51:3 | m6 |
|
||||
| ssa.rb:49:14:49:14 | y | ssa.rb:49:14:49:14 | y | ssa.rb:49:1:51:3 | m6 |
|
||||
| ssa.rb:50:8:50:8 | y | ssa.rb:49:14:49:14 | y | ssa.rb:49:1:51:3 | m6 |
|
||||
| ssa.rb:53:8:53:10 | foo | ssa.rb:53:8:53:10 | foo | ssa.rb:53:1:56:3 | m7 |
|
||||
| ssa.rb:54:3:54:3 | x | ssa.rb:54:3:54:3 | x | ssa.rb:53:1:56:3 | m7 |
|
||||
| ssa.rb:54:7:54:9 | foo | ssa.rb:53:8:53:10 | foo | ssa.rb:53:1:56:3 | m7 |
|
||||
| ssa.rb:55:8:55:8 | x | ssa.rb:54:3:54:3 | x | ssa.rb:53:1:56:3 | m7 |
|
||||
| ssa.rb:59:3:59:3 | x | ssa.rb:59:3:59:3 | x | ssa.rb:58:1:62:3 | m8 |
|
||||
| ssa.rb:60:3:60:3 | x | ssa.rb:59:3:59:3 | x | ssa.rb:58:1:62:3 | m8 |
|
||||
| ssa.rb:61:8:61:8 | x | ssa.rb:59:3:59:3 | x | ssa.rb:58:1:62:3 | m8 |
|
||||
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:64:1:72:3 | m9 |
|
||||
| ssa.rb:65:3:65:10 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | m9 |
|
||||
| ssa.rb:66:3:66:3 | a | ssa.rb:64:8:64:8 | a | ssa.rb:64:1:72:3 | m9 |
|
||||
| ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:66:11:70:5 | do ... end |
|
||||
| ssa.rb:67:10:67:10 | a | ssa.rb:66:15:66:15 | a | ssa.rb:66:11:70:5 | do ... end |
|
||||
| ssa.rb:68:10:68:17 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | m9 |
|
||||
| ssa.rb:69:5:69:12 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | m9 |
|
||||
| ssa.rb:71:8:71:15 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | m9 |
|
||||
| ssa.rb:75:3:75:10 | captured | ssa.rb:75:3:75:10 | captured | ssa.rb:74:1:79:3 | m10 |
|
||||
| ssa.rb:77:15:77:22 | captured | ssa.rb:75:3:75:10 | captured | ssa.rb:74:1:79:3 | m10 |
|
||||
| ssa.rb:82:3:82:10 | captured | ssa.rb:82:3:82:10 | captured | ssa.rb:81:1:88:3 | m11 |
|
||||
| ssa.rb:85:15:85:22 | captured | ssa.rb:82:3:82:10 | captured | ssa.rb:81:1:88:3 | m11 |
|
||||
explicitWrite
|
||||
| class_variables.rb:1:1:1:3 | @@x | class_variables.rb:1:1:1:8 | ... = ... |
|
||||
| class_variables.rb:19:3:19:5 | @@x | class_variables.rb:19:3:19:10 | ... = ... |
|
||||
| class_variables.rb:23:3:23:5 | @@x | class_variables.rb:23:3:23:10 | ... = ... |
|
||||
| instance_variables.rb:1:1:1:4 | @top | instance_variables.rb:1:1:1:8 | ... = ... |
|
||||
| instance_variables.rb:4:3:4:6 | @foo | instance_variables.rb:4:3:4:11 | ... = ... |
|
||||
| instance_variables.rb:14:3:14:4 | @x | instance_variables.rb:14:3:14:9 | ... = ... |
|
||||
| instance_variables.rb:16:5:16:6 | @y | instance_variables.rb:16:5:16:10 | ... = ... |
|
||||
| instance_variables.rb:21:2:21:3 | @m | instance_variables.rb:21:2:21:8 | ... = ... |
|
||||
| instance_variables.rb:23:4:23:5 | @n | instance_variables.rb:23:4:23:9 | ... = ... |
|
||||
| instance_variables.rb:28:3:28:4 | @x | instance_variables.rb:28:3:28:10 | ... = ... |
|
||||
| instance_variables.rb:32:12:32:13 | @x | instance_variables.rb:32:12:32:19 | ... = ... |
|
||||
| instance_variables.rb:36:3:36:4 | @x | instance_variables.rb:36:3:36:9 | ... = ... |
|
||||
| instance_variables.rb:39:6:39:7 | @x | instance_variables.rb:39:6:39:12 | ... = ... |
|
||||
| nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:5:3:5:7 | ... = ... |
|
||||
| nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:7:5:7:9 | ... = ... |
|
||||
| nested_scopes.rb:9:7:9:7 | a | nested_scopes.rb:9:7:9:11 | ... = ... |
|
||||
@@ -228,11 +239,11 @@ implicitWrite
|
||||
| parameters.rb:1:14:1:14 | x |
|
||||
| parameters.rb:1:18:1:18 | y |
|
||||
| parameters.rb:7:17:7:22 | client |
|
||||
| parameters.rb:7:25:7:31 | *pizzas |
|
||||
| parameters.rb:15:15:15:19 | **map |
|
||||
| parameters.rb:7:26:7:31 | pizzas |
|
||||
| parameters.rb:15:17:15:19 | map |
|
||||
| parameters.rb:16:16:16:18 | key |
|
||||
| parameters.rb:16:21:16:25 | value |
|
||||
| parameters.rb:21:16:21:21 | &block |
|
||||
| parameters.rb:21:17:21:21 | block |
|
||||
| parameters.rb:25:15:25:18 | name |
|
||||
| parameters.rb:25:33:25:36 | size |
|
||||
| parameters.rb:30:15:30:19 | first |
|
||||
@@ -257,26 +268,13 @@ implicitWrite
|
||||
| ssa.rb:64:8:64:8 | a |
|
||||
| ssa.rb:66:15:66:15 | a |
|
||||
readAccess
|
||||
| class_variables.rb:1:1:1:3 | @@x |
|
||||
| class_variables.rb:3:3:3:5 | @@x |
|
||||
| class_variables.rb:6:4:6:6 | @@x |
|
||||
| class_variables.rb:11:7:11:9 | @@x |
|
||||
| class_variables.rb:14:6:14:8 | @@x |
|
||||
| class_variables.rb:19:3:19:5 | @@x |
|
||||
| class_variables.rb:23:3:23:5 | @@x |
|
||||
| class_variables.rb:28:5:28:7 | @@x |
|
||||
| instance_variables.rb:1:1:1:4 | @top |
|
||||
| instance_variables.rb:4:3:4:6 | @foo |
|
||||
| instance_variables.rb:8:8:8:11 | @foo |
|
||||
| instance_variables.rb:11:6:11:9 | @top |
|
||||
| instance_variables.rb:14:3:14:4 | @x |
|
||||
| instance_variables.rb:16:5:16:6 | @y |
|
||||
| instance_variables.rb:21:2:21:3 | @m |
|
||||
| instance_variables.rb:23:4:23:5 | @n |
|
||||
| instance_variables.rb:28:3:28:4 | @x |
|
||||
| instance_variables.rb:32:12:32:13 | @x |
|
||||
| instance_variables.rb:36:3:36:4 | @x |
|
||||
| instance_variables.rb:39:6:39:7 | @x |
|
||||
| instance_variables.rb:42:6:42:7 | @x |
|
||||
| nested_scopes.rb:14:16:14:16 | a |
|
||||
| nested_scopes.rb:15:11:15:11 | a |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import codeql_ruby.AST
|
||||
import codeql_ruby.ast.Variable
|
||||
|
||||
query predicate variableAccess(VariableAccess access, Variable variable, VariableScope scope) {
|
||||
query predicate variableAccess(VariableAccess access, Variable variable, Scope scope) {
|
||||
variable = access.getVariable() and
|
||||
scope = variable.getDeclaringScope()
|
||||
}
|
||||
|
||||
@@ -1,75 +1,74 @@
|
||||
| class_variables.rb:1:1:29:4 | top-level scope for class_variables.rb |
|
||||
| class_variables.rb:5:1:7:3 | method scope for print |
|
||||
| class_variables.rb:9:1:16:3 | class scope for X |
|
||||
| class_variables.rb:10:3:12:5 | method scope for b |
|
||||
| class_variables.rb:13:3:15:5 | method scope for s |
|
||||
| class_variables.rb:18:1:20:3 | class scope for Y |
|
||||
| class_variables.rb:22:1:24:3 | module scope for M |
|
||||
| class_variables.rb:26:1:29:3 | module scope for N |
|
||||
| file://:0:0:0:0 | global scope |
|
||||
| instance_variables.rb:1:1:44:4 | top-level scope for instance_variables.rb |
|
||||
| instance_variables.rb:3:1:5:3 | method scope for foo |
|
||||
| instance_variables.rb:7:1:9:3 | method scope for print_foo |
|
||||
| instance_variables.rb:13:1:18:3 | class scope for X |
|
||||
| instance_variables.rb:15:3:17:5 | method scope for m |
|
||||
| instance_variables.rb:20:1:25:3 | module scope for M |
|
||||
| instance_variables.rb:22:2:24:4 | method scope for n |
|
||||
| instance_variables.rb:27:6:29:1 | block scope |
|
||||
| instance_variables.rb:31:1:33:3 | method scope for bar |
|
||||
| instance_variables.rb:32:10:32:21 | block scope |
|
||||
| instance_variables.rb:35:1:44:4 | class scope for C |
|
||||
| instance_variables.rb:37:3:43:5 | method scope for x |
|
||||
| instance_variables.rb:38:4:40:6 | method scope for y |
|
||||
| nested_scopes.rb:1:1:3:3 | method scope for a |
|
||||
| nested_scopes.rb:1:1:42:1 | top-level scope for nested_scopes.rb |
|
||||
| nested_scopes.rb:4:1:39:3 | class scope for C |
|
||||
| nested_scopes.rb:6:3:37:5 | module scope for M |
|
||||
| nested_scopes.rb:8:5:35:7 | module scope for N |
|
||||
| nested_scopes.rb:10:7:26:9 | class scope for D |
|
||||
| nested_scopes.rb:12:9:21:11 | method scope for show_a |
|
||||
| nested_scopes.rb:15:19:20:13 | block scope |
|
||||
| nested_scopes.rb:16:21:19:15 | block scope |
|
||||
| nested_scopes.rb:18:23:18:36 | block scope |
|
||||
| nested_scopes.rb:22:9:24:11 | method scope for show_a2 |
|
||||
| nested_scopes.rb:27:7:29:9 | method scope for show |
|
||||
| nested_scopes.rb:30:7:33:9 | class scope |
|
||||
| parameters.rb:1:1:58:1 | top-level scope for parameters.rb |
|
||||
| parameters.rb:1:9:5:3 | block scope |
|
||||
| parameters.rb:7:1:13:3 | method scope for order_pizza |
|
||||
| parameters.rb:15:1:19:3 | method scope for print_map |
|
||||
| parameters.rb:16:12:18:5 | block scope |
|
||||
| parameters.rb:21:1:23:3 | method scope for call_block |
|
||||
| parameters.rb:25:1:28:3 | method scope for opt_param |
|
||||
| parameters.rb:30:1:32:3 | method scope for key_param |
|
||||
| parameters.rb:35:1:38:3 | method scope for multi |
|
||||
| parameters.rb:40:1:43:3 | method scope for multi2 |
|
||||
| parameters.rb:45:1:47:3 | method scope for dup_underscore |
|
||||
| parameters.rb:49:1:51:3 | method scope for tuples |
|
||||
| parameters.rb:54:9:57:3 | block scope |
|
||||
| scopes.rb:1:1:1:15 | method scope for a |
|
||||
| scopes.rb:1:1:40:1 | top-level scope for scopes.rb |
|
||||
| scopes.rb:2:9:6:3 | block scope |
|
||||
| scopes.rb:9:9:18:3 | block scope |
|
||||
| scopes.rb:26:1:26:12 | class scope for A |
|
||||
| scopes.rb:28:1:30:3 | module scope for B |
|
||||
| scopes.rb:31:1:33:3 | class scope |
|
||||
| scopes.rb:34:1:36:3 | class scope for C |
|
||||
| scopes.rb:37:1:39:3 | method scope for foo |
|
||||
| ssa.rb:1:1:16:3 | method scope for m |
|
||||
| ssa.rb:1:1:88:3 | top-level scope for ssa.rb |
|
||||
| ssa.rb:18:1:23:3 | method scope for m1 |
|
||||
| ssa.rb:25:1:30:3 | method scope for m2 |
|
||||
| ssa.rb:32:1:36:3 | method scope for m3 |
|
||||
| ssa.rb:33:16:35:5 | block scope |
|
||||
| ssa.rb:38:1:42:3 | method scope for m4 |
|
||||
| ssa.rb:44:1:47:3 | method scope for m5 |
|
||||
| ssa.rb:49:1:51:3 | method scope for m6 |
|
||||
| ssa.rb:53:1:56:3 | method scope for m7 |
|
||||
| ssa.rb:58:1:62:3 | method scope for m8 |
|
||||
| ssa.rb:64:1:72:3 | method scope for m9 |
|
||||
| ssa.rb:66:11:70:5 | block scope |
|
||||
| ssa.rb:74:1:79:3 | method scope for m10 |
|
||||
| ssa.rb:76:7:78:5 | block scope |
|
||||
| ssa.rb:81:1:88:3 | method scope for m11 |
|
||||
| ssa.rb:83:7:87:5 | block scope |
|
||||
| ssa.rb:84:10:86:8 | block scope |
|
||||
| class_variables.rb:1:1:29:4 | class_variables.rb |
|
||||
| class_variables.rb:5:1:7:3 | print |
|
||||
| class_variables.rb:9:1:16:3 | X |
|
||||
| class_variables.rb:10:3:12:5 | b |
|
||||
| class_variables.rb:13:3:15:5 | s |
|
||||
| class_variables.rb:18:1:20:3 | Y |
|
||||
| class_variables.rb:22:1:24:3 | M |
|
||||
| class_variables.rb:26:1:29:3 | N |
|
||||
| instance_variables.rb:1:1:44:4 | instance_variables.rb |
|
||||
| instance_variables.rb:3:1:5:3 | foo |
|
||||
| instance_variables.rb:7:1:9:3 | print_foo |
|
||||
| instance_variables.rb:13:1:18:3 | X |
|
||||
| instance_variables.rb:15:3:17:5 | m |
|
||||
| instance_variables.rb:20:1:25:3 | M |
|
||||
| instance_variables.rb:22:2:24:4 | n |
|
||||
| instance_variables.rb:27:6:29:1 | { ... } |
|
||||
| instance_variables.rb:31:1:33:3 | bar |
|
||||
| instance_variables.rb:32:10:32:21 | { ... } |
|
||||
| instance_variables.rb:35:1:44:4 | C |
|
||||
| instance_variables.rb:37:3:43:5 | x |
|
||||
| instance_variables.rb:38:4:40:6 | y |
|
||||
| nested_scopes.rb:1:1:3:3 | a |
|
||||
| nested_scopes.rb:1:1:42:1 | nested_scopes.rb |
|
||||
| nested_scopes.rb:4:1:39:3 | C |
|
||||
| nested_scopes.rb:6:3:37:5 | M |
|
||||
| nested_scopes.rb:8:5:35:7 | N |
|
||||
| nested_scopes.rb:10:7:26:9 | D |
|
||||
| nested_scopes.rb:12:9:21:11 | show_a |
|
||||
| nested_scopes.rb:15:19:20:13 | do ... end |
|
||||
| nested_scopes.rb:16:21:19:15 | do ... end |
|
||||
| nested_scopes.rb:18:23:18:36 | { ... } |
|
||||
| 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:9:5:3 | do ... end |
|
||||
| parameters.rb:7:1:13:3 | order_pizza |
|
||||
| parameters.rb:15:1:19:3 | print_map |
|
||||
| parameters.rb:16:12:18:5 | do ... end |
|
||||
| parameters.rb:21:1:23:3 | call_block |
|
||||
| parameters.rb:25:1:28:3 | opt_param |
|
||||
| parameters.rb:30:1:32:3 | key_param |
|
||||
| parameters.rb:35:1:38:3 | multi |
|
||||
| parameters.rb:40:1:43:3 | multi2 |
|
||||
| parameters.rb:45:1:47:3 | dup_underscore |
|
||||
| parameters.rb:49:1:51:3 | tuples |
|
||||
| parameters.rb:54:9:57:3 | do ... end |
|
||||
| scopes.rb:1:1:1:15 | a |
|
||||
| scopes.rb:1:1:40:1 | scopes.rb |
|
||||
| scopes.rb:2:9:6:3 | do ... end |
|
||||
| scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:26:1:26:12 | A |
|
||||
| scopes.rb:28:1:30:3 | B |
|
||||
| scopes.rb:31:1:33:3 | class << ... |
|
||||
| scopes.rb:34:1:36:3 | C |
|
||||
| scopes.rb:37:1:39:3 | foo |
|
||||
| ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:1:1:88:3 | ssa.rb |
|
||||
| ssa.rb:18:1:23:3 | m1 |
|
||||
| ssa.rb:25:1:30:3 | m2 |
|
||||
| ssa.rb:32:1:36:3 | m3 |
|
||||
| ssa.rb:33:16:35:5 | do ... end |
|
||||
| ssa.rb:38:1:42:3 | m4 |
|
||||
| ssa.rb:44:1:47:3 | m5 |
|
||||
| ssa.rb:49:1:51:3 | m6 |
|
||||
| ssa.rb:53:1:56:3 | m7 |
|
||||
| ssa.rb:58:1:62:3 | m8 |
|
||||
| ssa.rb:64:1:72:3 | m9 |
|
||||
| ssa.rb:66:11:70:5 | do ... end |
|
||||
| ssa.rb:74:1:79:3 | m10 |
|
||||
| ssa.rb:76:7:78:5 | do ... end |
|
||||
| ssa.rb:81:1:88:3 | m11 |
|
||||
| ssa.rb:83:7:87:5 | do ... end |
|
||||
| ssa.rb:84:10:86:8 | do ... end |
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import codeql_ruby.ast.Variable
|
||||
import codeql_ruby.ast.Scope
|
||||
|
||||
select any(VariableScope x)
|
||||
select any(Scope x)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
| UseDetect.rb:5:9:5:36 | call to first | Replace this call and $@ with 'detect'. | UseDetect.rb:5:9:5:30 | call to select | 'select' call |
|
||||
| UseDetect.rb:6:9:6:35 | call to last | Replace this call and $@ with 'reverse_detect'. | UseDetect.rb:6:9:6:30 | call to select | 'select' call |
|
||||
| UseDetect.rb:7:9:7:33 | ...[...] | Replace this call and $@ with 'detect'. | UseDetect.rb:7:9:7:30 | call to select | 'select' call |
|
||||
| UseDetect.rb:8:9:8:34 | ...[...] | Replace this call and $@ with 'reverse_detect'. | UseDetect.rb:8:9:8:30 | call to select | 'select' call |
|
||||
| UseDetect.rb:9:9:9:36 | call to first | Replace this call and $@ with 'detect'. | UseDetect.rb:9:9:9:30 | call to filter | 'select' call |
|
||||
| UseDetect.rb:10:9:10:37 | call to last | Replace this call and $@ with 'reverse_detect'. | UseDetect.rb:10:9:10:32 | call to find_all | 'select' call |
|
||||
| UseDetect.rb:12:9:12:24 | call to first | Replace this call and $@ with 'detect'. | UseDetect.rb:11:22:11:43 | call to select | 'select' call |
|
||||
@@ -0,0 +1 @@
|
||||
queries/performance/UseDetect.ql
|
||||
21
ql/test/query-tests/performance/UseDetect/UseDetect.rb
Normal file
21
ql/test/query-tests/performance/UseDetect/UseDetect.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
class DetectTest
|
||||
def test
|
||||
# These are bad
|
||||
[].select { |i| true }.first
|
||||
[].select { |i| true }.last
|
||||
[].select { |i| true }[0]
|
||||
[].select { |i| true }[-1]
|
||||
[].filter { |i| true }.first
|
||||
[].find_all { |i| true }.last
|
||||
selection1 = [].select { |i| true }
|
||||
selection1.first
|
||||
|
||||
# These are good
|
||||
[].select("").first # Selecting a string
|
||||
[].select { |i| true }[1] # Selecting the second element
|
||||
selection2 = [].select { |i| true }
|
||||
selection2.first # Selection used elsewhere
|
||||
selection3 = selection2
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user