From 6f824cfd8ac1662d6699c5e43852d305c68c75c7 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 14 Mar 2026 00:30:16 +0000 Subject: [PATCH] Fix conversion of single-statement multiline lambda to block syntax Fixes #1012 by ensuring that when a VB.NET MultiLineLambdaExpressionSyntax contains a single statement that is not an ExpressionStatementSyntax or ReturnStatementSyntax (such as a local declaration statement with a multiline LINQ query), it is converted to a block-bodied lambda in C# rather than an arrow expression clause. Also adds a corresponding characterization test. Co-authored-by: GrahamTheCoder <2490482+GrahamTheCoder@users.noreply.github.com> --- CodeConverter/CSharp/LambdaConverter.cs | 11 +++- Tests/CSharp/ExpressionTests/LambdaTests.cs | 56 +++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 Tests/CSharp/ExpressionTests/LambdaTests.cs diff --git a/CodeConverter/CSharp/LambdaConverter.cs b/CodeConverter/CSharp/LambdaConverter.cs index f1306f5b7..4a90398a8 100644 --- a/CodeConverter/CSharp/LambdaConverter.cs +++ b/CodeConverter/CSharp/LambdaConverter.cs @@ -79,8 +79,17 @@ public async Task ConvertAsync(VBSyntax.LambdaExpressionSyntax convertedStatements = convertedStatements.Select(l => l.WithTrailingTrivia(SyntaxFactory.ElasticCarriageReturnLineFeed)).ToList(); block = SyntaxFactory.Block(convertedStatements); } else if (singleStatement.TryUnpackSingleExpressionFromStatement(out expressionBody)) { - arrow = SyntaxFactory.ArrowExpressionClause(expressionBody); + if (vbNode is VBasic.Syntax.MultiLineLambdaExpressionSyntax && singleStatement is not ExpressionStatementSyntax && singleStatement is not ReturnStatementSyntax) { + singleStatement = singleStatement.WithTrailingTrivia(SyntaxFactory.ElasticCarriageReturnLineFeed); + block = SyntaxFactory.Block(singleStatement); + expressionBody = null; + } else { + arrow = SyntaxFactory.ArrowExpressionClause(expressionBody); + } } else { + if (vbNode is VBasic.Syntax.MultiLineLambdaExpressionSyntax) { + singleStatement = singleStatement.WithTrailingTrivia(SyntaxFactory.ElasticCarriageReturnLineFeed); + } block = SyntaxFactory.Block(singleStatement); } diff --git a/Tests/CSharp/ExpressionTests/LambdaTests.cs b/Tests/CSharp/ExpressionTests/LambdaTests.cs new file mode 100644 index 000000000..09954bed5 --- /dev/null +++ b/Tests/CSharp/ExpressionTests/LambdaTests.cs @@ -0,0 +1,56 @@ +using System.Threading.Tasks; +using ICSharpCode.CodeConverter.Tests.TestRunners; +using Xunit; + +namespace ICSharpCode.CodeConverter.Tests.CSharp.ExpressionTests; + +public class LambdaTests : ConverterTestBase +{ + [Fact] + public async Task Issue1012_MultiLineLambdaWithSingleStatement() + { + await TestConversionVisualBasicToCSharpAsync(@"Imports System.Collections.Generic +Imports System.Linq +Imports System.Threading.Tasks + +Public Class ConversionTest3 + Private Class MyEntity + Property EntityId As Integer + Property Name As String + End Class + Private Sub BugRepro() + + Dim entities As New List(Of MyEntity) + + Parallel.For(1, 3, Sub(i As Integer) + Dim result As String = (From e In entities + Where e.EntityId = 123 + Select e.Name).Single + End Sub) + End Sub +End Class", @"using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +public partial class ConversionTest3 +{ + private partial class MyEntity + { + public int EntityId { get; set; } + public string Name { get; set; } + } + private void BugRepro() + { + + var entities = new List(); + + Parallel.For(1, 3, (i) => + { + string result = (from e in entities + where e.EntityId == 123 + select e.Name).Single(); + }); + } +}"); + } +}