Skip to content

Commit 5fb45be

Browse files
committed
C#: Update the mutation definition assignable definition logic to account for implicit assignment of built and user-definied static operator calls.
1 parent 73c6d89 commit 5fb45be

1 file changed

Lines changed: 76 additions & 8 deletions

File tree

csharp/ql/lib/semmle/code/csharp/Assignable.qll

Lines changed: 76 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,62 @@ class AssignableRead extends AssignableAccess {
117117
AssignableRead getANextRead() { result.getControlFlowNode() = this.getAnAdjacentReadSameVar() }
118118
}
119119

120+
private newtype TMutationOperationAssignment =
121+
TBuiltInMutationOperation(MutatorOperation mo) or
122+
TUserMutatorOperatorCall(MutatorOperatorCall moc) {
123+
not moc instanceof InstanceMutatorOperatorCall
124+
}
125+
126+
/**
127+
* A mutation operation that implicitly assigns the result to its operand. For example, `a++` in
128+
* line 7 in
129+
*
130+
* ```csharp
131+
* class A {
132+
* public static A operator++(A a) {
133+
* return a;
134+
* }
135+
*
136+
* public static A Increment(A a) {
137+
* return a++;
138+
* }
139+
* }
140+
* ```
141+
*/
142+
private class MutationOperationAssignment extends TMutationOperationAssignment {
143+
string toString() { none() }
144+
145+
Expr getOperand() { none() }
146+
147+
Expr getMutationOperation() { none() }
148+
}
149+
150+
private class BuiltInMutationOperation extends MutationOperationAssignment,
151+
TBuiltInMutationOperation
152+
{
153+
private MutatorOperation mo;
154+
155+
BuiltInMutationOperation() { this = TBuiltInMutationOperation(mo) }
156+
157+
override string toString() { result = mo.toString() }
158+
159+
override Expr getOperand() { result = mo.getOperand() }
160+
161+
override Expr getMutationOperation() { result = mo }
162+
}
163+
164+
private class UserMutatorOperatorCall extends MutationOperationAssignment, TUserMutatorOperatorCall {
165+
private MutatorOperatorCall moc;
166+
167+
UserMutatorOperatorCall() { this = TUserMutatorOperatorCall(moc) }
168+
169+
override string toString() { result = moc.toString() }
170+
171+
override Expr getOperand() { result = moc.getArgument(0) }
172+
173+
override Expr getMutationOperation() { result = moc }
174+
}
175+
120176
/**
121177
* An access to an assignable that updates the underlying value. Either a
122178
* variable write (`VariableWrite`), a property write (`PropertyWrite`),
@@ -262,7 +318,8 @@ module AssignableInternal {
262318
or
263319
def = TOutRefDefinition(any(AssignableAccess aa | result = aa.getParent()))
264320
or
265-
def = TMutationDefinition(result)
321+
def =
322+
TMutationDefinition(any(MutationOperationAssignment moa | result = moa.getMutationOperation()))
266323
or
267324
def = TLocalVariableDefinition(result)
268325
or
@@ -299,7 +356,7 @@ module AssignableInternal {
299356
or
300357
aa.(RefArg).isPotentialAssignment()
301358
} or
302-
TMutationDefinition(MutatorOperation mo) or
359+
TMutationDefinition(MutationOperationAssignment mo) or
303360
TLocalVariableDefinition(LocalVariableDeclExpr lvde) {
304361
not lvde.hasInitializer() and
305362
not exists(getTupleSource(TTupleAssignmentDefinition(_, lvde))) and
@@ -372,7 +429,7 @@ module AssignableInternal {
372429
or
373430
def = TOutRefDefinition(result)
374431
or
375-
def = TMutationDefinition(any(MutatorOperation mo | mo.getOperand() = result))
432+
def = TMutationDefinition(any(MutationOperationAssignment mo | mo.getOperand() = result))
376433
or
377434
def = TAddressOfDefinition(any(AddressOfExpr aoe | aoe.getOperand() = result))
378435
or
@@ -645,14 +702,25 @@ module AssignableDefinitions {
645702
* A definition by mutation, for example `x++`.
646703
*/
647704
class MutationDefinition extends AssignableDefinition, TMutationDefinition {
648-
MutatorOperation mo;
705+
MutationOperationAssignment moa;
706+
707+
MutationDefinition() { this = TMutationDefinition(moa) }
708+
709+
/**
710+
* DEPRECATED: Use `getMutationOperation()` instead.
711+
*
712+
* Gets the underlying mutator operation.
713+
*/
714+
deprecated MutatorOperation getMutatorOperation() { moa = TBuiltInMutationOperation(result) }
649715

650-
MutationDefinition() { this = TMutationDefinition(mo) }
716+
/**
717+
* Gets the underlying mutation operation.
718+
*/
719+
Expr getMutationOperation() { result = moa.getMutationOperation() }
651720

652-
/** Gets the underlying mutator operation. */
653-
MutatorOperation getMutatorOperation() { result = mo }
721+
override Expr getSource() { result = this.getMutationOperation() }
654722

655-
override string toString() { result = mo.toString() }
723+
override string toString() { result = moa.toString() }
656724
}
657725

658726
/**

0 commit comments

Comments
 (0)