From 8d211e143cb589ab626b80cbe77c5301c3b8a5d6 Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Sun, 9 Jul 2023 17:50:57 +0100 Subject: [PATCH] Pay attention to lambda expressions - fixes #930 Inspired by https://github.com/JosefPihrt/Roslynator/blob/7ba2f29f5090aa13f4dd6b7936af55180b678333/src/CSharp/CSharp/Extensions/SyntaxExtensions.cs#L3114 --- CodeConverter/CSharp/CommonConversions.cs | 2 + CodeConverter/CSharp/ExpressionNodeVisitor.cs | 59 +++++++++++++++---- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/CodeConverter/CSharp/CommonConversions.cs b/CodeConverter/CSharp/CommonConversions.cs index d8545e15e..8564a8f3b 100644 --- a/CodeConverter/CSharp/CommonConversions.cs +++ b/CodeConverter/CSharp/CommonConversions.cs @@ -19,6 +19,7 @@ namespace ICSharpCode.CodeConverter.CSharp; internal class CommonConversions { + public ITypeSymbol System_Linq_Expressions_Expression_T { get; } private static readonly Type ExtensionAttributeType = typeof(ExtensionAttribute); public Document Document { get; } public SemanticModel SemanticModel { get; } @@ -47,6 +48,7 @@ public CommonConversions(Document document, SemanticModel semanticModel, _typeContext = typeContext; VisualBasicEqualityComparison = visualBasicEqualityComparison; WinformsConversions = new WinformsConversions(typeContext); + System_Linq_Expressions_Expression_T = semanticModel.Compilation.GetTypeByMetadataName("System.Linq.Expressions.Expression`1"); } public record VariablePair(CSSyntax.VariableDeclaratorSyntax CsVar, VBSyntax.ModifiedIdentifierSyntax VbVar); diff --git a/CodeConverter/CSharp/ExpressionNodeVisitor.cs b/CodeConverter/CSharp/ExpressionNodeVisitor.cs index 6f82e78f2..5647bef1a 100644 --- a/CodeConverter/CSharp/ExpressionNodeVisitor.cs +++ b/CodeConverter/CSharp/ExpressionNodeVisitor.cs @@ -1231,29 +1231,64 @@ private static bool NextStatementDefinitelyExecutedAfter(VBSyntax.InvocationExpr public override async Task VisitSingleLineLambdaExpression(VBasic.Syntax.SingleLineLambdaExpressionSyntax node) { - IReadOnlyCollection convertedStatements; - if (node.Body is VBasic.Syntax.StatementSyntax statement) { - convertedStatements = await ConvertMethodBodyStatementsAsync(statement, statement.Yield().ToArray()); - } else { - var csNode = await node.Body.AcceptAsync(TriviaConvertingExpressionVisitor); - convertedStatements = new[] { SyntaxFactory.ExpressionStatement(csNode)}; + var originalIsWithinQuery = TriviaConvertingExpressionVisitor.IsWithinQuery; + TriviaConvertingExpressionVisitor.IsWithinQuery = IsLinqExpression(node); + try { + return await ConvertInnerAsync(); + } finally { + TriviaConvertingExpressionVisitor.IsWithinQuery = originalIsWithinQuery; + } + + async Task ConvertInnerAsync() + { + IReadOnlyCollection convertedStatements; + if (node.Body is VBasic.Syntax.StatementSyntax statement) + { + convertedStatements = await ConvertMethodBodyStatementsAsync(statement, statement.Yield().ToArray()); + } + else + { + var csNode = await node.Body.AcceptAsync(TriviaConvertingExpressionVisitor); + convertedStatements = new[] {SyntaxFactory.ExpressionStatement(csNode)}; + } + + var param = await node.SubOrFunctionHeader.ParameterList.AcceptAsync(TriviaConvertingExpressionVisitor); + return await _lambdaConverter.ConvertAsync(node, param, convertedStatements); } - var param = await node.SubOrFunctionHeader.ParameterList.AcceptAsync(TriviaConvertingExpressionVisitor); - return await _lambdaConverter.ConvertAsync(node, param, convertedStatements); } public override async Task VisitMultiLineLambdaExpression(VBasic.Syntax.MultiLineLambdaExpressionSyntax node) { - var body = await ConvertMethodBodyStatementsAsync(node, node.Statements); - var param = await node.SubOrFunctionHeader.ParameterList.AcceptAsync(TriviaConvertingExpressionVisitor); - return await _lambdaConverter.ConvertAsync(node, param, body.ToList()); + var originalIsWithinQuery = TriviaConvertingExpressionVisitor.IsWithinQuery; + TriviaConvertingExpressionVisitor.IsWithinQuery = IsLinqExpression(node); + try { + return await ConvertInnerAsync(); + } finally { + TriviaConvertingExpressionVisitor.IsWithinQuery = originalIsWithinQuery; + } + + async Task ConvertInnerAsync() + { + var body = await ConvertMethodBodyStatementsAsync(node, node.Statements); + var param = await node.SubOrFunctionHeader.ParameterList.AcceptAsync(TriviaConvertingExpressionVisitor); + return await _lambdaConverter.ConvertAsync(node, param, body.ToList()); + } + } + + private bool IsLinqExpression(VisualBasicSyntaxNode node) + { + var convertedType = _semanticModel.GetTypeInfo(node).ConvertedType; + if (CommonConversions.System_Linq_Expressions_Expression_T.Equals(convertedType?.OriginalDefinition, SymbolEqualityComparer.Default)) { + return true; + } + + return false; } public async Task> ConvertMethodBodyStatementsAsync(VBasic.VisualBasicSyntaxNode node, IReadOnlyCollection statements, bool isIterator = false, IdentifierNameSyntax csReturnVariable = null) { var innerMethodBodyVisitor = await MethodBodyExecutableStatementVisitor.CreateAsync(node, _semanticModel, TriviaConvertingExpressionVisitor, CommonConversions, _withBlockLhs, _extraUsingDirectives, _typeContext, isIterator, csReturnVariable); - return await GetWithConvertedGotosOrNull(statements) ?? await ConvertStatements(statements); async Task> ConvertStatements(IEnumerable readOnlyCollection)