diff --git a/rust/ql/lib/codeql/rust/elements/AssignmentOperation.qll b/rust/ql/lib/codeql/rust/elements/AssignmentOperation.qll index 368e5738c191..a3ca1722b577 100644 --- a/rust/ql/lib/codeql/rust/elements/AssignmentOperation.qll +++ b/rust/ql/lib/codeql/rust/elements/AssignmentOperation.qll @@ -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; * ``` @@ -22,8 +29,7 @@ final class AssignmentExpr extends AssignmentOperationImpl { } /** - * A compound assignment expression, for example - * + * A compound assignment expression, for example: * ```rust * x += y; * ``` diff --git a/rust/ql/lib/codeql/rust/elements/LogicalOperation.qll b/rust/ql/lib/codeql/rust/elements/LogicalOperation.qll index fdbfb5d4613a..72cc4ffdf57e 100644 --- a/rust/ql/lib/codeql/rust/elements/LogicalOperation.qll +++ b/rust/ql/lib/codeql/rust/elements/LogicalOperation.qll @@ -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() } } diff --git a/rust/ql/lib/codeql/rust/elements/Operation.qll b/rust/ql/lib/codeql/rust/elements/Operation.qll new file mode 100644 index 000000000000..b3615bddb33e --- /dev/null +++ b/rust/ql/lib/codeql/rust/elements/Operation.qll @@ -0,0 +1,8 @@ +/** + * Provides classes for operations. + */ + +import internal.OperationImpl +private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl + +final class Operation = OperationImpl::Operation; diff --git a/rust/ql/lib/codeql/rust/elements/internal/BinaryExprImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/BinaryExprImpl.qll index 6aac95fcacee..42ac0521db3c 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/BinaryExprImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/BinaryExprImpl.qll @@ -5,6 +5,7 @@ */ private import codeql.rust.elements.internal.generated.BinaryExpr +private import codeql.rust.elements.Operation::OperationImpl as OperationImpl /** * INTERNAL: This module contains the customizable definition of `BinaryExpr` and should not @@ -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()] } } } diff --git a/rust/ql/lib/codeql/rust/elements/internal/OperationImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/OperationImpl.qll new file mode 100644 index 000000000000..7b2d1a9d62e2 --- /dev/null +++ b/rust/ql/lib/codeql/rust/elements/internal/OperationImpl.qll @@ -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 OperationImpl { + /** + * 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(); + } +} diff --git a/rust/ql/lib/codeql/rust/elements/internal/PrefixExprImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/PrefixExprImpl.qll index bf77c7b88ea4..56cc43babd0c 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/PrefixExprImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/PrefixExprImpl.qll @@ -5,6 +5,7 @@ */ private import codeql.rust.elements.internal.generated.PrefixExpr +private import codeql.rust.elements.Operation::OperationImpl as OperationImpl /** * INTERNAL: This module contains the customizable definition of `PrefixExpr` and should not @@ -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() } } } diff --git a/rust/ql/lib/rust.qll b/rust/ql/lib/rust.qll index ff97a37b5d1f..f09f49b30bb6 100644 --- a/rust/ql/lib/rust.qll +++ b/rust/ql/lib/rust.qll @@ -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 diff --git a/rust/ql/test/library-tests/operations/Operations.expected b/rust/ql/test/library-tests/operations/Operations.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/rust/ql/test/library-tests/operations/Operations.ql b/rust/ql/test/library-tests/operations/Operations.ql new file mode 100644 index 000000000000..cbb81bdcb025 --- /dev/null +++ b/rust/ql/test/library-tests/operations/Operations.ql @@ -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 diff --git a/rust/ql/test/library-tests/operations/test.rs b/rust/ql/test/library-tests/operations/test.rs new file mode 100644 index 000000000000..f82a9501fef4 --- /dev/null +++ b/rust/ql/test/library-tests/operations/test.rs @@ -0,0 +1,57 @@ + +// --- tests --- + +fn test_operations( + y: i32, a: bool, b: bool, + ptr: &i32, res: Result) -> 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(()); +}