mirror of
https://github.com/github/codeql.git
synced 2026-02-20 17:03:41 +01:00
231 lines
7.1 KiB
Plaintext
231 lines
7.1 KiB
Plaintext
/** Provides classes for modeling program variables. */
|
|
|
|
private import codeql_ruby.AST
|
|
private import codeql.Locations
|
|
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;
|
|
|
|
Variable() { range = this }
|
|
|
|
/** Gets the name of this variable. */
|
|
final string getName() { result = range.getName() }
|
|
|
|
/** Gets a textual representation of this variable. */
|
|
final string toString() { result = this.getName() }
|
|
|
|
/** Gets the location of this variable. */
|
|
final Location getLocation() { result = range.getLocation() }
|
|
|
|
/** Gets the scope this variable is declared in. */
|
|
final VariableScope getDeclaringScope() { result = range.getDeclaringScope() }
|
|
|
|
/** Gets an access to this variable. */
|
|
VariableAccess getAnAccess() { result.getVariable() = this }
|
|
}
|
|
|
|
/** A local variable. */
|
|
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. */
|
|
class GlobalVariable extends Variable, TGlobalVariable {
|
|
override GlobalVariable::Range range;
|
|
|
|
final override GlobalVariableAccess getAnAccess() { result.getVariable() = this }
|
|
}
|
|
|
|
/** An instance variable. */
|
|
class InstanceVariable extends Variable, TInstanceVariable {
|
|
override InstanceVariable::Range range;
|
|
|
|
/** Holds is this variable is a class instance variable. */
|
|
final predicate isClassInstanceVariable() { range.isClassInstanceVariable() }
|
|
|
|
final override InstanceVariableAccess getAnAccess() { result.getVariable() = this }
|
|
}
|
|
|
|
/** A class variable. */
|
|
class ClassVariable extends Variable, TClassVariable {
|
|
override ClassVariable::Range range;
|
|
|
|
final override ClassVariableAccess getAnAccess() { result.getVariable() = this }
|
|
}
|
|
|
|
/** An access to a variable. */
|
|
class VariableAccess extends Expr {
|
|
override VariableAccess::Range range;
|
|
|
|
/** Gets the variable this identifier refers to. */
|
|
Variable getVariable() { result = range.getVariable() }
|
|
|
|
/**
|
|
* Holds if this access is a write access belonging to the explicit
|
|
* assignment `assignment`. For example, in
|
|
*
|
|
* ```rb
|
|
* a, b = foo
|
|
* ```
|
|
*
|
|
* both `a` and `b` are write accesses belonging to the same assignment.
|
|
*/
|
|
predicate isExplicitWrite(AstNode assignment) { explicitWriteAccess(this, assignment) }
|
|
|
|
/**
|
|
* Holds if this access is a write access belonging to an implicit assignment.
|
|
* For example, in
|
|
*
|
|
* ```rb
|
|
* def m elements
|
|
* for e in elements do
|
|
* puts e
|
|
* end
|
|
* end
|
|
* ```
|
|
*
|
|
* the access to `elements` in the parameter list is an implicit assignment,
|
|
* as is the first access to `e`.
|
|
*/
|
|
predicate isImplicitWrite() { implicitWriteAccess(this) }
|
|
|
|
final override string toString() { result = this.getVariable().getName() }
|
|
}
|
|
|
|
/** An access to a variable where the value is updated. */
|
|
class VariableWriteAccess extends VariableAccess {
|
|
VariableWriteAccess() {
|
|
this.isExplicitWrite(_) or
|
|
this.isImplicitWrite()
|
|
}
|
|
}
|
|
|
|
/** An access to a variable where the value is read. */
|
|
class VariableReadAccess extends VariableAccess {
|
|
VariableReadAccess() {
|
|
not this instanceof VariableWriteAccess
|
|
or
|
|
// `x` in `x += y` is considered both a read and a write
|
|
this = any(AssignOperation a).getLhs()
|
|
}
|
|
}
|
|
|
|
/** An access to a local variable. */
|
|
class LocalVariableAccess extends VariableAccess, @token_identifier {
|
|
final override LocalVariableAccess::Range range;
|
|
|
|
final override LocalVariable getVariable() { result = range.getVariable() }
|
|
|
|
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. */
|
|
class LocalVariableWriteAccess extends LocalVariableAccess, VariableWriteAccess { }
|
|
|
|
/** An access to a local variable where the value is read. */
|
|
class LocalVariableReadAccess extends LocalVariableAccess, VariableReadAccess { }
|
|
|
|
/** An access to a global variable. */
|
|
class GlobalVariableAccess extends VariableAccess, @token_global_variable {
|
|
final override GlobalVariableAccess::Range range;
|
|
|
|
final override GlobalVariable getVariable() { result = range.getVariable() }
|
|
|
|
final override string getAPrimaryQlClass() { result = "GlobalVariableAccess" }
|
|
}
|
|
|
|
/** An access to a global variable where the value is updated. */
|
|
class GlobalVariableWriteAccess extends GlobalVariableAccess, VariableWriteAccess { }
|
|
|
|
/** An access to a global variable where the value is read. */
|
|
class GlobalVariableReadAccess extends GlobalVariableAccess, VariableReadAccess { }
|
|
|
|
/** An access to an instance variable. */
|
|
class InstanceVariableAccess extends VariableAccess, @token_instance_variable {
|
|
final override InstanceVariableAccess::Range range;
|
|
|
|
final override InstanceVariable getVariable() { result = range.getVariable() }
|
|
|
|
final override string getAPrimaryQlClass() { result = "InstanceVariableAccess" }
|
|
}
|
|
|
|
/** An access to a class variable. */
|
|
class ClassVariableAccess extends VariableAccess, @token_class_variable {
|
|
final override ClassVariableAccess::Range range;
|
|
|
|
final override ClassVariable getVariable() { result = range.getVariable() }
|
|
|
|
final override string getAPrimaryQlClass() { result = "ClassVariableAccess" }
|
|
}
|