mirror of
https://github.com/github/codeql.git
synced 2026-02-20 17:03:41 +01:00
Merge pull request #131 from github/aibaars/pattern
AST: split method call into normal and setter calls
This commit is contained in:
@@ -9,32 +9,6 @@ class Call extends Expr {
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Call" }
|
||||
|
||||
/**
|
||||
* Gets the receiver of this call, if any. For example:
|
||||
*
|
||||
* ```rb
|
||||
* foo.bar
|
||||
* Baz::qux
|
||||
* corge()
|
||||
* ```
|
||||
*
|
||||
* The result for the call to `bar` is the `Expr` for `foo`; the result for
|
||||
* the call to `qux` is the `Expr` for `Baz`; for the call to `corge` there
|
||||
* is no result.
|
||||
*/
|
||||
final Expr getReceiver() { result = range.getReceiver() }
|
||||
|
||||
/**
|
||||
* Gets the name of the method being called. For example, in:
|
||||
*
|
||||
* ```rb
|
||||
* foo.bar x, y
|
||||
* ```
|
||||
*
|
||||
* the result is `"bar"`.
|
||||
*/
|
||||
final string getMethodName() { result = range.getMethodName() }
|
||||
|
||||
/**
|
||||
* Gets the `n`th argument of this method call. In the following example, the
|
||||
* result for n=0 is the `IntegerLiteral` 0, while for n=1 the result is a
|
||||
@@ -44,6 +18,7 @@ class Call extends Expr {
|
||||
* `getKeywordArgument(string keyword)` predicate.
|
||||
* ```rb
|
||||
* foo(0, bar: 1)
|
||||
* yield 0, bar: 1
|
||||
* ```
|
||||
*/
|
||||
final Expr getArgument(int n) { result = range.getArgument(n) }
|
||||
@@ -73,6 +48,41 @@ class Call extends Expr {
|
||||
* Gets the number of arguments of this method call.
|
||||
*/
|
||||
final int getNumberOfArguments() { result = count(this.getAnArgument()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A method call.
|
||||
*/
|
||||
class MethodCall extends Call {
|
||||
override MethodCall::Range range;
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MethodCall" }
|
||||
|
||||
/**
|
||||
* Gets the receiver of this call, if any. For example:
|
||||
*
|
||||
* ```rb
|
||||
* foo.bar
|
||||
* Baz::qux
|
||||
* corge()
|
||||
* ```
|
||||
*
|
||||
* The result for the call to `bar` is the `Expr` for `foo`; the result for
|
||||
* the call to `qux` is the `Expr` for `Baz`; for the call to `corge` there
|
||||
* is no result.
|
||||
*/
|
||||
final Expr getReceiver() { result = range.getReceiver() }
|
||||
|
||||
/**
|
||||
* Gets the name of the method being called. For example, in:
|
||||
*
|
||||
* ```rb
|
||||
* foo.bar x, y
|
||||
* ```
|
||||
*
|
||||
* the result is `"bar"`.
|
||||
*/
|
||||
final string getMethodName() { result = range.getMethodName() }
|
||||
|
||||
/**
|
||||
* Gets the block of this method call, if any.
|
||||
@@ -83,13 +93,26 @@ class Call extends Expr {
|
||||
final Block getBlock() { result = range.getBlock() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a setter method.
|
||||
* ```rb
|
||||
* self.foo = 10
|
||||
* a[0] = 10
|
||||
* ```
|
||||
*/
|
||||
class SetterMethodCall extends MethodCall, LhsExpr {
|
||||
final override SetterMethodCall::Range range;
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "SetterMethodCall" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An element reference; a call to the `[]` method.
|
||||
* ```rb
|
||||
* a[0]
|
||||
* ```
|
||||
*/
|
||||
class ElementReference extends Call, @element_reference {
|
||||
class ElementReference extends MethodCall, @element_reference {
|
||||
final override ElementReference::Range range;
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "ElementReference" }
|
||||
@@ -117,7 +140,7 @@ class YieldCall extends Call, @yield {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class SuperCall extends Call {
|
||||
class SuperCall extends MethodCall {
|
||||
final override SuperCall::Range range;
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "SuperCall" }
|
||||
|
||||
@@ -1,64 +1,100 @@
|
||||
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 getReceiver();
|
||||
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();
|
||||
|
||||
abstract Expr getArgument(int n);
|
||||
|
||||
abstract Block getBlock();
|
||||
|
||||
override string toString() { result = "call to " + this.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) {
|
||||
label = "getReceiver" and child = getReceiver()
|
||||
super.child(label, child)
|
||||
or
|
||||
label = "getArgument" and child = getArgument(_)
|
||||
label = "getReceiver" and child = getReceiver()
|
||||
or
|
||||
label = "getBlock" and child = getBlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class IdentifierCallRange extends Call::Range, @token_identifier {
|
||||
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 getMethodName() { result = generated.getValue() }
|
||||
final override string getMethod() { result = generated.getValue() }
|
||||
|
||||
final override Expr getArgument(int n) { none() }
|
||||
|
||||
final override Block getBlock() { none() }
|
||||
}
|
||||
|
||||
private class ScopeResolutionIdentifierCallRange extends Call::Range, @scope_resolution {
|
||||
private class ScopeResolutionIdentifierCallRange extends MethodCallRange::Range, @scope_resolution {
|
||||
final override Generated::ScopeResolution generated;
|
||||
Generated::Identifier identifier;
|
||||
|
||||
ScopeResolutionIdentifierCallRange() {
|
||||
identifier = generated.getName() and
|
||||
vcall(this) and
|
||||
not access(identifier, _)
|
||||
not exists(Generated::Call c | c.getMethod() = this)
|
||||
}
|
||||
|
||||
final override Expr getReceiver() { result = generated.getScope() }
|
||||
|
||||
final override string getMethodName() { result = identifier.getValue() }
|
||||
final override string getMethod() { result = identifier.getValue() }
|
||||
|
||||
final override Expr getArgument(int n) { none() }
|
||||
|
||||
final override Block getBlock() { none() }
|
||||
}
|
||||
|
||||
private class RegularCallRange extends Call::Range, @call {
|
||||
private class RegularCallRange extends MethodCallRange::Range, @call {
|
||||
final override Generated::Call generated;
|
||||
|
||||
final override Expr getReceiver() {
|
||||
@@ -68,25 +104,33 @@ module Call {
|
||||
result = generated.getMethod().(Generated::ScopeResolution).getScope()
|
||||
}
|
||||
|
||||
final override string getMethodName() {
|
||||
result = generated.getMethod().(Generated::Token).getValue() or
|
||||
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) }
|
||||
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 ElementReference {
|
||||
class Range extends Call::Range, @element_reference {
|
||||
module ElementReferenceRange {
|
||||
class Range extends MethodCallRange::Range, @element_reference {
|
||||
final override Generated::ElementReference generated;
|
||||
|
||||
final override Expr getReceiver() { result = generated.getObject() }
|
||||
|
||||
final override string getMethodName() { result = "[]" }
|
||||
final override string getMethod() { result = "[]" }
|
||||
|
||||
final override string toString() { result = "...[...]" }
|
||||
|
||||
@@ -96,24 +140,53 @@ module ElementReference {
|
||||
}
|
||||
}
|
||||
|
||||
module YieldCall {
|
||||
class Range extends Call::Range, @yield {
|
||||
final override Generated::Yield generated;
|
||||
module NormalMethodCall {
|
||||
class Range extends MethodCall::Range {
|
||||
Range() {
|
||||
not this instanceof LhsExpr::Range or
|
||||
generated.getParent() instanceof AssignOperation
|
||||
}
|
||||
|
||||
final override Expr getReceiver() { none() }
|
||||
final override string getMethodName() { result = range.getMethod() }
|
||||
}
|
||||
}
|
||||
|
||||
final override string getMethodName() { result = "yield" }
|
||||
module SetterMethodCall {
|
||||
class Range extends MethodCall::Range, LhsExpr::Range {
|
||||
final override string getMethodName() { result = range.getMethod() + "=" }
|
||||
|
||||
final override Expr getArgument(int n) { result = generated.getChild().getChild(n) }
|
||||
final override string toString() { result = MethodCall::Range.super.toString() }
|
||||
}
|
||||
}
|
||||
|
||||
final override Block getBlock() { none() }
|
||||
module ElementReference {
|
||||
class Range extends MethodCall::Range {
|
||||
override ElementReferenceRange::Range range;
|
||||
|
||||
final override string getMethodName() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
module SuperCall {
|
||||
abstract class Range extends Call::Range { }
|
||||
class Range extends NormalMethodCall::Range {
|
||||
override SuperCallRange::Range range;
|
||||
}
|
||||
}
|
||||
|
||||
private class SuperTokenCallRange extends SuperCall::Range, @token_super {
|
||||
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
|
||||
@@ -122,21 +195,21 @@ module SuperCall {
|
||||
|
||||
final override Expr getReceiver() { none() }
|
||||
|
||||
final override string getMethodName() { result = generated.getValue() }
|
||||
final override string getMethod() { result = generated.getValue() }
|
||||
|
||||
final override Expr getArgument(int n) { none() }
|
||||
|
||||
final override Block getBlock() { none() }
|
||||
}
|
||||
|
||||
private class RegularSuperCallRange extends SuperCall::Range, @call {
|
||||
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 getMethodName() {
|
||||
final override string getMethod() {
|
||||
result = generated.getMethod().(Generated::Super).getValue()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user