Skip to content
Open
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
16 changes: 14 additions & 2 deletions CodeConverter/CSharp/ArgumentConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,10 +226,10 @@ private CSSyntax.ArgumentSyntax CreateOptionalRefArg(IParameterSymbol p, RefKind
var type = CommonConversions.GetTypeSyntax(p.Type);
CSSyntax.ExpressionSyntax initializer;
if (p.HasExplicitDefaultValue) {
initializer = CommonConversions.Literal(p.ExplicitDefaultValue);
initializer = LiteralOrDefault(p.ExplicitDefaultValue, p.Type);
} else if (HasOptionalAttribute(p)) {
if (TryGetDefaultParameterValueAttributeValue(p, out var defaultValue)) {
initializer = CommonConversions.Literal(defaultValue);
initializer = LiteralOrDefault(defaultValue, p.Type);
} else {
initializer = CS.SyntaxFactory.DefaultExpression(type);
}
Expand Down Expand Up @@ -273,6 +273,18 @@ bool TryGetDefaultParameterValueAttributeValue(IParameterSymbol p, out object de
}
}

/// <summary>
/// Returns a literal expression for the given value, or a <c>default</c> expression when the value is null
/// and the parameter type is a value type (e.g. a struct), since null is not a valid C# initializer for value types.
/// </summary>
private static CSSyntax.ExpressionSyntax LiteralOrDefault(object value, ITypeSymbol paramType)
{
if (value is null && paramType.IsValueType) {
return ValidSyntaxFactory.DefaultExpression;
}
return CommonConversions.Literal(value);
}

public CSSyntax.ArgumentListSyntax CreateArgList(ISymbol invocationSymbol)
{
return CS.SyntaxFactory.ArgumentList(CS.SyntaxFactory.SeparatedList(
Expand Down
37 changes: 37 additions & 0 deletions Tests/CSharp/ExpressionTests/ByRefTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -914,4 +914,41 @@ public static void LogAndReset(ref int arg)
}");
}

[Fact]
public async Task OptionalStructRefParameterUsesDefaultNotNullIssue886Async()
{
await TestConversionVisualBasicToCSharpAsync(@"Public Class Issue886
Private Shared Sub OptionalParams()
FunctionWithOptionalParams()
End Sub

Private Shared Sub FunctionWithOptionalParams(Optional ByRef structParam As TestStruct = Nothing)
structParam = New TestStruct
End Sub

Friend Structure TestStruct
Friend A As Boolean
End Structure
End Class", @"using System.Runtime.InteropServices;

public partial class Issue886
{
private static void OptionalParams()
{
TestStruct argstructParam = default;
FunctionWithOptionalParams(structParam: ref argstructParam);
}

private static void FunctionWithOptionalParams([Optional] ref TestStruct structParam)
{
structParam = new TestStruct();
}

internal struct TestStruct
{
internal bool A;
}
}");
}

}
Loading