diff --git a/CHANGELOG.md b/CHANGELOG.md index 1175e8516..bc1ffe647 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### VB -> C# +* Convert optional parameters before ref parameters using attributes to avoid compile error [#1057](https://github.com/icsharpcode/CodeConverter/issues/1057) * Remove square brackets when escaping labels and identifiers [#1043](https://github.com/icsharpcode/CodeConverter/issues/1043) and [#1044](https://github.com/icsharpcode/CodeConverter/issues/1044) * Exit Property now returns value assigned to return variable [#1051](https://github.com/icsharpcode/CodeConverter/issues/1051) * Avoid stack overflow for very deeply nested binary expressions [#1033](https://github.com/icsharpcode/CodeConverter/issues/1033) diff --git a/CodeConverter/CSharp/ExpressionNodeVisitor.cs b/CodeConverter/CSharp/ExpressionNodeVisitor.cs index 94be3fa4a..6146bc331 100644 --- a/CodeConverter/CSharp/ExpressionNodeVisitor.cs +++ b/CodeConverter/CSharp/ExpressionNodeVisitor.cs @@ -1403,7 +1403,7 @@ public override async Task VisitParameter(VBSyntax.ParameterSy attributes.Insert(0, SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList(optionalDateTimeAttributes))); } - } else if (node.Modifiers.Any(m => m.IsKind(VBasic.SyntaxKind.ByRefKeyword))) { + } else if (node.Modifiers.Any(m => m.IsKind(VBasic.SyntaxKind.ByRefKeyword)) || HasRefParametersAfterThisOne()) { var defaultExpression = await node.Default.Value.AcceptAsync(TriviaConvertingExpressionVisitor); var arg = CommonConversions.CreateAttributeArgumentList(SyntaxFactory.AttributeArgument(defaultExpression)); _extraUsingDirectives.Add("System.Runtime.InteropServices"); @@ -1432,6 +1432,8 @@ public override async Task VisitParameter(VBSyntax.ParameterSy id, @default ); + + bool HasRefParametersAfterThisOne() => vbSymbol is not null && baseParameters is {} bp && bp.Skip(vbSymbol.Ordinal + 1).Any(x => x.RefKind != RefKind.None); } private async Task SyntaxOnlyConvertParamAsync(VBSyntax.ParameterSyntax node) diff --git a/Tests/CSharp/ExpressionTests/ByRefTests.cs b/Tests/CSharp/ExpressionTests/ByRefTests.cs index 2f56d1c6a..c8b1d23c5 100644 --- a/Tests/CSharp/ExpressionTests/ByRefTests.cs +++ b/Tests/CSharp/ExpressionTests/ByRefTests.cs @@ -343,6 +343,21 @@ public static bool CallingFunc() }"); } + [Fact] + public async Task RefAfterOptionalArgumentAsync() + { + await TestConversionVisualBasicToCSharpAsync(@" + Sub S(Optional a As Integer = 0, Optional ByRef b As Integer = 0) + S() + End Sub +", @" +public void S([Optional, DefaultParameterValue(0)] int a, [Optional, DefaultParameterValue(0)] ref int b) +{ + int argb = 0; + S(b: ref argb); +}"); + } + [Fact] public async Task OutOptionalArgumentAsync() {