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] 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; + } + } + } +}"); + } +}