mirror of
https://github.com/github/codeql.git
synced 2026-02-21 01:13:43 +01:00
@@ -1,5 +1,8 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.CFG
|
||||
private import internal.Expr
|
||||
private import internal.Variable
|
||||
private import codeql_ruby.controlflow.internal.ControlFlowGraphImpl
|
||||
|
||||
/**
|
||||
* An expression.
|
||||
@@ -10,6 +13,18 @@ class Expr extends AstNode {
|
||||
Expr::Range range;
|
||||
|
||||
Expr() { this = range }
|
||||
|
||||
/** Gets a control-flow node for this expression, if any. */
|
||||
CfgNodes::AstCfgNode getAControlFlowNode() { result.getNode() = this }
|
||||
|
||||
/** Gets the control-flow scope of this expression, if any. */
|
||||
CfgScope getCfgScope() { result = getCfgScope(this) }
|
||||
|
||||
/** Gets the variable scope that this expression belongs to. */
|
||||
VariableScope getVariableScope() { result = enclosingScope(this) }
|
||||
|
||||
/** Gets the enclosing callable, if any. */
|
||||
Callable getEnclosingCallable() { result = this.getCfgScope() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.controlflow.ControlFlowGraph
|
||||
private import internal.TreeSitter
|
||||
private import internal.Method
|
||||
|
||||
/** A callable. */
|
||||
class Callable extends AstNode {
|
||||
class Callable extends AstNode, CfgScope {
|
||||
Callable::Range range;
|
||||
|
||||
Callable() { range = this }
|
||||
|
||||
@@ -22,10 +22,10 @@ class Parameter extends AstNode {
|
||||
final int getPosition() { result = pos }
|
||||
|
||||
/** Gets a variable introduced by this parameter. */
|
||||
Variable getAVariable() { none() }
|
||||
LocalVariable getAVariable() { none() }
|
||||
|
||||
/** Gets the variable named `name` introduced by this parameter. */
|
||||
final Variable getVariable(string name) {
|
||||
final LocalVariable getVariable(string name) {
|
||||
result = this.getAVariable() and
|
||||
result.getName() = name
|
||||
}
|
||||
@@ -37,7 +37,7 @@ class Parameter extends AstNode {
|
||||
* This includes both simple parameters and tuple parameters.
|
||||
*/
|
||||
class PatternParameter extends Parameter, Pattern {
|
||||
override Variable getAVariable() { result = Pattern.super.getAVariable() }
|
||||
override LocalVariable getAVariable() { result = Pattern.super.getAVariable() }
|
||||
}
|
||||
|
||||
/** A parameter defined using a tuple pattern. */
|
||||
@@ -53,9 +53,9 @@ class NamedParameter extends Parameter {
|
||||
string getName() { none() }
|
||||
|
||||
/** Gets the variable introduced by this parameter. */
|
||||
Variable getVariable() { none() }
|
||||
LocalVariable getVariable() { none() }
|
||||
|
||||
override Variable getAVariable() { result = this.getVariable() }
|
||||
override LocalVariable getAVariable() { result = this.getVariable() }
|
||||
|
||||
/** Gets an access to this parameter. */
|
||||
final VariableAccess getAnAccess() { result = this.getVariable().getAnAccess() }
|
||||
@@ -65,9 +65,9 @@ class NamedParameter extends Parameter {
|
||||
class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern {
|
||||
final override string getName() { result = range.getVariableName() }
|
||||
|
||||
final override Variable getVariable() { result = TLocalVariable(_, _, this) }
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, this) }
|
||||
|
||||
final override Variable getAVariable() { result = this.getVariable() }
|
||||
final override LocalVariable getAVariable() { result = this.getVariable() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "SimpleParameter" }
|
||||
|
||||
@@ -85,7 +85,7 @@ class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern
|
||||
class BlockParameter extends @block_parameter, NamedParameter {
|
||||
final override Generated::BlockParameter generated;
|
||||
|
||||
final override Variable getVariable() { result = TLocalVariable(_, _, generated.getName()) }
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, generated.getName()) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "BlockParameter" }
|
||||
|
||||
@@ -106,7 +106,7 @@ class BlockParameter extends @block_parameter, NamedParameter {
|
||||
class HashSplatParameter extends @hash_splat_parameter, NamedParameter {
|
||||
final override Generated::HashSplatParameter generated;
|
||||
|
||||
final override Variable getVariable() { result = TLocalVariable(_, _, generated.getName()) }
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, generated.getName()) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "HashSplatParameter" }
|
||||
|
||||
@@ -129,7 +129,7 @@ class HashSplatParameter extends @hash_splat_parameter, NamedParameter {
|
||||
class KeywordParameter extends @keyword_parameter, NamedParameter {
|
||||
final override Generated::KeywordParameter generated;
|
||||
|
||||
final override Variable getVariable() { result = TLocalVariable(_, _, generated.getName()) }
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, generated.getName()) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "KeywordParameter" }
|
||||
|
||||
@@ -164,7 +164,7 @@ class KeywordParameter extends @keyword_parameter, NamedParameter {
|
||||
class OptionalParameter extends @optional_parameter, NamedParameter {
|
||||
final override Generated::OptionalParameter generated;
|
||||
|
||||
final override Variable getVariable() { result = TLocalVariable(_, _, generated.getName()) }
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, generated.getName()) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "OptionalParameter" }
|
||||
|
||||
@@ -191,7 +191,7 @@ class OptionalParameter extends @optional_parameter, NamedParameter {
|
||||
class SplatParameter extends @splat_parameter, NamedParameter {
|
||||
final override Generated::SplatParameter generated;
|
||||
|
||||
final override Variable getVariable() { result = TLocalVariable(_, _, generated.getName()) }
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, generated.getName()) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "SplatParameter" }
|
||||
|
||||
|
||||
@@ -57,6 +57,25 @@ class LocalVariable extends Variable, TLocalVariable {
|
||||
override LocalVariable::Range range;
|
||||
|
||||
final override LocalVariableAccess getAnAccess() { result.getVariable() = this }
|
||||
|
||||
/** Gets the access where this local variable is first introduced. */
|
||||
VariableAccess getDefiningAccess() { result = range.getDefiningAccess() }
|
||||
|
||||
/**
|
||||
* Holds if this variable is captured. For example in
|
||||
*
|
||||
* ```rb
|
||||
* def m x
|
||||
* x.times do |y|
|
||||
* puts x
|
||||
* end
|
||||
* puts x
|
||||
* end
|
||||
* ```
|
||||
*
|
||||
* `x` is a captured variable, whereas `y` is not.
|
||||
*/
|
||||
predicate isCaptured() { this.getAnAccess().isCapturedAccess() }
|
||||
}
|
||||
|
||||
/** A global variable. */
|
||||
@@ -133,6 +152,23 @@ class LocalVariableAccess extends VariableAccess, @token_identifier {
|
||||
final override string getAPrimaryQlClass() {
|
||||
not this instanceof SimpleParameter and result = "LocalVariableAccess"
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this access is a captured variable access. For example in
|
||||
*
|
||||
* ```rb
|
||||
* def m x
|
||||
* x.times do |y|
|
||||
* puts x
|
||||
* end
|
||||
* puts x
|
||||
* end
|
||||
* ```
|
||||
*
|
||||
* the access to `x` in the first `puts x` is a captured access, while
|
||||
* the access to `x` in the second `puts x` is not.
|
||||
*/
|
||||
final predicate isCapturedAccess() { isCapturedAccess(this) }
|
||||
}
|
||||
|
||||
/** An access to a local variable where the value is updated. */
|
||||
|
||||
@@ -39,6 +39,7 @@ predicate implicitParameterAssignmentNode(Generated::AstNode n, Callable c) {
|
||||
|
||||
module Pattern {
|
||||
abstract class Range extends AstNode {
|
||||
cached
|
||||
Range() {
|
||||
explicitAssignmentNode(this, _)
|
||||
or
|
||||
|
||||
@@ -9,11 +9,6 @@ private Generated::AstNode parent(Generated::AstNode n) {
|
||||
not n = any(VariableScope s).getScopeElement()
|
||||
}
|
||||
|
||||
/** Gets the enclosing scope for `node`. */
|
||||
private VariableScope enclosingScope(Generated::AstNode node) {
|
||||
result.getScopeElement() = parent*(node.getParent())
|
||||
}
|
||||
|
||||
private predicate parameterAssignment(
|
||||
CallableScope::Range scope, string name, Generated::Identifier i
|
||||
) {
|
||||
@@ -98,6 +93,12 @@ private class CapturingScope extends VariableScope {
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/** Gets the enclosing scope for `node`. */
|
||||
cached
|
||||
VariableScope enclosingScope(Generated::AstNode node) {
|
||||
result.getScopeElement() = parent*(node.getParent())
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TScope =
|
||||
TGlobalScope() or
|
||||
@@ -301,6 +302,11 @@ private module Cached {
|
||||
or
|
||||
scopeDefinesParameterVariable(_, _, access)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate isCapturedAccess(LocalVariableAccess::Range access) {
|
||||
access.getVariable().getDeclaringScope() != enclosingScope(access)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -391,6 +397,8 @@ module LocalVariable {
|
||||
final override Location getLocation() { result = i.getLocation() }
|
||||
|
||||
final override VariableScope getDeclaringScope() { result = scope }
|
||||
|
||||
final VariableAccess getDefiningAccess() { result = i }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user