Move AST files into ast folder

This commit is contained in:
Tom Hvitved
2020-11-27 14:45:15 +01:00
parent 00f3daabfe
commit 59d45de118
9 changed files with 8 additions and 8 deletions

View File

@@ -0,0 +1,119 @@
import codeql_ruby.AST
private import codeql_ruby.Generated
/** A Ruby method. */
class Method extends @method, AstNode {
Generated::Method generated;
Method() { generated = this }
override string describeQlClass() { result = "Method" }
override string toString() { result = this.getName() }
/** Gets the name of the method. */
string getName() {
result = generated.getName().(Generated::Token).getValue() or
// TODO: use hand-written Symbol class
result = generated.getName().(Generated::Symbol).toString() or
result = generated.getName().(Generated::Setter).getName().getValue() + "="
}
/**
* Holds if this is a setter method, as in the following example:
* ```
* class Person
* def name=(n)
* @name = n
* end
* end
* ```
*/
predicate isSetter() { generated.getName() instanceof Generated::Setter }
/** Gets the number of parameters of this method. */
int getNumberOfParameters() { result = count(this.getAParameter()) }
/** Gets a parameter of this method. */
Parameter getAParameter() { result = this.getParameter(_) }
/** Gets the nth parameter of this method. */
Parameter getParameter(int n) { result = generated.getParameters().getChild(n) }
}
/**
* A Ruby lambda (anonymous method). For example:
* ```
* -> (x) { x + 1 }
* ```
*/
class Lambda extends @lambda, AstNode {
Generated::Lambda generated;
Lambda() { generated = this }
override string describeQlClass() { result = "Lambda" }
override string toString() { result = "-> { ... }" }
/** Gets the number of parameters of this lambda. */
int getNumberOfParameters() { result = count(this.getAParameter()) }
/** Gets a parameter of this lambda. */
Parameter getAParameter() { result = this.getParameter(_) }
/** Gets the nth parameter of this lambda. */
Parameter getParameter(int n) { result = generated.getParameters().getChild(n) }
}
/** A Ruby block. */
abstract class Block extends AstNode {
/** Gets the number of parameters of this block. */
abstract int getNumberOfParameters();
/** Gets the nth parameter of this block. */
abstract Parameter getParameter(int n);
/** Gets a parameter of this block. */
Parameter getAParameter() { result = this.getParameter(_) }
// TODO: body/statements
}
/** A Ruby block enclosed within `do` and `end`. */
class DoBlock extends @do_block, Block {
Generated::DoBlock generated;
DoBlock() { generated = this }
override string describeQlClass() { result = "DoBlock" }
override string toString() { result = "| ... |" }
/** Gets the number of parameters of this block. */
override int getNumberOfParameters() { result = count(this.getAParameter()) }
/** Gets the nth parameter of this block. */
override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) }
}
/**
* A Ruby block defined using curly braces, e.g. in the following code:
* ```
* names.each { |name| puts name }
* ```
*/
class BraceBlock extends @block, Block {
Generated::Block generated;
BraceBlock() { generated = this }
override string describeQlClass() { result = "BraceBlock" }
override string toString() { result = "{ ... }" }
/** Gets the number of parameters of this block. */
override int getNumberOfParameters() { result = count(this.getAParameter()) }
/** Gets the nth parameter of this block. */
override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) }
}

View File

@@ -0,0 +1,182 @@
import codeql_ruby.AST
private import codeql_ruby.Generated
/**
* A parameter to a block, lambda, or method.
*/
abstract class Parameter extends AstNode {
/**
* Gets the position of this parameter in the parent block, lambda, or
* method's parameter list.
*/
int getPosition() {
exists(Method m | m.getParameter(result) = this) or
exists(Block b | b.getParameter(result) = this) or
exists(Lambda l | l.getParameter(result) = this)
}
}
/**
* A parameter that is a block. For example, `&bar` in the following code:
* ```
* def foo(&bar)
* bar.call if block_given?
* end
* ```
*/
class BlockParameter extends @block_parameter, Parameter {
Generated::BlockParameter generated;
BlockParameter() { generated = this }
override string describeQlClass() { result = "BlockParameter" }
override string toString() { result = "&" + this.getName() }
/** Gets the name of the parameter. */
string getName() { result = generated.getName().getValue() }
}
/**
* A parameter that is destructured. For example, the parameter `(a, b)` in the
* following code:
* ```
* pairs.each do |(a, b)|
* puts a + b
* end
* ```
*/
class PatternParameter extends @destructured_parameter, Parameter, Pattern {
Generated::DestructuredParameter generated;
PatternParameter() { generated = this }
override string describeQlClass() { result = "PatternParameter" }
override string toString() { result = "(..., ...)" }
/**
* Gets the number of parameters of this destructuring.
*/
override int getNumberOfElements() { result = count(this.getElement(_)) }
/**
* Gets the nth parameter of this pattern.
*/
override AstNode getElement(int n) { result = generated.getChild(n) }
}
/**
* A hash-splat (or double-splat) parameter. For example, `**options` in the
* following code:
* ```
* def foo(bar, **options)
* ...
* end
* ```
*/
class HashSplatParameter extends @hash_splat_parameter, Parameter {
Generated::HashSplatParameter generated;
HashSplatParameter() { generated = this }
override string describeQlClass() { result = "HashSplatParameter" }
override string toString() { result = "**" + this.getName() }
/** Gets the name of the parameter. */
string getName() { result = generated.getName().getValue() }
}
/**
* TODO
*/
class KeywordParameter extends @keyword_parameter, Parameter {
Generated::KeywordParameter generated;
KeywordParameter() { generated = this }
override string describeQlClass() { result = "KeywordParameter" }
/** Gets the name of the parameter. */
string getName() { result = generated.getName().getValue() }
/**
* 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.
* TODO: better return type (Expr?)
*/
AstNode getDefaultValue() { result = generated.getValue() }
override string toString() { result = this.getName() }
}
/**
* An optional parameter. For example, the parameter `name` in the following
* code:
* ```
* def say_hello(name = 'Anon')
* puts "hello #{name}"
* end
* ```
*/
class OptionalParameter extends @optional_parameter, Parameter {
Generated::OptionalParameter generated;
OptionalParameter() { generated = this }
override string describeQlClass() { result = "OptionalParameter" }
override string toString() { result = this.getName() }
/** Gets the name of the parameter. */
string getName() { result = generated.getName().getValue() }
/**
* Gets the default value, i.e. the value assigned to the parameter when one
* is not provided by the caller.
* TODO: better return type (Expr?)
*/
AstNode getDefaultValue() { result = generated.getValue() }
}
/**
* A splat parameter. For example, `*values` in the following code:
* ```
* def foo(bar, *values)
* ...
* end
* ```
*/
class SplatParameter extends @splat_parameter, Parameter {
Generated::SplatParameter generated;
SplatParameter() { generated = this }
override string describeQlClass() { result = "SplatParameter" }
override string toString() { result = this.getName() }
/** Gets the name of the parameter. */
string getName() { result = generated.getName().getValue() }
}
/**
* An identifier that is a parameter in a block, lambda, or method.
*/
class IdentifierParameter extends @token_identifier, Parameter {
IdentifierParameter() {
block_parameters_child(_, _, this) or
destructured_parameter_child(_, _, this) or
lambda_parameters_child(_, _, this) or
method_parameters_child(_, _, this)
}
override string describeQlClass() { result = "IdentifierParameter" }
override string toString() { result = this.getName() }
/** Gets the name of the parameter. */
string getName() { result = this.(Generated::Identifier).getValue() }
}

View File

@@ -0,0 +1,256 @@
/** Provides classes for modeling program variables. */
private import codeql_ruby.Generated::Generated
private import codeql.Locations
private AstNode parent(AstNode n) {
result = n.getParent() and
not n = any(VariableScope s).getScopeElement()
}
/** Gets the enclosing scope for `node`. */
private VariableScope enclosingScope(AstNode node) {
result.getScopeElement() = parent*(node.getParent())
}
/** A parameter. */
class Parameter extends AstNode {
private int position;
private VariableScope scope;
Parameter() {
this =
scope.(BlockScope).getScopeElement().getAFieldOrChild().(BlockParameters).getChild(position)
or
this =
scope.(MethodScope).getScopeElement().getAFieldOrChild().(MethodParameters).getChild(position)
}
/** Gets the (zero-based) position of this parameter. */
final int getPosition() { result = position }
/** Gets the scope this parameter is declared in. */
final VariableScope getDeclaringScope() { result = scope }
/** Gets an access to this parameter. */
final ParameterAccess getAnAccess() { result.getParameter() = this }
}
private Identifier parameterIdentifier(Parameter p) {
result = p or
result = p.(SplatParameter).getName() or
result = p.(HashSplatParameter).getName() or
result = p.(BlockParameter).getName() or
result = p.(OptionalParameter).getName() or
result = p.(KeywordParameter).getName() or
result = destructuredIdentifier(p.(DestructuredParameter))
}
private Identifier destructuredIdentifier(AstNode node) {
result = node or
result = destructuredIdentifier(node.(DestructuredParameter).getAFieldOrChild())
}
/** Holds if `scope` defines `name` in its parameter declaration. */
private predicate scopeDefinesParameter(VariableScope scope, string name, Location location) {
location =
min(Parameter p, Identifier i |
scope = p.getDeclaringScope() and
i = parameterIdentifier(p) and
name = i.getValue()
|
i.getLocation() as loc order by loc.getStartLine(), loc.getStartColumn()
)
}
/** Holds if `var` is assigned in `scope`. */
private predicate scopeAssigns(VariableScope scope, Identifier var) {
var in [any(Assignment assign).getLeft(), any(OperatorAssignment assign).getLeft()] and
scope = enclosingScope(var)
}
/** Holds if location `one` starts strictly before location `two` */
pragma[inline]
predicate strictlyBefore(Location one, Location two) {
one.getStartLine() < two.getStartLine()
or
one.getStartLine() = two.getStartLine() and one.getStartColumn() < two.getStartColumn()
}
/** Holds if block scope `scope` inherits `var` from an outer scope `outer`. */
private predicate blockScopeInherits(BlockScope scope, string var, VariableScope outer) {
not scopeDefinesParameter(scope, var, _) and
(
outer = scope.getOuterScope() and
(
scopeDefinesParameter(outer, var, _)
or
exists(Identifier i | i.getValue() = var |
scopeAssigns(outer, i) and
strictlyBefore(i.getLocation(), scope.getLocation())
)
)
or
blockScopeInherits(scope.getOuterScope(), var, outer)
)
}
cached
private module Cached {
cached
newtype TScope =
TTopLevelScope(Program node) or
TModuleScope(Module node) or
TClassScope(AstNode cls) { cls instanceof Class or cls instanceof SingletonClass } or
TMethodScope(AstNode method) { method instanceof Method or method instanceof SingletonMethod } or
TBlockScope(AstNode block) { block instanceof Block or block instanceof DoBlock }
cached
newtype TVariable =
TLocalVariable(VariableScope scope, string name, Location location) {
scopeDefinesParameter(scope, name, location)
or
not scopeDefinesParameter(scope, name, _) and
not blockScopeInherits(scope, name, _) and
location =
min(Location loc, Identifier other |
loc = other.getLocation() and name = other.getValue() and scopeAssigns(scope, other)
|
loc order by loc.getStartLine(), loc.getStartColumn()
)
}
cached
predicate access(Identifier access, Variable variable) {
exists(string name | name = access.getValue() |
variable = enclosingScope(access).getVariable(name) and
not strictlyBefore(access.getLocation(), variable.getLocation())
or
exists(VariableScope declScope |
variable = declScope.getVariable(name) and
blockScopeInherits(enclosingScope(access), name, declScope)
)
)
}
}
private import Cached
/** A scope in which variables can be declared. */
class VariableScope extends TScope {
/** Gets a textual representation of this element. */
string toString() { none() }
/** Gets the program element this scope is associated with, if any. */
AstNode getScopeElement() { none() }
/** 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
}
}
/** A variable declared in a scope. */
class Variable extends TVariable {
/** Gets the name of this variable. */
string getName() { none() }
/** Gets a textual representation of this variable. */
final string toString() { result = this.getName() }
/** Gets the location of this variable. */
Location getLocation() { none() }
/** Gets the scope this variable is declared in. */
VariableScope getDeclaringScope() { none() }
/** Gets an access to this variable. */
VariableAccess getAnAccess() { result.getVariable() = this }
}
/** A local variable. */
class LocalVariable extends Variable {
private VariableScope scope;
private string name;
private Location location;
LocalVariable() { this = TLocalVariable(scope, name, location) }
final override string getName() { result = name }
final override Location getLocation() { result = location }
final override VariableScope getDeclaringScope() { result = scope }
}
/** An identifier that refers to a variable. */
class VariableAccess extends Identifier {
Variable variable;
VariableAccess() { access(this, variable) }
/**
* Gets the variable this identifier refers to.
*/
Variable getVariable() { result = variable }
}
/** An identifier that refers to a parameter. */
class ParameterAccess extends VariableAccess {
Parameter parameter;
ParameterAccess() {
exists(Identifier i |
i = parameterIdentifier(parameter) and
variable.getDeclaringScope() = parameter.getDeclaringScope() and
variable.getLocation() = i.getLocation()
)
}
final Parameter getParameter() { result = parameter }
}
/** A top-level scope. */
class TopLevelScope extends VariableScope, TTopLevelScope {
final override string toString() { result = "top-level scope" }
final override AstNode getScopeElement() { TTopLevelScope(result) = this }
}
/** A module scope. */
class ModuleScope extends VariableScope, TModuleScope {
final override string toString() { result = "module scope" }
final override Module getScopeElement() { TModuleScope(result) = this }
}
/** A class scope. */
class ClassScope extends VariableScope, TClassScope {
final override string toString() { result = "class scope" }
final override AstNode getScopeElement() { TClassScope(result) = this }
}
/** A method scope. */
class MethodScope extends VariableScope, TMethodScope {
final override string toString() { result = "method scope" }
final override AstNode getScopeElement() { TMethodScope(result) = this }
}
/** A block scope. */
class BlockScope extends VariableScope, TBlockScope {
final override string toString() { result = "block scope" }
final override AstNode getScopeElement() { TBlockScope(result) = this }
/** Gets the scope in which this scope is nested, if any. */
final VariableScope getOuterScope() { result = enclosingScope(this.getScopeElement()) }
}