Skip to content

Commit c699415

Browse files
committed
C#: Extract calls to user defined compound assignments as operator calls.
1 parent b46eaa8 commit c699415

File tree

3 files changed

+64
-2
lines changed

3 files changed

+64
-2
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Microsoft.CodeAnalysis;
2+
3+
namespace Semmle.Extraction.CSharp.Entities.Expressions
4+
{
5+
internal static class CompoundAssignment
6+
{
7+
public static Expression Create(ExpressionNodeInfo info)
8+
{
9+
if (info.SymbolInfo.Symbol is IMethodSymbol op &&
10+
op.MethodKind == MethodKind.UserDefinedOperator &&
11+
!op.IsStatic)
12+
{
13+
// This is a user-defined instance operator such as `a += b` where `a` is of a type that defines an `operator +=`.
14+
// In this case, we want to extract the operator call rather than desugar it into `a = a + b`.
15+
return UserCompoundAssignmentInvocation.Create(info);
16+
}
17+
return Assignment.Create(info);
18+
}
19+
}
20+
}

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ internal static Expression Create(ExpressionNodeInfo info)
7070
return NormalElementAccess.Create(info);
7171

7272
case SyntaxKind.SimpleAssignmentExpression:
73+
case SyntaxKind.CoalesceAssignmentExpression:
74+
return Assignment.Create(info);
75+
7376
case SyntaxKind.OrAssignmentExpression:
7477
case SyntaxKind.AndAssignmentExpression:
7578
case SyntaxKind.SubtractAssignmentExpression:
@@ -81,8 +84,7 @@ internal static Expression Create(ExpressionNodeInfo info)
8184
case SyntaxKind.UnsignedRightShiftAssignmentExpression:
8285
case SyntaxKind.DivideAssignmentExpression:
8386
case SyntaxKind.ModuloAssignmentExpression:
84-
case SyntaxKind.CoalesceAssignmentExpression:
85-
return Assignment.Create(info);
87+
return CompoundAssignment.Create(info);
8688

8789
case SyntaxKind.ObjectCreationExpression:
8890
return ExplicitObjectCreation.Create(info);
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System.IO;
2+
using Microsoft.CodeAnalysis.CSharp.Syntax;
3+
using Semmle.Extraction.Kinds;
4+
5+
namespace Semmle.Extraction.CSharp.Entities.Expressions
6+
{
7+
/// <summary>
8+
/// Represents a user-defined compound assignment operator such as `a += b` where `a` is of a type that defines an `operator +=`.
9+
/// In this case, we don't want to desugar it into `a = a + b`, but instead extract the operator call directly as it should
10+
/// be considered an instance method call on `a` with `b` as an argument.
11+
/// </summary>
12+
internal class UserCompoundAssignmentInvocation : Expression<AssignmentExpressionSyntax>
13+
{
14+
private readonly ExpressionNodeInfo info;
15+
16+
protected UserCompoundAssignmentInvocation(ExpressionNodeInfo info)
17+
: base(info.SetKind(ExprKind.OPERATOR_INVOCATION))
18+
{
19+
this.info = info;
20+
}
21+
22+
public static Expression Create(ExpressionNodeInfo info) => new UserCompoundAssignmentInvocation(info).TryPopulate();
23+
24+
protected override void PopulateExpression(TextWriter trapFile)
25+
{
26+
Create(Context, Syntax.Left, this, 0);
27+
Create(Context, Syntax.Right, this, 1);
28+
29+
var target = info.GetTargetSymbol(Context);
30+
if (target is null)
31+
{
32+
Context.ModelError(Syntax, "Unable to resolve target method for user-defined compound assignment operator");
33+
return;
34+
}
35+
36+
var targetKey = Method.Create(Context, target);
37+
trapFile.expr_call(this, targetKey);
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)