Merge pull request #58 from github/hvitved/pattern-get-a-variable

Add `Pattern::getAVariable()` and use `self` range field throughout
This commit is contained in:
Tom Hvitved
2020-12-02 12:57:52 +01:00
committed by GitHub
7 changed files with 207 additions and 149 deletions

View File

@@ -4,7 +4,9 @@ private import internal.Method
/** A callable. */
class Callable extends AstNode {
Callable() { this instanceof CallableRange }
Callable::Range range;
Callable() { range = this }
/** Gets the number of parameters of this callable. */
final int getNumberOfParameters() { result = count(this.getAParameter()) }
@@ -12,12 +14,13 @@ class Callable extends AstNode {
/** Gets a parameter of this callable. */
final Parameter getAParameter() { result = this.getParameter(_) }
/** Gets the nth parameter of this callable. */
final Parameter getParameter(int n) { result = this.(CallableRange).getParameter(n) }
/** Gets the `n`th parameter of this callable. */
final Parameter getParameter(int n) { result = range.getParameter(n) }
}
/** A method. */
class Method extends Callable, @method {
final override Method::Range range;
final override Generated::Method generated;
final override string describeQlClass() { result = "Method" }
@@ -25,12 +28,7 @@ class Method extends Callable, @method {
final override string toString() { result = this.getName() }
/** Gets the name of this method. */
final 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() + "="
}
final string getName() { result = range.getName() }
/**
* Holds if this is a setter method, as in the following example:
@@ -47,19 +45,14 @@ class Method extends Callable, @method {
/** A singleton method. */
class SingletonMethod extends Callable, @singleton_method {
final override Generated::SingletonMethod generated;
final override SingletonMethod::Range range;
final override string describeQlClass() { result = "SingletonMethod" }
final override string toString() { result = this.getName() }
/** Gets the name of this method. */
final 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() + "="
}
final string getName() { result = range.getName() }
}
/**
@@ -69,7 +62,7 @@ class SingletonMethod extends Callable, @singleton_method {
* ```
*/
class Lambda extends Callable, @lambda {
final override Generated::Lambda generated;
final override Lambda::Range range;
final override string describeQlClass() { result = "Lambda" }
@@ -78,12 +71,12 @@ class Lambda extends Callable, @lambda {
/** A block. */
class Block extends AstNode, Callable {
Block() { this instanceof BlockRange }
override Block::Range range;
}
/** A block enclosed within `do` and `end`. */
class DoBlock extends Block, @do_block {
final override Generated::DoBlock generated;
final override DoBlock::Range range;
final override string describeQlClass() { result = "DoBlock" }
@@ -97,7 +90,7 @@ class DoBlock extends Block, @do_block {
* ```
*/
class BraceBlock extends Block, @block {
final override Generated::Block generated;
final override BraceBlock::Range range;
final override string describeQlClass() { result = "BraceBlock" }

View File

@@ -1,6 +1,5 @@
import codeql_ruby.AST
private import Variable
private import Pattern
private import internal.Pattern
private import internal.TreeSitter
private import internal.Variable
@@ -37,15 +36,13 @@ class Parameter extends AstNode {
*
* This includes both simple parameters and tuple parameters.
*/
class PatternParameter extends Parameter, Pattern { }
class PatternParameter extends Parameter, Pattern {
override Variable getAVariable() { result = Pattern.super.getAVariable() }
}
/** A parameter defined using a tuple pattern. */
class TuplePatternParameter extends PatternParameter, TuplePattern {
final override string describeQlClass() { result = "TuplePatternParameter" }
final override Variable getAVariable() {
result = this.getAnElement+().(VariablePattern).getVariable()
}
}
/** A named parameter. */
@@ -58,7 +55,7 @@ class NamedParameter extends Parameter {
/** Gets the variable introduced by this parameter. */
Variable getVariable() { none() }
final override Variable getAVariable() { result = this.getVariable() }
override Variable getAVariable() { result = this.getVariable() }
/** Gets an access to this parameter. */
final VariableAccess getAnAccess() { result = this.getVariable().getAnAccess() }
@@ -66,10 +63,12 @@ class NamedParameter extends Parameter {
/** A simple (normal) parameter. */
class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern {
final override string getName() { result = this.getVariableName() }
final override string getName() { result = range.getVariableName() }
final override Variable getVariable() { result = TLocalVariable(_, _, this) }
final override Variable getAVariable() { result = this.getVariable() }
final override string describeQlClass() { result = "SimpleParameter" }
final override string toString() { result = this.getName() }

View File

@@ -7,20 +7,23 @@ private import Variable
/** A pattern. */
class Pattern extends AstNode {
Pattern() { this instanceof PatternRange }
Pattern::Range range;
Pattern() { range = this }
/** Gets a variable used in (or introduced by) this pattern. */
Variable getAVariable() { result = range.getAVariable() }
}
/** A simple variable pattern. */
class VariablePattern extends Pattern {
final override VariablePattern::Range range;
final override Generated::Identifier generated;
/** Gets the name of the variable used in this pattern. */
final string getVariableName() { result = generated.getValue() }
/** Gets the variable used in (or introduced by) this pattern. */
Variable getVariable() { access(this, result) }
override string toString() { result = this.getVariableName() }
override string toString() { result = range.getVariableName() }
}
/**
@@ -29,10 +32,10 @@ class VariablePattern extends Pattern {
* This includes both tuple patterns in parameters and assignments.
*/
class TuplePattern extends Pattern {
TuplePattern() { this instanceof TuplePatternRange }
final override TuplePattern::Range range;
/** Gets the `i`th pattern in this tuple pattern. */
final Pattern getElement(int i) { result = this.(TuplePatternRange).getElement(i) }
final Pattern getElement(int i) { result = range.getElement(i) }
/** Gets a sub pattern in this tuple pattern. */
final Pattern getAnElement() { result = this.getElement(_) }

View File

@@ -7,11 +7,15 @@ 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 = this.(VariableScopeRange).toString() }
final string toString() { result = range.toString() }
/** Gets the program element this scope is associated with, if any. */
final AstNode getScopeElement() { result = this.(VariableScopeRange).getScopeElement() }
final AstNode getScopeElement() { result = range.getScopeElement() }
/** Gets the location of the program element this scope is associated with. */
final Location getLocation() { result = getScopeElement().getLocation() }
@@ -28,17 +32,21 @@ class VariableScope extends TScope {
/** 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 = this.(VariableRange).getName() }
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 = this.(VariableRange).getLocation() }
final Location getLocation() { result = range.getLocation() }
/** Gets the scope this variable is declared in. */
final VariableScope getDeclaringScope() { result = this.(VariableRange).getDeclaringScope() }
final VariableScope getDeclaringScope() { result = range.getDeclaringScope() }
/** Gets an access to this variable. */
VariableAccess getAnAccess() { result.getVariable() = this }
@@ -46,11 +54,7 @@ class Variable extends TVariable {
/** A local variable. */
class LocalVariable extends Variable {
private VariableScope scope;
private string name;
private Generated::Identifier i;
LocalVariable() { this = TLocalVariable(scope, name, i) }
override LocalVariable::Range range;
final override LocalVariableAccess getAnAccess() { result.getVariable() = this }
}

View File

@@ -1,42 +1,70 @@
import codeql_ruby.AST
private import TreeSitter
abstract class CallableRange extends AstNode {
abstract Parameter getParameter(int n);
module Callable {
abstract class Range extends AstNode {
abstract Parameter getParameter(int n);
}
}
private class MethodRange extends CallableRange, @method {
final override Generated::Method generated;
module Method {
class Range extends Callable::Range, @method {
final override Generated::Method generated;
override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) }
override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) }
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() + "="
}
}
}
private class SingletonMethodRange extends CallableRange, @singleton_method {
final override Generated::SingletonMethod generated;
module SingletonMethod {
class Range extends Callable::Range, @singleton_method {
final override Generated::SingletonMethod generated;
override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) }
override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) }
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() + "="
}
}
}
private class LambdaRange extends CallableRange, @lambda {
final override Generated::Lambda generated;
module Lambda {
class Range extends Callable::Range, @lambda {
final override Generated::Lambda generated;
final override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) }
final override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) }
}
}
abstract class BlockRange extends CallableRange {
Generated::BlockParameters params;
module Block {
abstract class Range extends Callable::Range {
Generated::BlockParameters params;
final override Parameter getParameter(int n) { result = params.getChild(n) }
final override Parameter getParameter(int n) { result = params.getChild(n) }
}
}
private class DoBlockRange extends BlockRange, @do_block {
final override Generated::DoBlock generated;
module DoBlock {
class Range extends Block::Range, @do_block {
final override Generated::DoBlock generated;
DoBlockRange() { params = generated.getParameters() }
Range() { params = generated.getParameters() }
}
}
private class BraceBlockRange extends BlockRange, @block {
final override Generated::Block generated;
module BraceBlock {
class Range extends Block::Range, @block {
final override Generated::Block generated;
BraceBlockRange() { params = generated.getParameters() }
Range() { params = generated.getParameters() }
}
}

View File

@@ -1,5 +1,6 @@
import codeql_ruby.AST
private import TreeSitter
private import Variable
private import codeql.Locations
private predicate tuplePatternNode(Generated::AstNode n, boolean parameter) {
@@ -34,32 +35,46 @@ private predicate patternNode(Generated::AstNode n, boolean parameter) {
*/
predicate assignment(Generated::Identifier i, boolean parameter) { patternNode(i, parameter) }
abstract class PatternRange extends AstNode {
PatternRange() { patternNode(this, _) }
module Pattern {
abstract class Range extends AstNode {
Range() { patternNode(this, _) }
abstract Variable getAVariable();
}
}
private class VariablePatternRange extends PatternRange {
override Generated::Identifier generated;
module VariablePattern {
class Range extends Pattern::Range {
override Generated::Identifier generated;
string getVariableName() { result = generated.getValue() }
override Variable getAVariable() { access(this, result) }
}
}
abstract class TuplePatternRange extends PatternRange {
abstract Pattern getElement(int i);
}
private class ParameterTuplePatternRange extends TuplePatternRange {
override Generated::DestructuredParameter generated;
override Pattern getElement(int i) { result = generated.getChild(i) }
}
private class AssignmentTuplePatternRange extends TuplePatternRange {
override Generated::DestructuredLeftAssignment generated;
override Pattern getElement(int i) { result = generated.getChild(i) }
}
private class AssignmentListPatternRange extends TuplePatternRange {
override Generated::LeftAssignmentList generated;
override Pattern getElement(int i) { result = generated.getChild(i) }
module TuplePattern {
abstract class Range extends Pattern::Range {
abstract Pattern::Range getElement(int i);
override Variable getAVariable() { result = this.getElement(_).getAVariable() }
}
private class ParameterTuplePatternRange extends Range {
override Generated::DestructuredParameter generated;
override Pattern::Range getElement(int i) { result = generated.getChild(i) }
}
private class AssignmentTuplePatternRange extends Range {
override Generated::DestructuredLeftAssignment generated;
override Pattern::Range getElement(int i) { result = generated.getChild(i) }
}
private class AssignmentListPatternRange extends Range {
override Generated::LeftAssignmentList generated;
override Pattern::Range getElement(int i) { result = generated.getChild(i) }
}
}

View File

@@ -13,7 +13,9 @@ private VariableScope enclosingScope(Generated::AstNode node) {
result.getScopeElement() = parent*(node.getParent())
}
private predicate parameterAssignment(CallableScopeRange scope, string name, Generated::Identifier i) {
private predicate parameterAssignment(
CallableScope::Range scope, string name, Generated::Identifier i
) {
assignment(i, true) and
scope = enclosingScope(i) and
name = i.getValue()
@@ -21,7 +23,7 @@ private predicate parameterAssignment(CallableScopeRange scope, string name, Gen
/** Holds if `scope` defines `name` in its parameter declaration at `i`. */
private predicate scopeDefinesParameterVariable(
CallableScopeRange scope, string name, Generated::Identifier i
CallableScope::Range scope, string name, Generated::Identifier i
) {
parameterAssignment(scope, name, i) and
// In case of overlapping parameter names (e.g. `_`), only the first
@@ -142,69 +144,83 @@ private module Cached {
import Cached
abstract class VariableScopeRange extends TScope {
abstract string toString();
module VariableScope {
abstract class Range extends TScope {
abstract string toString();
abstract AstNode getScopeElement();
}
class TopLevelScopeRange extends VariableScopeRange, TTopLevelScope {
override string toString() { result = "top-level scope" }
override AstNode getScopeElement() { TTopLevelScope(result) = this }
}
class ModuleScopeRange extends VariableScopeRange, TModuleScope {
override string toString() { result = "module scope" }
override AstNode getScopeElement() { TModuleScope(result) = this }
}
class ClassScopeRange extends VariableScopeRange, TClassScope {
override string toString() { result = "class scope" }
override AstNode getScopeElement() { TClassScope(result) = this }
}
class CallableScopeRange extends VariableScopeRange, TCallableScope {
private Callable c;
CallableScopeRange() { this = TCallableScope(c) }
override string toString() {
(c instanceof Method or c instanceof SingletonMethod) and
result = "method scope"
or
c instanceof Lambda and
result = "lambda scope"
or
c instanceof Block and
result = "block scope"
abstract AstNode getScopeElement();
}
override Callable getScopeElement() { TCallableScope(result) = this }
}
class VariableRange extends TVariable {
abstract string getName();
module TopLevelScope {
class Range extends VariableScope::Range, TTopLevelScope {
override string toString() { result = "top-level scope" }
string toString() { result = this.getName() }
abstract Location getLocation();
abstract VariableScope getDeclaringScope();
override AstNode getScopeElement() { TTopLevelScope(result) = this }
}
}
class LocalVariableRange extends VariableRange {
private VariableScope scope;
private string name;
private Generated::Identifier i;
module ModuleScope {
class Range extends VariableScope::Range, TModuleScope {
override string toString() { result = "module scope" }
LocalVariableRange() { this = TLocalVariable(scope, name, i) }
final override string getName() { result = name }
final override Location getLocation() { result = i.getLocation() }
final override VariableScope getDeclaringScope() { result = scope }
override AstNode getScopeElement() { TModuleScope(result) = this }
}
}
module ClassScope {
class Range extends VariableScope::Range, TClassScope {
override string toString() { result = "class scope" }
override AstNode getScopeElement() { TClassScope(result) = this }
}
}
module CallableScope {
class Range extends VariableScope::Range, TCallableScope {
private Callable c;
Range() { this = TCallableScope(c) }
override string toString() {
(c instanceof Method or c instanceof SingletonMethod) and
result = "method scope"
or
c instanceof Lambda and
result = "lambda scope"
or
c instanceof Block and
result = "block scope"
}
override Callable getScopeElement() { TCallableScope(result) = this }
}
}
module Variable {
class Range extends TVariable {
abstract string getName();
string toString() { result = this.getName() }
abstract Location getLocation();
abstract VariableScope getDeclaringScope();
}
}
module LocalVariable {
class Range extends Variable::Range {
private VariableScope scope;
private string name;
private Generated::Identifier i;
Range() { this = TLocalVariable(scope, name, i) }
final override string getName() { result = name }
final override Location getLocation() { result = i.getLocation() }
final override VariableScope getDeclaringScope() { result = scope }
}
}