From 21472c40339a8fdd7de26a61c660382c6f04ee74 Mon Sep 17 00:00:00 2001 From: GrahamTheCoder <2490482+GrahamTheCoder@users.noreply.github.com> Date: Wed, 25 Mar 2026 00:14:24 +0000 Subject: [PATCH 1/2] Fix Issue #803: Use relational patterns in switch statements - Modifies `MethodBodyExecutableStatementVisitor` to generate `RelationalPatternSyntax` instead of `VarPattern` with a `when` clause for VB `RelationalCaseClauseSyntax`. - Adds helper `GetRelationalTokenKind` to map VB syntax kinds to the appropriate C# relational operators. - Added corresponding unit test demonstrating the new output. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- .../MethodBodyExecutableStatementVisitor.cs | 21 ++++-- .../MethodStatementTests_803.cs | 68 +++++++++++++++++++ 2 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 Tests/CSharp/StatementTests/MethodStatementTests_803.cs diff --git a/CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs b/CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs index bc48a7dc..b3b9eb68 100644 --- a/CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs +++ b/CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs @@ -844,11 +844,16 @@ public override async Task> VisitSelectBlock(VBSynta caseSwitchLabelSyntax = WrapInCasePatternSwitchLabelSyntax(node, relational.Value, csRelationalValue, false, operatorKind); } else { - var varName = CommonConversions.CsEscapedIdentifier(GetUniqueVariableNameInScope(node, "case")); - ExpressionSyntax csLeft = ValidSyntaxFactory.IdentifierName(varName); csRelationalValue = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(relational.Value, csRelationalValue); - var binaryExp = SyntaxFactory.BinaryExpression(operatorKind.ConvertToken(), csLeft, csRelationalValue); - caseSwitchLabelSyntax = VarWhen(varName, binaryExp); + PatternSyntax pattern; + if (operatorKind == VBasic.SyntaxKind.CaseEqualsClause) { + pattern = SyntaxFactory.ConstantPattern(csRelationalValue); + } else if (operatorKind == VBasic.SyntaxKind.CaseNotEqualsClause) { + pattern = SyntaxFactory.UnaryPattern(SyntaxFactory.Token(SyntaxKind.NotKeyword), SyntaxFactory.ConstantPattern(csRelationalValue)); + } else { + pattern = SyntaxFactory.RelationalPattern(SyntaxFactory.Token(GetRelationalTokenKind(operatorKind)), csRelationalValue); + } + caseSwitchLabelSyntax = SyntaxFactory.CasePatternSwitchLabel(pattern, null, SyntaxFactory.Token(SyntaxKind.ColonToken)); } labels.Add(caseSwitchLabelSyntax); } else if (c is VBSyntax.RangeCaseClauseSyntax range) { @@ -1201,4 +1206,12 @@ private static SyntaxList SingleStatement(ExpressionSyntax expr { return SyntaxFactory.SingletonList(SyntaxFactory.ExpressionStatement(expression)); } + + private static SyntaxKind GetRelationalTokenKind(VBasic.SyntaxKind caseClauseKind) => caseClauseKind switch { + VBasic.SyntaxKind.CaseLessThanClause => SyntaxKind.LessThanToken, + VBasic.SyntaxKind.CaseLessThanOrEqualClause => SyntaxKind.LessThanEqualsToken, + VBasic.SyntaxKind.CaseGreaterThanOrEqualClause => SyntaxKind.GreaterThanEqualsToken, + VBasic.SyntaxKind.CaseGreaterThanClause => SyntaxKind.GreaterThanToken, + _ => throw new ArgumentOutOfRangeException(nameof(caseClauseKind), caseClauseKind, null) + }; } \ No newline at end of file diff --git a/Tests/CSharp/StatementTests/MethodStatementTests_803.cs b/Tests/CSharp/StatementTests/MethodStatementTests_803.cs new file mode 100644 index 00000000..69202454 --- /dev/null +++ b/Tests/CSharp/StatementTests/MethodStatementTests_803.cs @@ -0,0 +1,68 @@ +using System.Threading.Tasks; +using ICSharpCode.CodeConverter.Tests.TestRunners; +using Xunit; + +namespace ICSharpCode.CodeConverter.Tests.CSharp.StatementTests; + +public class MethodStatementTests_803 : ConverterTestBase +{ + [Fact] + public async Task Issue803_SelectCaseWithRelationalPatternAsync() + { + await TestConversionVisualBasicToCSharpAsync(@"Class TestClass + Private Sub TestMethod(ByVal Breite As Integer) + Dim Rollo_FederUmdrehungen_Berechnen As Integer + Select Case Breite + Case Is < 1000 + Rollo_FederUmdrehungen_Berechnen = 12 + Case Is < 1200 + Rollo_FederUmdrehungen_Berechnen = 15 + Case Is < 1600 + Rollo_FederUmdrehungen_Berechnen = 19 + Case Is < 1800 + Rollo_FederUmdrehungen_Berechnen = 25 + Case Else + Rollo_FederUmdrehungen_Berechnen = 28 + End Select + End Sub +End Class", @"internal partial class TestClass +{ + private void TestMethod(int Breite) + { + int Rollo_FederUmdrehungen_Berechnen; + switch (Breite) + { + case < 1000: + { + Rollo_FederUmdrehungen_Berechnen = 12; + break; + } + + case < 1200: + { + Rollo_FederUmdrehungen_Berechnen = 15; + break; + } + + case < 1600: + { + Rollo_FederUmdrehungen_Berechnen = 19; + break; + } + + case < 1800: + { + Rollo_FederUmdrehungen_Berechnen = 25; + break; + } + + default: + { + Rollo_FederUmdrehungen_Berechnen = 28; + break; + } + } + } +}"); + } +} From 00255f9c40e098d0c22249600b23174bd4617539 Mon Sep 17 00:00:00 2001 From: GrahamTheCoder <2490482+GrahamTheCoder@users.noreply.github.com> Date: Sun, 12 Apr 2026 11:43:47 +0000 Subject: [PATCH 2/2] Fix #803: Use relational patterns for VB Select Case When converting a Visual Basic Select Case statement with a relational clause (e.g., `Case Is < 1000`), the C# code converter used to output a variable pattern with a when clause (e.g., `case var @case when @case < 1000:`). With modern C#, this can be represented more concisely using relational patterns (e.g., `case < 1000:`). This commit modifies `MethodBodyExecutableStatementVisitor.cs` to map Visual Basic relational case clauses to C# `RelationalPatternSyntax`, `ConstantPatternSyntax` (for equality), and `UnaryPatternSyntax` (for inequality using `not`). It also updates existing tests that were affected by this change to expect the new, cleaner syntax, and adds a test specific to Issue 803. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- .../StatementTests/MethodStatementTests.cs | 76 ++++++++++++++++--- .../MethodStatementTests_803.cs | 68 ----------------- 2 files changed, 66 insertions(+), 78 deletions(-) delete mode 100644 Tests/CSharp/StatementTests/MethodStatementTests_803.cs diff --git a/Tests/CSharp/StatementTests/MethodStatementTests.cs b/Tests/CSharp/StatementTests/MethodStatementTests.cs index bc20f218..a28e5ea2 100644 --- a/Tests/CSharp/StatementTests/MethodStatementTests.cs +++ b/Tests/CSharp/StatementTests/MethodStatementTests.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using ICSharpCode.CodeConverter.Tests.TestRunners; using Xunit; @@ -1089,13 +1089,13 @@ public static string TimeAgo(int daysAgo) { case var @case when 0 <= @case && @case <= 3: case 4: - case var case1 when case1 >= 5: - case var case2 when case2 < 6: - case var case3 when case3 <= 7: + case >= 5: + case < 6: + case <= 7: { return ""this week""; } - case var case4 when case4 > 0: + case > 0: { return daysAgo / 7 + "" weeks ago""; } @@ -1249,7 +1249,7 @@ public void DoesNotThrow() var rand = new Random(); switch (rand.Next(8)) { - case var @case when @case < 4: + case < 4: { break; } @@ -1257,7 +1257,7 @@ public void DoesNotThrow() { break; } - case var case1 when case1 > 4: + case > 4: { break; } @@ -1268,9 +1268,7 @@ public void DoesNotThrow() } } } -} -1 target compilation errors: -CS0825: The contextual keyword 'var' may only appear within a local variable declaration or in script code"); +}"); } [Fact] @@ -1786,6 +1784,64 @@ public void AllAssignmentOperators() set_Item(0, get_Item(0) >> 2); set_StrItem(0, get_StrItem(0) + "" World""); } +}"); + } + + [Fact] + public async Task Issue803_SelectCaseWithRelationalPatternAsync() + { + await TestConversionVisualBasicToCSharpAsync(@"Class TestClass + Private Sub TestMethod(ByVal Breite As Integer) + Dim Rollo_FederUmdrehungen_Berechnen As Integer + Select Case Breite + Case Is < 1000 + Rollo_FederUmdrehungen_Berechnen = 12 + Case Is < 1200 + Rollo_FederUmdrehungen_Berechnen = 15 + Case Is < 1600 + Rollo_FederUmdrehungen_Berechnen = 19 + Case Is < 1800 + Rollo_FederUmdrehungen_Berechnen = 25 + Case Else + Rollo_FederUmdrehungen_Berechnen = 28 + End Select + End Sub +End Class", @" +internal partial class TestClass +{ + private void TestMethod(int Breite) + { + int Rollo_FederUmdrehungen_Berechnen; + switch (Breite) + { + case < 1000: + { + Rollo_FederUmdrehungen_Berechnen = 12; + break; + } + case < 1200: + { + Rollo_FederUmdrehungen_Berechnen = 15; + break; + } + case < 1600: + { + Rollo_FederUmdrehungen_Berechnen = 19; + break; + } + case < 1800: + { + Rollo_FederUmdrehungen_Berechnen = 25; + break; + } + + default: + { + Rollo_FederUmdrehungen_Berechnen = 28; + break; + } + } + } }"); } } diff --git a/Tests/CSharp/StatementTests/MethodStatementTests_803.cs b/Tests/CSharp/StatementTests/MethodStatementTests_803.cs deleted file mode 100644 index 69202454..00000000 --- a/Tests/CSharp/StatementTests/MethodStatementTests_803.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Threading.Tasks; -using ICSharpCode.CodeConverter.Tests.TestRunners; -using Xunit; - -namespace ICSharpCode.CodeConverter.Tests.CSharp.StatementTests; - -public class MethodStatementTests_803 : ConverterTestBase -{ - [Fact] - public async Task Issue803_SelectCaseWithRelationalPatternAsync() - { - await TestConversionVisualBasicToCSharpAsync(@"Class TestClass - Private Sub TestMethod(ByVal Breite As Integer) - Dim Rollo_FederUmdrehungen_Berechnen As Integer - Select Case Breite - Case Is < 1000 - Rollo_FederUmdrehungen_Berechnen = 12 - Case Is < 1200 - Rollo_FederUmdrehungen_Berechnen = 15 - Case Is < 1600 - Rollo_FederUmdrehungen_Berechnen = 19 - Case Is < 1800 - Rollo_FederUmdrehungen_Berechnen = 25 - Case Else - Rollo_FederUmdrehungen_Berechnen = 28 - End Select - End Sub -End Class", @"internal partial class TestClass -{ - private void TestMethod(int Breite) - { - int Rollo_FederUmdrehungen_Berechnen; - switch (Breite) - { - case < 1000: - { - Rollo_FederUmdrehungen_Berechnen = 12; - break; - } - - case < 1200: - { - Rollo_FederUmdrehungen_Berechnen = 15; - break; - } - - case < 1600: - { - Rollo_FederUmdrehungen_Berechnen = 19; - break; - } - - case < 1800: - { - Rollo_FederUmdrehungen_Berechnen = 25; - break; - } - - default: - { - Rollo_FederUmdrehungen_Berechnen = 28; - break; - } - } - } -}"); - } -}