C#: Synthetic DateTime object creation for DateTime defaults via attributes.

This commit is contained in:
Michael Nebel
2023-05-17 11:05:08 +02:00
parent 3647b9cfeb
commit 2ca543e217
2 changed files with 75 additions and 0 deletions

View File

@@ -211,6 +211,11 @@ namespace Semmle.Extraction.CSharp.Entities
return Default.CreateGenerated(cx, parent, childIndex, location, ValueAsString(null));
}
if (type.SpecialType is SpecialType.System_DateTime)
{
return DateTimeObjectCreation.CreateGenerated(cx, parent, childIndex, type, defaultValue, location);
}
// const literal:
return Literal.CreateGenerated(cx, parent, childIndex, type, defaultValue, location);
}

View File

@@ -0,0 +1,70 @@
using Microsoft.CodeAnalysis;
using System.Linq;
using System.IO;
using Semmle.Extraction.Kinds;
namespace Semmle.Extraction.CSharp.Entities.Expressions
{
internal class DateTimeObjectCreation : Expression
{
private readonly IMethodSymbol constructorSymbol;
private DateTimeObjectCreation(IMethodSymbol constructorSymbol, ExpressionInfo info) : base(info)
{
this.constructorSymbol = constructorSymbol;
}
// Gets the value of a System.DateTime object as a string containing the ticks.
private static long ValueAsLong(object? value) =>
value is System.DateTime d ? d.Ticks : 0;
// Gets the System.DateTime(long) constructor from the `type` symbol.
private static IMethodSymbol? GetDateTimeConstructor(ITypeSymbol? type)
{
return type?.GetMembers()
.Where(m =>
m is IMethodSymbol c &&
c.GetName() == "ctor" &&
c.Parameters.Length == 1 &&
c.Parameters[0].Type.SpecialType == SpecialType.System_Int64)
.Cast<IMethodSymbol>()
.FirstOrDefault();
}
protected void PopulateExpression(TextWriter trapFile)
{
var constructor = Constructor.Create(Context, constructorSymbol);
trapFile.expr_call(this, constructor);
}
protected new Expression TryPopulate()
{
Context.Try(null, null, () => PopulateExpression(Context.TrapWriter.Writer));
return this;
}
// Gets an expression that represents a System.DateTime object creation.
// The `type` symbol must be a System.DateTime type and the value must be a System.DateTime object.
// The expression that is being created is a call to the System.DateTime(long) constructor, where
// the number of ticks from the `value` object is used as the argument to the constructor call.
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object? value, Extraction.Entities.Location location)
{
var constructorSymbol = GetDateTimeConstructor(type) ?? throw new InternalError("Could not find symbol for System.DateTime(long)");
var expr = new DateTimeObjectCreation(constructorSymbol, new ExpressionInfo(
cx,
AnnotatedTypeSymbol.CreateNotAnnotated(type),
location,
ExprKind.OBJECT_CREATION,
parent,
childIndex,
true,
null));
var longTypeSymbol = constructorSymbol.Parameters[0].Type;
Literal.CreateGenerated(cx, expr, 0, longTypeSymbol, ValueAsLong(value), location);
return expr.TryPopulate();
}
}
}