Skip to content
18 changes: 12 additions & 6 deletions rust/ql/lib/codeql/rust/elements/AssignmentOperation.qll
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
/** Provides classes for assignment operations. */
/**
* Provides classes for assignment operations.
*/

private import rust
private import codeql.rust.elements.internal.BinaryExprImpl

/** An assignment operation. */
/**
* An assignment operation, for example:
* ```rust
* x = y;
* x += y;
* ```
*/
abstract private class AssignmentOperationImpl extends Impl::BinaryExpr { }

final class AssignmentOperation = AssignmentOperationImpl;

/**
* An assignment expression, for example
*
* An assignment expression, for example:
* ```rust
* x = y;
* ```
Expand All @@ -22,8 +29,7 @@ final class AssignmentExpr extends AssignmentOperationImpl {
}

/**
* A compound assignment expression, for example
*
* A compound assignment expression, for example:
* ```rust
* x += y;
* ```
Expand Down
29 changes: 21 additions & 8 deletions rust/ql/lib/codeql/rust/elements/LogicalOperation.qll
Original file line number Diff line number Diff line change
@@ -1,33 +1,46 @@
private import codeql.rust.elements.Expr
private import codeql.rust.elements.BinaryExpr
private import codeql.rust.elements.PrefixExpr
private import codeql.rust.elements.Operation

abstract private class LogicalOperationImpl extends Expr {
abstract Expr getAnOperand();
}
/**
* A logical operation, such as `&&`, `||` or `!`.
*/
abstract private class LogicalOperationImpl extends Operation { }

final class LogicalOperation = LogicalOperationImpl;

abstract private class BinaryLogicalOperationImpl extends BinaryExpr, LogicalOperationImpl {
override Expr getAnOperand() { result = [this.getLhs(), this.getRhs()] }
}
/**
* A binary logical operation, such as `&&` or `||`.
*/
abstract private class BinaryLogicalOperationImpl extends BinaryExpr, LogicalOperationImpl { }

final class BinaryLogicalOperation = BinaryLogicalOperationImpl;

/**
* The logical "and" operation, `&&`.
*/
final class LogicalAndExpr extends BinaryLogicalOperationImpl, BinaryExpr {
LogicalAndExpr() { this.getOperatorName() = "&&" }
}

/**
* The logical "or" operation, `||`.
*/
final class LogicalOrExpr extends BinaryLogicalOperationImpl {
LogicalOrExpr() { this.getOperatorName() = "||" }
}

/**
* A unary logical operation, such as `!`.
*/
abstract private class UnaryLogicalOperationImpl extends PrefixExpr, LogicalOperationImpl { }

final class UnaryLogicalOperation = UnaryLogicalOperationImpl;

/**
* A logical "not" operation, `!`.
*/
final class LogicalNotExpr extends UnaryLogicalOperationImpl {
LogicalNotExpr() { this.getOperatorName() = "!" }

override Expr getAnOperand() { result = this.getExpr() }
}
8 changes: 8 additions & 0 deletions rust/ql/lib/codeql/rust/elements/Operation.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Provides classes for operations.
*/

private import internal.OperationImpl
private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl

final class Operation = Impl::Operation;
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

private import codeql.rust.elements.internal.generated.BinaryExpr
private import codeql.rust.elements.internal.OperationImpl::Impl as OperationImpl

/**
* INTERNAL: This module contains the customizable definition of `BinaryExpr` and should not
Expand All @@ -22,7 +23,11 @@ module Impl {
* x += y;
* ```
*/
class BinaryExpr extends Generated::BinaryExpr {
class BinaryExpr extends Generated::BinaryExpr, OperationImpl::Operation {
override string toStringImpl() { result = "... " + this.getOperatorName() + " ..." }

override string getOperatorName() { result = Generated::BinaryExpr.super.getOperatorName() }

override Expr getAnOperand() { result = [this.getLhs(), this.getRhs()] }
}
}
29 changes: 29 additions & 0 deletions rust/ql/lib/codeql/rust/elements/internal/OperationImpl.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Provides classes for operations.
*
* INTERNAL: Do not use.
*/

private import rust
private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl

/**
* INTERNAL: This module contains the customizable definition of `Operation` and should not
* be referenced directly.
*/
module Impl {
/**
* An operation, for example `&&`, `+=`, `!` or `*`.
*/
abstract class Operation extends ExprImpl::Expr {
/**
* Gets the operator name of this operation, if it exists.
*/
abstract string getOperatorName();

/**
* Gets an operand of this operation.
*/
abstract Expr getAnOperand();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

private import codeql.rust.elements.internal.generated.PrefixExpr
private import codeql.rust.elements.internal.OperationImpl::Impl as OperationImpl

/**
* INTERNAL: This module contains the customizable definition of `PrefixExpr` and should not
Expand All @@ -20,7 +21,11 @@ module Impl {
* let z = *ptr;
* ```
*/
class PrefixExpr extends Generated::PrefixExpr {
class PrefixExpr extends Generated::PrefixExpr, OperationImpl::Operation {
override string toStringImpl() { result = this.getOperatorName() + " ..." }

override string getOperatorName() { result = Generated::PrefixExpr.super.getOperatorName() }

override Expr getAnOperand() { result = this.getExpr() }
}
}
1 change: 1 addition & 0 deletions rust/ql/lib/rust.qll
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import codeql.rust.elements
import codeql.Locations
import codeql.files.FileSystem
import codeql.rust.elements.Operation
import codeql.rust.elements.AssignmentOperation
import codeql.rust.elements.LogicalOperation
import codeql.rust.elements.AsyncBlockExpr
Expand Down
Empty file.
41 changes: 41 additions & 0 deletions rust/ql/test/library-tests/operations/Operations.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import rust
import utils.test.InlineExpectationsTest

string describe(Expr op) {
op instanceof Operation and result = "Operation"
or
op instanceof PrefixExpr and result = "PrefixExpr"
or
op instanceof BinaryExpr and result = "BinaryExpr"
or
op instanceof AssignmentOperation and result = "AssignmentOperation"
or
op instanceof LogicalOperation and result = "LogicalOperation"
or
op instanceof RefExpr and result = "RefExpr"
}

module OperationsTest implements TestSig {
string getARelevantTag() { result = describe(_) or result = ["Op", "Operands"] }

predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr op |
location = op.getLocation() and
location.getFile().getBaseName() != "" and
element = op.toString() and
(
tag = describe(op) and
value = ""
or
tag = "Op" and
value = op.(Operation).getOperatorName()
or
op instanceof Operation and
tag = "Operands" and
value = count(op.(Operation).getAnOperand()).toString()
)
)
}
}

import MakeTest<OperationsTest>
57 changes: 57 additions & 0 deletions rust/ql/test/library-tests/operations/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

// --- tests ---

fn test_operations(
y: i32, a: bool, b: bool,
ptr: &i32, res: Result<i32, ()>) -> Result<(), ()>
{
let mut x: i32;

// simple assignment
x = y; // $ Operation Op== Operands=2 AssignmentOperation BinaryExpr

// comparison operations
x == y; // $ Operation Op=== Operands=2 BinaryExpr
x != y; // $ Operation Op=!= Operands=2 BinaryExpr
x < y; // $ Operation Op=< Operands=2 BinaryExpr
x <= y; // $ Operation Op=<= Operands=2 BinaryExpr
x > y; // $ Operation Op=> Operands=2 BinaryExpr
x >= y; // $ Operation Op=>= Operands=2 BinaryExpr

// arithmetic operations
x + y; // $ Operation Op=+ Operands=2 BinaryExpr
x - y; // $ Operation Op=- Operands=2 BinaryExpr
x * y; // $ Operation Op=* Operands=2 BinaryExpr
x / y; // $ Operation Op=/ Operands=2 BinaryExpr
x % y; // $ Operation Op=% Operands=2 BinaryExpr
x += y; // $ Operation Op=+= Operands=2 AssignmentOperation BinaryExpr
x -= y; // $ Operation Op=-= Operands=2 AssignmentOperation BinaryExpr
x *= y; // $ Operation Op=*= Operands=2 AssignmentOperation BinaryExpr
x /= y; // $ Operation Op=/= Operands=2 AssignmentOperation BinaryExpr
x %= y; // $ Operation Op=%= Operands=2 AssignmentOperation BinaryExpr
-x; // $ Operation Op=- Operands=1 PrefixExpr

// logical operations
a && b; // $ Operation Op=&& Operands=2 BinaryExpr LogicalOperation
a || b; // $ Operation Op=|| Operands=2 BinaryExpr LogicalOperation
!a; // $ Operation Op=! Operands=1 PrefixExpr LogicalOperation

// bitwise operations
x & y; // $ Operation Op=& Operands=2 BinaryExpr
x | y; // $ Operation Op=| Operands=2 BinaryExpr
x ^ y; // $ Operation Op=^ Operands=2 BinaryExpr
x << y; // $ Operation Op=<< Operands=2 BinaryExpr
x >> y; // $ Operation Op=>> Operands=2 BinaryExpr
x &= y; // $ Operation Op=&= Operands=2 AssignmentOperation BinaryExpr
x |= y; // $ Operation Op=|= Operands=2 AssignmentOperation BinaryExpr
x ^= y; // $ Operation Op=^= Operands=2 AssignmentOperation BinaryExpr
x <<= y; // $ Operation Op=<<= Operands=2 AssignmentOperation BinaryExpr
x >>= y; // $ Operation Op=>>= Operands=2 AssignmentOperation BinaryExpr

// miscellaneous expressions that might be operations
*ptr; // $ Operation Op=* Operands=1 PrefixExpr
&x; // $ RefExpr
res?;

return Ok(());
}