diff --git a/CodeConverter/CSharp/VbNameExpander.cs b/CodeConverter/CSharp/VbNameExpander.cs index 7022e65a..b75b0cf3 100644 --- a/CodeConverter/CSharp/VbNameExpander.cs +++ b/CodeConverter/CSharp/VbNameExpander.cs @@ -65,7 +65,7 @@ public SyntaxNode ExpandNode(SyntaxNode node, SemanticModel semanticModel, semanticModel.GetOperation(node) is IMemberReferenceOperation { Instance: { Syntax: ExpressionSyntax promotedInstance }, Member: {} member }) { return MemberAccess(promotedInstance, SyntaxFactory.IdentifierName(member.Name)); } - return IsOriginalSymbolGenericMethod(semanticModel, node) ? node : Simplifier.Expand(node, semanticModel, workspace); + return IsOriginalSymbolGenericOrExtensionMethod(semanticModel, node) ? node : Simplifier.Expand(node, semanticModel, workspace); } private static bool IsReducedExtensionInExtendedTypeOrDerivedType(SyntaxNode node, ISymbol symbol, SemanticModel semanticModel) @@ -136,8 +136,15 @@ public static bool IsRoslynInstanceExpressionBug(MemberAccessExpressionSyntax no /// Roslyn bug - accidentally expands anonymous types to just "Global." /// Since the C# reducer also doesn't seem to reduce generic extension methods, it's best to avoid those too, so let's just avoid all generic methods /// - private static bool IsOriginalSymbolGenericMethod(SemanticModel semanticModel, SyntaxNode node) => - semanticModel.GetSymbolInfo(node).Symbol.IsGenericMethod(); + private static bool IsOriginalSymbolGenericOrExtensionMethod(SemanticModel semanticModel, SyntaxNode node) + { + var symbolInfo = semanticModel.GetSymbolInfo(node); + var symbol = symbolInfo.Symbol ?? symbolInfo.CandidateSymbols.FirstOrDefault(); + if (symbol?.IsGenericMethod() == true) return true; + if (symbol is IMethodSymbol ms && (ms.MethodKind == MethodKind.ReducedExtension || ms.IsExtensionMethod)) return true; + return false; + } + private static bool IsQualifiableInstanceReference(ISymbol symbol) => symbol?.IsStatic == false && (symbol.IsKind(SymbolKind.Method) || symbol.IsKind(SymbolKind.Field) || diff --git a/Tests/CSharp/ExpressionTests/LinqExtensionMethodReproTests.cs b/Tests/CSharp/ExpressionTests/LinqExtensionMethodReproTests.cs new file mode 100644 index 00000000..a05fe1b5 --- /dev/null +++ b/Tests/CSharp/ExpressionTests/LinqExtensionMethodReproTests.cs @@ -0,0 +1,53 @@ +using System.Threading.Tasks; +using Xunit; +using ICSharpCode.CodeConverter.Tests.TestRunners; + +namespace ICSharpCode.CodeConverter.Tests.CSharp.ExpressionTests; + +public class LinqExtensionMethodReproTests : ConverterTestBase +{ + [Fact] + public async Task TestLinqExtensionMethods() + { + await TestConversionVisualBasicToCSharpAsync(@"Imports System.Linq + +Public Class TestClass + Public Shared Sub Test() + Dim intCol = New Integer() {1, 2, 3} + Dim intCol2 = New Integer() {1, 2, 3} + + Dim intColQuery = intCol.Select(Function(x) x) + Dim intColCopy = intCol.Select(Function(x) x).ToArray() + Dim intSum = intCol.Select(Function(x) x).Sum(Function(x) x) + Dim intMax = intCol.Select(Function(x) x).Max(Function(x) x) + Dim intCnt = intCol.Select(Function(x) x).Count(Function(x) x > 1) + + Dim intSum2 = intCol.Select(Function(x) x).Sum() + Dim intMax2 = intCol.OrderBy(Function(x) x).Max() + Dim intCnt2 = intCol.Select(Function(x) x).Count() + Dim intSum3 = intCol.Zip(intCol2, Function(x, y) x + y).Sum() + End Sub +End Class", @"using System; +using System.Linq; + +public partial class TestClass +{ + public static void Test() + { + int[] intCol = new int[] { 1, 2, 3 }; + int[] intCol2 = new int[] { 1, 2, 3 }; + + var intColQuery = intCol.Select(x => x); + int[] intColCopy = intCol.Select(x => x).ToArray(); + int intSum = intCol.Select(x => x).Sum(x => x); + int intMax = intCol.Select(x => x).Max(x => x); + int intCnt = intCol.Select(x => x).Count(x => x > 1); + + int intSum2 = intCol.Select(x => x).Sum(); + int intMax2 = intCol.OrderBy(x => x).Max(); + int intCnt2 = intCol.Select(x => x).Count(); + int intSum3 = intCol.Zip(intCol2, (x, y) => x + y).Sum(); + } +}"); + } +}