Model implicit reads of self variables

We already synthesise `self` nodes for method calls with no receiver.
This change creates read accesses for each of these synthesised nodes.
This commit is contained in:
Harry Maclean
2021-10-11 13:50:28 +01:00
parent e7a3050fb2
commit 0d39a15786
5 changed files with 30 additions and 16 deletions

View File

@@ -193,3 +193,6 @@ class ClassVariableReadAccess extends ClassVariableAccess, VariableReadAccess {
class SelfVariableAccess extends VariableAccess instanceof SelfVariableAccessImpl {
final override string getAPrimaryQlClass() { result = "SelfVariableAccess" }
}
/** An access to the `self` variable where the value is read. */
class SelfVariableReadAccess extends SelfVariableAccess, VariableReadAccess { }

View File

@@ -236,8 +236,9 @@ private module Cached {
isScopeResolutionMethodCall(g, i)
} or
TSelfReal(Ruby::Self g) or
TSelfSynth(AST::AstNode parent, int i) { mkSynthChild(SelfKind(), parent, i) } or
TSelfVariableAccessReal(Ruby::Self self, MethodBase::Range scope) { scopeOf(self) = scope } or
TSelfSynth(AST::AstNode parent, int i, AST::SelfVariable v) {
mkSynthChild(SelfKind(v), parent, i)
} or
TSimpleParameter(Ruby::Identifier g) { g instanceof Parameter::Range } or
TSimpleSymbolLiteral(Ruby::SimpleSymbol g) or
TSingletonClass(Ruby::SingletonClass g) or
@@ -478,7 +479,7 @@ private module Cached {
or
result = TRShiftExprSynth(parent, i)
or
result = TSelfSynth(parent, i)
result = TSelfSynth(parent, i, _)
or
result = TSplatExprSynth(parent, i)
or
@@ -706,4 +707,4 @@ class TInstanceVariableAccess = TInstanceVariableAccessReal or TInstanceVariable
class TClassVariableAccess = TClassVariableAccessReal or TClassVariableAccessSynth;
class TSelfVariableAccess = TSelfVariableAccessReal;
class TSelfVariableAccess = TSelfReal or TSelfSynth;

View File

@@ -60,7 +60,7 @@ class IdentifierMethodCall extends MethodCallImpl, TIdentifierMethodCall {
final override string getMethodNameImpl() { result = g.getValue() }
final override AstNode getReceiverImpl() { result = TSelfSynth(this, 0) }
final override AstNode getReceiverImpl() { result = TSelfSynth(this, 0, _) }
final override Expr getArgumentImpl(int n) { none() }
@@ -97,7 +97,7 @@ class RegularMethodCall extends MethodCallImpl, TRegularMethodCall {
not exists(g.getReceiver()) and
toGenerated(result) = g.getMethod().(Ruby::ScopeResolution).getScope()
or
result = TSelfSynth(this, 0)
result = TSelfSynth(this, 0, _)
}
final override string getMethodNameImpl() {

View File

@@ -5,6 +5,7 @@ private import TreeSitter
private import codeql.ruby.ast.internal.Call
private import codeql.ruby.ast.internal.Variable
private import codeql.ruby.ast.internal.Pattern
private import codeql.ruby.ast.internal.Scope
private import codeql.ruby.AST
/** A synthesized AST node kind. */
@@ -34,7 +35,7 @@ newtype SynthKind =
RShiftExprKind() or
SplatExprKind() or
StmtSequenceKind() or
SelfKind() or
SelfKind(SelfVariable v) or
SubExprKind() or
ConstantReadAccessKind(string value) { any(Synthesis s).constantReadAccess(value) }
@@ -142,7 +143,7 @@ private predicate hasLocation(AstNode n, Location l) {
private module ImplicitSelfSynthesis {
pragma[nomagic]
private predicate identifierMethodCallSelfSynthesis(AstNode mc, int i, Child child) {
child = SynthChild(SelfKind()) and
child = SynthChild(SelfKind(TSelfVariable(scopeOf(toGenerated(mc))))) and
mc = TIdentifierMethodCall(_) and
i = 0
}
@@ -163,7 +164,7 @@ private module ImplicitSelfSynthesis {
not exists(g.(Ruby::Call).getReceiver()) and
not exists(g.(Ruby::Call).getMethod().(Ruby::ScopeResolution).getScope())
) and
child = SynthChild(SelfKind()) and
child = SynthChild(SelfKind(TSelfVariable(scopeOf(toGenerated(mc))))) and
i = 0
}

View File

@@ -308,7 +308,8 @@ private module Cached {
access(this, _) or
this instanceof Ruby::GlobalVariable or
this instanceof Ruby::InstanceVariable or
this instanceof Ruby::ClassVariable
this instanceof Ruby::ClassVariable or
this instanceof Ruby::Self
}
}
@@ -619,15 +620,23 @@ private class ClassVariableAccessSynth extends ClassVariableAccessRealImpl,
abstract class SelfVariableAccessImpl extends VariableAccessImpl, TSelfVariableAccess { }
private class SelfVariableAccessReal extends SelfVariableAccessImpl, TSelfVariableAccessReal {
private class SelfVariableAccessReal extends SelfVariableAccessImpl, TSelfReal {
private Ruby::Self self;
private SelfVariable var;
SelfVariableAccessReal() {
exists(MethodBase::Range scope |
var = TSelfVariable(scope) and this = TSelfVariableAccessReal(self, scope)
)
}
SelfVariableAccessReal() { this = TSelfReal(self) and var = TSelfVariable(scopeOf(self)) }
final override SelfVariable getVariableImpl() { result = var }
final override string toString() { result = var.toString() }
}
private class SelfVariableAccessSynth extends SelfVariableAccessImpl, TSelfSynth {
private SelfVariable v;
SelfVariableAccessSynth() { this = TSelfSynth(_, _, v) }
final override LocalVariable getVariableImpl() { result = v }
final override string toString() { result = v.getName() }
}