Skip to content

Commit 2ca543e

Browse files
committed
C#: Synthetic DateTime object creation for DateTime defaults via attributes.
1 parent 3647b9c commit 2ca543e

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
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.System_DateTime)
215+
{
216+
return DateTimeObjectCreation.CreateGenerated(cx, parent, childIndex, type, defaultValue, location);
217+
}
218+
214219
// const literal:
215220
return Literal.CreateGenerated(cx, parent, childIndex, type, defaultValue, location);
216221
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using Microsoft.CodeAnalysis;
2+
using System.Linq;
3+
using System.IO;
4+
using Semmle.Extraction.Kinds;
5+
6+
namespace Semmle.Extraction.CSharp.Entities.Expressions
7+
{
8+
internal class DateTimeObjectCreation : Expression
9+
{
10+
private readonly IMethodSymbol constructorSymbol;
11+
12+
private DateTimeObjectCreation(IMethodSymbol constructorSymbol, ExpressionInfo info) : base(info)
13+
{
14+
this.constructorSymbol = constructorSymbol;
15+
}
16+
17+
// Gets the value of a System.DateTime object as a string containing the ticks.
18+
private static long ValueAsLong(object? value) =>
19+
value is System.DateTime d ? d.Ticks : 0;
20+
21+
// Gets the System.DateTime(long) constructor from the `type` symbol.
22+
private static IMethodSymbol? GetDateTimeConstructor(ITypeSymbol? type)
23+
{
24+
return type?.GetMembers()
25+
.Where(m =>
26+
m is IMethodSymbol c &&
27+
c.GetName() == "ctor" &&
28+
c.Parameters.Length == 1 &&
29+
c.Parameters[0].Type.SpecialType == SpecialType.System_Int64)
30+
.Cast<IMethodSymbol>()
31+
.FirstOrDefault();
32+
}
33+
34+
35+
protected void PopulateExpression(TextWriter trapFile)
36+
{
37+
var constructor = Constructor.Create(Context, constructorSymbol);
38+
trapFile.expr_call(this, constructor);
39+
}
40+
41+
protected new Expression TryPopulate()
42+
{
43+
Context.Try(null, null, () => PopulateExpression(Context.TrapWriter.Writer));
44+
return this;
45+
}
46+
47+
// Gets an expression that represents a System.DateTime object creation.
48+
// The `type` symbol must be a System.DateTime type and the value must be a System.DateTime object.
49+
// The expression that is being created is a call to the System.DateTime(long) constructor, where
50+
// the number of ticks from the `value` object is used as the argument to the constructor call.
51+
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object? value, Extraction.Entities.Location location)
52+
{
53+
var constructorSymbol = GetDateTimeConstructor(type) ?? throw new InternalError("Could not find symbol for System.DateTime(long)");
54+
var expr = new DateTimeObjectCreation(constructorSymbol, new ExpressionInfo(
55+
cx,
56+
AnnotatedTypeSymbol.CreateNotAnnotated(type),
57+
location,
58+
ExprKind.OBJECT_CREATION,
59+
parent,
60+
childIndex,
61+
true,
62+
null));
63+
64+
var longTypeSymbol = constructorSymbol.Parameters[0].Type;
65+
Literal.CreateGenerated(cx, expr, 0, longTypeSymbol, ValueAsLong(value), location);
66+
67+
return expr.TryPopulate();
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)