Create synthetic self nodes for calls without explicit receivers

This commit is contained in:
Nick Rolfe
2021-04-28 16:43:40 +01:00
parent bc6aec7a99
commit f3852f9b56
10 changed files with 744 additions and 190 deletions

View File

@@ -32,14 +32,16 @@ class AstNode extends TAstNode {
/** Gets the enclosing module, if any. */
ModuleBase getEnclosingModule() {
exists(Scope::Range s |
s = scopeOf(toGenerated(this)) and toGenerated(result) = s.getEnclosingModule()
s = scopeOf(toGeneratedInclSynth(this)) and
toGeneratedInclSynth(result) = s.getEnclosingModule()
)
}
/** Gets the enclosing method, if any. */
MethodBase getEnclosingMethod() {
exists(Scope::Range s |
s = scopeOf(toGenerated(this)) and toGenerated(result) = s.getEnclosingMethod()
s = scopeOf(toGeneratedInclSynth(this)) and
toGeneratedInclSynth(result) = s.getEnclosingMethod()
)
}
@@ -48,7 +50,7 @@ class AstNode extends TAstNode {
string toString() { none() }
/** Gets the location of this node. */
Location getLocation() { result = toGenerated(this).getLocation() }
Location getLocation() { result = toGeneratedInclSynth(this).getLocation() }
/** Gets a child node of this `AstNode`. */
final AstNode getAChild() { result = this.getAChild(_) }

View File

@@ -136,6 +136,8 @@ private class IdentifierMethodCall extends MethodCall, TIdentifierMethodCall {
IdentifierMethodCall() { this = TIdentifierMethodCall(g) }
final override string getMethodName() { result = getMethodName(this, g.getValue()) }
final override Self getReceiver() { result = TIdentifierMethodCallImplicitSelf(g) }
}
private class ScopeResolutionMethodCall extends MethodCall, TScopeResolutionMethodCall {
@@ -159,6 +161,10 @@ private class RegularMethodCall extends MethodCall, TRegularMethodCall {
or
not exists(g.getReceiver()) and
toGenerated(result) = g.getMethod().(Generated::ScopeResolution).getScope()
or
not exists(g.getReceiver()) and
not exists(g.getMethod().(Generated::ScopeResolution).getScope()) and
result = TRegularMethodCallImplicitSelf(g)
}
final override string getMethodName() {

View File

@@ -14,6 +14,10 @@ class Expr extends Stmt, TExpr { }
* - `self == other`
* - `self.method_name`
* - `def self.method_name ... end`
*
* This also includes implicit references to the current object in method
* calls. For example, the method call `foo(123)` has an implicit `self`
* receiver, and is equivalent to the explicit `self.foo(123)`.
*/
class Self extends Expr, TSelf {
final override string getAPrimaryQlClass() { result = "Self" }

View File

@@ -103,6 +103,7 @@ private module Cached {
TEndBlock(Generated::EndBlock g) or
TEnsure(Generated::Ensure g) or
TEqExpr(Generated::Binary g) { g instanceof @binary_equalequal } or
TExplicitSelf(Generated::Self g) or
TExponentExpr(Generated::Binary g) { g instanceof @binary_starstar } or
TFalseLiteral(Generated::False g) or
TFloatLiteral(Generated::Float g) { not any(Generated::Rational r).getChild() = g } or
@@ -119,6 +120,7 @@ private module Cached {
THashSplatParameter(Generated::HashSplatParameter g) or
THereDoc(Generated::HeredocBeginning g) or
TIdentifierMethodCall(Generated::Identifier g) { vcall(g) and not access(g, _) } or
TIdentifierMethodCallImplicitSelf(Generated::Identifier g) { vcall(g) and not access(g, _) } or
TIf(Generated::If g) or
TIfModifierExpr(Generated::IfModifier g) or
TInstanceVariableAccess(Generated::InstanceVariable g, AST::InstanceVariable v) {
@@ -158,6 +160,11 @@ private module Cached {
TRegexMatchExpr(Generated::Binary g) { g instanceof @binary_equaltilde } or
TRegularArrayLiteral(Generated::Array g) or
TRegularMethodCall(Generated::Call g) { not g.getMethod() instanceof Generated::Super } or
TRegularMethodCallImplicitSelf(Generated::Call g) {
not g.getMethod() instanceof Generated::Super and
not exists(g.getReceiver()) and
not exists(g.getMethod().(Generated::ScopeResolution).getScope())
} or
TRegularStringLiteral(Generated::String g) or
TRegularSuperCall(Generated::Call g) { g.getMethod() instanceof Generated::Super } or
TRescueClause(Generated::Rescue g) or
@@ -179,7 +186,6 @@ private module Cached {
i = g.getName() and
not exists(Generated::Call c | c.getMethod() = g)
} or
TSelf(Generated::Self g) or
TSimpleParameter(Generated::Identifier g) { g instanceof Parameter::Range } or
TSimpleSymbolLiteral(Generated::SimpleSymbol g) or
TSingletonClass(Generated::SingletonClass g) or
@@ -223,7 +229,11 @@ private module Cached {
TWhileModifierExpr(Generated::WhileModifier g) or
TYieldCall(Generated::Yield g)
/** Gets the underlying TreeSitter entity for a given AST node. */
/**
* Gets the underlying TreeSitter entity for a given AST node. This does not
* include synthesized AST nodes, because they are not the primary AST node
* for any given generated node.
*/
cached
Generated::AstNode toGenerated(AST::AstNode n) {
n = TAddExpr(result) or
@@ -274,6 +284,7 @@ private module Cached {
n = TEndBlock(result) or
n = TEnsure(result) or
n = TEqExpr(result) or
n = TExplicitSelf(result) or
n = TExponentExpr(result) or
n = TFalseLiteral(result) or
n = TFloatLiteral(result) or
@@ -329,7 +340,6 @@ private module Cached {
n = TReturnStmt(result) or
n = TScopeResolutionConstantAccess(result, _) or
n = TScopeResolutionMethodCall(result, _) or
n = TSelf(result) or
n = TSimpleParameter(result) or
n = TSimpleSymbolLiteral(result) or
n = TSingletonClass(result) or
@@ -365,12 +375,25 @@ private module Cached {
n = TWhileModifierExpr(result) or
n = TYieldCall(result)
}
/**
* Like `toGenerated`, but also returns generated nodes for synthesized AST
* nodes.
*/
cached
Generated::AstNode toGeneratedInclSynth(AST::AstNode n) {
result = toGenerated(n) or
n = TIdentifierMethodCallImplicitSelf(result) or
n = TRegularMethodCallImplicitSelf(result)
}
}
import Cached
TAstNode fromGenerated(Generated::AstNode n) { n = toGenerated(result) }
TAstNode fromGeneratedInclSynth(Generated::AstNode n) { n = toGeneratedInclSynth(result) }
class TCall = TMethodCall or TYieldCall;
class TMethodCall =
@@ -392,6 +415,8 @@ class TConditionalLoop = TWhileExpr or TUntilExpr or TWhileModifierExpr or TUnti
class TLoop = TConditionalLoop or TForExpr;
class TSelf = TExplicitSelf or TIdentifierMethodCallImplicitSelf or TRegularMethodCallImplicitSelf;
class TExpr =
TSelf or TArgumentList or TRescueClause or TRescueModifierExpr or TPair or TStringConcatenation or
TCall or TBlockArgument or TSplatArgument or THashSplatArgument or TConstantAccess or

View File

@@ -358,9 +358,9 @@ private module JoinBlockPredecessors {
private predicate idOf(Generated::AstNode x, int y) = equivalenceRelation(id/2)(x, y)
int getId(JoinBlockPredecessor jbp) {
idOf(toGenerated(jbp.getFirstNode().(AstCfgNode).getNode()), result)
idOf(toGeneratedInclSynth(jbp.getFirstNode().(AstCfgNode).getNode()), result)
or
idOf(toGenerated(jbp.(EntryBasicBlock).getScope()), result)
idOf(toGeneratedInclSynth(jbp.(EntryBasicBlock).getScope()), result)
}
string getSplitString(JoinBlockPredecessor jbp) {

View File

@@ -1318,7 +1318,8 @@ private module Cached {
/** Gets the CFG scope of node `n`. */
cached
CfgScope getCfgScopeImpl(AstNode n) {
result = parent*(ASTInternal::fromGenerated(scopeOf(ASTInternal::toGenerated(n))))
result =
parent*(ASTInternal::fromGeneratedInclSynth(scopeOf(ASTInternal::toGeneratedInclSynth(n))))
}
private predicate isAbnormalExitType(SuccessorType t) {