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);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems a bit risky to cast decimal to double if someone really did need the last half of the precision. We should add a condition to check if the number round trips and error otherwise

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