C#: Add compound assignment operator call classes.

This commit is contained in:
Michael Nebel
2026-04-22 15:42:35 +02:00
parent 43ebcb68f0
commit bdf0c8ff5a
2 changed files with 72 additions and 3 deletions

View File

@@ -94,13 +94,17 @@ class AssignOperation extends Assignment, @assign_op_expr {
}
/**
* A compound assignment operation that implicitly invokes an operator.
* For example, `x += y` assigns the result of `x + y` to `x`.
* A compound assignment operation that invokes an operator.
*
* (1) `x += y` invokes the compound assignment operator `+=` (if it exists).
* (2) `x += y` invokes the operator `+` and assigns `x + y` to `x`.
*
* Either an arithmetic assignment operation (`AssignArithmeticOperation`) or a bitwise
* assignment operation (`AssignBitwiseOperation`).
*/
class AssignCallOperation extends AssignOperation, OperatorCall, @assign_op_call_expr {
class AssignCallOperation extends AssignOperation, OperatorCall, QualifiableExpr,
@assign_op_call_expr
{
override string toString() { result = AssignOperation.super.toString() }
}

View File

@@ -529,6 +529,19 @@ class ExtensionOperatorCall extends OperatorCall {
ExtensionOperatorCall() { this.getTarget() instanceof ExtensionOperator }
override string getAPrimaryQlClass() { result = "ExtensionOperatorCall" }
private predicate isOrdinaryStaticCall() {
not exists(Expr e | e = this.getChildExpr(-1) | not e instanceof TypeAccess)
}
override Expr getArgument(int i) {
exists(int j | result = this.getChildExpr(j) |
i >= 0 and
if this.isOrdinaryStaticCall() or this.getTarget() instanceof CompoundAssignmentOperator
then j = i
else j = i - 1
)
}
}
/**
@@ -557,6 +570,58 @@ class MutatorOperatorCall extends OperatorCall {
predicate isPostfix() { mutator_invocation_mode(this, 2) }
}
/**
* A call to a compound assignment operator, for example `this += other`
* on line 7 in
*
* ```csharp
* class A {
* public void operator +=(A other) {
* ...
* }
*
* public void Add(A other) {
* this += other;
* }
* }
* ```
*/
class CompoundAssignmentOperatorCall extends AssignCallOperation {
CompoundAssignmentOperatorCall() { this.getTarget() instanceof CompoundAssignmentOperator }
override Expr getArgument(int i) { result = this.getChildExpr(i + 1) and i >= 0 }
/** Gets the qualifier of this compound assignment operator call. */
override Expr getQualifier() { result = this.getChildExpr(0) }
}
/**
* A call to a compound assignment extension operator, for example `s1 *= s2` on
* line 9 in
*
* ```csharp
* static class MyExtensions {
* extension(string s) {
* public void operator *=(string other) { ... }
* }
* }
*
* class A {
* void M(string s1, string s2) {
* s1 *= s2;
* }
* }
*/
class ExtensionCompoundAssignmentOperatorCall extends CompoundAssignmentOperatorCall,
ExtensionOperatorCall
{
override Expr getArgument(int i) { result = ExtensionOperatorCall.super.getArgument(i) }
override Expr getQualifier() { none() }
override string getAPrimaryQlClass() { result = "ExtensionCompoundAssignmentOperatorCall" }
}
private class DelegateLikeCall_ = @delegate_invocation_expr or @function_pointer_invocation_expr;
/**