mirror of
https://github.com/github/codeql.git
synced 2026-05-29 18:41:27 +02:00
Merge PR #21873 branch to get files
This commit is contained in:
@@ -134,7 +134,7 @@ class BlockParameter extends NamedParameter, TBlockParameter {
|
||||
final override string getName() { result = g.getName().getValue() }
|
||||
|
||||
final override LocalVariable getVariable() {
|
||||
result = TLocalVariableReal(_, _, g.getName()) or
|
||||
result.(LocalVariableReal).getDefiningNode() = g.getName() or
|
||||
result = TLocalVariableSynth(this, 0)
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ class HashSplatParameter extends NamedParameter, THashSplatParameter {
|
||||
final override string getAPrimaryQlClass() { result = "HashSplatParameter" }
|
||||
|
||||
final override LocalVariable getVariable() {
|
||||
result = TLocalVariableReal(_, _, g.getName()) or
|
||||
result.(LocalVariableReal).getDefiningNode() = g.getName() or
|
||||
result = TLocalVariableSynth(this, 0)
|
||||
}
|
||||
|
||||
@@ -212,7 +212,9 @@ class KeywordParameter extends NamedParameter, TKeywordParameter {
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "KeywordParameter" }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) }
|
||||
final override LocalVariable getVariable() {
|
||||
result.(LocalVariableReal).getDefiningNode() = g.getName()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default value, i.e. the value assigned to the parameter when one
|
||||
@@ -262,7 +264,9 @@ class OptionalParameter extends NamedParameter, TOptionalParameter {
|
||||
*/
|
||||
final Expr getDefaultValue() { toGenerated(result) = g.getValue() }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) }
|
||||
final override LocalVariable getVariable() {
|
||||
result.(LocalVariableReal).getDefiningNode() = g.getName()
|
||||
}
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
|
||||
@@ -293,7 +297,7 @@ class SplatParameter extends NamedParameter, TSplatParameter {
|
||||
final override string getAPrimaryQlClass() { result = "SplatParameter" }
|
||||
|
||||
final override LocalVariable getVariable() {
|
||||
result = TLocalVariableReal(_, _, g.getName()) or
|
||||
result.(LocalVariableReal).getDefiningNode() = g.getName() or
|
||||
result = TLocalVariableSynth(this, 0)
|
||||
}
|
||||
|
||||
|
||||
@@ -207,9 +207,7 @@ private module Cached {
|
||||
TLambda(Ruby::Lambda g) or
|
||||
TLine(Ruby::Line g) or
|
||||
TLeftAssignmentList(Ruby::LeftAssignmentList g) or
|
||||
TLocalVariableAccessReal(Ruby::Identifier g, TLocalVariableReal v) {
|
||||
LocalVariableAccess::range(g, v)
|
||||
} or
|
||||
TLocalVariableAccessReal(Ruby::Identifier g, TLocalVariableReal v) { access(g, v) } or
|
||||
TLocalVariableAccessSynth(Ast::AstNode parent, int i, Ast::LocalVariable v) {
|
||||
mkSynthChild(LocalVariableAccessRealKind(v), parent, i)
|
||||
or
|
||||
|
||||
@@ -33,7 +33,7 @@ class SimpleParameterRealImpl extends SimpleParameterImpl, TSimpleParameterReal
|
||||
|
||||
SimpleParameterRealImpl() { this = TSimpleParameterReal(g) }
|
||||
|
||||
override LocalVariable getVariableImpl() { result = TLocalVariableReal(_, _, g) }
|
||||
override LocalVariable getVariableImpl() { result.(LocalVariableReal).getDefiningNode() = g }
|
||||
|
||||
override string getNameImpl() { result = g.getValue() }
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ private Ruby::AstNode specialParentOf(Ruby::AstNode n) {
|
||||
]
|
||||
}
|
||||
|
||||
private Ruby::AstNode parentOf(Ruby::AstNode n) {
|
||||
Ruby::AstNode parentOf(Ruby::AstNode n) {
|
||||
n = getHereDocBody(result)
|
||||
or
|
||||
result = specialParentOf(n).getParent()
|
||||
@@ -172,13 +172,15 @@ private module Cached {
|
||||
}
|
||||
}
|
||||
|
||||
bindingset[n]
|
||||
pragma[inline_late]
|
||||
Scope::Range scopeOf(Ruby::AstNode n) { result = Cached::scopeOfImpl(n) }
|
||||
import Cached
|
||||
|
||||
bindingset[n]
|
||||
pragma[inline_late]
|
||||
Scope scopeOfInclSynth(AstNode n) { result = Cached::scopeOfInclSynthImpl(n) }
|
||||
Scope::Range scopeOf(Ruby::AstNode n) { result = scopeOfImpl(n) }
|
||||
|
||||
bindingset[n]
|
||||
pragma[inline_late]
|
||||
Scope scopeOfInclSynth(AstNode n) { result = scopeOfInclSynthImpl(n) }
|
||||
|
||||
abstract class ScopeImpl extends AstNode, TScopeType {
|
||||
final Scope getOuterScopeImpl() { result = scopeOfInclSynth(this) }
|
||||
|
||||
@@ -299,9 +299,12 @@ 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)).getEnclosingSelfScope()))) and
|
||||
mc = TIdentifierMethodCall(_) and
|
||||
i = 0
|
||||
exists(SelfVariableImpl self |
|
||||
self.getDeclaringScopeImpl() = scopeOf(toGenerated(mc)).getEnclosingSelfScope() and
|
||||
child = SynthChild(SelfKind(self)) and
|
||||
mc = TIdentifierMethodCall(_) and
|
||||
i = 0
|
||||
)
|
||||
}
|
||||
|
||||
private class IdentifierMethodCallSelfSynthesis extends Synthesis {
|
||||
@@ -312,13 +315,14 @@ private module ImplicitSelfSynthesis {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate regularMethodCallSelfSynthesis(TRegularMethodCall mc, int i, Child child) {
|
||||
exists(Ruby::AstNode g |
|
||||
exists(Ruby::AstNode g, SelfVariableImpl self |
|
||||
mc = TRegularMethodCall(g) and
|
||||
// If there's no explicit receiver, then the receiver is implicitly `self`.
|
||||
not exists(g.(Ruby::Call).getReceiver())
|
||||
) and
|
||||
child = SynthChild(SelfKind(TSelfVariable(scopeOf(toGenerated(mc)).getEnclosingSelfScope()))) and
|
||||
i = 0
|
||||
not exists(g.(Ruby::Call).getReceiver()) and
|
||||
self.getDeclaringScopeImpl() = scopeOf(toGenerated(mc)).getEnclosingSelfScope() and
|
||||
child = SynthChild(SelfKind(self)) and
|
||||
i = 0
|
||||
)
|
||||
}
|
||||
|
||||
private class RegularMethodCallSelfSynthesis extends Synthesis {
|
||||
@@ -341,9 +345,10 @@ private module ImplicitSelfSynthesis {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private SelfKind getSelfKind(InstanceVariableAccess var) {
|
||||
exists(Ruby::AstNode owner |
|
||||
exists(Ruby::AstNode owner, SelfVariableImpl self |
|
||||
self.getDeclaringScopeImpl() = scopeOf(owner).getEnclosingSelfScope() and
|
||||
owner = toGenerated(instanceVarAccessSynthParentStar(var)) and
|
||||
result = SelfKind(TSelfVariable(scopeOf(owner).getEnclosingSelfScope()))
|
||||
result = SelfKind(self)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1566,20 +1571,20 @@ private module ForLoopDesugar {
|
||||
* { a: a }
|
||||
* ```
|
||||
*/
|
||||
private module ImplicitHashValueSynthesis {
|
||||
private Ruby::AstNode keyWithoutValue(AstNode parent, int i) {
|
||||
module ImplicitHashValueSynthesis {
|
||||
Ruby::AstNode keyWithoutValue(Ruby::AstNode parent, int i) {
|
||||
exists(Ruby::KeywordPattern pair |
|
||||
result = pair.getKey() and
|
||||
result = toGenerated(parent.(HashPattern).getKey(i)) and
|
||||
result = parent.(Ruby::HashPattern).getChild(i).(Ruby::KeywordPattern).getKey() and
|
||||
not exists(pair.getValue())
|
||||
)
|
||||
or
|
||||
exists(Ruby::Pair pair |
|
||||
i = 0 and
|
||||
result = pair.getKey() and
|
||||
pair = toGenerated(parent) and
|
||||
not exists(pair.getValue())
|
||||
)
|
||||
parent =
|
||||
any(Ruby::Pair pair |
|
||||
i = 0 and
|
||||
result = pair.getKey() and
|
||||
not exists(pair.getValue())
|
||||
)
|
||||
}
|
||||
|
||||
private string keyName(Ruby::AstNode key) {
|
||||
@@ -1589,7 +1594,7 @@ private module ImplicitHashValueSynthesis {
|
||||
|
||||
private class ImplicitHashValueSynthesis extends Synthesis {
|
||||
final override predicate child(AstNode parent, int i, Child child) {
|
||||
exists(Ruby::AstNode key | key = keyWithoutValue(parent, i) |
|
||||
exists(Ruby::AstNode key | key = keyWithoutValue(toGenerated(parent), i) |
|
||||
exists(TVariableReal variable |
|
||||
access(key, variable) and
|
||||
child = SynthChild(LocalVariableAccessRealKind(variable))
|
||||
@@ -1616,7 +1621,7 @@ private module ImplicitHashValueSynthesis {
|
||||
}
|
||||
|
||||
final override predicate location(AstNode n, Location l) {
|
||||
exists(AstNode p, int i | l = keyWithoutValue(p, i).getLocation() |
|
||||
exists(AstNode p, int i | l = keyWithoutValue(toGenerated(p), i).getLocation() |
|
||||
n = p.(HashPattern).getValue(i)
|
||||
or
|
||||
i = 0 and n = p.(Pair).getValue()
|
||||
|
||||
@@ -2,6 +2,7 @@ overlay[local]
|
||||
module;
|
||||
|
||||
private import TreeSitter
|
||||
private import codeql.namebinding.LocalNameBinding
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.CFG
|
||||
private import codeql.ruby.ast.internal.AST
|
||||
@@ -94,10 +95,11 @@ predicate scopeDefinesParameterVariable(
|
||||
// In case of overlapping parameter names (e.g. `_`), only the first
|
||||
// parameter will give rise to a variable
|
||||
i =
|
||||
min(Ruby::Identifier other |
|
||||
parameterAssignment(scope, name, other, _)
|
||||
min(Ruby::Identifier other, int startline, int startcolumn |
|
||||
parameterAssignment(scope, name, other, _) and
|
||||
other.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
||||
|
|
||||
other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn()
|
||||
other order by startline, startcolumn
|
||||
) and
|
||||
parameterAssignment(scope, name, _, pos)
|
||||
or
|
||||
@@ -113,7 +115,8 @@ predicate scopeDefinesParameterVariable(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
bindingset[i]
|
||||
pragma[inline_late]
|
||||
private string variableNameInScope(Ruby::AstNode i, Scope::Range scope) {
|
||||
scope = scopeOf(i) and
|
||||
(
|
||||
@@ -137,40 +140,142 @@ private predicate scopeAssigns(Scope::Range scope, string name, Ruby::AstNode i)
|
||||
name = variableNameInScope(i, scope)
|
||||
}
|
||||
|
||||
private module Input implements LocalNameBindingInputSig<Location> {
|
||||
predicate cacheRevRef() { exists(TVariable v) implies any() }
|
||||
|
||||
class AstNode = Ruby::AstNode;
|
||||
|
||||
AstNode getChild(AstNode parent, int index) {
|
||||
parent = parentOf(result) and
|
||||
(
|
||||
index = result.getParentIndex()
|
||||
or
|
||||
not exists(result.getParentIndex()) and
|
||||
index = -1
|
||||
)
|
||||
}
|
||||
|
||||
class Conditional extends AstNode {
|
||||
Conditional() { none() }
|
||||
|
||||
AstNode getCondition() { none() }
|
||||
|
||||
AstNode getThen() { none() }
|
||||
|
||||
AstNode getElse() { none() }
|
||||
}
|
||||
|
||||
class SiblingShadowingDecl extends AstNode {
|
||||
SiblingShadowingDecl() { none() }
|
||||
|
||||
AstNode getLhs() { none() }
|
||||
|
||||
AstNode getRhs() { none() }
|
||||
|
||||
AstNode getElse() { none() }
|
||||
}
|
||||
|
||||
predicate isTopScope(AstNode scope) {
|
||||
scope instanceof Scope::Range and
|
||||
not (
|
||||
scope instanceof Ruby::Block or
|
||||
scope instanceof Ruby::DoBlock or
|
||||
scope instanceof Ruby::Lambda
|
||||
)
|
||||
}
|
||||
|
||||
private Scope::Range getParentScope(Scope::Range scope) {
|
||||
result = scopeOf(scope) and
|
||||
not isTopScope(scope)
|
||||
}
|
||||
|
||||
bindingset[name, scope]
|
||||
pragma[inline_late]
|
||||
private predicate declInScope0(AstNode definingNode, string name, AstNode scope) {
|
||||
scopeDefinesParameterVariable(scope, name, definingNode, _) or
|
||||
scopeAssigns(scope, name, definingNode)
|
||||
}
|
||||
|
||||
predicate declInScope(AstNode definingNode, string name, AstNode scope) {
|
||||
scopeDefinesParameterVariable(scope, name, definingNode, _)
|
||||
or
|
||||
/*
|
||||
* Variables are not declared explicitly in Ruby, so we consider the _first_ assignment to
|
||||
* be the declaration:
|
||||
*
|
||||
* ```rb
|
||||
* a = 1 # declares `a`
|
||||
* a = 2 # does not declare `a`
|
||||
* 1.times do | x | # declares `x`
|
||||
* a = 2 # does not declare `a`
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
|
||||
scopeAssigns(scope, name, definingNode) and
|
||||
not scopeDefinesParameterVariable(scope, name, _, _) and
|
||||
not exists(AstNode prev, AstNode prevScope |
|
||||
prevScope = getParentScope*(scope) and
|
||||
declInScope0(prev, name, prevScope) and
|
||||
prev.getLocation().strictlyBefore(definingNode.getLocation())
|
||||
)
|
||||
}
|
||||
|
||||
predicate implicitDeclInScope(string name, AstNode scope) {
|
||||
name = "self" and
|
||||
scope instanceof SelfBase::Range
|
||||
}
|
||||
|
||||
predicate accessCand(AstNode n, string name) {
|
||||
name = variableNameInScope(n, _) and
|
||||
(
|
||||
explicitAssignmentNode(n, _)
|
||||
or
|
||||
implicitAssignmentNode(n)
|
||||
or
|
||||
scopeDefinesParameterVariable(_, _, n, _)
|
||||
or
|
||||
vcall(n)
|
||||
or
|
||||
n = any(Ruby::VariableReferencePattern vr).getName()
|
||||
or
|
||||
n = ImplicitHashValueSynthesis::keyWithoutValue(_, _)
|
||||
)
|
||||
or
|
||||
n instanceof Ruby::Self and
|
||||
name = "self"
|
||||
}
|
||||
}
|
||||
|
||||
private import LocalNameBinding<Location, Input>
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
newtype TVariable =
|
||||
TGlobalVariable(string name) { name = any(Ruby::GlobalVariable var).getValue() } or
|
||||
TGlobalVariable(string name) {
|
||||
CachedStage::ref() and
|
||||
name = any(Ruby::GlobalVariable var).getValue()
|
||||
} or
|
||||
TClassVariable(Scope::Range scope, string name, Ruby::AstNode decl) {
|
||||
decl =
|
||||
min(Ruby::ClassVariable other |
|
||||
classVariableAccess(other, name, scope)
|
||||
min(Ruby::ClassVariable other, int startline, int startcolumn |
|
||||
classVariableAccess(other, name, scope) and
|
||||
other.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
||||
|
|
||||
other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn()
|
||||
other order by startline, startcolumn
|
||||
)
|
||||
} or
|
||||
TInstanceVariable(Scope::Range scope, string name, boolean instance, Ruby::AstNode decl) {
|
||||
decl =
|
||||
min(Ruby::InstanceVariable other |
|
||||
instanceVariableAccess(other, name, scope, instance)
|
||||
min(Ruby::InstanceVariable other, int startline, int startcolumn |
|
||||
instanceVariableAccess(other, name, scope, instance) and
|
||||
other.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
||||
|
|
||||
other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn()
|
||||
other order by startline, startcolumn
|
||||
)
|
||||
} or
|
||||
TLocalVariableReal(Scope::Range scope, string name, Ruby::AstNode i) {
|
||||
scopeDefinesParameterVariable(scope, name, i, _)
|
||||
or
|
||||
i =
|
||||
min(Ruby::AstNode other |
|
||||
scopeAssigns(scope, name, other)
|
||||
|
|
||||
other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn()
|
||||
) and
|
||||
not scopeDefinesParameterVariable(scope, name, _, _) and
|
||||
not inherits(scope, name, _)
|
||||
} or
|
||||
TSelfVariable(SelfBase::Range scope) or
|
||||
TLocalVariableReal(Local l) or
|
||||
TLocalVariableSynth(AstNode n, int i) { any(Synthesis s).localVariable(n, i) }
|
||||
|
||||
// Db types that can be vcalls
|
||||
@@ -321,39 +426,37 @@ private module Cached {
|
||||
i = any(Ruby::ExpressionReferencePattern x).getValue()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasScopeAndName(VariableReal variable, Scope::Range scope, string name) {
|
||||
variable.getNameImpl() = name and
|
||||
scope = variable.getDeclaringScopeImpl()
|
||||
}
|
||||
|
||||
cached
|
||||
predicate access(Ruby::AstNode access, VariableReal variable) {
|
||||
exists(string name, Scope::Range scope |
|
||||
pragma[only_bind_into](name) = variableNameInScope(access, scope)
|
||||
exists(Local l |
|
||||
variable = TLocalVariableReal(l) and
|
||||
access = l.getAnAccess()
|
||||
|
|
||||
hasScopeAndName(variable, scope, name) and
|
||||
not access.getLocation().strictlyBefore(variable.getLocationImpl()) and
|
||||
// In case of overlapping parameter names, later parameters should not
|
||||
// be considered accesses to the first parameter
|
||||
if parameterAssignment(_, _, access, _)
|
||||
then scopeDefinesParameterVariable(_, _, access, _)
|
||||
else any()
|
||||
l instanceof ImplicitLocal
|
||||
or
|
||||
exists(Scope::Range declScope |
|
||||
hasScopeAndName(variable, declScope, pragma[only_bind_into](name)) and
|
||||
inherits(scope, name, declScope)
|
||||
)
|
||||
/*
|
||||
* In the example below, `a` is declared in the scope of `M`, but only the
|
||||
* second mention of `a` is an actual access:
|
||||
*
|
||||
* ```rb
|
||||
* module M
|
||||
* puts a # calls method `a`
|
||||
* a = 1 # declares `a`
|
||||
* puts a # accesses variable `a`
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
|
||||
not access.getLocation().strictlyBefore(l.getDefiningNode().getLocation())
|
||||
)
|
||||
}
|
||||
|
||||
private class Access extends Ruby::Token {
|
||||
Access() {
|
||||
access(this.(Ruby::Identifier), _) or
|
||||
access(this, _) or
|
||||
this instanceof Ruby::GlobalVariable or
|
||||
this instanceof Ruby::InstanceVariable or
|
||||
this instanceof Ruby::ClassVariable or
|
||||
this instanceof Ruby::Self
|
||||
this instanceof Ruby::ClassVariable
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,29 +501,6 @@ private module Cached {
|
||||
|
||||
import Cached
|
||||
|
||||
/** Holds if this scope inherits `name` from an outer scope `outer`. */
|
||||
private predicate inherits(Scope::Range scope, string name, Scope::Range outer) {
|
||||
(
|
||||
scope instanceof Ruby::Block or
|
||||
scope instanceof Ruby::DoBlock or
|
||||
scope instanceof Ruby::Lambda
|
||||
) and
|
||||
not scopeDefinesParameterVariable(scope, name, _, _) and
|
||||
(
|
||||
outer = scope.getOuterScope() and
|
||||
(
|
||||
scopeDefinesParameterVariable(outer, name, _, _)
|
||||
or
|
||||
exists(Ruby::AstNode i |
|
||||
scopeAssigns(outer, name, i) and
|
||||
i.getLocation().strictlyBefore(scope.getLocation())
|
||||
)
|
||||
)
|
||||
or
|
||||
inherits(scope.getOuterScope(), name, outer)
|
||||
)
|
||||
}
|
||||
|
||||
abstract class VariableImpl extends TVariable {
|
||||
abstract string getNameImpl();
|
||||
|
||||
@@ -429,10 +509,9 @@ abstract class VariableImpl extends TVariable {
|
||||
abstract Location getLocationImpl();
|
||||
}
|
||||
|
||||
class TVariableReal =
|
||||
TGlobalVariable or TClassVariable or TInstanceVariable or TLocalVariableReal or TSelfVariable;
|
||||
class TVariableReal = TGlobalVariable or TClassVariable or TInstanceVariable or TLocalVariableReal;
|
||||
|
||||
class TLocalVariable = TLocalVariableReal or TLocalVariableSynth or TSelfVariable;
|
||||
class TLocalVariable = TLocalVariableReal or TLocalVariableSynth;
|
||||
|
||||
/**
|
||||
* A "real" (i.e. non-synthesized) variable. This class only exists to
|
||||
@@ -458,19 +537,19 @@ private class VariableRealAdapter extends VariableImpl, TVariableReal instanceof
|
||||
}
|
||||
|
||||
class LocalVariableReal extends VariableReal, TLocalVariableReal {
|
||||
private Scope::Range scope;
|
||||
private string name;
|
||||
private Ruby::AstNode i;
|
||||
private Local l;
|
||||
|
||||
LocalVariableReal() { this = TLocalVariableReal(scope, name, i) }
|
||||
LocalVariableReal() { this = TLocalVariableReal(l) }
|
||||
|
||||
final override string getNameImpl() { result = name }
|
||||
Ruby::AstNode getDefiningNode() { result = l.getDefiningNode() }
|
||||
|
||||
final override Location getLocationImpl() { result = i.getLocation() }
|
||||
final override string getNameImpl() { result = l.getName() }
|
||||
|
||||
final override Scope::Range getDeclaringScopeImpl() { result = scope }
|
||||
final override Location getLocationImpl() { result = l.getLocation() }
|
||||
|
||||
final VariableAccess getDefiningAccessImpl() { toGenerated(result) = i }
|
||||
final override Scope::Range getDeclaringScopeImpl() { result = l.getScope() }
|
||||
|
||||
final VariableAccess getDefiningAccessImpl() { toGenerated(result) = l.getDefiningNode() }
|
||||
}
|
||||
|
||||
class LocalVariableSynth extends VariableImpl, TLocalVariableSynth {
|
||||
@@ -531,34 +610,16 @@ class ClassVariableImpl extends VariableReal, TClassVariable {
|
||||
final override Scope::Range getDeclaringScopeImpl() { result = scope }
|
||||
}
|
||||
|
||||
class SelfVariableImpl extends VariableReal, TSelfVariable {
|
||||
private SelfBase::Range scope;
|
||||
class SelfVariableImpl extends LocalVariableReal {
|
||||
private ImplicitLocal l;
|
||||
|
||||
SelfVariableImpl() { this = TSelfVariable(scope) }
|
||||
|
||||
final override string getNameImpl() { result = "self" }
|
||||
|
||||
final override Location getLocationImpl() { result = scope.getLocation() }
|
||||
|
||||
final override Scope::Range getDeclaringScopeImpl() { result = scope }
|
||||
SelfVariableImpl() { this = TLocalVariableReal(l) }
|
||||
}
|
||||
|
||||
abstract class VariableAccessImpl extends Expr, TVariableAccess {
|
||||
abstract VariableImpl getVariableImpl();
|
||||
}
|
||||
|
||||
module LocalVariableAccess {
|
||||
predicate range(Ruby::Identifier id, TLocalVariableReal v) {
|
||||
access(id, v) and
|
||||
(
|
||||
explicitWriteAccess(id, _) or
|
||||
implicitWriteAccess(id) or
|
||||
vcall(id) or
|
||||
id = any(Ruby::VariableReferencePattern vr).getName()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TVariableAccessReal =
|
||||
TLocalVariableAccessReal or TGlobalVariableAccess or TInstanceVariableAccess or
|
||||
TClassVariableAccess;
|
||||
@@ -681,7 +742,8 @@ private class SelfVariableAccessReal extends SelfVariableAccessImpl, TSelfReal {
|
||||
|
||||
SelfVariableAccessReal() {
|
||||
exists(Ruby::Self self |
|
||||
this = TSelfReal(self) and var = TSelfVariable(scopeOf(self).getEnclosingSelfScope())
|
||||
this = TSelfReal(self) and
|
||||
access(self, var)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ dependencies:
|
||||
codeql/ssa: ${workspace}
|
||||
codeql/tutorial: ${workspace}
|
||||
codeql/util: ${workspace}
|
||||
codeql/namebinding: ${workspace}
|
||||
dataExtensions:
|
||||
- codeql/ruby/frameworks/**/model.yml
|
||||
- codeql/ruby/frameworks/**/*.model.yml
|
||||
|
||||
@@ -28,6 +28,7 @@ parameterVariable
|
||||
| parameters.rb:59:22:59:26 | (..., ...) | parameters.rb:59:25:59:25 | c |
|
||||
| scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x |
|
||||
| scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x |
|
||||
| scopes.rb:69:15:69:15 | x | scopes.rb:69:15:69:15 | x |
|
||||
| ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b |
|
||||
| ssa.rb:18:8:18:8 | x | ssa.rb:18:8:18:8 | x |
|
||||
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements |
|
||||
|
||||
@@ -47,3 +47,27 @@ module M
|
||||
#{var2}
|
||||
EOF
|
||||
end
|
||||
|
||||
module ExceptionVariable
|
||||
class MyException < Exception
|
||||
end
|
||||
|
||||
x = 1
|
||||
puts x
|
||||
|
||||
begin
|
||||
raise MyException
|
||||
rescue MyException => x # reuses `x` from above
|
||||
puts x
|
||||
end
|
||||
puts x # prints `MyException`, not `1`
|
||||
end
|
||||
|
||||
module ParameterShadowing
|
||||
x = 1
|
||||
xs = [1, 2, 3]
|
||||
xs.each do |x|
|
||||
puts x
|
||||
end
|
||||
puts x # prints `1`, not `3`
|
||||
end
|
||||
@@ -86,12 +86,12 @@ definition
|
||||
| parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a |
|
||||
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b |
|
||||
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c |
|
||||
| scopes.rb:1:1:49:4 | self (scopes.rb) | scopes.rb:1:1:49:4 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured entry> self | scopes.rb:1:1:49:4 | self |
|
||||
| scopes.rb:1:1:73:3 | self (scopes.rb) | scopes.rb:1:1:73:3 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured entry> self | scopes.rb:1:1:73:3 | self |
|
||||
| scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:4 | a |
|
||||
| scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> a | scopes.rb:7:1:7:1 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:49:4 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:73:3 | self |
|
||||
| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a |
|
||||
| scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a |
|
||||
| scopes.rb:13:7:13:7 | b | scopes.rb:13:7:13:7 | b |
|
||||
@@ -99,13 +99,18 @@ definition
|
||||
| scopes.rb:13:11:13:11 | c | scopes.rb:13:11:13:11 | c |
|
||||
| scopes.rb:13:14:13:14 | d | scopes.rb:13:14:13:14 | d |
|
||||
| scopes.rb:13:19:13:32 | __synth__3 | scopes.rb:13:4:13:32 | __synth__3 |
|
||||
| scopes.rb:26:1:26:12 | self (A) | scopes.rb:26:1:26:12 | self |
|
||||
| scopes.rb:27:1:27:1 | x | scopes.rb:27:1:27:1 | x |
|
||||
| scopes.rb:28:1:30:3 | self (B) | scopes.rb:28:1:30:3 | self |
|
||||
| scopes.rb:34:1:36:3 | self (C) | scopes.rb:34:1:36:3 | self |
|
||||
| scopes.rb:41:1:49:3 | self (M) | scopes.rb:41:1:49:3 | self |
|
||||
| scopes.rb:42:2:42:4 | var | scopes.rb:42:2:42:4 | var |
|
||||
| scopes.rb:46:5:46:8 | var2 | scopes.rb:46:5:46:8 | var2 |
|
||||
| scopes.rb:51:1:64:3 | self (ExceptionVariable) | scopes.rb:51:1:64:3 | self |
|
||||
| scopes.rb:55:3:55:3 | x | scopes.rb:55:3:55:3 | x |
|
||||
| scopes.rb:60:25:60:25 | x | scopes.rb:55:3:55:3 | x |
|
||||
| scopes.rb:66:1:73:3 | self (ParameterShadowing) | scopes.rb:66:1:73:3 | self |
|
||||
| scopes.rb:67:3:67:3 | x | scopes.rb:67:3:67:3 | x |
|
||||
| scopes.rb:68:3:68:4 | xs | scopes.rb:68:3:68:4 | xs |
|
||||
| scopes.rb:69:11:71:5 | <captured entry> self | scopes.rb:66:1:73:3 | self |
|
||||
| scopes.rb:69:15:69:15 | x | scopes.rb:69:15:69:15 | x |
|
||||
| ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self |
|
||||
| ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b |
|
||||
| ssa.rb:2:3:2:3 | i | ssa.rb:2:3:2:3 | i |
|
||||
@@ -262,20 +267,20 @@ read
|
||||
| parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a | parameters.rb:60:11:60:11 | a |
|
||||
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b |
|
||||
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c |
|
||||
| scopes.rb:1:1:49:4 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | scopes.rb:8:1:8:6 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:5:4:5:9 | self |
|
||||
| scopes.rb:1:1:73:3 | self (scopes.rb) | scopes.rb:1:1:73:3 | self | scopes.rb:8:1:8:6 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:3:4:3:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:3:9:3:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:5:4:5:9 | self |
|
||||
| scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
|
||||
| scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> a | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:12:4:12:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:14:4:14:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:15:4:15:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:16:4:16:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:17:4:17:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:10:4:10:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:12:4:12:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:14:4:14:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:15:4:15:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:16:4:16:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:17:4:17:9 | self |
|
||||
| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a |
|
||||
| scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a |
|
||||
| scopes.rb:13:7:13:7 | b | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b |
|
||||
@@ -294,6 +299,18 @@ read
|
||||
| scopes.rb:41:1:49:3 | self (M) | scopes.rb:41:1:49:3 | self | scopes.rb:45:5:45:7 | self |
|
||||
| scopes.rb:42:2:42:4 | var | scopes.rb:42:2:42:4 | var | scopes.rb:44:5:44:7 | var |
|
||||
| scopes.rb:46:5:46:8 | var2 | scopes.rb:46:5:46:8 | var2 | scopes.rb:47:5:47:8 | var2 |
|
||||
| scopes.rb:51:1:64:3 | self (ExceptionVariable) | scopes.rb:51:1:64:3 | self | scopes.rb:56:3:56:8 | self |
|
||||
| scopes.rb:51:1:64:3 | self (ExceptionVariable) | scopes.rb:51:1:64:3 | self | scopes.rb:59:5:59:21 | self |
|
||||
| scopes.rb:51:1:64:3 | self (ExceptionVariable) | scopes.rb:51:1:64:3 | self | scopes.rb:61:5:61:10 | self |
|
||||
| scopes.rb:51:1:64:3 | self (ExceptionVariable) | scopes.rb:51:1:64:3 | self | scopes.rb:63:3:63:8 | self |
|
||||
| scopes.rb:55:3:55:3 | x | scopes.rb:55:3:55:3 | x | scopes.rb:56:8:56:8 | x |
|
||||
| scopes.rb:60:25:60:25 | x | scopes.rb:55:3:55:3 | x | scopes.rb:61:10:61:10 | x |
|
||||
| scopes.rb:60:25:60:25 | x | scopes.rb:55:3:55:3 | x | scopes.rb:63:8:63:8 | x |
|
||||
| scopes.rb:66:1:73:3 | self (ParameterShadowing) | scopes.rb:66:1:73:3 | self | scopes.rb:72:3:72:8 | self |
|
||||
| scopes.rb:67:3:67:3 | x | scopes.rb:67:3:67:3 | x | scopes.rb:72:8:72:8 | x |
|
||||
| scopes.rb:68:3:68:4 | xs | scopes.rb:68:3:68:4 | xs | scopes.rb:69:3:69:4 | xs |
|
||||
| scopes.rb:69:11:71:5 | <captured entry> self | scopes.rb:66:1:73:3 | self | scopes.rb:70:5:70:10 | self |
|
||||
| scopes.rb:69:15:69:15 | x | scopes.rb:69:15:69:15 | x | scopes.rb:70:10:70:10 | x |
|
||||
| ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:3:3:3:8 | self |
|
||||
| ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:4:3:4:12 | self |
|
||||
| ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:7:5:7:10 | self |
|
||||
@@ -443,12 +460,12 @@ firstRead
|
||||
| parameters.rb:59:20:59:20 | a | parameters.rb:59:20:59:20 | a | parameters.rb:60:11:60:11 | a |
|
||||
| parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b |
|
||||
| parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c |
|
||||
| scopes.rb:1:1:49:4 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | scopes.rb:8:1:8:6 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self |
|
||||
| scopes.rb:1:1:73:3 | self (scopes.rb) | scopes.rb:1:1:73:3 | self | scopes.rb:8:1:8:6 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:3:4:3:9 | self |
|
||||
| scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
|
||||
| scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:10:4:10:9 | self |
|
||||
| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a |
|
||||
| scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a |
|
||||
| scopes.rb:13:7:13:7 | b | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b |
|
||||
@@ -460,6 +477,14 @@ firstRead
|
||||
| scopes.rb:41:1:49:3 | self (M) | scopes.rb:41:1:49:3 | self | scopes.rb:45:5:45:7 | self |
|
||||
| scopes.rb:42:2:42:4 | var | scopes.rb:42:2:42:4 | var | scopes.rb:44:5:44:7 | var |
|
||||
| scopes.rb:46:5:46:8 | var2 | scopes.rb:46:5:46:8 | var2 | scopes.rb:47:5:47:8 | var2 |
|
||||
| scopes.rb:51:1:64:3 | self (ExceptionVariable) | scopes.rb:51:1:64:3 | self | scopes.rb:56:3:56:8 | self |
|
||||
| scopes.rb:55:3:55:3 | x | scopes.rb:55:3:55:3 | x | scopes.rb:56:8:56:8 | x |
|
||||
| scopes.rb:60:25:60:25 | x | scopes.rb:55:3:55:3 | x | scopes.rb:61:10:61:10 | x |
|
||||
| scopes.rb:66:1:73:3 | self (ParameterShadowing) | scopes.rb:66:1:73:3 | self | scopes.rb:72:3:72:8 | self |
|
||||
| scopes.rb:67:3:67:3 | x | scopes.rb:67:3:67:3 | x | scopes.rb:72:8:72:8 | x |
|
||||
| scopes.rb:68:3:68:4 | xs | scopes.rb:68:3:68:4 | xs | scopes.rb:69:3:69:4 | xs |
|
||||
| scopes.rb:69:11:71:5 | <captured entry> self | scopes.rb:66:1:73:3 | self | scopes.rb:70:5:70:10 | self |
|
||||
| scopes.rb:69:15:69:15 | x | scopes.rb:69:15:69:15 | x | scopes.rb:70:10:70:10 | x |
|
||||
| ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:3:3:3:8 | self |
|
||||
| ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | ssa.rb:5:6:5:6 | b |
|
||||
| ssa.rb:2:3:2:3 | i | ssa.rb:2:3:2:3 | i | ssa.rb:3:8:3:8 | i |
|
||||
@@ -532,14 +557,14 @@ adjacentReads
|
||||
| parameters.rb:25:1:28:3 | self (opt_param) | parameters.rb:25:1:28:3 | self | parameters.rb:26:3:26:11 | self | parameters.rb:27:3:27:11 | self |
|
||||
| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:40:25:43 | name | parameters.rb:26:8:26:11 | name |
|
||||
| parameters.rb:54:9:57:3 | <captured entry> self | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self | parameters.rb:56:4:56:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self | scopes.rb:3:9:3:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self | scopes.rb:5:4:5:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:3:4:3:9 | self | scopes.rb:3:9:3:9 | self |
|
||||
| scopes.rb:2:9:6:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:3:9:3:9 | self | scopes.rb:5:4:5:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | scopes.rb:11:4:11:4 | a |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self | scopes.rb:12:4:12:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:12:4:12:9 | self | scopes.rb:14:4:14:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:14:4:14:9 | self | scopes.rb:15:4:15:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:15:4:15:9 | self | scopes.rb:16:4:16:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:49:4 | self | scopes.rb:16:4:16:9 | self | scopes.rb:17:4:17:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:10:4:10:9 | self | scopes.rb:12:4:12:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:12:4:12:9 | self | scopes.rb:14:4:14:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:14:4:14:9 | self | scopes.rb:15:4:15:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:15:4:15:9 | self | scopes.rb:16:4:16:9 | self |
|
||||
| scopes.rb:9:9:18:3 | <captured entry> self | scopes.rb:1:1:73:3 | self | scopes.rb:16:4:16:9 | self | scopes.rb:17:4:17:9 | self |
|
||||
| scopes.rb:13:10:13:15 | __synth__2__1 | scopes.rb:13:10:13:15 | __synth__2__1 | scopes.rb:13:11:13:11 | __synth__2__1 | scopes.rb:13:14:13:14 | __synth__2__1 |
|
||||
| scopes.rb:13:19:13:32 | __synth__3 | scopes.rb:13:4:13:32 | __synth__3 | scopes.rb:13:4:13:4 | __synth__3 | scopes.rb:13:7:13:7 | __synth__3 |
|
||||
| scopes.rb:13:19:13:32 | __synth__3 | scopes.rb:13:4:13:32 | __synth__3 | scopes.rb:13:7:13:7 | __synth__3 | scopes.rb:13:10:13:15 | __synth__3 |
|
||||
@@ -547,6 +572,10 @@ adjacentReads
|
||||
| scopes.rb:27:1:27:1 | x | scopes.rb:27:1:27:1 | x | scopes.rb:31:10:31:10 | x | scopes.rb:34:7:34:7 | x |
|
||||
| scopes.rb:27:1:27:1 | x | scopes.rb:27:1:27:1 | x | scopes.rb:34:7:34:7 | x | scopes.rb:34:14:34:14 | x |
|
||||
| scopes.rb:27:1:27:1 | x | scopes.rb:27:1:27:1 | x | scopes.rb:34:14:34:14 | x | scopes.rb:37:5:37:5 | x |
|
||||
| scopes.rb:51:1:64:3 | self (ExceptionVariable) | scopes.rb:51:1:64:3 | self | scopes.rb:56:3:56:8 | self | scopes.rb:59:5:59:21 | self |
|
||||
| scopes.rb:51:1:64:3 | self (ExceptionVariable) | scopes.rb:51:1:64:3 | self | scopes.rb:59:5:59:21 | self | scopes.rb:61:5:61:10 | self |
|
||||
| scopes.rb:51:1:64:3 | self (ExceptionVariable) | scopes.rb:51:1:64:3 | self | scopes.rb:61:5:61:10 | self | scopes.rb:63:3:63:8 | self |
|
||||
| scopes.rb:60:25:60:25 | x | scopes.rb:55:3:55:3 | x | scopes.rb:61:10:61:10 | x | scopes.rb:63:8:63:8 | x |
|
||||
| ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:3:3:3:8 | self | ssa.rb:4:3:4:12 | self |
|
||||
| ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:4:3:4:12 | self | ssa.rb:7:5:7:10 | self |
|
||||
| ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | ssa.rb:4:3:4:12 | self | ssa.rb:11:5:11:10 | self |
|
||||
|
||||
@@ -155,43 +155,43 @@ variableAccess
|
||||
| parameters.rb:60:16:60:16 | b | parameters.rb:59:23:59:23 | b | parameters.rb:59:1:61:3 | tuples_nested |
|
||||
| parameters.rb:60:21:60:21 | c | parameters.rb:59:25:59:25 | c | parameters.rb:59:1:61:3 | tuples_nested |
|
||||
| scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x | scopes.rb:2:9:6:3 | do ... end |
|
||||
| scopes.rb:3:4:3:9 | self | scopes.rb:1:1:49:4 | self | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:3:9:3:9 | self | scopes.rb:1:1:49:4 | self | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:3:4:3:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:3:9:3:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:4 | a | scopes.rb:2:9:6:3 | do ... end |
|
||||
| scopes.rb:5:4:5:9 | self | scopes.rb:1:1:49:4 | self | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:5:4:5:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:5:9:5:9 | a | scopes.rb:4:4:4:4 | a | scopes.rb:2:9:6:3 | do ... end |
|
||||
| scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:8:1:8:6 | self | scopes.rb:1:1:49:4 | self | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:8:6:8:6 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:8:1:8:6 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:8:6:8:6 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x | scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:10:4:10:9 | self | scopes.rb:1:1:49:4 | self | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:10:9:10:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:12:4:12:9 | self | scopes.rb:1:1:49:4 | self | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:12:9:12:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:10:4:10:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:10:9:10:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:12:4:12:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:12:9:12:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:13:7:13:7 | b | scopes.rb:13:7:13:7 | b | scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:13:11:13:11 | c | scopes.rb:13:11:13:11 | c | scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:13:14:13:14 | d | scopes.rb:13:14:13:14 | d | scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:14:4:14:9 | self | scopes.rb:1:1:49:4 | self | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:14:9:14:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:15:4:15:9 | self | scopes.rb:1:1:49:4 | self | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:14:4:14:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:14:9:14:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:15:4:15:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:15:9:15:9 | b | scopes.rb:13:7:13:7 | b | scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:16:4:16:9 | self | scopes.rb:1:1:49:4 | self | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:16:4:16:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:16:9:16:9 | c | scopes.rb:13:11:13:11 | c | scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:17:4:17:9 | self | scopes.rb:1:1:49:4 | self | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:17:4:17:9 | self | scopes.rb:1:1:73:3 | self | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:17:9:17:9 | d | scopes.rb:13:14:13:14 | d | scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:24:1:24:6 | script | scopes.rb:24:1:24:6 | script | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:27:1:27:1 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:28:8:28:8 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:24:1:24:6 | script | scopes.rb:24:1:24:6 | script | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:27:1:27:1 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:28:8:28:8 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:29:3:29:3 | x | scopes.rb:29:3:29:3 | x | scopes.rb:28:1:30:3 | B |
|
||||
| scopes.rb:31:10:31:10 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:31:10:31:10 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:32:3:32:3 | x | scopes.rb:32:3:32:3 | x | scopes.rb:31:1:33:3 | class << ... |
|
||||
| scopes.rb:34:7:34:7 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:34:14:34:14 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:34:7:34:7 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:34:14:34:14 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:35:3:35:3 | x | scopes.rb:35:3:35:3 | x | scopes.rb:34:1:36:3 | C |
|
||||
| scopes.rb:37:5:37:5 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:37:5:37:5 | x | scopes.rb:27:1:27:1 | x | scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:38:3:38:3 | x | scopes.rb:38:3:38:3 | x | scopes.rb:37:1:39:3 | foo |
|
||||
| scopes.rb:42:2:42:4 | var | scopes.rb:42:2:42:4 | var | scopes.rb:41:1:49:3 | M |
|
||||
| scopes.rb:43:2:43:4 | foo | scopes.rb:43:2:43:4 | foo | scopes.rb:41:1:49:3 | M |
|
||||
@@ -199,6 +199,23 @@ variableAccess
|
||||
| scopes.rb:45:5:45:7 | self | scopes.rb:41:1:49:3 | self | scopes.rb:41:1:49:3 | M |
|
||||
| scopes.rb:46:5:46:8 | var2 | scopes.rb:46:5:46:8 | var2 | scopes.rb:41:1:49:3 | M |
|
||||
| scopes.rb:47:5:47:8 | var2 | scopes.rb:46:5:46:8 | var2 | scopes.rb:41:1:49:3 | M |
|
||||
| scopes.rb:55:3:55:3 | x | scopes.rb:55:3:55:3 | x | scopes.rb:51:1:64:3 | ExceptionVariable |
|
||||
| scopes.rb:56:3:56:8 | self | scopes.rb:51:1:64:3 | self | scopes.rb:51:1:64:3 | ExceptionVariable |
|
||||
| scopes.rb:56:8:56:8 | x | scopes.rb:55:3:55:3 | x | scopes.rb:51:1:64:3 | ExceptionVariable |
|
||||
| scopes.rb:59:5:59:21 | self | scopes.rb:51:1:64:3 | self | scopes.rb:51:1:64:3 | ExceptionVariable |
|
||||
| scopes.rb:60:25:60:25 | x | scopes.rb:55:3:55:3 | x | scopes.rb:51:1:64:3 | ExceptionVariable |
|
||||
| scopes.rb:61:5:61:10 | self | scopes.rb:51:1:64:3 | self | scopes.rb:51:1:64:3 | ExceptionVariable |
|
||||
| scopes.rb:61:10:61:10 | x | scopes.rb:55:3:55:3 | x | scopes.rb:51:1:64:3 | ExceptionVariable |
|
||||
| scopes.rb:63:3:63:8 | self | scopes.rb:51:1:64:3 | self | scopes.rb:51:1:64:3 | ExceptionVariable |
|
||||
| scopes.rb:63:8:63:8 | x | scopes.rb:55:3:55:3 | x | scopes.rb:51:1:64:3 | ExceptionVariable |
|
||||
| scopes.rb:67:3:67:3 | x | scopes.rb:67:3:67:3 | x | scopes.rb:66:1:73:3 | ParameterShadowing |
|
||||
| scopes.rb:68:3:68:4 | xs | scopes.rb:68:3:68:4 | xs | scopes.rb:66:1:73:3 | ParameterShadowing |
|
||||
| scopes.rb:69:3:69:4 | xs | scopes.rb:68:3:68:4 | xs | scopes.rb:66:1:73:3 | ParameterShadowing |
|
||||
| scopes.rb:69:15:69:15 | x | scopes.rb:69:15:69:15 | x | scopes.rb:69:11:71:5 | do ... end |
|
||||
| scopes.rb:70:5:70:10 | self | scopes.rb:66:1:73:3 | self | scopes.rb:66:1:73:3 | ParameterShadowing |
|
||||
| scopes.rb:70:10:70:10 | x | scopes.rb:69:15:69:15 | x | scopes.rb:69:11:71:5 | do ... end |
|
||||
| scopes.rb:72:3:72:8 | self | scopes.rb:66:1:73:3 | self | scopes.rb:66:1:73:3 | ParameterShadowing |
|
||||
| scopes.rb:72:8:72:8 | x | scopes.rb:67:3:67:3 | x | scopes.rb:66:1:73:3 | ParameterShadowing |
|
||||
| ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:2:3:2:3 | i | ssa.rb:2:3:2:3 | i | ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:3:3:3:8 | self | ssa.rb:1:1:16:3 | self | ssa.rb:1:1:16:3 | m |
|
||||
@@ -350,6 +367,9 @@ explicitWrite
|
||||
| scopes.rb:42:2:42:4 | var | scopes.rb:42:2:42:9 | ... = ... |
|
||||
| scopes.rb:43:2:43:4 | foo | scopes.rb:43:2:43:13 | ... = ... |
|
||||
| scopes.rb:46:5:46:8 | var2 | scopes.rb:46:5:46:13 | ... = ... |
|
||||
| scopes.rb:55:3:55:3 | x | scopes.rb:55:3:55:7 | ... = ... |
|
||||
| scopes.rb:67:3:67:3 | x | scopes.rb:67:3:67:7 | ... = ... |
|
||||
| scopes.rb:68:3:68:4 | xs | scopes.rb:68:3:68:16 | ... = ... |
|
||||
| ssa.rb:2:3:2:3 | i | ssa.rb:2:3:2:7 | ... = ... |
|
||||
| ssa.rb:6:5:6:5 | i | ssa.rb:6:5:6:9 | ... = ... |
|
||||
| ssa.rb:10:5:10:5 | i | ssa.rb:10:5:10:9 | ... = ... |
|
||||
@@ -400,6 +420,8 @@ implicitWrite
|
||||
| parameters.rb:59:25:59:25 | c |
|
||||
| scopes.rb:2:14:2:14 | x |
|
||||
| scopes.rb:9:14:9:14 | x |
|
||||
| scopes.rb:60:25:60:25 | x |
|
||||
| scopes.rb:69:15:69:15 | x |
|
||||
| ssa.rb:1:7:1:7 | b |
|
||||
| ssa.rb:18:8:18:8 | x |
|
||||
| ssa.rb:25:8:25:15 | elements |
|
||||
@@ -550,6 +572,18 @@ readAccess
|
||||
| scopes.rb:44:5:44:7 | var |
|
||||
| scopes.rb:45:5:45:7 | self |
|
||||
| scopes.rb:47:5:47:8 | var2 |
|
||||
| scopes.rb:56:3:56:8 | self |
|
||||
| scopes.rb:56:8:56:8 | x |
|
||||
| scopes.rb:59:5:59:21 | self |
|
||||
| scopes.rb:61:5:61:10 | self |
|
||||
| scopes.rb:61:10:61:10 | x |
|
||||
| scopes.rb:63:3:63:8 | self |
|
||||
| scopes.rb:63:8:63:8 | x |
|
||||
| scopes.rb:69:3:69:4 | xs |
|
||||
| scopes.rb:70:5:70:10 | self |
|
||||
| scopes.rb:70:10:70:10 | x |
|
||||
| scopes.rb:72:3:72:8 | self |
|
||||
| scopes.rb:72:8:72:8 | x |
|
||||
| ssa.rb:3:3:3:8 | self |
|
||||
| ssa.rb:3:8:3:8 | i |
|
||||
| ssa.rb:4:3:4:12 | self |
|
||||
@@ -647,6 +681,7 @@ captureAccess
|
||||
| scopes.rb:15:4:15:9 | self |
|
||||
| scopes.rb:16:4:16:9 | self |
|
||||
| scopes.rb:17:4:17:9 | self |
|
||||
| scopes.rb:70:5:70:10 | self |
|
||||
| ssa.rb:26:7:26:10 | elem |
|
||||
| ssa.rb:27:5:27:13 | self |
|
||||
| ssa.rb:27:10:27:13 | elem |
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
| parameters.rb:59:23:59:23 | b |
|
||||
| parameters.rb:59:25:59:25 | c |
|
||||
| scopes.rb:1:1:1:15 | self |
|
||||
| scopes.rb:1:1:49:4 | self |
|
||||
| scopes.rb:1:1:73:3 | self |
|
||||
| scopes.rb:2:14:2:14 | x |
|
||||
| scopes.rb:4:4:4:4 | a |
|
||||
| scopes.rb:7:1:7:1 | a |
|
||||
@@ -124,6 +124,13 @@
|
||||
| scopes.rb:42:2:42:4 | var |
|
||||
| scopes.rb:43:2:43:4 | foo |
|
||||
| scopes.rb:46:5:46:8 | var2 |
|
||||
| scopes.rb:51:1:64:3 | self |
|
||||
| scopes.rb:52:3:53:5 | self |
|
||||
| scopes.rb:55:3:55:3 | x |
|
||||
| scopes.rb:66:1:73:3 | self |
|
||||
| scopes.rb:67:3:67:3 | x |
|
||||
| scopes.rb:68:3:68:4 | xs |
|
||||
| scopes.rb:69:15:69:15 | x |
|
||||
| ssa.rb:1:1:16:3 | self |
|
||||
| ssa.rb:1:1:103:3 | self |
|
||||
| ssa.rb:1:7:1:7 | b |
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
| parameters.rb:54:9:57:3 | do ... end |
|
||||
| parameters.rb:59:1:61:3 | tuples_nested |
|
||||
| scopes.rb:1:1:1:15 | a |
|
||||
| scopes.rb:1:1:49:4 | scopes.rb |
|
||||
| scopes.rb:1:1:73:3 | scopes.rb |
|
||||
| scopes.rb:2:9:6:3 | do ... end |
|
||||
| scopes.rb:9:9:18:3 | do ... end |
|
||||
| scopes.rb:26:1:26:12 | A |
|
||||
@@ -56,6 +56,10 @@
|
||||
| scopes.rb:34:1:36:3 | C |
|
||||
| scopes.rb:37:1:39:3 | foo |
|
||||
| scopes.rb:41:1:49:3 | M |
|
||||
| scopes.rb:51:1:64:3 | ExceptionVariable |
|
||||
| scopes.rb:52:3:53:5 | MyException |
|
||||
| scopes.rb:66:1:73:3 | ParameterShadowing |
|
||||
| scopes.rb:69:11:71:5 | do ... end |
|
||||
| ssa.rb:1:1:16:3 | m |
|
||||
| ssa.rb:1:1:103:3 | ssa.rb |
|
||||
| ssa.rb:18:1:23:3 | m1 |
|
||||
|
||||
1
rust/ql/.generated.list
generated
1
rust/ql/.generated.list
generated
@@ -332,7 +332,6 @@ lib/codeql/rust/elements/internal/NeverTypeReprConstructor.qll 2e0a9c75e389e9ef4
|
||||
lib/codeql/rust/elements/internal/OffsetOfExprConstructor.qll 616e146562adb3ac0fba4d6f55dd6ce60518ed377c0856f1f09ba49593e7bfab 80518ce90fc6d08011d6f5fc2a543958067739e1b0a6a5f2ed90fc9b1db078f0
|
||||
lib/codeql/rust/elements/internal/OffsetOfExprImpl.qll e52d4596068cc54719438121f7d5afcaab04e0c70168ac5e4df1a3a0969817a6 6ab37e659d79e02fb2685d6802ae124157bf14b6f790b31688f437c87f40f52c
|
||||
lib/codeql/rust/elements/internal/OrPatConstructor.qll 4ef583e07298487c0c4c6d7c76ffcc04b1e5fe58aba0c1da3e2c8446a9e0c92b 980a6bd176ae5e5b11c134569910c5468ba91f480982d846e222d031a6a05f1a
|
||||
lib/codeql/rust/elements/internal/ParamBaseImpl.qll fe11999c728c443c46c992e9bed7a2b3e23afa16ae99592e70054bc57ae371b8 df86fdb23266bdfb9ed8a8f02558a760b67f173943b9d075b081229eb5844f66
|
||||
lib/codeql/rust/elements/internal/ParamConstructor.qll b98a2d8969f289fdcc8c0fb11cbd19a3b0c71be038c4a74f5988295a2bae52f0 77d81b31064167945b79b19d9697b57ca24462c3a7cc19e462c4693ce87db532
|
||||
lib/codeql/rust/elements/internal/ParamListConstructor.qll 3123142ab3cab46fb53d7f3eff6ba2d3ff7a45b78839a53dc1979a9c6a54920e 165f3d777ea257cfcf142cc4ba9a0ebcd1902eb99842b8a6657c87087f3df6fe
|
||||
lib/codeql/rust/elements/internal/ParenExprConstructor.qll 104b67dc3fd53ab52e2a42ffde37f3a3a50647aa7bf35df9ba9528e9670da210 d1f5937756e87a477710c61698d141cdad0ccce8b07ecb51bab00330a1ca9835
|
||||
|
||||
1
rust/ql/.gitattributes
generated
vendored
1
rust/ql/.gitattributes
generated
vendored
@@ -334,7 +334,6 @@
|
||||
/lib/codeql/rust/elements/internal/OffsetOfExprConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/OffsetOfExprImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/OrPatConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ParamBaseImpl.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ParamConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ParamListConstructor.qll linguist-generated
|
||||
/lib/codeql/rust/elements/internal/ParenExprConstructor.qll linguist-generated
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// generated by codegen, remove this comment if you wish to edit this file
|
||||
/**
|
||||
* This module provides a hand-modifiable wrapper around the generated class `ParamBase`.
|
||||
*
|
||||
@@ -6,14 +5,19 @@
|
||||
*/
|
||||
|
||||
private import codeql.rust.elements.internal.generated.ParamBase
|
||||
private import codeql.rust.elements.Callable
|
||||
|
||||
/**
|
||||
* INTERNAL: This module contains the customizable definition of `ParamBase` and should not
|
||||
* be referenced directly.
|
||||
*/
|
||||
module Impl {
|
||||
// the following QLdoc is generated: if you need to edit it, do it in the schema file
|
||||
/**
|
||||
* A normal parameter, `Param`, or a self parameter `SelfParam`.
|
||||
*/
|
||||
class ParamBase extends Generated::ParamBase { }
|
||||
class ParamBase extends Generated::ParamBase {
|
||||
/** Gets the callable this parameter belongs to. */
|
||||
Callable getCallable() { this = result.getParamList().getAParamBase() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,71 +1,13 @@
|
||||
private import rust
|
||||
private import codeql.namebinding.LocalNameBinding
|
||||
private import codeql.rust.controlflow.ControlFlowGraph
|
||||
private import codeql.rust.internal.PathResolution as PathResolution
|
||||
private import codeql.rust.elements.internal.generated.ParentChild as ParentChild
|
||||
private import codeql.rust.elements.internal.AstNodeImpl::Impl as AstNodeImpl
|
||||
private import codeql.rust.elements.internal.PathImpl::Impl as PathImpl
|
||||
private import codeql.rust.elements.internal.FormatTemplateVariableAccessImpl::Impl as FormatTemplateVariableAccessImpl
|
||||
private import codeql.util.DenseRank
|
||||
|
||||
module Impl {
|
||||
/**
|
||||
* A variable scope. Either a block `{ ... }`, the guard/rhs
|
||||
* of a match arm, or the body of a closure.
|
||||
*/
|
||||
abstract class VariableScope extends AstNode { }
|
||||
|
||||
class BlockExprScope extends VariableScope, BlockExpr { }
|
||||
|
||||
class MatchArmExprScope extends VariableScope {
|
||||
MatchArmExprScope() { this = any(MatchArm arm).getExpr() }
|
||||
}
|
||||
|
||||
class MatchArmGuardScope extends VariableScope {
|
||||
MatchArmGuardScope() { this = any(MatchArm arm).getGuard() }
|
||||
}
|
||||
|
||||
class ClosureBodyScope extends VariableScope {
|
||||
ClosureBodyScope() { this = any(ClosureExpr ce).getBody() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A scope for conditions, which may introduce variables using `let` expressions.
|
||||
*
|
||||
* Such variables are only available in the body guarded by the condition.
|
||||
*/
|
||||
class ConditionScope extends VariableScope {
|
||||
private AstNode parent;
|
||||
private AstNode body;
|
||||
|
||||
ConditionScope() {
|
||||
parent =
|
||||
any(IfExpr ie |
|
||||
this = ie.getCondition() and
|
||||
body = ie.getThen()
|
||||
)
|
||||
or
|
||||
parent =
|
||||
any(WhileExpr we |
|
||||
this = we.getCondition() and
|
||||
body = we.getLoopBody()
|
||||
)
|
||||
or
|
||||
parent =
|
||||
any(MatchArm ma |
|
||||
this = ma.getGuard() and
|
||||
body = ma.getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the parent of this condition. */
|
||||
AstNode getParent() { result = parent }
|
||||
|
||||
/**
|
||||
* Gets the body in which variables introduced in this scope are available.
|
||||
*/
|
||||
AstNode getBody() { result = body }
|
||||
}
|
||||
|
||||
private Pat getAPatAncestor(Pat p) {
|
||||
(p instanceof IdentPat or p instanceof OrPat) and
|
||||
exists(Pat p0 | result = p0.getParentPat() |
|
||||
@@ -100,7 +42,7 @@ module Impl {
|
||||
*/
|
||||
cached
|
||||
predicate variableDecl(AstNode definingNode, Name name, string text) {
|
||||
Cached::ref() and
|
||||
CachedStage::ref() and
|
||||
exists(SelfParam sp |
|
||||
name = sp.getName() and
|
||||
definingNode = name and
|
||||
@@ -127,34 +69,204 @@ module Impl {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* `let` chains like
|
||||
*
|
||||
* ```rust
|
||||
* if let x1 = ... && let x2 = ... && ... && let xn = ... { ... }
|
||||
* ```
|
||||
*
|
||||
* are parsed left-associatively, so the AST for the condition looks like
|
||||
*
|
||||
* ```rust
|
||||
* ((let x1 = ... && let x2 = ...) && ...) & let xn = ...
|
||||
* ```
|
||||
*
|
||||
* This, however, does not work with scoping and shadowing, so we instead treat
|
||||
* `let` chains as if there is just a single root `&&` node with `n` children,
|
||||
* skipping all intermediate `&&` nodes.
|
||||
*/
|
||||
private module LetChains {
|
||||
predicate isLetChainAncestor(LogicalAndExpr lae) {
|
||||
lae.getAnOperand() instanceof LetExpr
|
||||
or
|
||||
isLetChainAncestor(lae.getLhs())
|
||||
}
|
||||
|
||||
private predicate isLetChainRoot(LogicalAndExpr root) {
|
||||
isLetChainAncestor(root) and
|
||||
not root = any(LogicalAndExpr lae).getLhs()
|
||||
}
|
||||
|
||||
private predicate leftMostChildOfLetChainRoot(LogicalAndExpr left, LogicalAndExpr root) {
|
||||
isLetChainRoot(root) and
|
||||
left = root.getLhs*() and
|
||||
not left.getLhs() instanceof LogicalAndExpr
|
||||
}
|
||||
|
||||
private AstNode getLetChainChild(LogicalAndExpr sub, LogicalAndExpr root, int i) {
|
||||
leftMostChildOfLetChainRoot(sub, root) and
|
||||
i = 1 and
|
||||
result = sub.getRhs()
|
||||
or
|
||||
exists(LogicalAndExpr mid |
|
||||
exists(getLetChainChild(mid, root, i - 1)) and
|
||||
sub.getLhs() = mid and
|
||||
result = sub.getRhs()
|
||||
)
|
||||
}
|
||||
|
||||
AstNode getLetChainChild(LogicalAndExpr lae, int i) {
|
||||
exists(LogicalAndExpr left |
|
||||
leftMostChildOfLetChainRoot(left, lae) and
|
||||
i = 0 and
|
||||
result = left.getLhs()
|
||||
)
|
||||
or
|
||||
result = getLetChainChild(_, lae, i)
|
||||
}
|
||||
}
|
||||
|
||||
private import LetChains
|
||||
|
||||
private module Input implements LocalNameBindingInputSig<Location> {
|
||||
private import rust as Rust
|
||||
|
||||
predicate cacheRevRef() {
|
||||
(variableDecl(_, _, _) implies any())
|
||||
or
|
||||
(exists(VariableReadAccess a) implies any())
|
||||
or
|
||||
(exists(VariableWriteAccess a) implies any())
|
||||
or
|
||||
(exists(any(Variable v).getParameter()) implies any())
|
||||
}
|
||||
|
||||
class AstNode = Rust::AstNode;
|
||||
|
||||
AstNode getChild(AstNode parent, int index) {
|
||||
result = ParentChild::getImmediateChild(parent, index) and
|
||||
not isLetChainAncestor(parent)
|
||||
or
|
||||
result = getLetChainChild(parent, index)
|
||||
or
|
||||
exists(Format f |
|
||||
f = result.(FormatTemplateVariableAccess).getArgument().getParent() and
|
||||
parent = f.getParent() and
|
||||
index = f.getIndex()
|
||||
)
|
||||
}
|
||||
|
||||
abstract class Conditional extends AstNode {
|
||||
abstract AstNode getCondition();
|
||||
|
||||
abstract AstNode getThen();
|
||||
|
||||
abstract AstNode getElse();
|
||||
}
|
||||
|
||||
private class IfExprConditional extends Conditional instanceof IfExpr {
|
||||
override AstNode getCondition() { result = IfExpr.super.getCondition() }
|
||||
|
||||
override AstNode getThen() { result = IfExpr.super.getThen() }
|
||||
|
||||
override AstNode getElse() { result = IfExpr.super.getElse() }
|
||||
}
|
||||
|
||||
private class WhileExprConditional extends Conditional instanceof WhileExpr {
|
||||
override AstNode getCondition() { result = WhileExpr.super.getCondition() }
|
||||
|
||||
override AstNode getThen() { result = WhileExpr.super.getLoopBody() }
|
||||
|
||||
override AstNode getElse() { none() }
|
||||
}
|
||||
|
||||
private class MatchGuardConditional extends Conditional instanceof MatchGuard {
|
||||
override AstNode getCondition() { result = MatchGuard.super.getCondition() }
|
||||
|
||||
override AstNode getThen() {
|
||||
exists(MatchArm arm | this = arm.getGuard() and result = arm.getExpr())
|
||||
}
|
||||
|
||||
override AstNode getElse() { none() }
|
||||
}
|
||||
|
||||
abstract class SiblingShadowingDecl extends AstNode {
|
||||
abstract AstNode getLhs();
|
||||
|
||||
abstract AstNode getRhs();
|
||||
|
||||
abstract AstNode getElse();
|
||||
}
|
||||
|
||||
private class LetStmtSiblingShadowingDecl extends SiblingShadowingDecl instanceof LetStmt {
|
||||
override AstNode getLhs() { result = LetStmt.super.getPat() }
|
||||
|
||||
override AstNode getRhs() { result = LetStmt.super.getInitializer() }
|
||||
|
||||
override AstNode getElse() { result = LetStmt.super.getLetElse() }
|
||||
}
|
||||
|
||||
private class LetExprSiblingShadowingDecl extends SiblingShadowingDecl instanceof LetExpr {
|
||||
override AstNode getLhs() { result = LetExpr.super.getPat() }
|
||||
|
||||
override AstNode getRhs() { result = LetExpr.super.getScrutinee() }
|
||||
|
||||
override AstNode getElse() { none() }
|
||||
}
|
||||
|
||||
predicate declInScope(AstNode definingNode, string name, AstNode scope) {
|
||||
// local variable
|
||||
exists(Name n | variableDecl(definingNode, n, name) |
|
||||
scope = any(SelfParam self | n = self.getName()).getCallable()
|
||||
or
|
||||
exists(Pat pat, Pat pat0 |
|
||||
pat = getAPatAncestor*(pat0) and
|
||||
(pat0 = definingNode or pat0.(IdentPat).getName() = n)
|
||||
|
|
||||
scope = any(MatchArm arm | pat = arm.getPat())
|
||||
or
|
||||
scope = any(Input::SiblingShadowingDecl let | pat = let.getLhs())
|
||||
or
|
||||
scope = any(ForExpr fe | pat = fe.getPat()).getLoopBody()
|
||||
or
|
||||
scope = any(Param p | pat = p.getPat()).getCallable()
|
||||
)
|
||||
)
|
||||
or
|
||||
// local function; behave as if they are defined at the beginning of the scope
|
||||
definingNode = scope.(BlockExpr).getStmtList().getAStatement() and
|
||||
name = definingNode.(Function).getName().getText()
|
||||
}
|
||||
|
||||
predicate accessCand(AstNode n, string name) {
|
||||
name = n.(PathExpr).getPath().(PathImpl::IdentPath).getName()
|
||||
or
|
||||
name = n.(FormatTemplateVariableAccess).getName()
|
||||
}
|
||||
}
|
||||
|
||||
private import LocalNameBinding<Location, Input>
|
||||
|
||||
/** A variable. */
|
||||
class Variable extends MkVariable {
|
||||
private AstNode definingNode;
|
||||
private string text;
|
||||
|
||||
Variable() { this = MkVariable(definingNode, text) }
|
||||
|
||||
/** Gets the name of this variable as a string. */
|
||||
string getText() { result = text }
|
||||
|
||||
/** Gets the location of this variable. */
|
||||
Location getLocation() { result = definingNode.getLocation() }
|
||||
|
||||
/** Gets a textual representation of this variable. */
|
||||
string toString() { result = this.getText() }
|
||||
class Variable extends Local {
|
||||
Variable() { variableDecl(this.getDefiningNode(), _, _) }
|
||||
|
||||
/** Gets an access to this variable. */
|
||||
VariableAccess getAnAccess() { result.getVariable() = this }
|
||||
|
||||
/** Gets the name of this variable. */
|
||||
string getText() { result = super.getName() }
|
||||
|
||||
/**
|
||||
* Get the name of this variable.
|
||||
*
|
||||
* Normally, the name is unique, except when introduced in an or pattern.
|
||||
*/
|
||||
Name getName() { variableDecl(definingNode, result, text) }
|
||||
Name getName() { variableDecl(this.getDefiningNode(), result, super.getName()) }
|
||||
|
||||
/** Gets the block that encloses this variable, if any. */
|
||||
BlockExpr getEnclosingBlock() { result = definingNode.getEnclosingBlock() }
|
||||
BlockExpr getEnclosingBlock() { result = this.getDefiningNode().getEnclosingBlock() }
|
||||
|
||||
/** Gets the `self` parameter that declares this variable, if any. */
|
||||
SelfParam getSelfParam() { result.getName() = this.getName() }
|
||||
@@ -173,12 +285,20 @@ module Impl {
|
||||
IdentPat getPat() { result.getName() = this.getName() }
|
||||
|
||||
/** Gets the enclosing CFG scope for this variable declaration. */
|
||||
CfgScope getEnclosingCfgScope() { result = definingNode.getEnclosingCfgScope() }
|
||||
CfgScope getEnclosingCfgScope() { result = this.getDefiningNode().getEnclosingCfgScope() }
|
||||
|
||||
/** Gets the `let` statement that introduces this variable, if any. */
|
||||
/**
|
||||
* Gets the `let` statement that introduces this variable, if any.
|
||||
*
|
||||
* This is restricted to simple `let` statements of the form `let x = ...;`.
|
||||
*/
|
||||
LetStmt getLetStmt() { this.getPat() = result.getPat() }
|
||||
|
||||
/** Gets the `let` expression that introduces this variable, if any. */
|
||||
/**
|
||||
* Gets the `let` expression that introduces this variable, if any.
|
||||
*
|
||||
* This is restricted to simple `let` expressions of the form `let x = ...`.
|
||||
*/
|
||||
LetExpr getLetExpr() { this.getPat() = result.getPat() }
|
||||
|
||||
/** Gets the initial value of this variable, if any. */
|
||||
@@ -193,10 +313,10 @@ module Impl {
|
||||
/** Gets the parameter that introduces this variable, if any. */
|
||||
cached
|
||||
ParamBase getParameter() {
|
||||
Cached::ref() and
|
||||
CachedStage::ref() and
|
||||
result = this.getSelfParam()
|
||||
or
|
||||
result.(Param).getPat() = getAVariablePatAncestor(this)
|
||||
result.(Param).getPat() = getAPatAncestor*(this.getPat())
|
||||
}
|
||||
|
||||
/** Hold is this variable is mutable. */
|
||||
@@ -206,474 +326,17 @@ module Impl {
|
||||
predicate isImmutable() { not this.isMutable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A path expression that may access a local variable. These are paths that
|
||||
* only consist of a simple name (i.e., without generic arguments,
|
||||
* qualifiers, etc.).
|
||||
*/
|
||||
private class VariableAccessCand extends PathExprBase {
|
||||
string name_;
|
||||
|
||||
VariableAccessCand() {
|
||||
name_ = this.(PathExpr).getPath().(PathImpl::IdentPath).getName()
|
||||
or
|
||||
this.(FormatTemplateVariableAccess).getName() = name_
|
||||
}
|
||||
|
||||
string toString() { result = name_ }
|
||||
|
||||
string getName() { result = name_ }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Element getImmediateChildAdj(Element e, int preOrd, int index) {
|
||||
result = ParentChild::getImmediateChild(e, index) and
|
||||
preOrd = 0 and
|
||||
not exists(ConditionScope cs |
|
||||
e = cs.getParent() and
|
||||
result = cs.getBody()
|
||||
)
|
||||
or
|
||||
result = e.(ConditionScope).getBody() and
|
||||
preOrd = 1 and
|
||||
index = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* An adjusted version of `ParentChild::getImmediateChild`, which makes the following
|
||||
* two adjustments:
|
||||
*
|
||||
* 1. For conditions like `if cond body`, instead of letting `body` be the second child
|
||||
* of `if`, we make it the last child of `cond`. This ensures that variables
|
||||
* introduced in the `cond` scope are available in `body`.
|
||||
*
|
||||
* 2. A similar adjustment is made for `while` loops: the body of the loop is made a
|
||||
* child of the loop condition instead of the loop itself.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private Element getImmediateChildAdj(Element e, int index) {
|
||||
result =
|
||||
rank[index + 1](Element res, int preOrd, int i |
|
||||
res = getImmediateChildAdj(e, preOrd, i)
|
||||
|
|
||||
res order by preOrd, i
|
||||
)
|
||||
}
|
||||
|
||||
private Element getImmediateParentAdj(Element e) { e = getImmediateChildAdj(result, _) }
|
||||
|
||||
private AstNode getAnAncestorInVariableScope(AstNode n) {
|
||||
(
|
||||
n instanceof Pat or
|
||||
n instanceof VariableAccessCand or
|
||||
n instanceof LetStmt or
|
||||
n = any(LetExpr le).getScrutinee() or
|
||||
n instanceof VariableScope
|
||||
) and
|
||||
exists(AstNode n0 |
|
||||
result = getImmediateParentAdj(n0) or
|
||||
result = n0.(FormatTemplateVariableAccess).getArgument().getParent().getParent()
|
||||
|
|
||||
n0 = n
|
||||
or
|
||||
n0 = getAnAncestorInVariableScope(n) and
|
||||
not n0 instanceof VariableScope
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the immediately enclosing variable scope of `n`. */
|
||||
private VariableScope getEnclosingScope(AstNode n) { result = getAnAncestorInVariableScope(n) }
|
||||
|
||||
/**
|
||||
* Get all the pattern ancestors of this variable up to an including the
|
||||
* root of the pattern.
|
||||
*/
|
||||
private Pat getAVariablePatAncestor(Variable v) {
|
||||
result = v.getPat()
|
||||
or
|
||||
exists(Pat mid |
|
||||
mid = getAVariablePatAncestor(v) and
|
||||
result = mid.getParentPat()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a parameter declares the variable `v` inside variable scope `scope`.
|
||||
*/
|
||||
private predicate parameterDeclInScope(Variable v, VariableScope scope) {
|
||||
exists(Callable f |
|
||||
v.getParameter() = f.getParamList().getAParamBase() and
|
||||
scope = f.getBody()
|
||||
)
|
||||
}
|
||||
|
||||
/** A subset of `Element`s for which we want to compute pre-order numbers. */
|
||||
private class RelevantElement extends Element {
|
||||
RelevantElement() {
|
||||
this instanceof VariableScope or
|
||||
this instanceof VariableAccessCand or
|
||||
this instanceof LetStmt or
|
||||
this = any(LetExpr le).getScrutinee() or
|
||||
getImmediateChildAdj(this, _) instanceof RelevantElement
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private RelevantElement getChild(int index) { result = getImmediateChildAdj(this, index) }
|
||||
|
||||
pragma[nomagic]
|
||||
private RelevantElement getImmediateChildAdjMin(int index) {
|
||||
// A child may have multiple positions for different accessors,
|
||||
// so always use the first
|
||||
result = this.getChild(index) and
|
||||
index = min(int i | result = this.getChild(i) | i)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
RelevantElement getImmediateChildAdj(int index) {
|
||||
result =
|
||||
rank[index + 1](Element res, int i | res = this.getImmediateChildAdjMin(i) | res order by i)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
RelevantElement getImmediateLastChild() {
|
||||
exists(int last |
|
||||
result = this.getImmediateChildAdj(last) and
|
||||
not exists(this.getImmediateChildAdj(last + 1))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pre-order numbering of `n`, where the immediately enclosing
|
||||
* variable scope of `n` is `scope`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private int getPreOrderNumbering(VariableScope scope, RelevantElement n) {
|
||||
n = scope and
|
||||
result = 0
|
||||
or
|
||||
exists(RelevantElement parent |
|
||||
not parent instanceof VariableScope
|
||||
or
|
||||
parent = scope
|
||||
|
|
||||
// first child of a previously numbered node
|
||||
result = getPreOrderNumbering(scope, parent) + 1 and
|
||||
n = parent.getImmediateChildAdj(0)
|
||||
or
|
||||
// non-first child of a previously numbered node
|
||||
exists(RelevantElement child, int i |
|
||||
result = getLastPreOrderNumbering(scope, child) + 1 and
|
||||
child = parent.getImmediateChildAdj(i) and
|
||||
n = parent.getImmediateChildAdj(i + 1)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pre-order numbering of the _last_ node nested under `n`, where the
|
||||
* immediately enclosing variable scope of `n` (and the last node) is `scope`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private int getLastPreOrderNumbering(VariableScope scope, RelevantElement n) {
|
||||
exists(RelevantElement leaf |
|
||||
result = getPreOrderNumbering(scope, leaf) and
|
||||
leaf != scope and
|
||||
(
|
||||
not exists(leaf.getImmediateChildAdj(_))
|
||||
or
|
||||
leaf instanceof VariableScope
|
||||
)
|
||||
|
|
||||
n = leaf
|
||||
or
|
||||
n.getImmediateLastChild() = leaf and
|
||||
not n instanceof VariableScope
|
||||
)
|
||||
or
|
||||
exists(RelevantElement mid |
|
||||
mid = n.getImmediateLastChild() and
|
||||
result = getLastPreOrderNumbering(scope, mid) and
|
||||
not mid instanceof VariableScope and
|
||||
not n instanceof VariableScope
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is named `name` and is declared inside variable scope
|
||||
* `scope`. The pre-order numbering of the binding site of `v`, amongst
|
||||
* all nodes nested under `scope`, is `ord`.
|
||||
*/
|
||||
private predicate variableDeclInScope(Variable v, VariableScope scope, string name, int ord) {
|
||||
name = v.getText() and
|
||||
(
|
||||
parameterDeclInScope(v, scope) and
|
||||
ord = getPreOrderNumbering(scope, scope)
|
||||
or
|
||||
exists(Pat pat | pat = getAVariablePatAncestor(v) |
|
||||
exists(MatchArm arm |
|
||||
pat = arm.getPat() and
|
||||
ord = getPreOrderNumbering(scope, scope)
|
||||
|
|
||||
scope = arm.getGuard()
|
||||
or
|
||||
not arm.hasGuard() and scope = arm.getExpr()
|
||||
)
|
||||
or
|
||||
exists(LetStmt let |
|
||||
let.getPat() = pat and
|
||||
scope = getEnclosingScope(let) and
|
||||
// for `let` statements, variables are bound _after_ the statement, i.e.
|
||||
// not in the RHS
|
||||
ord = getLastPreOrderNumbering(scope, let) + 1
|
||||
)
|
||||
or
|
||||
exists(LetExpr let, Expr scrutinee |
|
||||
let.getPat() = pat and
|
||||
scrutinee = let.getScrutinee() and
|
||||
scope = getEnclosingScope(scrutinee) and
|
||||
// for `let` expressions, variables are bound _after_ the expression, i.e.
|
||||
// not in the RHS
|
||||
ord = getLastPreOrderNumbering(scope, scrutinee) + 1
|
||||
)
|
||||
or
|
||||
exists(ForExpr fe |
|
||||
fe.getPat() = pat and
|
||||
scope = fe.getLoopBody() and
|
||||
ord = getPreOrderNumbering(scope, scope)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cand` may access a variable named `name` at pre-order number `ord`
|
||||
* in the variable scope `scope`.
|
||||
*
|
||||
* `nestLevel` is the number of nested scopes that need to be traversed
|
||||
* to reach `scope` from `cand`.
|
||||
*/
|
||||
private predicate variableAccessCandInScope(
|
||||
VariableAccessCand cand, VariableScope scope, string name, int nestLevel, int ord
|
||||
) {
|
||||
name = cand.getName() and
|
||||
(
|
||||
scope = cand
|
||||
or
|
||||
not cand instanceof VariableScope and
|
||||
scope = getEnclosingScope(cand)
|
||||
) and
|
||||
ord = getPreOrderNumbering(scope, cand) and
|
||||
nestLevel = 0
|
||||
or
|
||||
exists(VariableScope inner |
|
||||
variableAccessCandInScope(cand, inner, name, nestLevel - 1, _) and
|
||||
scope = getEnclosingScope(inner) and
|
||||
// Use the pre-order number of the inner scope as the number of the access. This allows
|
||||
// us to collapse multiple accesses in inner scopes to a single entity
|
||||
ord = getPreOrderNumbering(scope, inner)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TDefOrAccessCand =
|
||||
TDefOrAccessCandNestedFunction(Function f, BlockExprScope scope) {
|
||||
f = scope.getStmtList().getAStatement()
|
||||
} or
|
||||
TDefOrAccessCandVariable(Variable v) or
|
||||
TDefOrAccessCandVariableAccessCand(VariableAccessCand va)
|
||||
|
||||
/**
|
||||
* A nested function declaration, variable declaration, or variable (or function)
|
||||
* access candidate.
|
||||
*
|
||||
* In order to determine whether a candidate is an actual variable/function access,
|
||||
* we rank declarations and candidates by their position in the AST.
|
||||
*
|
||||
* The ranking must take names into account, but also variable scopes; below a comment
|
||||
* `rank(scope, name, i)` means that the declaration/access on the given line has rank
|
||||
* `i` amongst all declarations/accesses inside variable scope `scope`, for name `name`:
|
||||
*
|
||||
* ```rust
|
||||
* fn f() { // scope0
|
||||
* let x = 0; // rank(scope0, "x", 0)
|
||||
* use(x); // rank(scope0, "x", 1)
|
||||
* let x = // rank(scope0, "x", 3)
|
||||
* x + 1; // rank(scope0, "x", 2)
|
||||
* let y = // rank(scope0, "y", 0)
|
||||
* x; // rank(scope0, "x", 4)
|
||||
*
|
||||
* { // scope1
|
||||
* use(x); // rank(scope1, "x", 0), rank(scope0, "x", 4)
|
||||
* use(y); // rank(scope1, "y", 0), rank(scope0, "y", 1)
|
||||
* let x = 2; // rank(scope1, "x", 1)
|
||||
* use(x); // rank(scope1, "x", 2), rank(scope0, "x", 4)
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Function/variable declarations are only ranked in the scope that they bind into,
|
||||
* while accesses candidates propagate outwards through scopes, as they may access
|
||||
* declarations from outer scopes.
|
||||
*
|
||||
* For an access candidate with ranks `{ rank(scope_i, name, rnk_i) | i in I }` and
|
||||
* declarations `d in D` with ranks `rnk(scope_d, name, rnk_d)`, the target is
|
||||
* calculated as
|
||||
* ```
|
||||
* max_{i in I} (
|
||||
* max_{d in D | scope_d = scope_i and rnk_d < rnk_i} (
|
||||
* d
|
||||
* )
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
* i.e., its the nearest declaration before the access in the same (or outer) scope
|
||||
* as the access.
|
||||
*/
|
||||
abstract private class DefOrAccessCand extends TDefOrAccessCand {
|
||||
abstract string toString();
|
||||
|
||||
abstract Location getLocation();
|
||||
|
||||
pragma[nomagic]
|
||||
abstract predicate rankBy(string name, VariableScope scope, int ord, int kind);
|
||||
}
|
||||
|
||||
abstract private class NestedFunctionOrVariable extends DefOrAccessCand { }
|
||||
|
||||
private class DefOrAccessCandNestedFunction extends NestedFunctionOrVariable,
|
||||
TDefOrAccessCandNestedFunction
|
||||
{
|
||||
private Function f;
|
||||
private BlockExprScope scope_;
|
||||
|
||||
DefOrAccessCandNestedFunction() { this = TDefOrAccessCandNestedFunction(f, scope_) }
|
||||
|
||||
override string toString() { result = f.toString() }
|
||||
|
||||
override Location getLocation() { result = f.getLocation() }
|
||||
|
||||
override predicate rankBy(string name, VariableScope scope, int ord, int kind) {
|
||||
// nested functions behave as if they are defined at the beginning of the scope
|
||||
name = f.getName().getText() and
|
||||
scope = scope_ and
|
||||
ord = 0 and
|
||||
kind = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class DefOrAccessCandVariable extends NestedFunctionOrVariable, TDefOrAccessCandVariable {
|
||||
private Variable v;
|
||||
|
||||
DefOrAccessCandVariable() { this = TDefOrAccessCandVariable(v) }
|
||||
|
||||
override string toString() { result = v.toString() }
|
||||
|
||||
override Location getLocation() { result = v.getLocation() }
|
||||
|
||||
override predicate rankBy(string name, VariableScope scope, int ord, int kind) {
|
||||
variableDeclInScope(v, scope, name, ord) and
|
||||
kind = 1
|
||||
}
|
||||
}
|
||||
|
||||
private class DefOrAccessCandVariableAccessCand extends DefOrAccessCand,
|
||||
TDefOrAccessCandVariableAccessCand
|
||||
{
|
||||
private VariableAccessCand va;
|
||||
|
||||
DefOrAccessCandVariableAccessCand() { this = TDefOrAccessCandVariableAccessCand(va) }
|
||||
|
||||
override string toString() { result = va.toString() }
|
||||
|
||||
override Location getLocation() { result = va.getLocation() }
|
||||
|
||||
override predicate rankBy(string name, VariableScope scope, int ord, int kind) {
|
||||
variableAccessCandInScope(va, scope, name, _, ord) and
|
||||
kind = 2
|
||||
}
|
||||
}
|
||||
|
||||
private module DenseRankInput implements DenseRankInputSig2 {
|
||||
class C1 = VariableScope;
|
||||
|
||||
class C2 = string;
|
||||
|
||||
class Ranked = DefOrAccessCand;
|
||||
|
||||
int getRank(VariableScope scope, string name, DefOrAccessCand v) {
|
||||
v =
|
||||
rank[result](DefOrAccessCand v0, int ord, int kind |
|
||||
v0.rankBy(name, scope, ord, kind)
|
||||
|
|
||||
v0 order by ord, kind
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rank of `v` amongst all other declarations or access candidates
|
||||
* to a variable named `name` in the variable scope `scope`.
|
||||
*/
|
||||
private int rankVariableOrAccess(VariableScope scope, string name, DefOrAccessCand v) {
|
||||
v = DenseRank2<DenseRankInput>::denseRank(scope, name, result + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` can reach rank `rnk` in the variable scope `scope`. This is needed to
|
||||
* take shadowing into account, for example in
|
||||
*
|
||||
* ```rust
|
||||
* let x = 0; // rank 0
|
||||
* use(x); // rank 1
|
||||
* let x = ""; // rank 2
|
||||
* use(x); // rank 3
|
||||
* ```
|
||||
*
|
||||
* the declaration at rank 0 can only reach the access at rank 1, while the declaration
|
||||
* at rank 2 can only reach the access at rank 3.
|
||||
*/
|
||||
private predicate variableReachesRank(
|
||||
VariableScope scope, string name, NestedFunctionOrVariable v, int rnk
|
||||
) {
|
||||
rnk = rankVariableOrAccess(scope, name, v)
|
||||
or
|
||||
variableReachesRank(scope, name, v, rnk - 1) and
|
||||
rnk = rankVariableOrAccess(scope, name, TDefOrAccessCandVariableAccessCand(_))
|
||||
}
|
||||
|
||||
private predicate variableReachesCand(
|
||||
VariableScope scope, string name, NestedFunctionOrVariable v, VariableAccessCand cand,
|
||||
int nestLevel
|
||||
) {
|
||||
exists(int rnk |
|
||||
variableReachesRank(scope, name, v, rnk) and
|
||||
rnk = rankVariableOrAccess(scope, name, TDefOrAccessCandVariableAccessCand(cand)) and
|
||||
variableAccessCandInScope(cand, scope, name, nestLevel, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate access(string name, NestedFunctionOrVariable v, VariableAccessCand cand) {
|
||||
v =
|
||||
min(NestedFunctionOrVariable v0, int nestLevel |
|
||||
variableReachesCand(_, name, v0, cand, nestLevel)
|
||||
|
|
||||
v0 order by nestLevel
|
||||
)
|
||||
}
|
||||
|
||||
/** A variable access. */
|
||||
class VariableAccess extends PathExprBase {
|
||||
private string name;
|
||||
private Variable v;
|
||||
|
||||
VariableAccess() { variableAccess(name, v, this) }
|
||||
class VariableAccess extends LocalAccess {
|
||||
VariableAccess() { this.getLocal() instanceof Variable }
|
||||
|
||||
/** Gets the variable being accessed. */
|
||||
Variable getVariable() { result = v }
|
||||
Variable getVariable() { result = super.getLocal() }
|
||||
|
||||
/** Holds if this access is a capture. */
|
||||
predicate isCapture() { this.getEnclosingCfgScope() != v.getEnclosingCfgScope() }
|
||||
predicate isCapture() {
|
||||
this.getEnclosingCfgScope() != this.getVariable().getEnclosingCfgScope()
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `e` occurs in the LHS of an assignment operation. */
|
||||
@@ -682,7 +345,7 @@ module Impl {
|
||||
or
|
||||
exists(Expr mid |
|
||||
assignmentOperationDescendant(ao, mid) and
|
||||
getImmediateParentAdj(e) = mid and
|
||||
mid = e.getParentNode() and
|
||||
not mid instanceof DerefExpr and
|
||||
not mid instanceof FieldExpr and
|
||||
not mid instanceof IndexExpr
|
||||
@@ -695,7 +358,7 @@ module Impl {
|
||||
|
||||
cached
|
||||
VariableWriteAccess() {
|
||||
Cached::ref() and
|
||||
CachedStage::ref() and
|
||||
assignmentOperationDescendant(ae, this)
|
||||
}
|
||||
|
||||
@@ -707,7 +370,7 @@ module Impl {
|
||||
class VariableReadAccess extends VariableAccess {
|
||||
cached
|
||||
VariableReadAccess() {
|
||||
Cached::ref() and
|
||||
CachedStage::ref() and
|
||||
not this instanceof VariableWriteAccess and
|
||||
not this = any(RefExpr re).getExpr() and
|
||||
not this = any(CompoundAssignmentExpr cae).getLhs()
|
||||
@@ -715,47 +378,10 @@ module Impl {
|
||||
}
|
||||
|
||||
/** A nested function access. */
|
||||
class NestedFunctionAccess extends PathExprBase {
|
||||
class NestedFunctionAccess extends LocalAccess {
|
||||
private Function f;
|
||||
|
||||
NestedFunctionAccess() { nestedFunctionAccess(_, f, this) }
|
||||
|
||||
/** Gets the function being accessed. */
|
||||
Function getFunction() { result = f }
|
||||
Function getFunction() { result = super.getLocal().getDefiningNode() }
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
predicate ref() { 1 = 1 }
|
||||
|
||||
cached
|
||||
predicate backref() {
|
||||
1 = 1
|
||||
or
|
||||
variableDecl(_, _, _)
|
||||
or
|
||||
exists(VariableReadAccess a)
|
||||
or
|
||||
exists(VariableWriteAccess a)
|
||||
or
|
||||
exists(any(Variable v).getParameter())
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TVariable =
|
||||
MkVariable(AstNode definingNode, string name) { variableDecl(definingNode, _, name) }
|
||||
|
||||
cached
|
||||
predicate variableAccess(string name, Variable v, VariableAccessCand cand) {
|
||||
access(name, TDefOrAccessCandVariable(v), cand)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate nestedFunctionAccess(string name, Function f, VariableAccessCand cand) {
|
||||
access(name, TDefOrAccessCandNestedFunction(f, _), cand)
|
||||
}
|
||||
}
|
||||
|
||||
private import Cached
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ dependencies:
|
||||
codeql/tutorial: ${workspace}
|
||||
codeql/typeinference: ${workspace}
|
||||
codeql/util: ${workspace}
|
||||
codeql/namebinding: ${workspace}
|
||||
dataExtensions:
|
||||
- /**/*.model.yml
|
||||
warnOnImplicitThis: true
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -110,11 +110,46 @@ fn let_pattern4() {
|
||||
}
|
||||
|
||||
fn let_pattern5() {
|
||||
let s1 = Some(String::from("Hello!")); // s1
|
||||
let s = Some(String::from("Hello!")); // s1
|
||||
|
||||
while let Some(ref s2) // s2
|
||||
= s1 { // $ read_access=s1
|
||||
print_str(s2); // $ read_access=s2
|
||||
while let Some(ref s) // s2
|
||||
= s { // $ read_access=s1
|
||||
print_str(s); // $ read_access=s2
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn let_pattern6() {
|
||||
if let Some(x) = Some(43) // x1
|
||||
&& let Ok(x) = // x2
|
||||
Ok::<_, ()>(x) // $ read_access=x1
|
||||
{
|
||||
print_i64(x); // $ read_access=x2
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn let_pattern7() {
|
||||
let x = 1; // x1
|
||||
if let x = // x2
|
||||
x + 1 // $ read_access=x1
|
||||
&& let x = // x3
|
||||
x + 1 // $ read_access=x2
|
||||
&& let x = // x4
|
||||
x + 1 // $ read_access=x3
|
||||
&& let x = // x5
|
||||
x + 1 // $ read_access=x4
|
||||
&& let x = // x6
|
||||
x + 1 // $ read_access=x5
|
||||
&& let x = // x7
|
||||
x + 1 // $ read_access=x6
|
||||
&& let x = // x8
|
||||
x + 1 // $ read_access=x7
|
||||
{
|
||||
print_i64(x); // $ read_access=x8
|
||||
}
|
||||
else {
|
||||
print_i64(x); // $ read_access=x1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,7 +408,8 @@ fn match_pattern16() {
|
||||
let x = Some(32);
|
||||
match x { // $ read_access=x
|
||||
Some(y) // y1
|
||||
if let Some(y) = // y2
|
||||
if y > 0 && // $ read_access=y1
|
||||
let Some(y) = // y2
|
||||
Some(y) // $ read_access=y1
|
||||
=> print_i64(y), // $ read_access=y2
|
||||
_ => {},
|
||||
@@ -798,6 +834,18 @@ mod patterns {
|
||||
}
|
||||
}
|
||||
|
||||
fn let_in_block_in_cond() {
|
||||
let x = 1; // x1
|
||||
if {
|
||||
let x = 1; // x2
|
||||
x > 0 // $ read_access=x2
|
||||
} {
|
||||
print_i64(x); // $ read_access=x1
|
||||
} else {
|
||||
print_i64(x); // $ read_access=x1
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
immutable_variable();
|
||||
mutable_variable();
|
||||
@@ -808,6 +856,8 @@ fn main() {
|
||||
let_pattern2();
|
||||
let_pattern3();
|
||||
let_pattern4();
|
||||
let_pattern5();
|
||||
let_pattern6();
|
||||
match_pattern1();
|
||||
match_pattern2();
|
||||
match_pattern3();
|
||||
@@ -842,4 +892,5 @@ fn main() {
|
||||
ref_methodcall_receiver();
|
||||
macro_invocation();
|
||||
capture_phi();
|
||||
let_in_block_in_cond();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
450
shared/namebinding/codeql/namebinding/LocalNameBinding.qll
Normal file
450
shared/namebinding/codeql/namebinding/LocalNameBinding.qll
Normal file
@@ -0,0 +1,450 @@
|
||||
/**
|
||||
* Provides a library for resolving local names based on syntactic scopes, including
|
||||
* handling of shadowing sibling declarations.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import codeql.util.DenseRank
|
||||
private import codeql.util.Location
|
||||
|
||||
/** Provides the input to `LocalNameBinding`. */
|
||||
signature module LocalNameBindingInputSig<LocationSig Location> {
|
||||
/**
|
||||
* Reverse references to the cached predicates that reference
|
||||
* `CachedStage::ref()`.
|
||||
*/
|
||||
default predicate cacheRevRef() { none() }
|
||||
|
||||
/** An AST node. */
|
||||
class AstNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString();
|
||||
|
||||
/** Gets the location of this element. */
|
||||
Location getLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the child of AST node `n` at the specified index.
|
||||
*
|
||||
* The order of the children is only relevant for determining nearest preceding
|
||||
* shadowing sibling declarations.
|
||||
*/
|
||||
AstNode getChild(AstNode n, int index);
|
||||
|
||||
/**
|
||||
* A conditional where any local declarations in the condition are in scope
|
||||
* in the then-branch but not the else-branch.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```rust
|
||||
* if let Some(x) = opt {
|
||||
* // x is in scope here
|
||||
* } else {
|
||||
* // x is not in scope here
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class Conditional extends AstNode {
|
||||
/** Gets the condition of this conditional. */
|
||||
AstNode getCondition();
|
||||
|
||||
/** Gets the then-branch of this conditional. */
|
||||
AstNode getThen();
|
||||
|
||||
/** Gets the else-branch of this conditional. */
|
||||
AstNode getElse();
|
||||
}
|
||||
|
||||
/**
|
||||
* A declaration where all local declarations in the left-hand side are in
|
||||
* scope _after_ the declaration, and where any sibling declarations with
|
||||
* the same name and syntactic scope preceding it are shadowed.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```rust
|
||||
* fn f() {
|
||||
* let x = 1;
|
||||
* // this declaration of `x` shadows the previous one (in the syntactic scope
|
||||
* // being the body of `f`), but the `x` in the right-hand side still refers
|
||||
* // to the first declaration
|
||||
* let x = x + 1;
|
||||
* // this access of `x` refers to the second declaration
|
||||
* println!("{}", x);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class SiblingShadowingDecl extends AstNode {
|
||||
/** Gets the left-hand side of this declaration. */
|
||||
AstNode getLhs();
|
||||
|
||||
/**
|
||||
* Gets the right-hand side of this declaration.
|
||||
*
|
||||
* Any local declared in the left-hand side of this declaration is _not_ in scope
|
||||
* in the right-hand side.
|
||||
*/
|
||||
AstNode getRhs();
|
||||
|
||||
/**
|
||||
* Gets the else-branch of this declaration, if any.
|
||||
*
|
||||
* Any local declared in the left-hand side of this declaration is _not_ in scope
|
||||
* in the else-branch.
|
||||
*/
|
||||
AstNode getElse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a local declaration named `name` exists at `definingNode` inside
|
||||
* the syntactic scope `scope`.
|
||||
*
|
||||
* Note that declarations with a `definingNode` in the left-hand side of a
|
||||
* shadowing sibling declaration `decl` should use `scope = decl`.
|
||||
*/
|
||||
predicate declInScope(AstNode definingNode, string name, AstNode scope);
|
||||
|
||||
/**
|
||||
* Holds if a local declaration named `name` is implicitly in scope in the given `scope`.
|
||||
*/
|
||||
default predicate implicitDeclInScope(string name, AstNode scope) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `scope` is a top scope, meaning that names may not be looked up
|
||||
* in ancestor scopes.
|
||||
*/
|
||||
default predicate isTopScope(AstNode scope) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `n` is a node that may access a local named `name`.
|
||||
*/
|
||||
predicate accessCand(AstNode n, string name);
|
||||
|
||||
/**
|
||||
* Holds if the access candidate `n` should begin its lookup in `scope` instead
|
||||
* of its immediately enclosing scope.
|
||||
*
|
||||
* For example, the `this` variable in an instance field initializer might need
|
||||
* to be resolved relative to a constructor body.
|
||||
*
|
||||
* If `scope` declares a local with the name of `n`, then `scope` is guaranteed
|
||||
* to be the scope that `n` ultimately resolves to. This can thus be used to take
|
||||
* full control of scope resolution for for specific types of references.
|
||||
*/
|
||||
default predicate lookupStartsAt(AstNode n, AstNode scope) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides logic for resolving local names based on syntactic scopes, including
|
||||
* handling of shadowing sibling declarations.
|
||||
*/
|
||||
module LocalNameBinding<LocationSig Location, LocalNameBindingInputSig<Location> Input> {
|
||||
private import Input
|
||||
|
||||
final private class AstNodeFinal = AstNode;
|
||||
|
||||
private class Scope extends AstNodeFinal {
|
||||
Scope() {
|
||||
declInScope(_, _, this)
|
||||
or
|
||||
implicitDeclInScope(_, this)
|
||||
or
|
||||
isTopScope(this)
|
||||
or
|
||||
lookupStartsAt(_, this)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate conditionHasChildAt(Conditional conditional, AstNode condition, int index) {
|
||||
condition = conditional.getCondition() and
|
||||
(
|
||||
exists(getChild(condition, index))
|
||||
or
|
||||
// safeguard against empty conditions
|
||||
not exists(getChild(condition, _)) and index = 0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An adjusted version of `getChild` from the `Input` module where in conditionals like
|
||||
* `if cond body`, instead of letting `body` be a child of `if`, we make it the last
|
||||
* child of `cond`. This ensures that shadowing sibling declarations inside `cond` are
|
||||
* properly handled inside `body`.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```rust
|
||||
* if let Some(x) = opt && let x = x + 1 {
|
||||
* // the second declaration of `x` is in scope here
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* We also move any `else` branch _before_ the condition to ensure that shadowing sibling
|
||||
* declarations inside the condition are not in scope.
|
||||
*/
|
||||
private AstNode getChildAdj(AstNode parent, int index) {
|
||||
result = getChild(parent, index) and
|
||||
not exists(Conditional cond | result = [cond.getElse(), cond.getThen()])
|
||||
or
|
||||
exists(Conditional cond |
|
||||
parent = cond and
|
||||
result = cond.getElse() and
|
||||
index = -1
|
||||
or
|
||||
exists(int last |
|
||||
result = cond.getThen() and
|
||||
last = max(int i | conditionHasChildAt(cond, parent, i)) and
|
||||
index = last + 1
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private module DenseRankInput implements DenseRankInputSig1 {
|
||||
class C = AstNode;
|
||||
|
||||
class Ranked = AstNode;
|
||||
|
||||
int getRank(C parent, Ranked child) {
|
||||
child = getChildAdj(parent, result) and
|
||||
getChildAdj(parent, _) instanceof SiblingShadowingDecl
|
||||
}
|
||||
}
|
||||
|
||||
private predicate getRankedChild = DenseRank1<DenseRankInput>::denseRank/2;
|
||||
|
||||
/**
|
||||
* Holds if `n` is the `i`th child of `parent`, but should instead be considered
|
||||
* a child of a shadowing sibling declaration `decl` when resolving accesses.
|
||||
*
|
||||
* This is the case when `decl` is the nearest shadowing sibling declaration
|
||||
* preceding `n` amongst all the children of `parent`.
|
||||
*
|
||||
* Note that `decl` may itself also have to be nested under another shadowing
|
||||
* sibling declaration.
|
||||
*/
|
||||
private predicate shouldBeShadowingDeclChild(
|
||||
AstNode parent, SiblingShadowingDecl decl, int i, AstNode n
|
||||
) {
|
||||
n = getRankedChild(parent, i) and
|
||||
(
|
||||
decl = getRankedChild(parent, i - 1)
|
||||
or
|
||||
shouldBeShadowingDeclChild(parent, decl, i - 1,
|
||||
any(AstNode prev | not prev instanceof SiblingShadowingDecl))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the AST parent of `n` with respect to determining enclosing scopes.
|
||||
*
|
||||
* For example, in
|
||||
*
|
||||
* ```rust
|
||||
* let x = 1;
|
||||
* let x = x + 1;
|
||||
* println!("{}", x);
|
||||
* ```
|
||||
*
|
||||
* we will have (eliding leaf nodes)
|
||||
*
|
||||
* ```text
|
||||
* let x = 1;
|
||||
* / \
|
||||
* x + 1 let x = x + 1
|
||||
* |
|
||||
* println!("{}", x);
|
||||
* ```
|
||||
*
|
||||
* and in
|
||||
*
|
||||
* ```rust
|
||||
* if let Some(x) = opt && let x = x + 1 {
|
||||
* println!("{}", x);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* we will have (again eliding leaf nodes)
|
||||
*
|
||||
* ```text
|
||||
* if ...
|
||||
* |
|
||||
* ... && ...
|
||||
* / \
|
||||
* let Some(x) = opt opt
|
||||
* / \
|
||||
* let x = x + 1 x + 1
|
||||
* |
|
||||
* println!("{}", x);
|
||||
* ```
|
||||
*/
|
||||
private AstNode getParentForScoping(AstNode n) {
|
||||
not shouldBeShadowingDeclChild(_, _, _, n) and
|
||||
not exists(SiblingShadowingDecl decl | n = [decl.getRhs(), decl.getElse()]) and
|
||||
n = getChildAdj(result, _)
|
||||
or
|
||||
shouldBeShadowingDeclChild(_, result, _, n)
|
||||
or
|
||||
exists(SiblingShadowingDecl decl |
|
||||
result = getParentForScoping(decl) and
|
||||
n = [decl.getRhs(), decl.getElse()]
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the immediately enclosing variable scope of `n`. */
|
||||
private Scope getEnclosingScope(AstNode n) {
|
||||
result = getParentForScoping(n)
|
||||
or
|
||||
exists(AstNode mid |
|
||||
result = getEnclosingScope(mid) and
|
||||
mid = getParentForScoping(n) and
|
||||
not mid instanceof Scope
|
||||
)
|
||||
}
|
||||
|
||||
private predicate accessCandInLookupScope(AstNode n, string name, Scope lookup) {
|
||||
accessCand(n, name) and
|
||||
(
|
||||
lookupStartsAt(n, lookup)
|
||||
or
|
||||
not lookupStartsAt(n, _) and
|
||||
lookup = getEnclosingScope(n)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate lookupInScope(string name, Scope lookup, Scope scope) {
|
||||
accessCandInLookupScope(_, name, lookup) and
|
||||
scope = lookup
|
||||
or
|
||||
exists(Scope mid |
|
||||
lookupInScope(name, lookup, mid) and
|
||||
not declInScope(_, name, mid) and
|
||||
not implicitDeclInScope(name, mid) and
|
||||
not isTopScope(mid) and
|
||||
scope = getEnclosingScope(mid)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TLocal =
|
||||
TExplicitLocal(AstNode definingNode, string name, AstNode scope) {
|
||||
CachedStage::ref() and
|
||||
declInScope(definingNode, name, scope)
|
||||
} or
|
||||
TImplicitLocal(string name, AstNode scope) { implicitDeclInScope(name, scope) }
|
||||
|
||||
/** A locally declared entity, for example a variable or a parameter. */
|
||||
abstract private class LocalImpl extends TLocal {
|
||||
/** Gets the AST node that defines this local entity, if any. */
|
||||
abstract AstNode getDefiningNode();
|
||||
|
||||
/** Gets the AST node that defines the scope of this local entity. */
|
||||
abstract AstNode getScope();
|
||||
|
||||
/** Gets the name of this local entity. */
|
||||
abstract string getName();
|
||||
|
||||
/** Gets the location of this local entity. */
|
||||
abstract Location getLocation();
|
||||
|
||||
/** Gets an access to this local entity. */
|
||||
LocalAccess getAnAccess() { result.getLocal() = this }
|
||||
|
||||
/** Gets a textual representation of this local entity. */
|
||||
string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
final class Local = LocalImpl;
|
||||
|
||||
/** An explicitly locally declared entity, for example a variable or a parameter. */
|
||||
class ExplicitLocal extends LocalImpl, TExplicitLocal {
|
||||
private AstNode definingNode;
|
||||
private string name;
|
||||
private AstNode scope;
|
||||
|
||||
ExplicitLocal() { this = TExplicitLocal(definingNode, name, scope) }
|
||||
|
||||
override AstNode getDefiningNode() { result = definingNode }
|
||||
|
||||
override AstNode getScope() { result = scope }
|
||||
|
||||
override string getName() { result = name }
|
||||
|
||||
override Location getLocation() { result = definingNode.getLocation() }
|
||||
}
|
||||
|
||||
/** An implicitly locally declared entity, for example a `self` parameter. */
|
||||
class ImplicitLocal extends LocalImpl, TImplicitLocal {
|
||||
private string name;
|
||||
private AstNode scope;
|
||||
|
||||
ImplicitLocal() { this = TImplicitLocal(name, scope) }
|
||||
|
||||
override AstNode getDefiningNode() { none() }
|
||||
|
||||
override AstNode getScope() { result = scope }
|
||||
|
||||
override string getName() { result = name }
|
||||
|
||||
override Location getLocation() { result = scope.getLocation() }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate resolveInScope(string name, Scope lookup, Local l) {
|
||||
exists(Scope scope | lookupInScope(name, lookup, scope) |
|
||||
l = TExplicitLocal(_, name, scope) or
|
||||
l = TImplicitLocal(name, scope)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
private predicate access(AstNode access, Local l) {
|
||||
CachedStage::ref() and
|
||||
exists(Scope lookup, string name |
|
||||
accessCandInLookupScope(access, name, lookup) and
|
||||
resolveInScope(name, lookup, l)
|
||||
)
|
||||
}
|
||||
|
||||
/** A local access. */
|
||||
final class LocalAccess extends AstNodeFinal {
|
||||
private Local l;
|
||||
|
||||
LocalAccess() { access(this, l) }
|
||||
|
||||
/** Gets the local entity being accessed. */
|
||||
Local getLocal() { result = l }
|
||||
}
|
||||
|
||||
/**
|
||||
* The cached stage of this module.
|
||||
*
|
||||
* Should not be exposed.
|
||||
*/
|
||||
cached
|
||||
module CachedStage {
|
||||
/** Reference to the cached stage of this module. */
|
||||
cached
|
||||
predicate ref() { any() }
|
||||
|
||||
/**
|
||||
* DO NOT USE!
|
||||
*
|
||||
* Reverse references to the cached predicates that reference `ref()`.
|
||||
*/
|
||||
cached
|
||||
predicate revRef() {
|
||||
any()
|
||||
or
|
||||
cacheRevRef()
|
||||
or
|
||||
(exists(Local l) implies any())
|
||||
or
|
||||
(exists(LocalAccess a) implies any())
|
||||
}
|
||||
}
|
||||
}
|
||||
7
shared/namebinding/qlpack.yml
Normal file
7
shared/namebinding/qlpack.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
name: codeql/namebinding
|
||||
version: 0.0.1-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
codeql/util: ${workspace}
|
||||
warnOnImplicitThis: true
|
||||
Reference in New Issue
Block a user