From e2fcaeb46a571905d246a41ed7f5d6cc58cb7ac6 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 22 Apr 2026 15:43:53 +0200 Subject: [PATCH] C#: Handle compound assignment operators in the dispatch logic (and assignable definition). --- .../ql/lib/semmle/code/csharp/Assignable.qll | 3 ++- .../semmle/code/csharp/dispatch/Dispatch.qll | 20 ++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/Assignable.qll b/csharp/ql/lib/semmle/code/csharp/Assignable.qll index af6861349d1..5cd9ee9ede0 100644 --- a/csharp/ql/lib/semmle/code/csharp/Assignable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Assignable.qll @@ -315,7 +315,8 @@ module AssignableInternal { TAddressOfDefinition(AddressOfExpr aoe) or TPatternDefinition(TopLevelPatternDecl tlpd) or TAssignOperationDefinition(AssignOperation ao) { - ao instanceof AssignCallOperation or + ao instanceof AssignCallOperation and not ao instanceof CompoundAssignmentOperatorCall + or ao instanceof AssignCoalesceExpr } diff --git a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll index 6d535025a19..15a64d12b49 100644 --- a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll +++ b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll @@ -99,7 +99,11 @@ private module Internal { or ac instanceof AssignableWrite and isRead = false } or - TDispatchOperatorCall(OperatorCall oc) { not oc.isLateBound() } or + TDispatchOperatorCall(OperatorCall oc) { + not oc.isLateBound() and + not oc instanceof CompoundAssignmentOperatorCall + } or + TDispatchCompoundAssignmentOperatorCall(CompoundAssignmentOperatorCall caoc) or TDispatchReflectionCall(MethodCall mc, string name, Expr object, Expr qualifier, int args) { isReflectionCall(mc, name, object, qualifier, args) } or @@ -886,6 +890,20 @@ private module Internal { override Operator getAStaticTarget() { result = this.getCall().getTarget() } } + private class DispatchCompoundAssignmentOperatorCall extends DispatchOverridableCall, + TDispatchCompoundAssignmentOperatorCall + { + override CompoundAssignmentOperatorCall getCall() { + this = TDispatchCompoundAssignmentOperatorCall(result) + } + + override Expr getArgument(int i) { result = this.getCall().getArgument(i) } + + override Expr getQualifier() { result = this.getCall().getQualifier() } + + override Operator getAStaticTarget() { result = this.getCall().getTarget() } + } + /** * A call to an accessor. *