C#: Handle Nullable<T> default parameter values in assemblies

This commit is contained in:
Tom Hvitved
2021-10-15 14:23:18 +02:00
parent 86b1305e35
commit 888a1b38aa
5 changed files with 34 additions and 9 deletions

View File

@@ -178,7 +178,13 @@ namespace Semmle.Extraction.CSharp.Entities
var defaultValue = parameter.ExplicitDefaultValue;
if (parameter.Type is INamedTypeSymbol nt && nt.EnumUnderlyingType is not null)
var type = parameter.Type;
if (type.IsBoundNullable() && type is INamedTypeSymbol named)
{
type = named.TypeArguments[0];
}
if (type is INamedTypeSymbol nt && nt.EnumUnderlyingType is not null)
{
// = (MyEnum)1, = MyEnum.Value1, = default(MyEnum), = new MyEnum()
// we're generating a (MyEnum)value cast expression:
@@ -194,7 +200,7 @@ namespace Semmle.Extraction.CSharp.Entities
return Default.CreateGenerated(cx, parent, childIndex, location, parameter.Type.IsReferenceType ? ValueAsString(null) : null);
}
if (parameter.Type.SpecialType == SpecialType.System_Object)
if (parameter.Type.SpecialType is SpecialType.System_Object)
{
// this can happen in VB.NET
cx.ExtractionError($"Extracting default argument value 'object {parameter.Name} = default' instead of 'object {parameter.Name} = {defaultValue}'. The latter is not supported in C#.",
@@ -205,7 +211,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
// const literal:
return Literal.CreateGenerated(cx, parent, childIndex, parameter.Type, defaultValue, location);
return Literal.CreateGenerated(cx, parent, childIndex, type, defaultValue, location);
}
/// <summary>

View File

@@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
{
if (info.Node is null)
{
info.Context.ModelError("Attempt to create a null expression");
info.Context.ModelError(info.Location, "Attempt to create a null expression");
return new Unknown(info);
}

View File

@@ -32,10 +32,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
}
var type = info.Type?.Symbol;
return GetExprKind(type, info.Node, info.Context);
return GetExprKind(type, info.Node, info.Location, info.Context);
}
private static ExprKind GetExprKind(ITypeSymbol? type, ExpressionSyntax? expr, Context context)
private static ExprKind GetExprKind(ITypeSymbol? type, ExpressionSyntax? expr, Extraction.Entities.Location loc, Context context)
{
switch (type?.SpecialType)
{
@@ -75,10 +75,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
case null:
default:
var kind = type?.SpecialType.ToString() ?? "null";
if (expr is not null)
context.ModelError(expr, "Unhandled literal type");
context.ModelError(expr, $"Unhandled literal type {kind}");
else
context.ModelError("Unhandled literal type");
context.ModelError(loc, $"Unhandled literal type {kind}");
return ExprKind.UNKNOWN;
}
}
@@ -86,11 +87,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object? value,
Extraction.Entities.Location location)
{
var kind = value is null ? ExprKind.NULL_LITERAL : GetExprKind(type, null, location, cx);
var info = new ExpressionInfo(
cx,
AnnotatedTypeSymbol.CreateNotAnnotated(type),
location,
GetExprKind(type, null, cx),
kind,
parent,
childIndex,
true,

View File

@@ -426,6 +426,16 @@ namespace Semmle.Extraction
ReportError(new InternalError(symbol, msg));
}
/// <summary>
/// Signal an error in the program model.
/// </summary>
/// <param name="loc">The location of the error.</param>
/// <param name="msg">The error message.</param>
public void ModelError(Entities.Location loc, string msg)
{
ReportError(new InternalError(loc.ReportingLocation, msg));
}
/// <summary>
/// Signal an error in the program model.
/// </summary>

View File

@@ -23,6 +23,13 @@ namespace Semmle.Extraction
Location = node.GetLocation();
}
public InternalError(Location? loc, string msg)
{
Text = msg;
EntityText = "";
Location = loc;
}
public InternalError(string msg)
{
Text = msg;