Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,13 @@ private static bool ContainsPattern(SyntaxNode node) =>

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:
Expand All @@ -194,7 +200,7 @@ private static bool ContainsPattern(SyntaxNode node) =>
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#.",
Expand All @@ -205,7 +211,7 @@ private static bool ContainsPattern(SyntaxNode node) =>
}

// const literal:
return Literal.CreateGenerated(cx, parent, childIndex, parameter.Type, defaultValue, location);
return Literal.CreateGenerated(cx, parent, childIndex, type, defaultValue, location);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal static Expression Create(ExpressionNodeInfo info)
{
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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ private static ExprKind GetKind(ExpressionNodeInfo info)
}

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)
{
Expand Down Expand Up @@ -75,22 +75,24 @@ private static ExprKind GetExprKind(ITypeSymbol? type, ExpressionSyntax? expr, C

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;
}
}

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,
Expand Down
10 changes: 10 additions & 0 deletions csharp/extractor/Semmle.Extraction/Context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,16 @@ public void ModelError(ISymbol symbol, string msg)
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>
Expand Down
7 changes: 7 additions & 0 deletions csharp/extractor/Semmle.Extraction/InternalError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ public InternalError(SyntaxNode node, string msg)
Location = node.GetLocation();
}

public InternalError(Location? loc, string msg)
{
Text = msg;
EntityText = "";
Location = loc;
}

public InternalError(string msg)
{
Text = msg;
Expand Down