mirror of
https://github.com/github/codeql.git
synced 2026-05-04 21:25:44 +02:00
Support synthesis of blocks (without a new variable scope)
This commit is contained in:
@@ -226,3 +226,22 @@ class BraceBlock extends Block, TBraceBlock {
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "BraceBlock" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A synthesized block, such as the block synthesized from the body of
|
||||
* a `for` loop.
|
||||
*/
|
||||
class SynthBlock extends Block, TBlockSynth {
|
||||
SynthBlock() { this = TBlockSynth(_, _) }
|
||||
|
||||
final override Parameter getParameter(int n) { synthChild(this, n, result) }
|
||||
|
||||
final override Stmt getStmt(int i) {
|
||||
i >= 0 and
|
||||
synthChild(this, i + this.getNumberOfParameters(), result)
|
||||
}
|
||||
|
||||
final override string toString() { result = "{ ... }" }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "SynthBlock" }
|
||||
}
|
||||
|
||||
@@ -3,22 +3,12 @@ private import internal.AST
|
||||
private import internal.Scope
|
||||
private import internal.TreeSitter
|
||||
|
||||
class Scope extends AstNode, TScopeType {
|
||||
private Scope::Range range;
|
||||
class Scope extends AstNode, TScopeType instanceof ScopeImpl {
|
||||
Scope getOuterScope() { result = super.getOuterScopeImpl() }
|
||||
|
||||
Scope() { range = toGenerated(this) }
|
||||
Variable getAVariable() { result = super.getAVariableImpl() }
|
||||
|
||||
/** Gets the scope in which this scope is nested, if any. */
|
||||
Scope getOuterScope() { toGenerated(result) = range.getOuterScope() }
|
||||
|
||||
/** Gets a variable that is declared in this scope. */
|
||||
final Variable getAVariable() { result.getDeclaringScope() = this }
|
||||
|
||||
/** Gets the variable declared in this scope with the given name, if any. */
|
||||
final Variable getVariable(string name) {
|
||||
result = this.getAVariable() and
|
||||
result.getName() = name
|
||||
}
|
||||
Variable getVariable(string name) { result = super.getVariableImpl(name) }
|
||||
}
|
||||
|
||||
class SelfScope extends Scope, TSelfScopeType { }
|
||||
|
||||
@@ -93,6 +93,7 @@ private module Cached {
|
||||
} or
|
||||
TBlockArgument(Ruby::BlockArgument g) or
|
||||
TBlockParameter(Ruby::BlockParameter g) or
|
||||
TBlockSynth(AST::AstNode parent, int i) { mkSynthChild(BlockKind(), parent, i) } or
|
||||
TBraceBlock(Ruby::Block g) { not g.getParent() instanceof Ruby::Lambda } or
|
||||
TBreakStmt(Ruby::Break g) or
|
||||
TCaseEqExpr(Ruby::Binary g) { g instanceof @ruby_binary_equalequalequal } or
|
||||
@@ -491,6 +492,8 @@ private module Cached {
|
||||
or
|
||||
result = TBitwiseXorExprSynth(parent, i)
|
||||
or
|
||||
result = TBlockSynth(parent, i)
|
||||
or
|
||||
result = TClassVariableAccessSynth(parent, i, _)
|
||||
or
|
||||
result = TConstantReadAccessSynth(parent, i, _)
|
||||
@@ -644,7 +647,7 @@ class TCallable = TMethodBase or TLambda or TBlock;
|
||||
|
||||
class TMethodBase = TMethod or TSingletonMethod;
|
||||
|
||||
class TBlock = TDoBlock or TBraceBlock;
|
||||
class TBlock = TDoBlock or TBraceBlock or TBlockSynth;
|
||||
|
||||
class TModuleBase = TToplevel or TNamespace or TSingletonClass;
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
private import TreeSitter
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.ast.Scope
|
||||
private import codeql.ruby.ast.internal.AST
|
||||
private import codeql.ruby.ast.internal.Parameter
|
||||
private import codeql.ruby.ast.internal.Variable
|
||||
|
||||
class TScopeType = TMethodBase or TModuleLike or TBlockLike;
|
||||
|
||||
@@ -15,6 +17,10 @@ private class TBlockLike = TDoBlock or TLambda or TBlock or TEndBlock;
|
||||
|
||||
private class TModuleLike = TToplevel or TModuleDeclaration or TClassDeclaration or TSingletonClass;
|
||||
|
||||
private class TScopeReal = TMethodBase or TModuleLike or TDoBlock or TLambda or TBraceBlock;
|
||||
|
||||
private class TScopeSynth = TBlockSynth;
|
||||
|
||||
module Scope {
|
||||
class TypeRange = Callable::TypeRange or ModuleBase::TypeRange or @ruby_end_block;
|
||||
|
||||
@@ -128,3 +134,44 @@ Scope::Range scopeOf(Ruby::AstNode n) {
|
||||
not p instanceof Scope::Range and result = scopeOf(p)
|
||||
)
|
||||
}
|
||||
|
||||
abstract class ScopeImpl extends AstNode, TScopeType {
|
||||
abstract Scope getOuterScopeImpl();
|
||||
|
||||
abstract Variable getAVariableImpl();
|
||||
|
||||
final Variable getVariableImpl(string name) {
|
||||
result = this.getAVariableImpl() and
|
||||
result.getName() = name
|
||||
}
|
||||
}
|
||||
|
||||
private class ScopeRealImpl extends ScopeImpl, TScopeReal {
|
||||
private Scope::Range range;
|
||||
|
||||
ScopeRealImpl() { range = toGenerated(this) }
|
||||
|
||||
override Scope getOuterScopeImpl() { toGenerated(result) = range.getOuterScope() }
|
||||
|
||||
override Variable getAVariableImpl() { result.getDeclaringScope() = this }
|
||||
}
|
||||
|
||||
// We desugar for loops by implementing them as calls to `each` with a block
|
||||
// argument. Though this is how the desugaring is described in the MRI parser,
|
||||
// in practice there is not a real nested scope created, so variables that
|
||||
// may appear to be local to the loop body (e.g. the iteration variable) are
|
||||
// scoped to the outer scope rather than the loop body.
|
||||
private class ScopeSynthImpl extends ScopeImpl, TScopeSynth {
|
||||
ScopeSynthImpl() { this = TBlockSynth(_, _) }
|
||||
|
||||
override Scope getOuterScopeImpl() { scopeOf(toGeneratedInclSynth(this)) = toGenerated(result) }
|
||||
|
||||
override Variable getAVariableImpl() {
|
||||
// Synthesized variables introduced as parameters to this scope
|
||||
// As this variable is also synthetic, it is genuinely local to this scope.
|
||||
exists(SimpleParameter p | p = TSimpleParameterSynth(this, _) |
|
||||
p.getVariable() = result and
|
||||
exists(TLocalVariableAccessSynth(p, _, result))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ newtype SynthKind =
|
||||
BitwiseAndExprKind() or
|
||||
BitwiseOrExprKind() or
|
||||
BitwiseXorExprKind() or
|
||||
BlockKind() or
|
||||
ClassVariableAccessKind(ClassVariable v) or
|
||||
DivExprKind() or
|
||||
ExponentExprKind() or
|
||||
|
||||
Reference in New Issue
Block a user