mirror of
https://github.com/github/codeql.git
synced 2026-02-20 00:43:44 +01:00
Merge pull request #179 from github/hvitved/synth-framework-take2
AST synthesis framework (take 2)
This commit is contained in:
@@ -14,6 +14,7 @@ import ast.Statement
|
||||
import ast.Variable
|
||||
private import ast.internal.AST
|
||||
private import ast.internal.Scope
|
||||
private import ast.internal.Synthesis
|
||||
|
||||
/**
|
||||
* A node in the abstract syntax tree. This class is the base class for all Ruby
|
||||
@@ -56,7 +57,11 @@ class AstNode extends TAstNode {
|
||||
final AstNode getAChild() { result = this.getAChild(_) }
|
||||
|
||||
/** Gets the parent of this `AstNode`, if this node is not a root node. */
|
||||
final AstNode getParent() { result.getAChild() = this }
|
||||
final AstNode getParent() {
|
||||
result.getAChild() = this
|
||||
or
|
||||
result.getAChild().getDesugared() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a child of this node, which can also be retrieved using a predicate
|
||||
@@ -75,5 +80,25 @@ class AstNode extends TAstNode {
|
||||
* foo(123)
|
||||
* ```
|
||||
*/
|
||||
predicate isSynthesized() { this instanceof TImplicitSelf }
|
||||
final predicate isSynthesized() { this = getSynthChild(_, _) }
|
||||
|
||||
/**
|
||||
* Gets the desugared version of this AST node, if any.
|
||||
*
|
||||
* For example, the desugared version of
|
||||
*
|
||||
* ```rb
|
||||
* x += y
|
||||
* ```
|
||||
*
|
||||
* is
|
||||
*
|
||||
* ```rb
|
||||
* x = x + y
|
||||
* ```
|
||||
*
|
||||
* when `x` is a variable. Whenever an AST node can be desugared,
|
||||
* then the desugared version is used in the control-flow graph.
|
||||
*/
|
||||
final AstNode getDesugared() { result = getSynthChild(this, -1) }
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ private class IdentifierMethodCall extends MethodCall, TIdentifierMethodCall {
|
||||
|
||||
final override string getMethodName() { result = getMethodName(this, g.getValue()) }
|
||||
|
||||
final override Self getReceiver() { result = TImplicitSelf(g) }
|
||||
final override Self getReceiver() { result = TSelfSynth(this, 0) }
|
||||
}
|
||||
|
||||
private class ScopeResolutionMethodCall extends MethodCall, TScopeResolutionMethodCall {
|
||||
@@ -162,12 +162,7 @@ private class RegularMethodCall extends MethodCall, TRegularMethodCall {
|
||||
not exists(g.getReceiver()) and
|
||||
toGenerated(result) = g.getMethod().(Generated::ScopeResolution).getScope()
|
||||
or
|
||||
// If there's no explicit receiver (or scope resolution that acts like a
|
||||
// receiver), then the receiver is implicitly `self`. N.B. `::Foo()` is
|
||||
// not valid Ruby.
|
||||
not exists(g.getReceiver()) and
|
||||
not exists(g.getMethod().(Generated::ScopeResolution).getScope()) and
|
||||
result = TImplicitSelf(g)
|
||||
result = TSelfSynth(this, 0)
|
||||
}
|
||||
|
||||
final override string getMethodName() {
|
||||
|
||||
@@ -79,6 +79,12 @@ class StmtSequence extends Expr, TStmtSequence {
|
||||
override AstNode getAChild(string pred) { pred = "getStmt" and result = this.getStmt(_) }
|
||||
}
|
||||
|
||||
private class StmtSequenceSynth extends StmtSequence, TStmtSequenceSynth {
|
||||
final override Stmt getStmt(int n) { synthChild(this, n, result) }
|
||||
|
||||
final override string toString() { result = "..." }
|
||||
}
|
||||
|
||||
private class Then extends StmtSequence, TThen {
|
||||
private Generated::Then g;
|
||||
|
||||
@@ -210,11 +216,11 @@ class ParenthesizedExpr extends StmtSequence, TParenthesizedExpr {
|
||||
|
||||
ParenthesizedExpr() { this = TParenthesizedExpr(g) }
|
||||
|
||||
final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "ParenthesizedExpr" }
|
||||
|
||||
final override string toString() { result = "( ... )" }
|
||||
|
||||
final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -101,12 +101,6 @@ class DefinedExpr extends UnaryOperation, TDefinedExpr {
|
||||
|
||||
/** A binary operation. */
|
||||
class BinaryOperation extends Operation, TBinaryOperation {
|
||||
private Generated::Binary g;
|
||||
|
||||
BinaryOperation() { g = toGenerated(this) }
|
||||
|
||||
final override string getOperator() { result = g.getOperator() }
|
||||
|
||||
final override Expr getAnOperand() {
|
||||
result = this.getLeftOperand() or result = this.getRightOperand()
|
||||
}
|
||||
@@ -122,10 +116,28 @@ class BinaryOperation extends Operation, TBinaryOperation {
|
||||
}
|
||||
|
||||
/** Gets the left operand of this binary operation. */
|
||||
final Stmt getLeftOperand() { toGenerated(result) = g.getLeft() }
|
||||
Stmt getLeftOperand() { none() }
|
||||
|
||||
/** Gets the right operand of this binary operation. */
|
||||
final Stmt getRightOperand() { toGenerated(result) = g.getRight() }
|
||||
Stmt getRightOperand() { none() }
|
||||
}
|
||||
|
||||
private class BinaryOperationReal extends BinaryOperation {
|
||||
private Generated::Binary g;
|
||||
|
||||
BinaryOperationReal() { g = toGenerated(this) }
|
||||
|
||||
final override string getOperator() { result = g.getOperator() }
|
||||
|
||||
final override Stmt getLeftOperand() { toGenerated(result) = g.getLeft() }
|
||||
|
||||
final override Stmt getRightOperand() { toGenerated(result) = g.getRight() }
|
||||
}
|
||||
|
||||
abstract private class BinaryOperationSynth extends BinaryOperation {
|
||||
final override Stmt getLeftOperand() { synthChild(this, 0, result) }
|
||||
|
||||
final override Stmt getRightOperand() { synthChild(this, 1, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,6 +155,10 @@ class AddExpr extends BinaryArithmeticOperation, TAddExpr {
|
||||
final override string getAPrimaryQlClass() { result = "AddExpr" }
|
||||
}
|
||||
|
||||
private class AddExprSynth extends AddExpr, BinaryOperationSynth, TAddExprSynth {
|
||||
final override string getOperator() { result = "+" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A subtract expression.
|
||||
* ```rb
|
||||
@@ -153,6 +169,10 @@ class SubExpr extends BinaryArithmeticOperation, TSubExpr {
|
||||
final override string getAPrimaryQlClass() { result = "SubExpr" }
|
||||
}
|
||||
|
||||
private class SubExprSynth extends SubExpr, BinaryOperationSynth, TSubExprSynth {
|
||||
final override string getOperator() { result = "-" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A multiply expression.
|
||||
* ```rb
|
||||
@@ -163,6 +183,10 @@ class MulExpr extends BinaryArithmeticOperation, TMulExpr {
|
||||
final override string getAPrimaryQlClass() { result = "MulExpr" }
|
||||
}
|
||||
|
||||
private class MulExprSynth extends MulExpr, BinaryOperationSynth, TMulExprSynth {
|
||||
final override string getOperator() { result = "*" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A divide expression.
|
||||
* ```rb
|
||||
@@ -173,6 +197,10 @@ class DivExpr extends BinaryArithmeticOperation, TDivExpr {
|
||||
final override string getAPrimaryQlClass() { result = "DivExpr" }
|
||||
}
|
||||
|
||||
private class DivExprSynth extends DivExpr, BinaryOperationSynth, TDivExprSynth {
|
||||
final override string getOperator() { result = "/" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A modulo expression.
|
||||
* ```rb
|
||||
@@ -183,6 +211,10 @@ class ModuloExpr extends BinaryArithmeticOperation, TModuloExpr {
|
||||
final override string getAPrimaryQlClass() { result = "ModuloExpr" }
|
||||
}
|
||||
|
||||
private class ModuloExprSynth extends ModuloExpr, BinaryOperationSynth, TModuloExprSynth {
|
||||
final override string getOperator() { result = "%" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An exponent expression.
|
||||
* ```rb
|
||||
@@ -193,6 +225,10 @@ class ExponentExpr extends BinaryArithmeticOperation, TExponentExpr {
|
||||
final override string getAPrimaryQlClass() { result = "ExponentExpr" }
|
||||
}
|
||||
|
||||
private class ExponentExprSynth extends ExponentExpr, BinaryOperationSynth, TExponentExprSynth {
|
||||
final override string getOperator() { result = "**" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A binary logical operation.
|
||||
*/
|
||||
@@ -209,6 +245,10 @@ class LogicalAndExpr extends BinaryLogicalOperation, TLogicalAndExpr {
|
||||
final override string getAPrimaryQlClass() { result = "LogicalAndExpr" }
|
||||
}
|
||||
|
||||
private class LogicalAndExprSynth extends LogicalAndExpr, BinaryOperationSynth, TLogicalAndExprSynth {
|
||||
final override string getOperator() { result = "&&" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A logical OR operation, using either `or` or `||`.
|
||||
* ```rb
|
||||
@@ -220,6 +260,10 @@ class LogicalOrExpr extends BinaryLogicalOperation, TLogicalOrExpr {
|
||||
final override string getAPrimaryQlClass() { result = "LogicalOrExpr" }
|
||||
}
|
||||
|
||||
private class LogicalOrExprSynth extends LogicalOrExpr, BinaryOperationSynth, TLogicalOrExprSynth {
|
||||
final override string getOperator() { result = "||" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A binary bitwise operation.
|
||||
*/
|
||||
@@ -235,6 +279,10 @@ class LShiftExpr extends BinaryBitwiseOperation, TLShiftExpr {
|
||||
final override string getAPrimaryQlClass() { result = "LShiftExpr" }
|
||||
}
|
||||
|
||||
private class LShiftExprSynth extends LShiftExpr, BinaryOperationSynth, TLShiftExprSynth {
|
||||
final override string getOperator() { result = "<<" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A right-shift operation.
|
||||
* ```rb
|
||||
@@ -245,6 +293,10 @@ class RShiftExpr extends BinaryBitwiseOperation, TRShiftExpr {
|
||||
final override string getAPrimaryQlClass() { result = "RShiftExpr" }
|
||||
}
|
||||
|
||||
private class RShiftExprSynth extends RShiftExpr, BinaryOperationSynth, TRShiftExprSynth {
|
||||
final override string getOperator() { result = ">>" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A bitwise AND operation.
|
||||
* ```rb
|
||||
@@ -255,6 +307,10 @@ class BitwiseAndExpr extends BinaryBitwiseOperation, TBitwiseAndExpr {
|
||||
final override string getAPrimaryQlClass() { result = "BitwiseAndExpr" }
|
||||
}
|
||||
|
||||
private class BitwiseAndSynthExpr extends BitwiseAndExpr, BinaryOperationSynth, TBitwiseAndExprSynth {
|
||||
final override string getOperator() { result = "&" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A bitwise OR operation.
|
||||
* ```rb
|
||||
@@ -265,6 +321,10 @@ class BitwiseOrExpr extends BinaryBitwiseOperation, TBitwiseOrExpr {
|
||||
final override string getAPrimaryQlClass() { result = "BitwiseOrExpr" }
|
||||
}
|
||||
|
||||
private class BitwiseOrSynthExpr extends BitwiseOrExpr, BinaryOperationSynth, TBitwiseOrExprSynth {
|
||||
final override string getOperator() { result = "|" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An XOR (exclusive OR) operation.
|
||||
* ```rb
|
||||
@@ -275,6 +335,10 @@ class BitwiseXorExpr extends BinaryBitwiseOperation, TBitwiseXorExpr {
|
||||
final override string getAPrimaryQlClass() { result = "BitwiseXorExpr" }
|
||||
}
|
||||
|
||||
private class BitwiseXorSynthExpr extends BitwiseXorExpr, BinaryOperationSynth, TBitwiseXorExprSynth {
|
||||
final override string getOperator() { result = "^" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A comparison operation. That is, either an equality operation or a
|
||||
* relational operation.
|
||||
@@ -455,17 +519,25 @@ class Assignment extends Operation, TAssignment {
|
||||
* ```
|
||||
*/
|
||||
class AssignExpr extends Assignment, TAssignExpr {
|
||||
final override string getOperator() { result = "=" }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "AssignExpr" }
|
||||
}
|
||||
|
||||
private class AssignExprReal extends AssignExpr, TAssignExprReal {
|
||||
private Generated::Assignment g;
|
||||
|
||||
AssignExpr() { this = TAssignExpr(g) }
|
||||
AssignExprReal() { this = TAssignExprReal(g) }
|
||||
|
||||
final override Pattern getLeftOperand() { toGenerated(result) = g.getLeft() }
|
||||
|
||||
final override Expr getRightOperand() { toGenerated(result) = g.getRight() }
|
||||
}
|
||||
|
||||
final override string getOperator() { result = "=" }
|
||||
private class AssignExprSynth extends AssignExpr, TAssignExprSynth {
|
||||
final override Pattern getLeftOperand() { synthChild(this, 0, result) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AssignExpr" }
|
||||
final override Expr getRightOperand() { synthChild(this, 1, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,10 +37,7 @@ class TuplePatternParameter extends PatternParameter, TuplePattern, TTuplePatter
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "TuplePatternParameter" }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = PatternParameter.super.getAChild(pred) or
|
||||
result = TuplePattern.super.getAChild(pred)
|
||||
}
|
||||
override AstNode getAChild(string pred) { result = TuplePattern.super.getAChild(pred) }
|
||||
}
|
||||
|
||||
/** A named parameter. */
|
||||
@@ -60,8 +57,6 @@ class NamedParameter extends Parameter, TNamedParameter {
|
||||
final VariableAccess getDefiningAccess() { result = this.getVariable().getDefiningAccess() }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = Parameter.super.getAChild(pred)
|
||||
or
|
||||
pred = "getDefiningAccess" and
|
||||
result = this.getDefiningAccess()
|
||||
}
|
||||
@@ -75,7 +70,7 @@ class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern,
|
||||
|
||||
final override string getName() { result = g.getValue() }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g) }
|
||||
final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g) }
|
||||
|
||||
final override LocalVariable getAVariable() { result = this.getVariable() }
|
||||
|
||||
@@ -99,7 +94,7 @@ class BlockParameter extends NamedParameter, TBlockParameter {
|
||||
|
||||
final override string getName() { result = g.getName().getValue() }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
|
||||
final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) }
|
||||
|
||||
final override string toString() { result = "&" + this.getName() }
|
||||
|
||||
@@ -122,7 +117,7 @@ class HashSplatParameter extends NamedParameter, THashSplatParameter {
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "HashSplatParameter" }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
|
||||
final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) }
|
||||
|
||||
final override string toString() { result = "**" + this.getName() }
|
||||
|
||||
@@ -147,7 +142,7 @@ class KeywordParameter extends NamedParameter, TKeywordParameter {
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "KeywordParameter" }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
|
||||
final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) }
|
||||
|
||||
/**
|
||||
* Gets the default value, i.e. the value assigned to the parameter when one
|
||||
@@ -197,7 +192,7 @@ class OptionalParameter extends NamedParameter, TOptionalParameter {
|
||||
*/
|
||||
final Expr getDefaultValue() { toGenerated(result) = g.getValue() }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
|
||||
final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) }
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
|
||||
@@ -227,7 +222,7 @@ class SplatParameter extends NamedParameter, TSplatParameter {
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "SplatParameter" }
|
||||
|
||||
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
|
||||
final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) }
|
||||
|
||||
final override string toString() { result = "*" + this.getName() }
|
||||
|
||||
|
||||
@@ -7,9 +7,13 @@ private import internal.Variable
|
||||
/** A pattern. */
|
||||
class Pattern extends AstNode {
|
||||
Pattern() {
|
||||
explicitAssignmentNode(toGenerated(this), _) or
|
||||
implicitAssignmentNode(toGenerated(this)) or
|
||||
explicitAssignmentNode(toGenerated(this), _)
|
||||
or
|
||||
implicitAssignmentNode(toGenerated(this))
|
||||
or
|
||||
implicitParameterAssignmentNode(toGenerated(this), _)
|
||||
or
|
||||
this = getSynthChild(any(AssignExpr ae), 0)
|
||||
}
|
||||
|
||||
/** Gets a variable used in (or introduced by) this pattern. */
|
||||
|
||||
@@ -8,21 +8,17 @@ private import internal.Variable
|
||||
|
||||
/** A variable declared in a scope. */
|
||||
class Variable extends TVariable {
|
||||
Variable::Range range;
|
||||
|
||||
Variable() { range = this }
|
||||
|
||||
/** Gets the name of this variable. */
|
||||
final string getName() { result = range.getName() }
|
||||
string getName() { none() }
|
||||
|
||||
/** Gets a textual representation of this variable. */
|
||||
final string toString() { result = this.getName() }
|
||||
|
||||
/** Gets the location of this variable. */
|
||||
final Location getLocation() { result = range.getLocation() }
|
||||
Location getLocation() { none() }
|
||||
|
||||
/** Gets the scope this variable is declared in. */
|
||||
final Scope getDeclaringScope() { toGenerated(result) = range.getDeclaringScope() }
|
||||
Scope getDeclaringScope() { none() }
|
||||
|
||||
/** Gets an access to this variable. */
|
||||
VariableAccess getAnAccess() { result.getVariable() = this }
|
||||
@@ -30,12 +26,10 @@ class Variable extends TVariable {
|
||||
|
||||
/** A local variable. */
|
||||
class LocalVariable extends Variable, TLocalVariable {
|
||||
override LocalVariable::Range range;
|
||||
|
||||
final override LocalVariableAccess getAnAccess() { result.getVariable() = this }
|
||||
override LocalVariableAccess getAnAccess() { none() }
|
||||
|
||||
/** Gets the access where this local variable is first introduced. */
|
||||
VariableAccess getDefiningAccess() { result = range.getDefiningAccess() }
|
||||
VariableAccess getDefiningAccess() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this variable is captured. For example in
|
||||
@@ -55,14 +49,14 @@ class LocalVariable extends Variable, TLocalVariable {
|
||||
}
|
||||
|
||||
/** A global variable. */
|
||||
class GlobalVariable extends Variable, TGlobalVariable {
|
||||
class GlobalVariable extends VariableReal, TGlobalVariable {
|
||||
override GlobalVariable::Range range;
|
||||
|
||||
final override GlobalVariableAccess getAnAccess() { result.getVariable() = this }
|
||||
}
|
||||
|
||||
/** An instance variable. */
|
||||
class InstanceVariable extends Variable, TInstanceVariable {
|
||||
class InstanceVariable extends VariableReal, TInstanceVariable {
|
||||
override InstanceVariable::Range range;
|
||||
|
||||
/** Holds is this variable is a class instance variable. */
|
||||
@@ -72,7 +66,7 @@ class InstanceVariable extends Variable, TInstanceVariable {
|
||||
}
|
||||
|
||||
/** A class variable. */
|
||||
class ClassVariable extends Variable, TClassVariable {
|
||||
class ClassVariable extends VariableReal, TClassVariable {
|
||||
override ClassVariable::Range range;
|
||||
|
||||
final override ClassVariableAccess getAnAccess() { result.getVariable() = this }
|
||||
@@ -95,6 +89,8 @@ class VariableAccess extends Expr, TVariableAccess {
|
||||
*/
|
||||
predicate isExplicitWrite(AstNode assignment) {
|
||||
explicitWriteAccess(toGenerated(this), toGenerated(assignment))
|
||||
or
|
||||
this = assignment.(AssignExpr).getLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,22 +121,12 @@ class VariableWriteAccess extends VariableAccess {
|
||||
|
||||
/** An access to a variable where the value is read. */
|
||||
class VariableReadAccess extends VariableAccess {
|
||||
VariableReadAccess() {
|
||||
not this instanceof VariableWriteAccess
|
||||
or
|
||||
// `x` in `x += y` is considered both a read and a write
|
||||
this = any(AssignOperation a).getLeftOperand()
|
||||
}
|
||||
VariableReadAccess() { not this instanceof VariableWriteAccess }
|
||||
}
|
||||
|
||||
/** An access to a local variable. */
|
||||
class LocalVariableAccess extends VariableAccess, TLocalVariableAccess {
|
||||
private Generated::Identifier g;
|
||||
private LocalVariable v;
|
||||
|
||||
LocalVariableAccess() { this = TLocalVariableAccess(g, v) }
|
||||
|
||||
final override LocalVariable getVariable() { result = v }
|
||||
override LocalVariable getVariable() { none() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "LocalVariableAccess" }
|
||||
|
||||
@@ -160,8 +146,6 @@ class LocalVariableAccess extends VariableAccess, TLocalVariableAccess {
|
||||
* the access to `x` in the second `puts x` is not.
|
||||
*/
|
||||
final predicate isCapturedAccess() { isCapturedAccess(this) }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
}
|
||||
|
||||
/** An access to a local variable where the value is updated. */
|
||||
@@ -172,16 +156,9 @@ class LocalVariableReadAccess extends LocalVariableAccess, VariableReadAccess {
|
||||
|
||||
/** An access to a global variable. */
|
||||
class GlobalVariableAccess extends VariableAccess, TGlobalVariableAccess {
|
||||
private Generated::GlobalVariable g;
|
||||
private GlobalVariable v;
|
||||
|
||||
GlobalVariableAccess() { this = TGlobalVariableAccess(g, v) }
|
||||
|
||||
final override GlobalVariable getVariable() { result = v }
|
||||
override GlobalVariable getVariable() { none() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "GlobalVariableAccess" }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
}
|
||||
|
||||
/** An access to a global variable where the value is updated. */
|
||||
@@ -192,28 +169,14 @@ class GlobalVariableReadAccess extends GlobalVariableAccess, VariableReadAccess
|
||||
|
||||
/** An access to an instance variable. */
|
||||
class InstanceVariableAccess extends VariableAccess, TInstanceVariableAccess {
|
||||
private Generated::InstanceVariable g;
|
||||
private InstanceVariable v;
|
||||
|
||||
InstanceVariableAccess() { this = TInstanceVariableAccess(g, v) }
|
||||
|
||||
final override InstanceVariable getVariable() { result = v }
|
||||
override InstanceVariable getVariable() { none() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "InstanceVariableAccess" }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
}
|
||||
|
||||
/** An access to a class variable. */
|
||||
class ClassVariableAccess extends VariableAccess, TClassVariableAccess {
|
||||
private Generated::ClassVariable g;
|
||||
private ClassVariable v;
|
||||
|
||||
ClassVariableAccess() { this = TClassVariableAccess(g, v) }
|
||||
|
||||
final override ClassVariable getVariable() { result = v }
|
||||
override ClassVariable getVariable() { none() }
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "ClassVariableAccess" }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ private import TreeSitter
|
||||
private import codeql_ruby.ast.internal.Parameter
|
||||
private import codeql_ruby.ast.internal.Variable
|
||||
private import codeql_ruby.AST as AST
|
||||
private import Synthesis
|
||||
|
||||
module MethodName {
|
||||
predicate range(Generated::UnderscoreMethodName g) {
|
||||
@@ -16,11 +17,16 @@ module MethodName {
|
||||
@token_identifier or @token_instance_variable or @token_operator;
|
||||
}
|
||||
|
||||
private predicate mkSynthChild(SynthKind kind, AST::AstNode parent, int i) {
|
||||
any(Synthesis s).child(parent, i, SynthChild(kind))
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
newtype TAstNode =
|
||||
TAddExpr(Generated::Binary g) { g instanceof @binary_plus } or
|
||||
TAddExprReal(Generated::Binary g) { g instanceof @binary_plus } or
|
||||
TAddExprSynth(AST::AstNode parent, int i) { mkSynthChild(AddExprKind(), parent, i) } or
|
||||
TAliasStmt(Generated::Alias g) or
|
||||
TArgumentList(Generated::AstNode g) {
|
||||
(
|
||||
@@ -50,7 +56,8 @@ private module Cached {
|
||||
TAssignExponentExpr(Generated::OperatorAssignment g) {
|
||||
g instanceof @operator_assignment_starstarequal
|
||||
} or
|
||||
TAssignExpr(Generated::Assignment g) or
|
||||
TAssignExprReal(Generated::Assignment g) or
|
||||
TAssignExprSynth(AST::AstNode parent, int i) { mkSynthChild(AssignExprKind(), parent, i) } or
|
||||
TAssignLShiftExpr(Generated::OperatorAssignment g) {
|
||||
g instanceof @operator_assignment_langlelangleequal
|
||||
} or
|
||||
@@ -72,9 +79,16 @@ private module Cached {
|
||||
TBareSymbolLiteral(Generated::BareSymbol g) or
|
||||
TBeginBlock(Generated::BeginBlock g) or
|
||||
TBeginExpr(Generated::Begin g) or
|
||||
TBitwiseAndExpr(Generated::Binary g) { g instanceof @binary_ampersand } or
|
||||
TBitwiseOrExpr(Generated::Binary g) { g instanceof @binary_pipe } or
|
||||
TBitwiseXorExpr(Generated::Binary g) { g instanceof @binary_caret } or
|
||||
TBitwiseAndExprReal(Generated::Binary g) { g instanceof @binary_ampersand } or
|
||||
TBitwiseAndExprSynth(AST::AstNode parent, int i) {
|
||||
mkSynthChild(BitwiseAndExprKind(), parent, i)
|
||||
} or
|
||||
TBitwiseOrExprReal(Generated::Binary g) { g instanceof @binary_pipe } or
|
||||
TBitwiseOrExprSynth(AST::AstNode parent, int i) { mkSynthChild(BitwiseOrExprKind(), parent, i) } or
|
||||
TBitwiseXorExprReal(Generated::Binary g) { g instanceof @binary_caret } or
|
||||
TBitwiseXorExprSynth(AST::AstNode parent, int i) {
|
||||
mkSynthChild(BitwiseXorExprKind(), parent, i)
|
||||
} or
|
||||
TBlockArgument(Generated::BlockArgument g) or
|
||||
TBlockParameter(Generated::BlockParameter g) or
|
||||
TBraceBlock(Generated::Block g) { not g.getParent() instanceof Generated::Lambda } or
|
||||
@@ -83,9 +97,12 @@ private module Cached {
|
||||
TCaseExpr(Generated::Case g) or
|
||||
TCharacterLiteral(Generated::Character g) or
|
||||
TClassDeclaration(Generated::Class g) or
|
||||
TClassVariableAccess(Generated::ClassVariable g, AST::ClassVariable v) {
|
||||
TClassVariableAccessReal(Generated::ClassVariable g, AST::ClassVariable v) {
|
||||
ClassVariableAccess::range(g, v)
|
||||
} or
|
||||
TClassVariableAccessSynth(AST::AstNode parent, int i, AST::ClassVariable v) {
|
||||
mkSynthChild(ClassVariableAccessKind(v), parent, i)
|
||||
} or
|
||||
TComplementExpr(Generated::Unary g) { g instanceof @unary_tilde } or
|
||||
TComplexLiteral(Generated::Complex g) or
|
||||
TDefinedExpr(Generated::Unary g) { g instanceof @unary_definedquestion } or
|
||||
@@ -93,7 +110,8 @@ private module Cached {
|
||||
TDestructuredLeftAssignment(Generated::DestructuredLeftAssignment g) {
|
||||
not strictcount(int i | exists(g.getParent().(Generated::LeftAssignmentList).getChild(i))) = 1
|
||||
} or
|
||||
TDivExpr(Generated::Binary g) { g instanceof @binary_slash } or
|
||||
TDivExprReal(Generated::Binary g) { g instanceof @binary_slash } or
|
||||
TDivExprSynth(AST::AstNode parent, int i) { mkSynthChild(DivExprKind(), parent, i) } or
|
||||
TDo(Generated::Do g) or
|
||||
TDoBlock(Generated::DoBlock g) { not g.getParent() instanceof Generated::Lambda } or
|
||||
TElementReference(Generated::ElementReference g) or
|
||||
@@ -103,17 +121,20 @@ private module Cached {
|
||||
TEndBlock(Generated::EndBlock g) or
|
||||
TEnsure(Generated::Ensure g) or
|
||||
TEqExpr(Generated::Binary g) { g instanceof @binary_equalequal } or
|
||||
TExplicitSelf(Generated::Self g) or
|
||||
TExponentExpr(Generated::Binary g) { g instanceof @binary_starstar } or
|
||||
TExponentExprReal(Generated::Binary g) { g instanceof @binary_starstar } or
|
||||
TExponentExprSynth(AST::AstNode parent, int i) { mkSynthChild(ExponentExprKind(), parent, i) } or
|
||||
TFalseLiteral(Generated::False g) or
|
||||
TFloatLiteral(Generated::Float g) { not any(Generated::Rational r).getChild() = g } or
|
||||
TForExpr(Generated::For g) or
|
||||
TForIn(Generated::In g) or // TODO REMOVE
|
||||
TGEExpr(Generated::Binary g) { g instanceof @binary_rangleequal } or
|
||||
TGTExpr(Generated::Binary g) { g instanceof @binary_rangle } or
|
||||
TGlobalVariableAccess(Generated::GlobalVariable g, AST::GlobalVariable v) {
|
||||
TGlobalVariableAccessReal(Generated::GlobalVariable g, AST::GlobalVariable v) {
|
||||
GlobalVariableAccess::range(g, v)
|
||||
} or
|
||||
TGlobalVariableAccessSynth(AST::AstNode parent, int i, AST::GlobalVariable v) {
|
||||
mkSynthChild(GlobalVariableAccessKind(v), parent, i)
|
||||
} or
|
||||
THashKeySymbolLiteral(Generated::HashKeySymbol g) or
|
||||
THashLiteral(Generated::Hash g) or
|
||||
THashSplatArgument(Generated::HashSplatArgument g) or
|
||||
@@ -122,34 +143,44 @@ private module Cached {
|
||||
TIdentifierMethodCall(Generated::Identifier g) { isIdentifierMethodCall(g) } or
|
||||
TIf(Generated::If g) or
|
||||
TIfModifierExpr(Generated::IfModifier g) or
|
||||
TImplicitSelf(Generated::AstNode g) {
|
||||
isIdentifierMethodCall(g)
|
||||
or
|
||||
isRegularMethodCall(g) and
|
||||
not exists(g.(Generated::Call).getReceiver()) and
|
||||
not exists(g.(Generated::Call).getMethod().(Generated::ScopeResolution).getScope())
|
||||
} or
|
||||
TInstanceVariableAccess(Generated::InstanceVariable g, AST::InstanceVariable v) {
|
||||
TInstanceVariableAccessReal(Generated::InstanceVariable g, AST::InstanceVariable v) {
|
||||
InstanceVariableAccess::range(g, v)
|
||||
} or
|
||||
TInstanceVariableAccessSynth(AST::AstNode parent, int i, AST::InstanceVariable v) {
|
||||
mkSynthChild(InstanceVariableAccessKind(v), parent, i)
|
||||
} or
|
||||
TIntegerLiteral(Generated::Integer g) { not any(Generated::Rational r).getChild() = g } or
|
||||
TKeywordParameter(Generated::KeywordParameter g) or
|
||||
TLEExpr(Generated::Binary g) { g instanceof @binary_langleequal } or
|
||||
TLShiftExpr(Generated::Binary g) { g instanceof @binary_langlelangle } or
|
||||
TLShiftExprReal(Generated::Binary g) { g instanceof @binary_langlelangle } or
|
||||
TLShiftExprSynth(AST::AstNode parent, int i) { mkSynthChild(LShiftExprKind(), parent, i) } or
|
||||
TLTExpr(Generated::Binary g) { g instanceof @binary_langle } or
|
||||
TLambda(Generated::Lambda g) or
|
||||
TLeftAssignmentList(Generated::LeftAssignmentList g) or
|
||||
TLocalVariableAccess(Generated::Identifier g, AST::LocalVariable v) {
|
||||
TLocalVariableAccessReal(Generated::Identifier g, AST::LocalVariable v) {
|
||||
LocalVariableAccess::range(g, v)
|
||||
} or
|
||||
TLogicalAndExpr(Generated::Binary g) {
|
||||
TLocalVariableAccessSynth(AST::AstNode parent, int i, AST::LocalVariable v) {
|
||||
mkSynthChild(LocalVariableAccessRealKind(v), parent, i)
|
||||
or
|
||||
mkSynthChild(LocalVariableAccessSynthKind(v), parent, i)
|
||||
} or
|
||||
TLogicalAndExprReal(Generated::Binary g) {
|
||||
g instanceof @binary_and or g instanceof @binary_ampersandampersand
|
||||
} or
|
||||
TLogicalOrExpr(Generated::Binary g) { g instanceof @binary_or or g instanceof @binary_pipepipe } or
|
||||
TLogicalAndExprSynth(AST::AstNode parent, int i) {
|
||||
mkSynthChild(LogicalAndExprKind(), parent, i)
|
||||
} or
|
||||
TLogicalOrExprReal(Generated::Binary g) {
|
||||
g instanceof @binary_or or g instanceof @binary_pipepipe
|
||||
} or
|
||||
TLogicalOrExprSynth(AST::AstNode parent, int i) { mkSynthChild(LogicalOrExprKind(), parent, i) } or
|
||||
TMethod(Generated::Method g) or
|
||||
TModuleDeclaration(Generated::Module g) or
|
||||
TModuloExpr(Generated::Binary g) { g instanceof @binary_percent } or
|
||||
TMulExpr(Generated::Binary g) { g instanceof @binary_star } or
|
||||
TModuloExprReal(Generated::Binary g) { g instanceof @binary_percent } or
|
||||
TModuloExprSynth(AST::AstNode parent, int i) { mkSynthChild(ModuloExprKind(), parent, i) } or
|
||||
TMulExprReal(Generated::Binary g) { g instanceof @binary_star } or
|
||||
TMulExprSynth(AST::AstNode parent, int i) { mkSynthChild(MulExprKind(), parent, i) } or
|
||||
TNEExpr(Generated::Binary g) { g instanceof @binary_bangequal } or
|
||||
TNextStmt(Generated::Next g) or
|
||||
TNilLiteral(Generated::Nil g) or
|
||||
@@ -158,7 +189,8 @@ private module Cached {
|
||||
TOptionalParameter(Generated::OptionalParameter g) or
|
||||
TPair(Generated::Pair g) or
|
||||
TParenthesizedExpr(Generated::ParenthesizedStatements g) or
|
||||
TRShiftExpr(Generated::Binary g) { g instanceof @binary_ranglerangle } or
|
||||
TRShiftExprReal(Generated::Binary g) { g instanceof @binary_ranglerangle } or
|
||||
TRShiftExprSynth(AST::AstNode parent, int i) { mkSynthChild(RShiftExprKind(), parent, i) } or
|
||||
TRangeLiteral(Generated::Range g) or
|
||||
TRationalLiteral(Generated::Rational g) or
|
||||
TRedoStmt(Generated::Redo g) or
|
||||
@@ -187,6 +219,8 @@ private module Cached {
|
||||
i = g.getName() and
|
||||
not exists(Generated::Call c | c.getMethod() = g)
|
||||
} or
|
||||
TSelfReal(Generated::Self g) or
|
||||
TSelfSynth(AST::AstNode parent, int i) { mkSynthChild(SelfKind(), parent, i) } or
|
||||
TSimpleParameter(Generated::Identifier g) { g instanceof Parameter::Range } or
|
||||
TSimpleSymbolLiteral(Generated::SimpleSymbol g) or
|
||||
TSingletonClass(Generated::SingletonClass g) or
|
||||
@@ -194,6 +228,7 @@ private module Cached {
|
||||
TSpaceshipExpr(Generated::Binary g) { g instanceof @binary_langleequalrangle } or
|
||||
TSplatArgument(Generated::SplatArgument g) or
|
||||
TSplatParameter(Generated::SplatParameter g) or
|
||||
TStmtSequenceSynth(AST::AstNode parent, int i) { mkSynthChild(StmtSequenceKind(), parent, i) } or
|
||||
TStringArrayLiteral(Generated::StringArray g) or
|
||||
TStringConcatenation(Generated::ChainedString g) or
|
||||
TStringEscapeSequenceComponent(Generated::EscapeSequence g) or
|
||||
@@ -201,7 +236,8 @@ private module Cached {
|
||||
TStringTextComponent(Generated::Token g) {
|
||||
g instanceof Generated::StringContent or g instanceof Generated::HeredocContent
|
||||
} or
|
||||
TSubExpr(Generated::Binary g) { g instanceof @binary_minus } or
|
||||
TSubExprReal(Generated::Binary g) { g instanceof @binary_minus } or
|
||||
TSubExprSynth(AST::AstNode parent, int i) { mkSynthChild(SubExprKind(), parent, i) } or
|
||||
TSubshellLiteral(Generated::Subshell g) or
|
||||
TSymbolArrayLiteral(Generated::SymbolArray g) or
|
||||
TTernaryIfExpr(Generated::Conditional g) or
|
||||
@@ -245,7 +281,7 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
Generated::AstNode toGenerated(AST::AstNode n) {
|
||||
n = TAddExpr(result) or
|
||||
n = TAddExprReal(result) or
|
||||
n = TAliasStmt(result) or
|
||||
n = TArgumentList(result) or
|
||||
n = TAssignAddExpr(result) or
|
||||
@@ -254,7 +290,7 @@ private module Cached {
|
||||
n = TAssignBitwiseXorExpr(result) or
|
||||
n = TAssignDivExpr(result) or
|
||||
n = TAssignExponentExpr(result) or
|
||||
n = TAssignExpr(result) or
|
||||
n = TAssignExprReal(result) or
|
||||
n = TAssignLShiftExpr(result) or
|
||||
n = TAssignLogicalAndExpr(result) or
|
||||
n = TAssignLogicalOrExpr(result) or
|
||||
@@ -266,9 +302,9 @@ private module Cached {
|
||||
n = TBareSymbolLiteral(result) or
|
||||
n = TBeginBlock(result) or
|
||||
n = TBeginExpr(result) or
|
||||
n = TBitwiseAndExpr(result) or
|
||||
n = TBitwiseOrExpr(result) or
|
||||
n = TBitwiseXorExpr(result) or
|
||||
n = TBitwiseAndExprReal(result) or
|
||||
n = TBitwiseOrExprReal(result) or
|
||||
n = TBitwiseXorExprReal(result) or
|
||||
n = TBlockArgument(result) or
|
||||
n = TBlockParameter(result) or
|
||||
n = TBraceBlock(result) or
|
||||
@@ -277,13 +313,13 @@ private module Cached {
|
||||
n = TCaseExpr(result) or
|
||||
n = TCharacterLiteral(result) or
|
||||
n = TClassDeclaration(result) or
|
||||
n = TClassVariableAccess(result, _) or
|
||||
n = TClassVariableAccessReal(result, _) or
|
||||
n = TComplementExpr(result) or
|
||||
n = TComplexLiteral(result) or
|
||||
n = TDefinedExpr(result) or
|
||||
n = TDelimitedSymbolLiteral(result) or
|
||||
n = TDestructuredLeftAssignment(result) or
|
||||
n = TDivExpr(result) or
|
||||
n = TDivExprReal(result) or
|
||||
n = TDo(result) or
|
||||
n = TDoBlock(result) or
|
||||
n = TElementReference(result) or
|
||||
@@ -293,15 +329,14 @@ private module Cached {
|
||||
n = TEndBlock(result) or
|
||||
n = TEnsure(result) or
|
||||
n = TEqExpr(result) or
|
||||
n = TExplicitSelf(result) or
|
||||
n = TExponentExpr(result) or
|
||||
n = TExponentExprReal(result) or
|
||||
n = TFalseLiteral(result) or
|
||||
n = TFloatLiteral(result) or
|
||||
n = TForExpr(result) or
|
||||
n = TForIn(result) or // TODO REMOVE
|
||||
n = TGEExpr(result) or
|
||||
n = TGTExpr(result) or
|
||||
n = TGlobalVariableAccess(result, _) or
|
||||
n = TGlobalVariableAccessReal(result, _) or
|
||||
n = THashKeySymbolLiteral(result) or
|
||||
n = THashLiteral(result) or
|
||||
n = THashSplatArgument(result) or
|
||||
@@ -310,21 +345,21 @@ private module Cached {
|
||||
n = TIdentifierMethodCall(result) or
|
||||
n = TIf(result) or
|
||||
n = TIfModifierExpr(result) or
|
||||
n = TInstanceVariableAccess(result, _) or
|
||||
n = TInstanceVariableAccessReal(result, _) or
|
||||
n = TIntegerLiteral(result) or
|
||||
n = TKeywordParameter(result) or
|
||||
n = TLEExpr(result) or
|
||||
n = TLShiftExpr(result) or
|
||||
n = TLShiftExprReal(result) or
|
||||
n = TLTExpr(result) or
|
||||
n = TLambda(result) or
|
||||
n = TLeftAssignmentList(result) or
|
||||
n = TLocalVariableAccess(result, _) or
|
||||
n = TLogicalAndExpr(result) or
|
||||
n = TLogicalOrExpr(result) or
|
||||
n = TLocalVariableAccessReal(result, _) or
|
||||
n = TLogicalAndExprReal(result) or
|
||||
n = TLogicalOrExprReal(result) or
|
||||
n = TMethod(result) or
|
||||
n = TModuleDeclaration(result) or
|
||||
n = TModuloExpr(result) or
|
||||
n = TMulExpr(result) or
|
||||
n = TModuloExprReal(result) or
|
||||
n = TMulExprReal(result) or
|
||||
n = TNEExpr(result) or
|
||||
n = TNextStmt(result) or
|
||||
n = TNilLiteral(result) or
|
||||
@@ -333,7 +368,7 @@ private module Cached {
|
||||
n = TOptionalParameter(result) or
|
||||
n = TPair(result) or
|
||||
n = TParenthesizedExpr(result) or
|
||||
n = TRShiftExpr(result) or
|
||||
n = TRShiftExprReal(result) or
|
||||
n = TRangeLiteral(result) or
|
||||
n = TRationalLiteral(result) or
|
||||
n = TRedoStmt(result) or
|
||||
@@ -349,6 +384,7 @@ private module Cached {
|
||||
n = TReturnStmt(result) or
|
||||
n = TScopeResolutionConstantAccess(result, _) or
|
||||
n = TScopeResolutionMethodCall(result, _) or
|
||||
n = TSelfReal(result) or
|
||||
n = TSimpleParameter(result) or
|
||||
n = TSimpleSymbolLiteral(result) or
|
||||
n = TSingletonClass(result) or
|
||||
@@ -361,7 +397,7 @@ private module Cached {
|
||||
n = TStringEscapeSequenceComponent(result) or
|
||||
n = TStringInterpolationComponent(result) or
|
||||
n = TStringTextComponent(result) or
|
||||
n = TSubExpr(result) or
|
||||
n = TSubExprReal(result) or
|
||||
n = TSubshellLiteral(result) or
|
||||
n = TSymbolArrayLiteral(result) or
|
||||
n = TTernaryIfExpr(result) or
|
||||
@@ -385,14 +421,105 @@ private module Cached {
|
||||
n = TYieldCall(result)
|
||||
}
|
||||
|
||||
/** Gets the `i`th synthesized child of `parent`. */
|
||||
cached
|
||||
AST::AstNode getSynthChild(AST::AstNode parent, int i) {
|
||||
exists(SynthKind kind | mkSynthChild(kind, parent, i) |
|
||||
kind = AddExprKind() and
|
||||
result = TAddExprSynth(parent, i)
|
||||
or
|
||||
kind = AssignExprKind() and
|
||||
result = TAssignExprSynth(parent, i)
|
||||
or
|
||||
kind = BitwiseAndExprKind() and
|
||||
result = TBitwiseAndExprSynth(parent, i)
|
||||
or
|
||||
kind = BitwiseOrExprKind() and
|
||||
result = TBitwiseOrExprSynth(parent, i)
|
||||
or
|
||||
kind = BitwiseXorExprKind() and
|
||||
result = TBitwiseXorExprSynth(parent, i)
|
||||
or
|
||||
exists(AST::ClassVariable v |
|
||||
kind = ClassVariableAccessKind(v) and
|
||||
result = TClassVariableAccessSynth(parent, i, v)
|
||||
)
|
||||
or
|
||||
kind = DivExprKind() and
|
||||
result = TDivExprSynth(parent, i)
|
||||
or
|
||||
kind = ExponentExprKind() and
|
||||
result = TExponentExprSynth(parent, i)
|
||||
or
|
||||
exists(AST::GlobalVariable v |
|
||||
kind = GlobalVariableAccessKind(v) and
|
||||
result = TGlobalVariableAccessSynth(parent, i, v)
|
||||
)
|
||||
or
|
||||
exists(AST::InstanceVariable v |
|
||||
kind = InstanceVariableAccessKind(v) and
|
||||
result = TInstanceVariableAccessSynth(parent, i, v)
|
||||
)
|
||||
or
|
||||
kind = LShiftExprKind() and
|
||||
result = TLShiftExprSynth(parent, i)
|
||||
or
|
||||
exists(AST::LocalVariable v | result = TLocalVariableAccessSynth(parent, i, v) |
|
||||
kind = LocalVariableAccessRealKind(v)
|
||||
or
|
||||
kind = LocalVariableAccessSynthKind(v)
|
||||
)
|
||||
or
|
||||
kind = LogicalAndExprKind() and
|
||||
result = TLogicalAndExprSynth(parent, i)
|
||||
or
|
||||
kind = LogicalOrExprKind() and
|
||||
result = TLogicalOrExprSynth(parent, i)
|
||||
or
|
||||
kind = ModuloExprKind() and
|
||||
result = TModuloExprSynth(parent, i)
|
||||
or
|
||||
kind = MulExprKind() and
|
||||
result = TMulExprSynth(parent, i)
|
||||
or
|
||||
kind = RShiftExprKind() and
|
||||
result = TRShiftExprSynth(parent, i)
|
||||
or
|
||||
kind = SelfKind() and
|
||||
result = TSelfSynth(parent, i)
|
||||
or
|
||||
kind = StmtSequenceKind() and
|
||||
result = TStmtSequenceSynth(parent, i)
|
||||
or
|
||||
kind = SubExprKind() and
|
||||
result = TSubExprSynth(parent, i)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th child of `parent` is `child`. Either `parent` or
|
||||
* `child` (or both) is a synthesized node.
|
||||
*/
|
||||
cached
|
||||
predicate synthChild(AST::AstNode parent, int i, AST::AstNode child) {
|
||||
child = getSynthChild(parent, i)
|
||||
or
|
||||
any(Synthesis s).child(parent, i, RealChild(child))
|
||||
}
|
||||
|
||||
/**
|
||||
* Like `toGenerated`, but also returns generated nodes for synthesized AST
|
||||
* nodes.
|
||||
*/
|
||||
cached
|
||||
Generated::AstNode toGeneratedInclSynth(AST::AstNode n) {
|
||||
result = toGenerated(n) or
|
||||
n = TImplicitSelf(result)
|
||||
result = toGenerated(n)
|
||||
or
|
||||
not exists(toGenerated(n)) and
|
||||
exists(AST::AstNode parent |
|
||||
synthChild(parent, _, n) and
|
||||
result = toGeneratedInclSynth(parent)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,7 +548,7 @@ class TConditionalLoop = TWhileExpr or TUntilExpr or TWhileModifierExpr or TUnti
|
||||
|
||||
class TLoop = TConditionalLoop or TForExpr;
|
||||
|
||||
class TSelf = TExplicitSelf or TImplicitSelf;
|
||||
class TSelf = TSelfReal or TSelfSynth;
|
||||
|
||||
class TExpr =
|
||||
TSelf or TArgumentList or TRescueClause or TRescueModifierExpr or TPair or TStringConcatenation or
|
||||
@@ -431,7 +558,7 @@ class TExpr =
|
||||
|
||||
class TStmtSequence =
|
||||
TBeginBlock or TEndBlock or TThen or TElse or TDo or TEnsure or TStringInterpolationComponent or
|
||||
TBlock or TBodyStmt or TParenthesizedExpr;
|
||||
TBlock or TBodyStmt or TParenthesizedExpr or TStmtSequenceSynth;
|
||||
|
||||
class TBodyStmt = TBeginExpr or TModuleBase or TMethod or TLambda or TDoBlock or TSingletonMethod;
|
||||
|
||||
@@ -485,17 +612,45 @@ class TBinaryOperation =
|
||||
class TBinaryArithmeticOperation =
|
||||
TAddExpr or TSubExpr or TMulExpr or TDivExpr or TModuloExpr or TExponentExpr;
|
||||
|
||||
class TAddExpr = TAddExprReal or TAddExprSynth;
|
||||
|
||||
class TSubExpr = TSubExprReal or TSubExprSynth;
|
||||
|
||||
class TMulExpr = TMulExprReal or TMulExprSynth;
|
||||
|
||||
class TDivExpr = TDivExprReal or TDivExprSynth;
|
||||
|
||||
class TModuloExpr = TModuloExprReal or TModuloExprSynth;
|
||||
|
||||
class TExponentExpr = TExponentExprReal or TExponentExprSynth;
|
||||
|
||||
class TBinaryLogicalOperation = TLogicalAndExpr or TLogicalOrExpr;
|
||||
|
||||
class TLogicalAndExpr = TLogicalAndExprReal or TLogicalAndExprSynth;
|
||||
|
||||
class TLogicalOrExpr = TLogicalOrExprReal or TLogicalOrExprSynth;
|
||||
|
||||
class TBinaryBitwiseOperation =
|
||||
TLShiftExpr or TRShiftExpr or TBitwiseAndExpr or TBitwiseOrExpr or TBitwiseXorExpr;
|
||||
|
||||
class TLShiftExpr = TLShiftExprReal or TLShiftExprSynth;
|
||||
|
||||
class TRShiftExpr = TRShiftExprReal or TRShiftExprSynth;
|
||||
|
||||
class TBitwiseAndExpr = TBitwiseAndExprReal or TBitwiseAndExprSynth;
|
||||
|
||||
class TBitwiseOrExpr = TBitwiseOrExprReal or TBitwiseOrExprSynth;
|
||||
|
||||
class TBitwiseXorExpr = TBitwiseXorExprReal or TBitwiseXorExprSynth;
|
||||
|
||||
class TComparisonOperation = TEqualityOperation or TRelationalOperation;
|
||||
|
||||
class TEqualityOperation = TEqExpr or TNEExpr or TCaseEqExpr;
|
||||
|
||||
class TRelationalOperation = TGTExpr or TGEExpr or TLTExpr or TLEExpr;
|
||||
|
||||
class TAssignExpr = TAssignExprReal or TAssignExprSynth;
|
||||
|
||||
class TAssignment = TAssignExpr or TAssignOperation;
|
||||
|
||||
class TAssignOperation =
|
||||
@@ -531,3 +686,11 @@ class TTuplePattern = TTuplePatternParameter or TDestructuredLeftAssignment or T
|
||||
|
||||
class TVariableAccess =
|
||||
TLocalVariableAccess or TGlobalVariableAccess or TInstanceVariableAccess or TClassVariableAccess;
|
||||
|
||||
class TLocalVariableAccess = TLocalVariableAccessReal or TLocalVariableAccessSynth;
|
||||
|
||||
class TGlobalVariableAccess = TGlobalVariableAccessReal or TGlobalVariableAccessSynth;
|
||||
|
||||
class TInstanceVariableAccess = TInstanceVariableAccessReal or TInstanceVariableAccessSynth;
|
||||
|
||||
class TClassVariableAccess = TClassVariableAccessReal or TClassVariableAccessSynth;
|
||||
|
||||
@@ -67,7 +67,7 @@ private module Cached {
|
||||
m = resolveScopeExpr(c.getReceiver())
|
||||
or
|
||||
m = enclosingModule(c).getModule() and
|
||||
c.receiverIsSelf()
|
||||
c.getReceiver() instanceof Self
|
||||
) and
|
||||
result = resolveScopeExpr(c.getAnArgument())
|
||||
)
|
||||
@@ -81,7 +81,7 @@ private module Cached {
|
||||
m = resolveScopeExpr(c.getReceiver())
|
||||
or
|
||||
m = enclosingModule(c).getModule() and
|
||||
c.receiverIsSelf()
|
||||
c.getReceiver() instanceof Self
|
||||
) and
|
||||
result = resolveScopeExpr(c.getAnArgument())
|
||||
)
|
||||
|
||||
173
ql/src/codeql_ruby/ast/internal/Synthesis.qll
Normal file
173
ql/src/codeql_ruby/ast/internal/Synthesis.qll
Normal file
@@ -0,0 +1,173 @@
|
||||
/** Provides predicates for synthesizing AST nodes. */
|
||||
|
||||
private import AST
|
||||
private import TreeSitter
|
||||
private import codeql_ruby.ast.internal.Parameter
|
||||
private import codeql_ruby.ast.internal.Variable
|
||||
private import codeql_ruby.AST
|
||||
|
||||
/** A synthesized AST node kind. */
|
||||
newtype SynthKind =
|
||||
AddExprKind() or
|
||||
AssignExprKind() or
|
||||
BitwiseAndExprKind() or
|
||||
BitwiseOrExprKind() or
|
||||
BitwiseXorExprKind() or
|
||||
ClassVariableAccessKind(ClassVariable v) or
|
||||
DivExprKind() or
|
||||
ExponentExprKind() or
|
||||
GlobalVariableAccessKind(GlobalVariable v) or
|
||||
InstanceVariableAccessKind(InstanceVariable v) or
|
||||
LShiftExprKind() or
|
||||
LocalVariableAccessRealKind(LocalVariableReal v) or
|
||||
LocalVariableAccessSynthKind(TLocalVariableSynth v) or
|
||||
LogicalAndExprKind() or
|
||||
LogicalOrExprKind() or
|
||||
ModuloExprKind() or
|
||||
MulExprKind() or
|
||||
StmtSequenceKind() or
|
||||
RShiftExprKind() or
|
||||
SelfKind() or
|
||||
SubExprKind()
|
||||
|
||||
/**
|
||||
* An AST child.
|
||||
*
|
||||
* Either a new synthesized node or a reference to an existing node.
|
||||
*/
|
||||
newtype Child =
|
||||
SynthChild(SynthKind k) or
|
||||
RealChild(AstNode n)
|
||||
|
||||
private newtype TSynthesis = MkSynthesis()
|
||||
|
||||
/** A class used for synthesizing AST nodes. */
|
||||
class Synthesis extends TSynthesis {
|
||||
/**
|
||||
* Holds if a node should be synthesized as the `i`th child of `parent`, or if
|
||||
* a non-synthesized node should be the `i`th child of synthesized node `parent`.
|
||||
*
|
||||
* `i = -1` is used to represent that the synthesized node is a desugared version
|
||||
* of its parent.
|
||||
*/
|
||||
predicate child(AstNode parent, int i, Child child) { none() }
|
||||
|
||||
/**
|
||||
* Holds if a local variable, identified by `i`, should be synthesized for AST
|
||||
* node `n`.
|
||||
*/
|
||||
predicate localVariable(AstNode n, int i) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `n` should be excluded from `ControlFlowTree` in the CFG construction.
|
||||
*/
|
||||
predicate excludeFromControlFlowTree(AstNode n) { none() }
|
||||
|
||||
final string toString() { none() }
|
||||
}
|
||||
|
||||
private module ImplicitSelfSynthesis {
|
||||
private class IdentifierMethodCallSelfSynthesis extends Synthesis {
|
||||
final override predicate child(AstNode parent, int i, Child child) {
|
||||
child = SynthChild(SelfKind()) and
|
||||
parent = TIdentifierMethodCall(_) and
|
||||
i = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class RegularMethodCallSelfSynthesis extends Synthesis {
|
||||
final override predicate child(AstNode parent, int i, Child child) {
|
||||
child = SynthChild(SelfKind()) and
|
||||
i = 0 and
|
||||
exists(Generated::AstNode g |
|
||||
parent = TRegularMethodCall(g) and
|
||||
// If there's no explicit receiver (or scope resolution that acts like a
|
||||
// receiver), then the receiver is implicitly `self`. N.B. `::Foo()` is
|
||||
// not valid Ruby.
|
||||
not exists(g.(Generated::Call).getReceiver()) and
|
||||
not exists(g.(Generated::Call).getMethod().(Generated::ScopeResolution).getScope())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private module AssignOperationDesugar {
|
||||
/**
|
||||
* Gets the operator kind to synthesize for operator assignment `ao`.
|
||||
*/
|
||||
private SynthKind getKind(AssignOperation ao) {
|
||||
ao instanceof AssignAddExpr and result = AddExprKind()
|
||||
or
|
||||
ao instanceof AssignSubExpr and result = SubExprKind()
|
||||
or
|
||||
ao instanceof AssignMulExpr and result = MulExprKind()
|
||||
or
|
||||
ao instanceof AssignDivExpr and result = DivExprKind()
|
||||
or
|
||||
ao instanceof AssignModuloExpr and result = ModuloExprKind()
|
||||
or
|
||||
ao instanceof AssignExponentExpr and result = ExponentExprKind()
|
||||
or
|
||||
ao instanceof AssignLogicalAndExpr and result = LogicalAndExprKind()
|
||||
or
|
||||
ao instanceof AssignLogicalOrExpr and result = LogicalOrExprKind()
|
||||
or
|
||||
ao instanceof AssignLShiftExpr and result = LShiftExprKind()
|
||||
or
|
||||
ao instanceof AssignRShiftExpr and result = RShiftExprKind()
|
||||
or
|
||||
ao instanceof AssignBitwiseAndExpr and result = BitwiseAndExprKind()
|
||||
or
|
||||
ao instanceof AssignBitwiseOrExpr and result = BitwiseOrExprKind()
|
||||
or
|
||||
ao instanceof AssignBitwiseXorExpr and result = BitwiseXorExprKind()
|
||||
}
|
||||
|
||||
/**
|
||||
* ```rb
|
||||
* x += y
|
||||
* ```
|
||||
*
|
||||
* desguars to
|
||||
*
|
||||
* ```rb
|
||||
* x = x + y
|
||||
* ```
|
||||
*
|
||||
* when `x` is a variable.
|
||||
*/
|
||||
private class VariableAssignOperationSynthesis extends Synthesis {
|
||||
final override predicate child(AstNode parent, int i, Child child) {
|
||||
exists(AssignOperation ao, VariableReal v |
|
||||
v = ao.getLeftOperand().(VariableAccessReal).getVariableReal()
|
||||
|
|
||||
parent = ao and
|
||||
i = -1 and
|
||||
child = SynthChild(AssignExprKind())
|
||||
or
|
||||
exists(AstNode assign | assign = getSynthChild(ao, -1) |
|
||||
parent = assign and
|
||||
i = 0 and
|
||||
child = RealChild(ao.getLeftOperand())
|
||||
or
|
||||
parent = assign and
|
||||
i = 1 and
|
||||
child = SynthChild(getKind(ao))
|
||||
or
|
||||
parent = getSynthChild(assign, 1) and
|
||||
(
|
||||
i = 0 and
|
||||
child =
|
||||
SynthChild([
|
||||
LocalVariableAccessRealKind(v).(SynthKind), InstanceVariableAccessKind(v),
|
||||
ClassVariableAccessKind(v), GlobalVariableAccessKind(v)
|
||||
])
|
||||
or
|
||||
i = 1 and
|
||||
child = RealChild(ao.getRightOperand())
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Parameter
|
||||
private import codeql_ruby.ast.internal.Scope
|
||||
private import codeql_ruby.ast.internal.Synthesis
|
||||
|
||||
/**
|
||||
* Holds if `n` is in the left-hand-side of an explicit assignment `assignment`.
|
||||
@@ -128,7 +129,7 @@ private module Cached {
|
||||
other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn()
|
||||
)
|
||||
} or
|
||||
TLocalVariable(Scope::Range scope, string name, Generated::Identifier i) {
|
||||
TLocalVariableReal(Scope::Range scope, string name, Generated::Identifier i) {
|
||||
scopeDefinesParameterVariable(scope, name, i)
|
||||
or
|
||||
i =
|
||||
@@ -139,7 +140,8 @@ private module Cached {
|
||||
) and
|
||||
not scopeDefinesParameterVariable(scope, name, _) and
|
||||
not inherits(scope, name, _)
|
||||
}
|
||||
} or
|
||||
TLocalVariableSynth(AstNode n, int i) { any(Synthesis s).localVariable(n, i) }
|
||||
|
||||
// Db types that can be vcalls
|
||||
private class VcallToken =
|
||||
@@ -288,7 +290,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate access(Generated::Identifier access, Variable::Range variable) {
|
||||
predicate access(Generated::Identifier access, VariableReal::Range variable) {
|
||||
exists(string name |
|
||||
variable.getName() = name and
|
||||
name = access.getValue()
|
||||
@@ -372,8 +374,10 @@ private predicate inherits(Scope::Range scope, string name, Scope::Range outer)
|
||||
)
|
||||
}
|
||||
|
||||
module Variable {
|
||||
class Range extends TVariable {
|
||||
class TVariableReal = TGlobalVariable or TClassVariable or TInstanceVariable or TLocalVariableReal;
|
||||
|
||||
module VariableReal {
|
||||
class Range extends TVariableReal {
|
||||
abstract string getName();
|
||||
|
||||
string toString() { result = this.getName() }
|
||||
@@ -384,13 +388,15 @@ module Variable {
|
||||
}
|
||||
}
|
||||
|
||||
class TLocalVariable = TLocalVariableReal or TLocalVariableSynth;
|
||||
|
||||
module LocalVariable {
|
||||
class Range extends Variable::Range, TLocalVariable {
|
||||
class Range extends VariableReal::Range, TLocalVariableReal {
|
||||
private Scope::Range scope;
|
||||
private string name;
|
||||
private Generated::Identifier i;
|
||||
|
||||
Range() { this = TLocalVariable(scope, name, i) }
|
||||
Range() { this = TLocalVariableReal(scope, name, i) }
|
||||
|
||||
final override string getName() { result = name }
|
||||
|
||||
@@ -402,8 +408,41 @@ module LocalVariable {
|
||||
}
|
||||
}
|
||||
|
||||
class VariableReal extends Variable, TVariableReal {
|
||||
VariableReal::Range range;
|
||||
|
||||
VariableReal() { range = this }
|
||||
|
||||
final override string getName() { result = range.getName() }
|
||||
|
||||
final override Location getLocation() { result = range.getLocation() }
|
||||
|
||||
final override Scope getDeclaringScope() { toGenerated(result) = range.getDeclaringScope() }
|
||||
}
|
||||
|
||||
class LocalVariableReal extends VariableReal, LocalVariable, TLocalVariableReal {
|
||||
override LocalVariable::Range range;
|
||||
|
||||
final override LocalVariableAccessReal getAnAccess() { result.getVariable() = this }
|
||||
|
||||
final override VariableAccess getDefiningAccess() { result = range.getDefiningAccess() }
|
||||
}
|
||||
|
||||
class LocalVariableSynth extends LocalVariable, TLocalVariableSynth {
|
||||
private AstNode n;
|
||||
private int i;
|
||||
|
||||
LocalVariableSynth() { this = TLocalVariableSynth(n, i) }
|
||||
|
||||
final override string getName() { result = "__synth__" + i }
|
||||
|
||||
final override Location getLocation() { result = n.getLocation() }
|
||||
|
||||
final override Scope getDeclaringScope() { none() } // not relevant for synthesized variables
|
||||
}
|
||||
|
||||
module GlobalVariable {
|
||||
class Range extends Variable::Range, TGlobalVariable {
|
||||
class Range extends VariableReal::Range, TGlobalVariable {
|
||||
private string name;
|
||||
|
||||
Range() { this = TGlobalVariable(name) }
|
||||
@@ -417,7 +456,7 @@ module GlobalVariable {
|
||||
}
|
||||
|
||||
module InstanceVariable {
|
||||
class Range extends Variable::Range, TInstanceVariable {
|
||||
class Range extends VariableReal::Range, TInstanceVariable {
|
||||
private ModuleBase::Range scope;
|
||||
private boolean instance;
|
||||
private string name;
|
||||
@@ -436,7 +475,7 @@ module InstanceVariable {
|
||||
}
|
||||
|
||||
module ClassVariable {
|
||||
class Range extends Variable::Range, TClassVariable {
|
||||
class Range extends VariableReal::Range, TClassVariable {
|
||||
private ModuleBase::Range scope;
|
||||
private string name;
|
||||
private Generated::AstNode decl;
|
||||
@@ -464,16 +503,126 @@ module LocalVariableAccess {
|
||||
}
|
||||
}
|
||||
|
||||
class TVariableAccessReal =
|
||||
TLocalVariableAccessReal or TGlobalVariableAccess or TInstanceVariableAccess or
|
||||
TClassVariableAccess;
|
||||
|
||||
abstract class VariableAccessReal extends VariableAccess, TVariableAccessReal {
|
||||
/**
|
||||
* Same as `getVariable()`, but restricted to non-synthesized variable accesses.
|
||||
*
|
||||
* The sole purpose of this predicate is to make AST synthesis monotonic.
|
||||
*/
|
||||
abstract VariableReal getVariableReal();
|
||||
}
|
||||
|
||||
private class LocalVariableAccessReal extends VariableAccessReal, LocalVariableAccess,
|
||||
TLocalVariableAccessReal {
|
||||
private Generated::Identifier g;
|
||||
private LocalVariable v;
|
||||
|
||||
LocalVariableAccessReal() { this = TLocalVariableAccessReal(g, v) }
|
||||
|
||||
final override LocalVariable getVariable() { result = v }
|
||||
|
||||
final override LocalVariableReal getVariableReal() { result = v }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
}
|
||||
|
||||
private class LocalVariableAccessSynth extends LocalVariableAccess, TLocalVariableAccessSynth {
|
||||
private LocalVariable v;
|
||||
|
||||
LocalVariableAccessSynth() { this = TLocalVariableAccessSynth(_, _, v) }
|
||||
|
||||
final override LocalVariable getVariable() { result = v }
|
||||
|
||||
final override string toString() { result = v.getName() }
|
||||
}
|
||||
|
||||
module GlobalVariableAccess {
|
||||
predicate range(Generated::GlobalVariable n, GlobalVariable v) { n.getValue() = v.getName() }
|
||||
}
|
||||
|
||||
private class GlobalVariableAccessReal extends VariableAccessReal, GlobalVariableAccess,
|
||||
TGlobalVariableAccessReal {
|
||||
private Generated::GlobalVariable g;
|
||||
private GlobalVariable v;
|
||||
|
||||
GlobalVariableAccessReal() { this = TGlobalVariableAccessReal(g, v) }
|
||||
|
||||
final override GlobalVariable getVariable() { result = v }
|
||||
|
||||
final override GlobalVariable getVariableReal() { result = v }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
}
|
||||
|
||||
private class GlobalVariableAccessSynth extends GlobalVariableAccess, TGlobalVariableAccessSynth {
|
||||
private GlobalVariable v;
|
||||
|
||||
GlobalVariableAccessSynth() { this = TGlobalVariableAccessSynth(_, _, v) }
|
||||
|
||||
final override GlobalVariable getVariable() { result = v }
|
||||
|
||||
final override string toString() { result = v.getName() }
|
||||
}
|
||||
|
||||
module InstanceVariableAccess {
|
||||
predicate range(Generated::InstanceVariable n, InstanceVariable v) {
|
||||
instanceVariableAccess(n, v)
|
||||
}
|
||||
}
|
||||
|
||||
private class InstanceVariableAccessReal extends VariableAccessReal, InstanceVariableAccess,
|
||||
TInstanceVariableAccessReal {
|
||||
private Generated::InstanceVariable g;
|
||||
private InstanceVariable v;
|
||||
|
||||
InstanceVariableAccessReal() { this = TInstanceVariableAccessReal(g, v) }
|
||||
|
||||
final override InstanceVariable getVariable() { result = v }
|
||||
|
||||
final override InstanceVariable getVariableReal() { result = v }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
}
|
||||
|
||||
private class InstanceVariableAccessSynth extends InstanceVariableAccess,
|
||||
TInstanceVariableAccessSynth {
|
||||
private InstanceVariable v;
|
||||
|
||||
InstanceVariableAccessSynth() { this = TInstanceVariableAccessSynth(_, _, v) }
|
||||
|
||||
final override InstanceVariable getVariable() { result = v }
|
||||
|
||||
final override string toString() { result = v.getName() }
|
||||
}
|
||||
|
||||
module ClassVariableAccess {
|
||||
predicate range(Generated::ClassVariable n, ClassVariable v) { classVariableAccess(n, v) }
|
||||
}
|
||||
|
||||
private class ClassVariableAccessReal extends VariableAccessReal, ClassVariableAccess,
|
||||
TClassVariableAccessReal {
|
||||
private Generated::ClassVariable g;
|
||||
private ClassVariable v;
|
||||
|
||||
ClassVariableAccessReal() { this = TClassVariableAccessReal(g, v) }
|
||||
|
||||
final override ClassVariable getVariable() { result = v }
|
||||
|
||||
final override ClassVariable getVariableReal() { result = v }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
}
|
||||
|
||||
private class ClassVariableAccessSynth extends ClassVariableAccess, TClassVariableAccessSynth {
|
||||
private ClassVariable v;
|
||||
|
||||
ClassVariableAccessSynth() { this = TClassVariableAccessSynth(_, _, v) }
|
||||
|
||||
final override ClassVariable getVariable() { result = v }
|
||||
|
||||
final override string toString() { result = v.getName() }
|
||||
}
|
||||
|
||||
@@ -159,6 +159,13 @@ abstract private class ExprChildMapping extends Expr {
|
||||
)
|
||||
}
|
||||
|
||||
private Expr desugar(Expr n) {
|
||||
result = n.getDesugared()
|
||||
or
|
||||
not exists(n.getDesugared()) and
|
||||
result = n
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a control-flow path from `cfn` to `cfnChild`, where `cfn`
|
||||
* is a control-flow node for this expression, and `cfnChild` is a control-flow
|
||||
@@ -171,13 +178,13 @@ abstract private class ExprChildMapping extends Expr {
|
||||
exists(BasicBlock bb |
|
||||
this.reachesBasicBlockBase(child, cfn, bb) and
|
||||
cfnChild = bb.getANode() and
|
||||
cfnChild = child.getAControlFlowNode()
|
||||
cfnChild = desugar(child).getAControlFlowNode()
|
||||
)
|
||||
or
|
||||
exists(BasicBlock bb |
|
||||
this.reachesBasicBlockRec(child, cfn, bb) and
|
||||
cfnChild = bb.getANode() and
|
||||
cfnChild = child.getAControlFlowNode()
|
||||
cfnChild = desugar(child).getAControlFlowNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* @kind graph
|
||||
* @id rb/test/cfg
|
||||
*/
|
||||
|
||||
import codeql_ruby.CFG
|
||||
|
||||
query predicate nodes(CfgNode n, string attr, string val) {
|
||||
attr = "semmle.order" and
|
||||
val =
|
||||
any(int i |
|
||||
n =
|
||||
rank[i](CfgNode p |
|
||||
|
|
||||
p
|
||||
order by
|
||||
p.getLocation().getFile().getBaseName(), p.getLocation().getFile().getAbsolutePath(),
|
||||
p.getLocation().getStartLine(), p.getLocation().getStartColumn()
|
||||
)
|
||||
).toString()
|
||||
}
|
||||
|
||||
query predicate edges(CfgNode pred, CfgNode succ, string attr, string val) {
|
||||
exists(SuccessorType t | succ = pred.getASuccessor(t) |
|
||||
attr = "semmle.label" and
|
||||
if t instanceof SuccessorTypes::NormalSuccessor then val = "" else val = t.toString()
|
||||
)
|
||||
}
|
||||
32
ql/src/codeql_ruby/controlflow/internal/Cfg.qll
Normal file
32
ql/src/codeql_ruby/controlflow/internal/Cfg.qll
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Import this module into a `.ql` file of `@kind graph` to render a CFG. The
|
||||
* graph is restricted to nodes from `RelevantCfgNode`.
|
||||
*/
|
||||
|
||||
private import codeql.Locations
|
||||
import codeql_ruby.CFG
|
||||
|
||||
abstract class RelevantCfgNode extends CfgNode { }
|
||||
|
||||
query predicate nodes(RelevantCfgNode n, string attr, string val) {
|
||||
attr = "semmle.order" and
|
||||
val =
|
||||
any(int i |
|
||||
n =
|
||||
rank[i](RelevantCfgNode p, Location l |
|
||||
l = p.getLocation()
|
||||
|
|
||||
p
|
||||
order by
|
||||
l.getFile().getBaseName(), l.getFile().getAbsolutePath(), l.getStartLine(),
|
||||
l.getStartColumn()
|
||||
)
|
||||
).toString()
|
||||
}
|
||||
|
||||
query predicate edges(RelevantCfgNode pred, RelevantCfgNode succ, string attr, string val) {
|
||||
exists(SuccessorType t | succ = pred.getASuccessor(t) |
|
||||
attr = "semmle.label" and
|
||||
if t instanceof SuccessorTypes::NormalSuccessor then val = "" else val = t.toString()
|
||||
)
|
||||
}
|
||||
@@ -35,6 +35,7 @@ private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST as ASTInternal
|
||||
private import codeql_ruby.ast.internal.Scope
|
||||
private import codeql_ruby.ast.Scope
|
||||
private import codeql_ruby.ast.internal.Synthesis
|
||||
private import codeql_ruby.ast.internal.TreeSitter
|
||||
private import codeql_ruby.ast.internal.Variable
|
||||
private import codeql_ruby.controlflow.ControlFlowGraph
|
||||
@@ -85,6 +86,8 @@ module CfgScope {
|
||||
}
|
||||
|
||||
abstract private class ControlFlowTree extends AstNode {
|
||||
ControlFlowTree() { not any(Synthesis s).excludeFromControlFlowTree(this) }
|
||||
|
||||
/**
|
||||
* Holds if `first` is the first element executed within this AST node.
|
||||
*/
|
||||
@@ -284,6 +287,8 @@ module Trees {
|
||||
}
|
||||
|
||||
private class AssignOperationTree extends StandardPostOrderTree, AssignOperation {
|
||||
AssignOperationTree() { not this.getLeftOperand() instanceof VariableAccess }
|
||||
|
||||
final override ControlFlowTree getChildNode(int i) {
|
||||
result = this.getLeftOperand() and i = 0
|
||||
or
|
||||
@@ -728,6 +733,22 @@ module Trees {
|
||||
}
|
||||
}
|
||||
|
||||
private class DesugaredTree extends ControlFlowTree {
|
||||
ControlFlowTree desugared;
|
||||
|
||||
DesugaredTree() { desugared = this.getDesugared() }
|
||||
|
||||
final override predicate propagatesAbnormal(AstNode child) {
|
||||
desugared.propagatesAbnormal(child)
|
||||
}
|
||||
|
||||
final override predicate first(AstNode first) { desugared.first(first) }
|
||||
|
||||
final override predicate last(AstNode last, Completion c) { desugared.last(last, c) }
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) { none() }
|
||||
}
|
||||
|
||||
private class DoBlockTree extends BodyStmtPostOrderTree, DoBlock {
|
||||
/** Gets the `i`th child in the body of this block. */
|
||||
final override AstNode getBodyChild(int i, boolean rescuable) {
|
||||
|
||||
@@ -8,6 +8,13 @@
|
||||
|
||||
import AST
|
||||
|
||||
/** Holds if `n` appears in the desugaring of some other node. */
|
||||
predicate isDesugared(AstNode n) {
|
||||
n = any(AstNode sugar).getDesugared()
|
||||
or
|
||||
isDesugared(n.getParent())
|
||||
}
|
||||
|
||||
/**
|
||||
* The query can extend this class to control which nodes are printed.
|
||||
*/
|
||||
@@ -17,7 +24,19 @@ class PrintAstConfiguration extends string {
|
||||
/**
|
||||
* Holds if the given node should be printed.
|
||||
*/
|
||||
predicate shouldPrintNode(AstNode n) { any() }
|
||||
predicate shouldPrintNode(AstNode n) {
|
||||
not isDesugared(n)
|
||||
or
|
||||
not n.isSynthesized()
|
||||
or
|
||||
n.isSynthesized() and
|
||||
not n = any(AstNode sugar).getDesugared() and
|
||||
exists(AstNode parent |
|
||||
parent = n.getParent() and
|
||||
not parent.isSynthesized() and
|
||||
not n = parent.getDesugared()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,12 +51,11 @@ class PrintAstNode extends AstNode {
|
||||
result =
|
||||
any(int i |
|
||||
this =
|
||||
rank[i](AstNode p |
|
||||
|
|
||||
p
|
||||
order by
|
||||
p.getLocation().getFile().getBaseName(), p.getLocation().getFile().getAbsolutePath(),
|
||||
p.getLocation().getStartLine(), p.getLocation().getStartColumn()
|
||||
rank[i](AstNode p, Location l, File f |
|
||||
l = p.getLocation() and
|
||||
f = l.getFile()
|
||||
|
|
||||
p order by f.getBaseName(), f.getAbsolutePath(), l.getStartLine(), l.getStartColumn()
|
||||
)
|
||||
).toString()
|
||||
}
|
||||
@@ -75,10 +93,10 @@ query predicate nodes(PrintAstNode node, string key, string value) {
|
||||
query predicate edges(PrintAstNode source, PrintAstNode target, string key, string value) {
|
||||
source.shouldPrint() and
|
||||
target.shouldPrint() and
|
||||
target = source.getAChild() and
|
||||
target = source.getChild(_) and
|
||||
(
|
||||
key = "semmle.label" and
|
||||
value = concat(string name | source.getChild(name) = target | name, "/")
|
||||
value = strictconcat(string name | source.getChild(name) = target | name, "/")
|
||||
or
|
||||
key = "semmle.order" and
|
||||
value = target.getProperty("semmle.order")
|
||||
|
||||
Reference in New Issue
Block a user