Remove ScopeResolution from AST

Now we handle it specially in calls and class/module names, so they have
predicate to get the scope expr.
This commit is contained in:
Nick Rolfe
2021-02-10 17:53:13 +00:00
parent d4ebcbf18f
commit 452a343e86
18 changed files with 473 additions and 245 deletions

View File

@@ -22,14 +22,16 @@ class Call extends Expr {
/**
* Gets the name of the method being called. For example, in:
*
* ```rb
* foo.bar x, y
* ```
* the result is `"bar"`.
*
* N.B. in the following example, where the method name is a scope
* resolution, the result is the name being resolved, i.e. `"bar"`. Use
* `getMethodScopeResolution` to get the complete `ScopeResolution`.
* N.B. in the following example, where the method name uses the scope
* resolution operator, the result is the name being resolved, i.e. `"bar"`.
* Use `getMethodNameScopeExpr` to get the expression for `Foo`.
*
* ```rb
* Foo::bar x, y
* ```
@@ -37,14 +39,33 @@ class Call extends Expr {
final string getMethodName() { result = range.getMethodName() }
/**
* Gets the scope resolution of this call, if any. In the following example,
* the result is the `ScopeResolution` for `Foo::bar`, while
* `getMethodName()` returns `"bar"`.
* Gets the scope expression used in the method name's scope resolution
* operation, if any.
*
* In the following example, the result is the `Expr` for `Foo`.
*
* ```rb
* Foo::bar()
* ```
*
* However, there is no result for the following example, since there is no
* scope resolution operation.
*
* ```rb
* baz()
* ```
*/
final ScopeResolution getMethodScopeResolution() { result = range.getMethodScopeResolution() }
final Expr getMethodNameScopeExpr() { result = range.getMethodNameScopeExpr() }
/**
* Holds if the method name uses the scope resolution operator to access the
* global scope, as in this example:
*
* ```rb
* ::foo
* ```
*/
final predicate methodNameHasGlobalScope() { range.methodNameHasGlobalScope() }
/**
* Gets the `n`th argument of this method call. In the following example, the

View File

@@ -168,39 +168,6 @@ class ParenthesizedExpr extends ExprSequence, @parenthesized_statements {
final override string getAPrimaryQlClass() { result = "ParenthesizedExpr" }
}
/**
* A scope resolution, typically used to access constants defined in a class or
* module.
* ```rb
* Foo::Bar
* ```
*/
class ScopeResolution extends Expr, @scope_resolution {
final override ScopeResolution::Range range;
final override string getAPrimaryQlClass() { result = "ScopeResolution" }
/**
* Gets the expression representing the scope, if any. In the following
* example, the scope is the `Expr` for `Foo`:
* ```rb
* Foo::Bar
* ```
* However, in the following example, accessing the `Bar` constant in the
* `Object` class, there is no result:
* ```rb
* ::Bar
* ```
*/
final Expr getScope() { result = range.getScope() }
/**
* Gets the name being resolved. For example, in `Foo::Bar`, the result is
* `"Bar"`.
*/
final string getName() { result = range.getName() }
}
/**
* A pair expression. For example, in a hash:
* ```rb

View File

@@ -49,9 +49,8 @@ class Class extends ModuleBase {
* end
* ```
*
* N.B. in the following example, where the class name is a scope resolution,
* the result is the name being resolved, i.e. `"Bar"`. Use
* `getScopeResolutionName` to get the complete `ScopeResolution`.
* N.B. in the following example, where the class name uses the scope
* resolution operator, the result is the name being resolved, i.e. `"Bar"`. Use `getNameScopeExpr` to get the `Foo` for `Foo`.
* ```rb
* class Foo::Bar
* end
@@ -60,22 +59,36 @@ class Class extends ModuleBase {
final string getName() { result = range.getName() }
/**
* Gets the scope resolution used to define the class name, if any. In the
* following example, the result is the `ScopeResolution` for `Foo::Bar`,
* while `getName()` returns `"Bar"`.
* Gets the scope expression used in the class name's scope resolution
* operation, if any.
*
* In the following example, the result is the `Expr` for `Foo`.
*
* ```rb
* class Foo::Bar
* end
* ```
*
* In the following example, the name is not a scope resolution, so there is
* no result.
* However, there is no result for the following example, since there is no
* scope resolution operation.
*
* ```rb
* class Baz
* end
* ```
*/
final ScopeResolution getNameScopeResolution() { result = range.getNameScopeResolution() }
final Expr getNameScopeExpr() { result = range.getNameScopeExpr() }
/**
* Holds if the class name uses the scope resolution operator to access the
* global scope, as in this example:
*
* ```rb
* class ::Foo
* end
* ```
*/
final predicate nameHasGlobalScope() { range.nameHasGlobalScope() }
/**
* Gets the `Expr` used as the superclass in the class definition, if any.
@@ -158,9 +171,8 @@ class Module extends ModuleBase, @module {
* end
* ```
*
* N.B. in the following example, where the module name is a scope
* resolution, the result is the name being resolved, i.e. `"Bar"`. Use
* `getScopeResolutionName` to get the complete `ScopeResolution`.
* N.B. in the following example, where the module name uses the scope
* resolution operator, the result is the name being resolved, i.e. `"Bar"`. Use `getNameScopeExpr` to get the `Expr` for `Foo`.
* ```rb
* module Foo::Bar
* end
@@ -169,20 +181,34 @@ class Module extends ModuleBase, @module {
final string getName() { result = range.getName() }
/**
* Gets the scope resolution used to define the module name, if any. In the
* following example, the result is the `ScopeResolution` for `Foo::Bar`,
* while `getName()` returns `"bar"`.
* Gets the scope expression used in the module name's scope resolution
* operation, if any.
*
* In the following example, the result is the `Expr` for `Foo`.
*
* ```rb
* module Foo::Bar
* end
* ```
*
* In the following example, the name is not a scope resolution, so this
* predicate has no result:
* However, there is no result for the following example, since there is no
* scope resolution operation.
*
* ```rb
* module Baz
* end
* ```
*/
final ScopeResolution getNameScopeResolution() { result = range.getNameScopeResolution() }
final Expr getNameScopeExpr() { result = range.getNameScopeExpr() }
/**
* Holds if the module name uses the scope resolution operator to access the
* global scope, as in this example:
*
* ```rb
* class ::Foo
* end
* ```
*/
final predicate nameHasGlobalScope() { range.nameHasGlobalScope() }
}

View File

@@ -9,7 +9,9 @@ module Call {
abstract string getMethodName();
abstract ScopeResolution getMethodScopeResolution();
abstract Expr getMethodNameScopeExpr();
abstract predicate methodNameHasGlobalScope();
abstract Expr getArgument(int n);
@@ -27,7 +29,32 @@ module Call {
final override string getMethodName() { result = generated.getValue() }
final override ScopeResolution getMethodScopeResolution() { none() }
final override Expr getMethodNameScopeExpr() { none() }
final override predicate methodNameHasGlobalScope() { none() }
final override Expr getArgument(int n) { none() }
final override Block getBlock() { none() }
}
private class ScopeResolutionIdentifierCallRange extends Call::Range, @scope_resolution {
final override Generated::ScopeResolution generated;
Generated::Identifier identifier;
ScopeResolutionIdentifierCallRange() {
identifier = generated.getName() and
vcall(this) and
not access(identifier, _)
}
final override Expr getReceiver() { none() }
final override string getMethodName() { result = identifier.getValue() }
final override Expr getMethodNameScopeExpr() { result = generated.getScope() }
final override predicate methodNameHasGlobalScope() { not exists(generated.getScope()) }
final override Expr getArgument(int n) { none() }
@@ -41,10 +68,20 @@ module Call {
final override string getMethodName() {
result = generated.getMethod().(Generated::Token).getValue() or
result = this.getMethodScopeResolution().getName()
result =
generated.getMethod().(Generated::ScopeResolution).getName().(Generated::Token).getValue()
}
final override ScopeResolution getMethodScopeResolution() { result = generated.getMethod() }
final override Expr getMethodNameScopeExpr() {
result = generated.getMethod().(Generated::ScopeResolution).getScope()
}
final override predicate methodNameHasGlobalScope() {
exists(Generated::ScopeResolution sr |
sr = generated.getMethod() and
not exists(sr.getScope())
)
}
final override Expr getArgument(int n) { result = generated.getArguments().getChild(n) }
@@ -60,7 +97,9 @@ module YieldCall {
final override string getMethodName() { result = "yield" }
final override ScopeResolution getMethodScopeResolution() { none() }
final override Expr getMethodNameScopeExpr() { none() }
final override predicate methodNameHasGlobalScope() { none() }
final override Expr getArgument(int n) { result = generated.getChild().getChild(n) }
@@ -82,7 +121,9 @@ module SuperCall {
final override string getMethodName() { result = generated.getValue() }
final override ScopeResolution getMethodScopeResolution() { none() }
final override Expr getMethodNameScopeExpr() { none() }
final override predicate methodNameHasGlobalScope() { none() }
final override Expr getArgument(int n) { none() }
@@ -100,7 +141,9 @@ module SuperCall {
result = generated.getMethod().(Generated::Super).getValue()
}
final override ScopeResolution getMethodScopeResolution() { none() }
final override Expr getMethodNameScopeExpr() { none() }
final override predicate methodNameHasGlobalScope() { none() }
final override Expr getArgument(int n) { result = generated.getArguments().getChild(n) }

View File

@@ -227,18 +227,6 @@ module DoExpr {
}
}
module ScopeResolution {
class Range extends Expr::Range, @scope_resolution {
final override Generated::ScopeResolution generated;
final Expr getScope() { result = generated.getScope() }
final string getName() { result = generated.getName().(Generated::Token).getValue() }
final override string toString() { result = "...::" + this.getName() }
}
}
module Pair {
class Range extends Expr::Range, @pair {
final override Generated::Pair generated;

View File

@@ -14,10 +14,20 @@ module Class {
final string getName() {
result = generated.getName().(Generated::Token).getValue() or
result = this.getNameScopeResolution().getName()
result =
generated.getName().(Generated::ScopeResolution).getName().(Generated::Token).getValue()
}
final ScopeResolution getNameScopeResolution() { result = generated.getName() }
final Expr getNameScopeExpr() {
result = generated.getName().(Generated::ScopeResolution).getScope()
}
final predicate nameHasGlobalScope() {
exists(Generated::ScopeResolution sr |
sr = generated.getName() and
not exists(sr.getScope())
)
}
final Expr getSuperclassExpr() { result = generated.getSuperclass().getChild() }
@@ -45,10 +55,20 @@ module Module {
final string getName() {
result = generated.getName().(Generated::Token).getValue() or
result = this.getNameScopeResolution().getName()
result =
generated.getName().(Generated::ScopeResolution).getName().(Generated::Token).getValue()
}
final ScopeResolution getNameScopeResolution() { result = generated.getName() }
final Expr getNameScopeExpr() {
result = generated.getName().(Generated::ScopeResolution).getScope()
}
final predicate nameHasGlobalScope() {
exists(Generated::ScopeResolution sr |
sr = generated.getName() and
not exists(sr.getScope())
)
}
final override string toString() { result = this.getName() }
}

View File

@@ -165,8 +165,8 @@ private module Cached {
not scope.inherits(name, _)
}
// Token types that can be vcalls
private class VcallToken = @token_identifier or @token_super;
// Db types that can be vcalls
private class VcallToken = @scope_resolution or @token_identifier or @token_super;
/**
* Holds if `i` is an `identifier` node occurring in the context where it