Merge pull request #106 from github/self

This commit is contained in:
Nick Rolfe
2021-01-28 20:16:48 +00:00
committed by GitHub
7 changed files with 140 additions and 4 deletions

View File

@@ -108,6 +108,22 @@ class YieldCall extends Call, @yield {
final override string getAPrimaryQlClass() { result = "YieldCall" }
}
/**
* A call to `super`.
* ```rb
* class Foo < Bar
* def baz
* super
* end
* end
* ```
*/
class SuperCall extends Call {
final override SuperCall::Range range;
final override string getAPrimaryQlClass() { result = "SuperCall" }
}
/**
* A block argument in a method call.
* ```rb

View File

@@ -66,6 +66,46 @@ module YieldCall {
}
}
module SuperCall {
abstract class Range extends Call::Range { }
private class SuperTokenCallRange extends SuperCall::Range, @token_super {
final override Generated::Super generated;
// N.B. `super` tokens can never be accesses, so any vcall with `super` must
// be a call.
SuperTokenCallRange() { vcall(this) }
final override Expr getReceiver() { none() }
final override string getMethodName() { result = generated.getValue() }
final override ScopeResolution getMethodScopeResolution() { none() }
final override Expr getArgument(int n) { none() }
final override Block getBlock() { none() }
}
private class RegularSuperCallRange extends SuperCall::Range, @call {
final override Generated::Call generated;
RegularSuperCallRange() { generated.getMethod() instanceof Generated::Super }
final override Expr getReceiver() { none() }
final override string getMethodName() {
result = generated.getMethod().(Generated::Super).getValue()
}
final override ScopeResolution getMethodScopeResolution() { none() }
final override Expr getArgument(int n) { result = generated.getArguments().getChild(n) }
final override Block getBlock() { result = generated.getBlock() }
}
}
module BlockArgument {
class Range extends Expr::Range, @block_argument {
final override Generated::BlockArgument generated;

View File

@@ -125,6 +125,9 @@ private module Cached {
not scope.(CapturingScope).inherits(name, _)
}
// Token types that can be vcalls
private class VcallToken = @token_identifier or @token_super;
/**
* Holds if `i` is an `identifier` node occurring in the context where it
* should be considered a VCALL. VCALL is the term that MRI/Ripper uses
@@ -139,7 +142,7 @@ private module Cached {
* ```
*/
cached
predicate vcall(Generated::Identifier i) {
predicate vcall(VcallToken i) {
i = any(Generated::ArgumentList x).getChild(_)
or
i = any(Generated::Array x).getChild(_)

View File

@@ -72,6 +72,11 @@ callsWithNoReceiverArgumentsOrBlock
| calls.rb:204:6:204:8 | call to bar | bar |
| calls.rb:207:7:207:9 | call to bar | bar |
| calls.rb:210:11:210:13 | call to bar | bar |
| calls.rb:217:5:217:9 | call to super | super |
| calls.rb:218:5:218:11 | call to super | super |
| calls.rb:234:5:234:7 | call to foo | foo |
| calls.rb:235:5:235:14 | call to super | super |
| calls.rb:236:5:236:9 | call to super | super |
callsWithScopeResolutionName
| calls.rb:5:1:5:10 | call to bar | calls.rb:5:1:5:8 | ...::bar |
callsWithArguments
@@ -86,16 +91,54 @@ callsWithArguments
| calls.rb:204:1:204:9 | call to foo | foo | 0 | calls.rb:204:5:204:8 | *... |
| calls.rb:207:1:207:10 | call to foo | foo | 0 | calls.rb:207:5:207:9 | **... |
| calls.rb:210:1:210:14 | call to foo | foo | 0 | calls.rb:210:5:210:13 | Pair |
| calls.rb:219:5:219:16 | call to super | super | 0 | calls.rb:219:11:219:16 | blah |
| calls.rb:220:5:220:17 | call to super | super | 0 | calls.rb:220:11:220:11 | 1 |
| calls.rb:220:5:220:17 | call to super | super | 1 | calls.rb:220:14:220:14 | 2 |
| calls.rb:220:5:220:17 | call to super | super | 2 | calls.rb:220:17:220:17 | 3 |
| calls.rb:223:5:223:30 | call to super | super | 0 | calls.rb:223:11:223:11 | 4 |
| calls.rb:223:5:223:30 | call to super | super | 1 | calls.rb:223:14:223:14 | 5 |
| calls.rb:224:5:224:33 | call to super | super | 0 | calls.rb:224:11:224:11 | 6 |
| calls.rb:224:5:224:33 | call to super | super | 1 | calls.rb:224:14:224:14 | 7 |
callsWithReceiver
| calls.rb:8:1:8:7 | call to bar | calls.rb:8:1:8:3 | 123 |
| calls.rb:22:1:24:3 | call to bar | calls.rb:22:1:22:3 | 123 |
| calls.rb:86:1:86:9 | call to bar | calls.rb:86:1:86:3 | call to foo |
| calls.rb:234:5:234:13 | call to super | calls.rb:234:5:234:7 | call to foo |
| calls.rb:236:5:236:15 | call to super | calls.rb:236:5:236:9 | call to super |
callsWithBlock
| calls.rb:14:1:14:17 | call to foo | calls.rb:14:5:14:17 | { ... } |
| calls.rb:17:1:19:3 | call to foo | calls.rb:17:5:19:3 | do ... end |
| calls.rb:22:1:24:3 | call to bar | calls.rb:22:16:24:3 | do ... end |
| calls.rb:80:1:80:13 | call to foo | calls.rb:80:7:80:13 | { ... } |
| calls.rb:83:1:83:16 | call to foo | calls.rb:83:7:83:16 | do ... end |
| calls.rb:221:5:221:23 | call to super | calls.rb:221:11:221:23 | { ... } |
| calls.rb:222:5:222:26 | call to super | calls.rb:222:11:222:26 | do ... end |
| calls.rb:223:5:223:30 | call to super | calls.rb:223:16:223:30 | { ... } |
| calls.rb:224:5:224:33 | call to super | calls.rb:224:16:224:33 | do ... end |
yieldCalls
| calls.rb:28:3:28:7 | call to yield |
| calls.rb:33:3:33:16 | call to yield |
superCalls
| calls.rb:217:5:217:9 | call to super |
| calls.rb:218:5:218:11 | call to super |
| calls.rb:219:5:219:16 | call to super |
| calls.rb:220:5:220:17 | call to super |
| calls.rb:221:5:221:23 | call to super |
| calls.rb:222:5:222:26 | call to super |
| calls.rb:223:5:223:30 | call to super |
| calls.rb:224:5:224:33 | call to super |
| calls.rb:236:5:236:9 | call to super |
superCallsWithArguments
| calls.rb:219:5:219:16 | call to super | 0 | calls.rb:219:11:219:16 | blah |
| calls.rb:220:5:220:17 | call to super | 0 | calls.rb:220:11:220:11 | 1 |
| calls.rb:220:5:220:17 | call to super | 1 | calls.rb:220:14:220:14 | 2 |
| calls.rb:220:5:220:17 | call to super | 2 | calls.rb:220:17:220:17 | 3 |
| calls.rb:223:5:223:30 | call to super | 0 | calls.rb:223:11:223:11 | 4 |
| calls.rb:223:5:223:30 | call to super | 1 | calls.rb:223:14:223:14 | 5 |
| calls.rb:224:5:224:33 | call to super | 0 | calls.rb:224:11:224:11 | 6 |
| calls.rb:224:5:224:33 | call to super | 1 | calls.rb:224:14:224:14 | 7 |
superCallsWithBlock
| calls.rb:221:5:221:23 | call to super | calls.rb:221:11:221:23 | { ... } |
| calls.rb:222:5:222:26 | call to super | calls.rb:222:11:222:26 | do ... end |
| calls.rb:223:5:223:30 | call to super | calls.rb:223:16:223:30 | { ... } |
| calls.rb:224:5:224:33 | call to super | calls.rb:224:16:224:33 | do ... end |

View File

@@ -22,3 +22,9 @@ query predicate callsWithReceiver(Call c, Expr rcv) { rcv = c.getReceiver() }
query predicate callsWithBlock(Call c, Block b) { b = c.getBlock() }
query predicate yieldCalls(YieldCall c) { any() }
query predicate superCalls(SuperCall c) { any() }
query predicate superCallsWithArguments(SuperCall c, int n, Expr argN) { argN = c.getArgument(n) }
query predicate superCallsWithBlock(SuperCall c, Block b) { b = c.getBlock() }

View File

@@ -207,4 +207,32 @@ foo(*bar)
foo(**bar)
# the value in a keyword argument
foo(blah: bar)
foo(blah: bar)
# ------------------------------------------------------------------------------
# calls to `super`
class MyClass
def my_method
super
super()
super 'blah'
super 1, 2, 3
super { |x| x + 1 }
super do |x| x * 2 end
super 4, 5 { |x| x + 100 }
super 6, 7 do |x| x + 200 end
end
end
# ------------------------------------------------------------------------------
# calls to methods simply named `super`, i.e. *not* calls to the same method in
# a parent classs, so these should be Call but not SuperCall
class AnotherClass
def another_method
foo.super
self.super # TODO: this shows up as a call without a receiver, but that should be fixed once we handle `self` expressions
super.super # we expect the receiver to be a SuperCall, while the outer call should not (it's just a regular Call)
end
end

View File

@@ -1631,12 +1631,12 @@ cfg.rb:
#-----| -> exit print (normal)
# 144| puts
#-----| -> super
#-----| -> call to super
# 144| call to print
#-----| -> call to puts
# 144| super
# 144| call to super
#-----| -> print
# 144| print