Skip to content
Draft
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
12 changes: 10 additions & 2 deletions CodeConverter/CSharp/ArgumentConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,10 +226,18 @@ private CSSyntax.ArgumentSyntax CreateOptionalRefArg(IParameterSymbol p, RefKind
var type = CommonConversions.GetTypeSyntax(p.Type);
CSSyntax.ExpressionSyntax initializer;
if (p.HasExplicitDefaultValue) {
initializer = CommonConversions.Literal(p.ExplicitDefaultValue);
if (p.ExplicitDefaultValue == null && p.Type.IsValueType && p.Type.OriginalDefinition.SpecialType != SpecialType.System_Nullable_T) {
initializer = CS.SyntaxFactory.DefaultExpression(type);
} else {
initializer = CommonConversions.Literal(p.ExplicitDefaultValue);
}
} else if (HasOptionalAttribute(p)) {
if (TryGetDefaultParameterValueAttributeValue(p, out var defaultValue)) {
initializer = CommonConversions.Literal(defaultValue);
if (defaultValue == null && p.Type.IsValueType && p.Type.OriginalDefinition.SpecialType != SpecialType.System_Nullable_T) {
initializer = CS.SyntaxFactory.DefaultExpression(type);
} else {
initializer = CommonConversions.Literal(defaultValue);
}
} else {
initializer = CS.SyntaxFactory.DefaultExpression(type);
}
Expand Down
17 changes: 16 additions & 1 deletion CodeConverter/CSharp/ExpressionNodeVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,22 @@ public override async Task<CSharpSyntaxNode> VisitParameter(VBSyntax.ParameterSy
CS.SyntaxFactory.Attribute(ValidSyntaxFactory.IdentifierName("Optional")),
};
if (!node.Default.Value.IsKind(VBasic.SyntaxKind.NothingLiteralExpression)) {
optionalAttributes.Add(CS.SyntaxFactory.Attribute(ValidSyntaxFactory.IdentifierName("DefaultParameterValue"), arg));
if (vbSymbol?.Type?.SpecialType == SpecialType.System_Decimal && defaultExpression is CSSyntax.LiteralExpressionSyntax literalExpr) {
var literalValue = literalExpr.Token.Value;
if (literalValue is decimal decimalVal) {
var isInteger = decimalVal == Math.Round(decimalVal);
var newLiteral = isInteger ? CommonConversions.Literal((int)decimalVal) : CommonConversions.Literal((double)decimalVal);
arg = CommonConversions.CreateAttributeArgumentList(CS.SyntaxFactory.AttributeArgument(newLiteral));
}
}

if (vbSymbol?.Type?.TypeKind == TypeKind.Struct && vbSymbol?.Type?.SpecialType == SpecialType.None) {
arg = null;
}

if (arg != null) {
optionalAttributes.Add(CS.SyntaxFactory.Attribute(ValidSyntaxFactory.IdentifierName("DefaultParameterValue"), arg));
}
}
attributes.Insert(0,
CS.SyntaxFactory.AttributeList(CS.SyntaxFactory.SeparatedList(optionalAttributes)));
Expand Down
41 changes: 40 additions & 1 deletion Tests/CSharp/MemberTests/MemberTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1576,4 +1576,43 @@ private void OptionalByRefWithDefault([Optional][DefaultParameterValue(""a"")] r
CS7036: There is no argument given that corresponds to the required parameter 'str1' of 'MissingByRefArgumentWithNoExplicitDefaultValue.ByRefNoDefault(ref string)'
");
}
}
[Fact]
public async Task OptionalByRefParameterAsync886()
{
await TestConversionVisualBasicToCSharpAsync(@"Class Issue886
Private Shared Sub OptionalParams()
FunctionWithOptionalParams()
End Sub

Private Shared Sub FunctionWithOptionalParams(Optional ByRef structParam As TestStruct = Nothing, Optional ByRef decimalParam As Decimal = 0)
structParam = New TestStruct
decimalParam = 0
End Sub

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

internal partial class Issue886
{
private static void OptionalParams()
{
TestStruct argstructParam = default;
decimal argdecimalParam = 0m;
FunctionWithOptionalParams(structParam: ref argstructParam, decimalParam: ref argdecimalParam);
}

private static void FunctionWithOptionalParams([Optional] ref TestStruct structParam, [Optional, DefaultParameterValue(0)] ref decimal decimalParam)
{
structParam = new TestStruct();
decimalParam = 0m;
}

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