Skip to content

Commit 43d6bf0

Browse files
committed
C#: Make synthetic implicit casts when values are provided using the DefaultParameterValue attribute.
1 parent 2266e28 commit 43d6bf0

File tree

3 files changed

+62
-15
lines changed

3 files changed

+62
-15
lines changed

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,11 @@ private static bool ContainsPattern(SyntaxNode node) =>
211211
return Default.CreateGenerated(cx, parent, childIndex, location, ValueAsString(null));
212212
}
213213

214+
if (type.SpecialType is SpecialType.None)
215+
{
216+
return ImplicitCast.CreateGenerated(cx, parent, childIndex, type, defaultValue, location);
217+
}
218+
214219
if (type.SpecialType is SpecialType.System_DateTime)
215220
{
216221
return DateTimeObjectCreation.CreateGenerated(cx, parent, childIndex, type, defaultValue, location);

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

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Linq;
12
using Microsoft.CodeAnalysis;
23
using Semmle.Extraction.Kinds;
34

@@ -11,33 +12,74 @@ public Expression Expr
1112
private set;
1213
}
1314

14-
public ImplicitCast(ExpressionNodeInfo info)
15+
private ImplicitCast(ExpressionNodeInfo info)
1516
: base(new ExpressionInfo(info.Context, info.ConvertedType, info.Location, ExprKind.CAST, info.Parent, info.Child, true, info.ExprValue))
1617
{
1718
Expr = Factory.Create(new ExpressionNodeInfo(Context, info.Node, this, 0));
1819
}
1920

20-
public ImplicitCast(ExpressionNodeInfo info, IMethodSymbol method)
21+
private ImplicitCast(ExpressionNodeInfo info, IMethodSymbol method)
2122
: base(new ExpressionInfo(info.Context, info.ConvertedType, info.Location, ExprKind.OPERATOR_INVOCATION, info.Parent, info.Child, true, info.ExprValue))
2223
{
2324
Expr = Factory.Create(info.SetParent(this, 0));
2425

26+
AddOperatorCall(method);
27+
}
28+
29+
private ImplicitCast(ExpressionInfo info, IMethodSymbol method, object value) : base(info)
30+
{
31+
Expr = Literal.CreateGenerated(Context, this, 0, method.Parameters[0].Type, value, info.Location);
32+
33+
AddOperatorCall(method);
34+
}
35+
36+
private void AddOperatorCall(IMethodSymbol method)
37+
{
2538
var target = Method.Create(Context, method);
26-
if (target is not null)
27-
Context.TrapWriter.Writer.expr_call(this, target);
39+
Context.TrapWriter.Writer.expr_call(this, target);
40+
}
41+
42+
private static IMethodSymbol? GetImplicitConversionMethod(ITypeSymbol type, object value) =>
43+
type
44+
.GetMembers()
45+
.Where(m =>
46+
m is IMethodSymbol method &&
47+
method.GetName() == "op_Implicit" &&
48+
method.Parameters.Length == 1 &&
49+
method.Parameters[0].Type.Name == value.GetType().Name
50+
)
51+
.Cast<IMethodSymbol>()
52+
.FirstOrDefault();
53+
54+
// Creates a new generated expression with an implicit cast added, if needed.
55+
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object value,
56+
Extraction.Entities.Location location)
57+
{
58+
ExpressionInfo create(ExprKind kind, string? v) =>
59+
new ExpressionInfo(
60+
cx,
61+
AnnotatedTypeSymbol.CreateNotAnnotated(type),
62+
location,
63+
kind,
64+
parent,
65+
childIndex,
66+
true,
67+
v);
68+
69+
var method = GetImplicitConversionMethod(type, value);
70+
if (method is not null)
71+
{
72+
var info = create(ExprKind.OPERATOR_INVOCATION, null);
73+
return new ImplicitCast(info, method, value);
74+
}
2875
else
29-
Context.ModelError(info.Node, "Failed to resolve target for operator invocation");
76+
{
77+
cx.ModelError(location, "Failed to resolve target for implicit operator invocation for a parameter default.");
78+
return new Expression(create(ExprKind.UNKNOWN, ValueAsString(value)));
79+
}
3080
}
3181

32-
/// <summary>
33-
/// Creates a new expression, adding casts as required.
34-
/// </summary>
35-
/// <param name="cx">The extraction context.</param>
36-
/// <param name="node">The expression node.</param>
37-
/// <param name="parent">The parent of the expression.</param>
38-
/// <param name="child">The child number.</param>
39-
/// <param name="type">A type hint.</param>
40-
/// <returns>A new expression.</returns>
82+
// Creates a new expression, adding casts as required.
4183
public static Expression Create(ExpressionNodeInfo info)
4284
{
4385
var resolvedType = info.ResolvedType;

csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public AnnotatedTypeSymbol(ITypeSymbol? symbol, NullableAnnotation nullability)
2525
Nullability = nullability;
2626
}
2727

28-
public static AnnotatedTypeSymbol? CreateNotAnnotated(ITypeSymbol symbol) =>
28+
public static AnnotatedTypeSymbol? CreateNotAnnotated(ITypeSymbol? symbol) =>
2929
symbol is null ? (AnnotatedTypeSymbol?)null : new AnnotatedTypeSymbol(symbol, NullableAnnotation.None);
3030
}
3131

0 commit comments

Comments
 (0)