mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Extend the scope of self variables
`self` variables are scoped to methods, modules, classes and the top-level of the program. Prior to this change, they were treated as being scoped just to methods. This change means we (once again) correctly synthesise `self` receivers for method calls in class bodies, module bodies and at the top-level.
This commit is contained in:
@@ -20,3 +20,5 @@ class Scope extends AstNode, TScopeType {
|
||||
result.getName() = name
|
||||
}
|
||||
}
|
||||
|
||||
class SelfScope extends Scope, TSelfScopeType { }
|
||||
|
||||
@@ -72,10 +72,7 @@ class ClassVariable extends Variable instanceof ClassVariableImpl {
|
||||
}
|
||||
|
||||
/** A `self` variable. */
|
||||
class SelfVariable extends LocalVariable instanceof SelfVariableImpl {
|
||||
/** Gets the method that this `self` variable belongs to. */
|
||||
MethodBase getMethod() { result = this.getDeclaringScope() }
|
||||
}
|
||||
class SelfVariable extends LocalVariable instanceof SelfVariableImpl { }
|
||||
|
||||
/** An access to a variable. */
|
||||
class VariableAccess extends Expr instanceof VariableAccessImpl {
|
||||
|
||||
@@ -5,6 +5,12 @@ private import codeql.ruby.ast.internal.Parameter
|
||||
|
||||
class TScopeType = TMethodBase or TModuleLike or TBlockLike;
|
||||
|
||||
/**
|
||||
* The scope of a `self` variable.
|
||||
* This differs from a normal scope because it is not affected by blocks or lambdas.
|
||||
*/
|
||||
class TSelfScopeType = TMethodBase or TModuleBase;
|
||||
|
||||
private class TBlockLike = TDoBlock or TLambda or TBlock or TEndBlock;
|
||||
|
||||
private class TModuleLike = TToplevel or TModuleDeclaration or TClassDeclaration or TSingletonClass;
|
||||
@@ -29,6 +35,12 @@ module Scope {
|
||||
result = this.getOuterScope().getEnclosingMethod()
|
||||
}
|
||||
|
||||
SelfBase::Range getEnclosingSelfScope() {
|
||||
this instanceof SelfBase::Range and result = this
|
||||
or
|
||||
not this instanceof SelfBase::Range and result = this.getOuterScope().getEnclosingSelfScope()
|
||||
}
|
||||
|
||||
Range getOuterScope() { result = scopeOf(this) }
|
||||
}
|
||||
}
|
||||
@@ -59,6 +71,15 @@ module ModuleBase {
|
||||
class Range extends Scope::Range, TypeRange { }
|
||||
}
|
||||
|
||||
module SelfBase {
|
||||
class TypeRange = MethodBase::TypeRange or ModuleBase::TypeRange;
|
||||
|
||||
/**
|
||||
* A `self` variable can appear in a class, module, method or at the top level.
|
||||
*/
|
||||
class Range extends Scope::Range, TypeRange { }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate rankHeredocBody(File f, Ruby::HeredocBody b, int i) {
|
||||
b =
|
||||
|
||||
@@ -143,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(TSelfVariable(scopeOf(toGenerated(mc))))) and
|
||||
child = SynthChild(SelfKind(TSelfVariable(scopeOf(toGenerated(mc)).getEnclosingSelfScope()))) and
|
||||
mc = TIdentifierMethodCall(_) and
|
||||
i = 0
|
||||
}
|
||||
@@ -164,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(TSelfVariable(scopeOf(toGenerated(mc))))) and
|
||||
child = SynthChild(SelfKind(TSelfVariable(scopeOf(toGenerated(mc)).getEnclosingSelfScope()))) and
|
||||
i = 0
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ private module Cached {
|
||||
not scopeDefinesParameterVariable(scope, name, _) and
|
||||
not inherits(scope, name, _)
|
||||
} or
|
||||
TSelfVariable(MethodBase::Range scope) or
|
||||
TSelfVariable(SelfBase::Range scope) or
|
||||
TLocalVariableSynth(AstNode n, int i) { any(Synthesis s).localVariable(n, i) }
|
||||
|
||||
// Db types that can be vcalls
|
||||
@@ -479,7 +479,7 @@ class ClassVariableImpl extends VariableReal, TClassVariable {
|
||||
}
|
||||
|
||||
class SelfVariableImpl extends VariableReal, TSelfVariable {
|
||||
private MethodBase::Range scope;
|
||||
private SelfBase::Range scope;
|
||||
|
||||
SelfVariableImpl() { this = TSelfVariable(scope) }
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ module Ssa {
|
||||
|
||||
SelfDefinition() { this.definesAt(v, _, _) }
|
||||
|
||||
final override string toString() { result = "self (" + v.getMethod() + ")" }
|
||||
final override string toString() { result = "self (" + v.getDeclaringScope() + ")" }
|
||||
|
||||
final override Location getLocation() { result = this.getControlFlowNode().getLocation() }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user