Merge pull request #138 from github/aibaars/part-1

AST: getChild/getParent
This commit is contained in:
Arthur Baars
2021-02-18 19:00:08 +01:00
committed by GitHub
22 changed files with 360 additions and 40 deletions

View File

@@ -36,4 +36,10 @@ class AstNode extends @ast_node {
/** Gets the location of this node. */
final Location getLocation() { result = range.getLocation() }
/** Gets a child node of this `AstNode`. */
final AstNode getAChild() { range.child(_, result) }
/** Gets the parent of this `AstNode`, if this node is not a root node. */
final AstNode getParent() { result.getAChild() = this }
}

View File

@@ -177,7 +177,7 @@ class RescueClause extends Expr, @rescue {
* end
* ```
*/
final Expr getVariableExpr() { result = range.getVariableExpr() }
final LhsExpr getVariableExpr() { result = range.getVariableExpr() }
/**
* Gets the exception handler body.

View File

@@ -445,10 +445,10 @@ class Assignment extends Operation {
override Assignment::Range range;
/** Gets the left hand side of this assignment. */
final Expr getLhs() { result = range.getLhs() }
final Expr getLeftOperand() { result = range.getLeftOperand() }
/** Gets the right hand side of this assignment. */
final Expr getRhs() { result = range.getRhs() }
final Expr getRightOperand() { result = range.getRightOperand() }
}
/**

View File

@@ -120,9 +120,8 @@ class KeywordParameter extends @keyword_parameter, NamedParameter {
* Gets the default value, i.e. the value assigned to the parameter when one
* is not provided by the caller. If the parameter is mandatory and does not
* have a default value, this predicate has no result.
* TODO: better return type (Expr?)
*/
final AstNode getDefaultValue() { result = range.getDefaultValue() }
final Expr getDefaultValue() { result = range.getDefaultValue() }
/**
* Holds if the parameter is optional. That is, there is a default value that
@@ -148,9 +147,8 @@ class OptionalParameter extends @optional_parameter, NamedParameter {
/**
* Gets the default value, i.e. the value assigned to the parameter when one
* is not provided by the caller.
* TODO: better return type (Expr?)
*/
final AstNode getDefaultValue() { result = range.getDefaultValue() }
final Expr getDefaultValue() { result = range.getDefaultValue() }
}
/**

View File

@@ -35,7 +35,7 @@ class LhsExpr extends Pattern, Expr {
}
/** A simple variable pattern. */
class VariablePattern extends Pattern {
class VariablePattern extends Pattern, VariablePattern::VariableToken {
override VariablePattern::Range range;
/** Gets the variable used in (or introduced by) this pattern. */

View File

@@ -36,7 +36,21 @@ class EmptyStmt extends Stmt, @token_empty_statement {
}
/**
* An `BEGIN` block.
* A `begin` statement.
* ```rb
* begin
* puts "hello world"
* end
* ```
*/
class BeginExpr extends BodyStatement, @begin {
final override Begin::Range range;
final override string getAPrimaryQlClass() { result = "BeginExpr" }
}
/**
* A `BEGIN` block.
* ```rb
* BEGIN { puts "starting ..." }
* ```

View File

@@ -156,7 +156,7 @@ class VariableReadAccess extends VariableAccess {
not this instanceof VariableWriteAccess
or
// `x` in `x += y` is considered both a read and a write
this = any(AssignOperation a).getLhs()
this = any(AssignOperation a).getLeftOperand()
}
}

View File

@@ -11,6 +11,8 @@ module AstNode {
abstract string toString();
Location getLocation() { result = generated.getLocation() }
predicate child(string label, AstNode::Range child) { none() }
}
// TODO: Remove

View File

@@ -1,4 +1,5 @@
private import codeql_ruby.AST
private import codeql_ruby.ast.internal.AST
private import codeql_ruby.ast.internal.Expr
private import codeql_ruby.ast.internal.TreeSitter
private import codeql_ruby.ast.internal.Variable
@@ -14,6 +15,14 @@ module Call {
abstract Block getBlock();
override string toString() { result = "call to " + this.getMethodName() }
final override predicate child(string label, AstNode::Range child) {
label = "getReceiver" and child = getReceiver()
or
label = "getArgument" and child = getArgument(_)
or
label = "getBlock" and child = getBlock()
}
}
private class IdentifierCallRange extends Call::Range, @token_identifier {
@@ -144,6 +153,10 @@ module BlockArgument {
final Expr getExpr() { result = generated.getChild() }
final override string toString() { result = "&..." }
final override predicate child(string label, AstNode::Range child) {
label = "getExpr" and child = getExpr()
}
}
}
@@ -154,6 +167,10 @@ module SplatArgument {
final Expr getExpr() { result = generated.getChild() }
final override string toString() { result = "*..." }
final override predicate child(string label, AstNode::Range child) {
label = "getExpr" and child = getExpr()
}
}
}
@@ -164,5 +181,9 @@ module HashSplatArgument {
final Expr getExpr() { result = generated.getChild() }
final override string toString() { result = "**..." }
final override predicate child(string label, AstNode::Range child) {
label = "getExpr" and child = getExpr()
}
}
}

View File

@@ -1,3 +1,4 @@
private import codeql_ruby.ast.internal.AST
private import codeql_ruby.ast.internal.Expr
private import codeql_ruby.ast.internal.Pattern
private import codeql_ruby.ast.internal.TreeSitter
@@ -12,6 +13,10 @@ module ConstantAccess {
abstract Expr::Range getScopeExpr();
abstract predicate hasGlobalScope();
override predicate child(string label, AstNode::Range child) {
label = "getScopeExpr" and child = getScopeExpr()
}
}
}

View File

@@ -1,4 +1,5 @@
private import codeql_ruby.AST
private import codeql_ruby.ast.internal.AST
private import codeql_ruby.ast.internal.Expr
private import codeql_ruby.ast.internal.Pattern
private import codeql_ruby.ast.internal.TreeSitter
@@ -12,6 +13,12 @@ module ConditionalExpr {
abstract Expr getCondition();
abstract Expr getBranch(boolean cond);
override predicate child(string label, AstNode::Range child) {
label = "getCondition" and child = getCondition()
or
label = "getBranch" and child = getBranch(_)
}
}
}
@@ -24,6 +31,14 @@ module IfExpr {
final override string toString() {
if this instanceof @elsif then result = "elsif ..." else result = "if ..."
}
override predicate child(string label, AstNode::Range child) {
super.child(label, child)
or
label = "getThen" and child = getThen()
or
label = "getElse" and child = getElse()
}
}
private class IfRange extends IfExpr::Range, @if {
@@ -76,6 +91,14 @@ module UnlessExpr {
}
final override string toString() { result = "unless ..." }
override predicate child(string label, AstNode::Range child) {
ConditionalExpr::Range.super.child(label, child)
or
label = "getThen" and child = getThen()
or
label = "getElse" and child = getElse()
}
}
}
@@ -90,6 +113,12 @@ module IfModifierExpr {
final override Expr getBranch(boolean cond) { cond = true and result = getExpr() }
final override string toString() { result = "... if ..." }
override predicate child(string label, AstNode::Range child) {
ConditionalExpr::Range.super.child(label, child)
or
label = "getExpr" and child = getExpr()
}
}
}
@@ -104,6 +133,12 @@ module UnlessModifierExpr {
final override Expr getBranch(boolean cond) { cond = false and result = getExpr() }
final override string toString() { result = "... unless ..." }
override predicate child(string label, AstNode::Range child) {
ConditionalExpr::Range.super.child(label, child)
or
label = "getExpr" and child = getExpr()
}
}
}
@@ -124,6 +159,14 @@ module TernaryIfExpr {
}
final override string toString() { result = "... ? ... : ..." }
override predicate child(string label, AstNode::Range child) {
ConditionalExpr::Range.super.child(label, child)
or
label = "getThen" and child = getThen()
or
label = "getElse" and child = getElse()
}
}
}
@@ -136,6 +179,12 @@ module CaseExpr {
final Expr getBranch(int n) { result = generated.getChild(n) }
final override string toString() { result = "case ..." }
override predicate child(string label, AstNode::Range child) {
label = "getValue" and child = getValue()
or
label = "getBranch" and child = getBranch(_)
}
}
}
@@ -148,18 +197,34 @@ module WhenExpr {
final Expr getPattern(int n) { result = generated.getPattern(n).getChild() }
final override string toString() { result = "when ..." }
override predicate child(string label, AstNode::Range child) {
label = "getBody" and child = getBody()
or
label = "getPattern" and child = getPattern(_)
}
}
}
module Loop {
abstract class Range extends ControlExpr::Range {
abstract Expr getBody();
override predicate child(string label, AstNode::Range child) {
label = "getBody" and child = getBody()
}
}
}
module ConditionalLoop {
abstract class Range extends Loop::Range {
abstract Expr getCondition();
override predicate child(string label, AstNode::Range child) {
super.child(label, child)
or
label = "getCondition" and child = getCondition()
}
}
}
@@ -222,5 +287,13 @@ module ForExpr {
final Expr getValue() { result = generated.getValue().getChild() }
final override string toString() { result = "for ... in ..." }
override predicate child(string label, AstNode::Range child) {
Loop::Range.super.child(label, child)
or
label = "getPattern" and child = getPattern()
or
label = "getValue" and child = getValue()
}
}
}

View File

@@ -1,4 +1,5 @@
private import codeql_ruby.AST
private import codeql_ruby.ast.internal.AST
private import codeql_ruby.ast.internal.Literal
private import codeql_ruby.ast.internal.Statement
private import codeql_ruby.ast.internal.TreeSitter
@@ -30,6 +31,10 @@ module StmtSequence {
c > 1 and result = "...; ..."
)
}
override predicate child(string label, AstNode::Range child) {
label = "getStmt" and child = getStmt(_)
}
}
}
@@ -56,6 +61,16 @@ module BodyStatement {
final StmtSequence getEnsure() { result = unique(Generated::Ensure s | s = getChild(_)) }
abstract Generated::AstNode getChild(int i);
override predicate child(string label, AstNode::Range child) {
StmtSequence::Range.super.child(label, child)
or
label = "getRescue" and child = getRescue(_)
or
label = "getElse" and child = getElse()
or
label = "getEnsure" and child = getEnsure()
}
}
}
@@ -75,16 +90,6 @@ module ParenthesizedExpr {
}
}
module BeginBlock {
class Range extends StmtSequence::Range, @begin_block {
final override Generated::BeginBlock generated;
final override Stmt getStmt(int n) { result = generated.getChild(n) }
final override string toString() { result = "BEGIN { ... }" }
}
}
module ThenExpr {
class Range extends StmtSequence::Range, @then {
final override Generated::Then generated;
@@ -123,13 +128,21 @@ module RescueClause {
class Range extends Expr::Range, @rescue {
final override Generated::Rescue generated;
final LhsExpr getException(int n) { result = generated.getExceptions().getChild(n) }
final Expr getException(int n) { result = generated.getExceptions().getChild(n) }
final Expr getVariableExpr() { result = generated.getVariable() }
final LhsExpr getVariableExpr() { result = generated.getVariable().getChild() }
final StmtSequence getBody() { result = generated.getBody() }
final override string toString() { result = "rescue ..." }
override predicate child(string label, AstNode::Range child) {
label = "getException" and child = getException(_)
or
label = "getVariableExpr" and child = getVariableExpr()
or
label = "getBody" and child = getBody()
}
}
}
@@ -142,6 +155,12 @@ module RescueModifierExpr {
final Stmt getHandler() { result = generated.getHandler() }
final override string toString() { result = "... rescue ..." }
override predicate child(string label, AstNode::Range child) {
label = "getBody" and child = getBody()
or
label = "getHandler" and child = getHandler()
}
}
}
@@ -154,6 +173,12 @@ module Pair {
final Expr getValue() { result = generated.getValue() }
final override string toString() { result = "Pair" }
override predicate child(string label, AstNode::Range child) {
label = "getKey" and child = getKey()
or
label = "getValue" and child = getValue()
}
}
}
@@ -164,5 +189,9 @@ module StringConcatenation {
final StringLiteral::Range getString(int i) { result = generated.getChild(i) }
final override string toString() { result = "\"...\" \"...\"" }
override predicate child(string label, AstNode::Range child) {
label = "getString" and child = getString(_)
}
}
}

View File

@@ -128,6 +128,10 @@ module StringInterpolationComponent {
}
final override string getValueText() { none() }
override predicate child(string label, AstNode::Range child) {
StmtSequence::Range.super.child(label, child)
}
}
}
@@ -176,6 +180,10 @@ module StringlikeLiteral {
result = this.getStartDelimiter() + summary + this.getEndDelimiter()
)
}
override predicate child(string label, AstNode::Range child) {
label = "getComponent" and child = getComponent(_)
}
}
}
@@ -340,6 +348,10 @@ module ArrayLiteral {
final override string getValueText() { none() }
abstract Expr getElement(int i);
override predicate child(string label, AstNode::Range child) {
label = "getElement" and child = getElement(_)
}
}
private class RegularArrayRange extends ArrayLiteral::Range, @array {
@@ -376,6 +388,10 @@ module HashLiteral {
final Expr getElement(int i) { result = generated.getChild(i) }
final override string toString() { result = "{...}" }
override predicate child(string label, AstNode::Range child) {
label = "getElement" and child = getElement(_)
}
}
}
@@ -394,6 +410,12 @@ module RangeLiteral {
final predicate isInclusive() { this instanceof @range_dotdot }
final predicate isExclusive() { this instanceof @range_dotdotdot }
override predicate child(string label, AstNode::Range child) {
label = "getBegin" and child = getBegin()
or
label = "getEnd" and child = getEnd()
}
}
}

View File

@@ -1,4 +1,5 @@
private import codeql_ruby.AST
private import codeql_ruby.ast.internal.AST
private import codeql_ruby.ast.internal.Expr
private import codeql_ruby.ast.internal.Parameter
private import TreeSitter
@@ -6,6 +7,10 @@ private import TreeSitter
module Callable {
abstract class Range extends Expr::Range {
abstract Parameter::Range getParameter(int n);
override predicate child(string label, AstNode::Range child) {
label = "getParameter" and child = getParameter(_)
}
}
}
@@ -25,6 +30,10 @@ module Method {
final override Generated::AstNode getChild(int i) { result = generated.getChild(i) }
final override string toString() { result = this.getName() }
override predicate child(string label, AstNode::Range child) {
Callable::Range.super.child(label, child) or BodyStatement::Range.super.child(label, child)
}
}
}
@@ -45,6 +54,14 @@ module SingletonMethod {
final override Generated::AstNode getChild(int i) { result = generated.getChild(i) }
final override string toString() { result = this.getName() }
override predicate child(string label, AstNode::Range child) {
Callable::Range.super.child(label, child)
or
BodyStatement::Range.super.child(label, child)
or
label = "getObject" and child = getObject()
}
}
}
@@ -62,12 +79,24 @@ module Lambda {
}
final override string toString() { result = "-> { ... }" }
override predicate child(string label, AstNode::Range child) {
Callable::Range.super.child(label, child)
or
BodyStatement::Range.super.child(label, child)
}
}
}
module Block {
abstract class Range extends Callable::Range, StmtSequence::Range {
Range() { not generated.getParent() instanceof Generated::Lambda }
override predicate child(string label, AstNode::Range child) {
Callable::Range.super.child(label, child)
or
StmtSequence::Range.super.child(label, child)
}
}
}
@@ -82,6 +111,12 @@ module DoBlock {
}
final override string toString() { result = "do ... end" }
override predicate child(string label, AstNode::Range child) {
Block::Range.super.child(label, child)
or
BodyStatement::Range.super.child(label, child)
}
}
}

View File

@@ -1,4 +1,5 @@
private import codeql_ruby.AST
private import codeql_ruby.ast.internal.AST
private import codeql_ruby.ast.internal.Constant
private import codeql_ruby.ast.internal.Expr
private import codeql_ruby.ast.internal.TreeSitter
@@ -23,6 +24,12 @@ module Toplevel {
}
final override string toString() { result = generated.getLocation().getFile().getBaseName() }
override predicate child(string label, AstNode::Range child) {
ModuleBase::Range.super.child(label, child)
or
label = "getBeginBlock" and child = getBeginBlock(_)
}
}
}
@@ -52,6 +59,14 @@ module Class {
final Expr getSuperclassExpr() { result = generated.getSuperclass().getChild() }
final override string toString() { result = this.getName() }
override predicate child(string label, AstNode::Range child) {
ModuleBase::Range.super.child(label, child)
or
ConstantWriteAccess::Range.super.child(label, child)
or
label = "getSuperclassExpr" and child = getSuperclassExpr()
}
}
}
@@ -64,6 +79,12 @@ module SingletonClass {
final Expr getValue() { result = generated.getValue() }
final override string toString() { result = "class << ..." }
override predicate child(string label, AstNode::Range child) {
ModuleBase::Range.super.child(label, child)
or
label = "getValue" and child = getValue()
}
}
}
@@ -91,5 +112,11 @@ module Module {
}
final override string toString() { result = this.getName() }
override predicate child(string label, AstNode::Range child) {
ModuleBase::Range.super.child(label, child)
or
ConstantWriteAccess::Range.super.child(label, child)
}
}
}

View File

@@ -1,4 +1,5 @@
import codeql_ruby.AST
private import codeql_ruby.AST
private import codeql_ruby.ast.internal.AST
private import codeql_ruby.ast.internal.TreeSitter
private import codeql_ruby.ast.internal.Expr
@@ -7,6 +8,10 @@ module Operation {
abstract string getOperator();
abstract Expr getAnOperand();
override predicate child(string label, AstNode::Range child) {
label = "getAnOperand" and child = getAnOperand()
}
}
}
@@ -21,6 +26,12 @@ module UnaryOperation {
final override Expr getAnOperand() { result = this.getOperand() }
override string toString() { result = this.getOperator() + " ..." }
override predicate child(string label, AstNode::Range child) {
Operation::Range.super.child(label, child)
or
label = "getOperand" and child = getOperand()
}
}
}
@@ -73,6 +84,14 @@ module BinaryOperation {
}
override string toString() { result = "... " + this.getOperator() + " ..." }
override predicate child(string label, AstNode::Range child) {
Operation::Range.super.child(label, child)
or
label = "getLeftOperand" and child = getLeftOperand()
or
label = "getRightOperand" and child = getRightOperand()
}
}
}
@@ -169,6 +188,14 @@ module RelationalOperation {
abstract Expr getGreaterOperand();
abstract Expr getLesserOperand();
override predicate child(string label, AstNode::Range child) {
ComparisonOperation::Range.super.child(label, child)
or
label = "getGreaterOperand" and child = getGreaterOperand()
or
label = "getLesserOperand" and child = getLesserOperand()
}
}
}
@@ -218,13 +245,23 @@ module NoRegexMatchExpr {
module Assignment {
abstract class Range extends Operation::Range {
abstract Expr getLhs();
abstract Expr getLeftOperand();
abstract Expr getRhs();
abstract Expr getRightOperand();
final override Expr getAnOperand() { result = this.getLhs() or result = this.getRhs() }
final override Expr getAnOperand() {
result = this.getLeftOperand() or result = this.getRightOperand()
}
override string toString() { result = "... " + this.getOperator() + " ..." }
override predicate child(string label, AstNode::Range child) {
Operation::Range.super.child(label, child)
or
label = "getLeftOperand" and child = getLeftOperand()
or
label = "getRightOperand" and child = getRightOperand()
}
}
}
@@ -232,9 +269,9 @@ module AssignExpr {
class Range extends Assignment::Range, @assignment {
final override Generated::Assignment generated;
final override Expr getLhs() { result = generated.getLeft() }
final override Expr getLeftOperand() { result = generated.getLeft() }
final override Expr getRhs() { result = generated.getRight() }
final override Expr getRightOperand() { result = generated.getRight() }
final override string getOperator() { result = "=" }
}
@@ -246,9 +283,9 @@ module AssignOperation {
final override string getOperator() { result = generated.getOperator() }
final override LhsExpr getLhs() { result = generated.getLeft() }
final override LhsExpr getLeftOperand() { result = generated.getLeft() }
final override Expr getRhs() { result = generated.getRight() }
final override Expr getRightOperand() { result = generated.getRight() }
}
}

View File

@@ -1,6 +1,7 @@
private import codeql_ruby.AST
private import TreeSitter
private import codeql_ruby.ast.internal.AST
private import codeql_ruby.ast.internal.Expr
private import codeql_ruby.ast.internal.Variable
private import codeql_ruby.ast.internal.Method
private import codeql_ruby.ast.internal.Pattern
@@ -61,6 +62,11 @@ module TuplePatternParameter {
override LocalVariable getAVariable() { result = TuplePattern::Range.super.getAVariable() }
override string toString() { result = TuplePattern::Range.super.toString() }
override predicate child(string label, AstNode::Range child) {
PatternParameter::Range.super.child(label, child) or
TuplePattern::Range.super.child(label, child)
}
}
}
@@ -100,7 +106,7 @@ module KeywordParameter {
result = TLocalVariable(_, _, generated.getName())
}
final Generated::AstNode getDefaultValue() { result = generated.getValue() }
final Expr::Range getDefaultValue() { result = generated.getValue() }
final override string toString() { result = this.getName() }
@@ -116,7 +122,7 @@ module OptionalParameter {
result = TLocalVariable(_, _, generated.getName())
}
final Generated::AstNode getDefaultValue() { result = generated.getValue() }
final Expr::Range getDefaultValue() { result = generated.getValue() }
final override string toString() { result = this.getName() }

View File

@@ -64,8 +64,11 @@ module LhsExpr {
}
module VariablePattern {
class Range extends LhsExpr::Range, @token_identifier {
override Generated::Identifier generated;
class VariableToken =
@token_identifier or @token_instance_variable or @token_class_variable or @token_global_variable;
class Range extends LhsExpr::Range, VariableToken {
override Generated::Token generated;
string getVariableName() { result = generated.getValue() }
@@ -101,5 +104,9 @@ module TuplePattern {
override Variable getAVariable() { result = this.getElement(_).getAVariable() }
override string toString() { result = "(..., ...)" }
override predicate child(string label, AstNode::Range child) {
label = "getElement" and child = getElement(_)
}
}
}

View File

@@ -12,6 +12,28 @@ module EmptyStmt {
final override Generated::EmptyStatement generated;
final override string toString() { result = ";" }
override predicate child(string label, AstNode::Range child) { none() }
}
}
module Begin {
class Range extends BodyStatement::Range, @begin {
final override Generated::Begin generated;
final override Generated::AstNode getChild(int n) { result = generated.getChild(n) }
final override string toString() { result = "begin ... " }
}
}
module BeginBlock {
class Range extends StmtSequence::Range, @begin_block {
final override Generated::BeginBlock generated;
final override Stmt getStmt(int n) { result = generated.getChild(n) }
final override string toString() { result = "BEGIN { ... }" }
}
}
@@ -32,6 +54,10 @@ module UndefStmt {
final MethodName getMethodName(int n) { result = generated.getChild(n) }
final override string toString() { result = "undef ..." }
override predicate child(string label, AstNode::Range child) {
label = "getMethodName" and child = getMethodName(_)
}
}
}
@@ -44,6 +70,12 @@ module AliasStmt {
final MethodName getOldName() { result = generated.getAlias() }
final override string toString() { result = "alias ..." }
override predicate child(string label, AstNode::Range child) {
label = "getNewName" and child = getNewName()
or
label = "getOldName" and child = getOldName()
}
}
}
@@ -60,6 +92,10 @@ module ReturningStmt {
result = a and c > 1
)
}
override predicate child(string label, AstNode::Range child) {
label = "getValue" and child = getValue()
}
}
}

View File

@@ -578,6 +578,8 @@ module VariableAccess {
abstract Variable getVariable();
final override string toString() { result = this.getVariable().getName() }
override predicate child(string label, AstNode::Range child) { none() }
}
}

View File

@@ -218,10 +218,10 @@ module ExprNodes {
final override Assignment getExpr() { result = ExprCfgNode.super.getExpr() }
/** Gets the LHS of this assignment. */
final ExprCfgNode getLhs() { e.hasCfgChild(e.getLhs(), this, result) }
final ExprCfgNode getLhs() { e.hasCfgChild(e.getLeftOperand(), this, result) }
/** Gets the RHS of this assignment. */
final ExprCfgNode getRhs() { e.hasCfgChild(e.getRhs(), this, result) }
final ExprCfgNode getRhs() { e.hasCfgChild(e.getRightOperand(), this, result) }
}
/** A control-flow node that wraps an `AssignExpr` AST expression. */

View File

@@ -2,8 +2,8 @@ import ruby
query predicate assignments(Assignment a, string operator, Expr left, Expr right, string pClass) {
operator = a.getOperator() and
left = a.getLhs() and
right = a.getRhs() and
left = a.getLeftOperand() and
right = a.getRightOperand() and
pClass = a.getAPrimaryQlClass()
}
@@ -11,8 +11,8 @@ query predicate assignOperations(
AssignOperation o, string operator, Expr left, Expr right, string pClass
) {
operator = o.getOperator() and
left = o.getLhs() and
right = o.getRhs() and
left = o.getLeftOperand() and
right = o.getRightOperand() and
pClass = o.getAPrimaryQlClass()
}