Skip to content

Commit

Permalink
It's a csharp compile error to use optional parameters before ref par…
Browse files Browse the repository at this point in the history
…ameters - fixes #1057
  • Loading branch information
GrahamTheCoder committed Dec 10, 2023
1 parent 4861f98 commit 8d57a1c
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion CodeConverter/CSharp/ExpressionNodeVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1403,7 +1403,7 @@ public override async Task<CSharpSyntaxNode> 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<ExpressionSyntax>(TriviaConvertingExpressionVisitor);
var arg = CommonConversions.CreateAttributeArgumentList(SyntaxFactory.AttributeArgument(defaultExpression));
_extraUsingDirectives.Add("System.Runtime.InteropServices");
Expand Down Expand Up @@ -1432,6 +1432,8 @@ public override async Task<CSharpSyntaxNode> 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<TypeSyntax> SyntaxOnlyConvertParamAsync(VBSyntax.ParameterSyntax node)
Expand Down
15 changes: 15 additions & 0 deletions Tests/CSharp/ExpressionTests/ByRefTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down

0 comments on commit 8d57a1c

Please sign in to comment.