private ExpressionSyntax TryVisitInvocationExpression(InvocationExpressionSyntax node, ForEachStatementSyntax containingForEach) { var memberAccess = node.Expression as MemberAccessExpressionSyntax; if (memberAccess != null) { var symbol = semantic.GetSymbolInfo(memberAccess).Symbol as IMethodSymbol; var owner = node.AncestorsAndSelf().OfType <MethodDeclarationSyntax>().FirstOrDefault(); if (owner != null) { currentMethodIsStatic = semantic.GetDeclaredSymbol(owner).IsStatic; currentMethodName = owner.Identifier.ValueText; currentMethodTypeParameters = owner.TypeParameterList; currentMethodConstraintClauses = owner.ConstraintClauses; } else { var accessor = node.AncestorsAndSelf().OfType <AccessorDeclarationSyntax>().FirstOrDefault(); if (accessor == null) { return(null); } var parent = accessor.Parent?.Parent; if (parent == null) { throw new NotSupportedException("Accessors must be in a property or event block"); } currentMethodIsStatic = semantic.GetDeclaredSymbol(parent).IsStatic; currentMethodTypeParameters = null; currentMethodConstraintClauses = new SyntaxList <TypeParameterConstraintClauseSyntax>(); var property = parent as PropertyDeclarationSyntax; if (property != null) { currentMethodName = property.Identifier.ValueText; } else { var ev = parent as EventDeclarationSyntax; if (ev == null) { throw new NotSupportedException("Accessors must be in properties or events. Not supported: " + parent); } currentMethodName = ev.Identifier.ValueText; } } if (IsSupportedMethod(node)) { var chain = new List <LinqStep>(); chain.Add(new LinqStep(GetMethodFullName(node), node.ArgumentList.Arguments.Select(x => x.Expression).ToList(), node)); var c = node; var lastNode = node; while (c.Expression is MemberAccessExpressionSyntax) { c = ((MemberAccessExpressionSyntax)c.Expression).Expression as InvocationExpressionSyntax; if (c != null && IsSupportedMethod(c)) { chain.Add(new LinqStep(GetMethodFullName(c), c.ArgumentList.Arguments.Select(x => x.Expression).ToList(), c)); lastNode = c; } else { break; } } if (containingForEach != null) { chain.Insert(0, new LinqStep(IEnumerableForEachMethod, new[] { SyntaxFactory.SimpleLambdaExpression(SyntaxFactory.Parameter(containingForEach.Identifier), containingForEach.Statement) }) { Lambda = new Lambda(containingForEach.Statement, new[] { CreateParameter(containingForEach.Identifier, semantic.GetTypeInfo(containingForEach.Type).ConvertedType) }) }); } if (!chain.Any(x => x.Arguments.Any(y => y is AnonymousFunctionExpressionSyntax))) { return(null); } if (chain.Count == 1 && RootMethodsThatRequireYieldReturn.Contains(chain[0].MethodName)) { return(null); } var flowsIn = new List <ISymbol>(); var flowsOut = new List <ISymbol>(); foreach (var item in chain) { foreach (var arg in item.Arguments) { if (item.Lambda != null) { var dataFlow = semantic.AnalyzeDataFlow(item.Lambda.Body); var pname = item.Lambda.Parameters.Single().Identifier.ValueText; foreach (var k in dataFlow.DataFlowsIn) { if (k.Name == pname) { continue; } if (!flowsIn.Contains(k)) { flowsIn.Add(k); } } foreach (var k in dataFlow.DataFlowsOut) { if (k.Name == pname) { continue; } if (!flowsOut.Contains(k)) { flowsOut.Add(k); } } } else { var dataFlow = semantic.AnalyzeDataFlow(arg); foreach (var k in dataFlow.DataFlowsIn) { if (!flowsIn.Contains(k)) { flowsIn.Add(k); } } foreach (var k in dataFlow.DataFlowsOut) { if (!flowsOut.Contains(k)) { flowsOut.Add(k); } } } } } currentFlow = flowsIn .Union(flowsOut) .Where(x => (x as IParameterSymbol)?.IsThis != true) .Select(x => CreateVariableCapture(x, flowsOut)) ?? Enumerable.Empty <VariableCapture>(); var collection = ((MemberAccessExpressionSyntax)lastNode.Expression).Expression; if (IsAnonymousType(semantic.GetTypeInfo(collection).Type)) { return(null); } var semanticReturnType = semantic.GetTypeInfo(node).Type; if (IsAnonymousType(semanticReturnType) || currentFlow.Any(x => IsAnonymousType(GetSymbolType(x.Symbol)))) { return(null); } return(TryRewrite(chain.First().MethodName, collection, semanticReturnType, chain, node) .WithLeadingTrivia(((CSharpSyntaxNode)containingForEach ?? node).GetLeadingTrivia()) .WithTrailingTrivia(((CSharpSyntaxNode)containingForEach ?? node).GetTrailingTrivia())); } } return(null); }
private ExpressionSyntax TryRewrite(string aggregationMethod, ExpressionSyntax collection, ITypeSymbol semanticReturnType, List <LinqStep> chain, InvocationExpressionSyntax node) { var returnType = SyntaxFactory.ParseTypeName(semanticReturnType.ToDisplayString()); if (RootMethodsThatRequireYieldReturn.Contains(aggregationMethod)) { return(RewriteAsLoop( returnType, Enumerable.Empty <StatementSyntax>(), Enumerable.Empty <StatementSyntax>(), collection, chain, (inv, arguments, param) => { return SyntaxFactory.YieldStatement(SyntaxKind.YieldReturnStatement, SyntaxFactory.IdentifierName(param.Identifier.ValueText)); }, true )); } if (aggregationMethod.Contains(".Sum")) { var elementType = ((returnType as NullableTypeSyntax)?.ElementType ?? returnType); return(RewriteAsLoop( returnType, new[] { CreateLocalVariableDeclaration("sum_", SyntaxFactory.CastExpression(elementType, SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(0)))) }, new[] { SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName("sum_")) }, collection, MaybeAddSelect(chain, node.ArgumentList.Arguments.Count != 0), (inv, arguments, param) => { var currentValue = SyntaxFactory.IdentifierName(param.Identifier.ValueText); return IfNullableIsNotNull(elementType != returnType, currentValue, x => { return SyntaxFactory.CheckedStatement(SyntaxKind.CheckedStatement, SyntaxFactory.Block(SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.AddAssignmentExpression, SyntaxFactory.IdentifierName("sum_"), x)))); }); } )); } if (aggregationMethod.Contains(".Max") || aggregationMethod.Contains(".Min")) { var minmax = aggregationMethod.Contains(".Max") ? "max_" : "min_"; var elementType = ((returnType as NullableTypeSyntax)?.ElementType ?? returnType); return(RewriteAsLoop( returnType, new[] { CreateLocalVariableDeclaration("found_", SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression)), CreateLocalVariableDeclaration(minmax, SyntaxFactory.CastExpression(elementType, SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(0)))) }, new[] { SyntaxFactory.Block( SyntaxFactory.IfStatement(SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, SyntaxFactory.IdentifierName("found_")), returnType == elementType ? (StatementSyntax)CreateThrowException("System.InvalidOperationException", "The sequence did not contain any elements.") : SyntaxFactory.ReturnStatement(SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression)) ), SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName(minmax)) ) }, collection, MaybeAddSelect(chain, node.ArgumentList.Arguments.Count != 0), (inv, arguments, param) => { var identifierNameSyntax = SyntaxFactory.IdentifierName(param.Identifier.ValueText); return IfNullableIsNotNull(elementType != returnType, identifierNameSyntax, x => { var assignmentExpressionSyntax = SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName(minmax), x); var condition = SyntaxFactory.BinaryExpression(aggregationMethod.Contains(".Max") ? SyntaxKind.GreaterThanExpression : SyntaxKind.LessThanExpression, x, SyntaxFactory.IdentifierName(minmax)); var kind = (elementType as PredefinedTypeSyntax).Keyword.Kind(); if (kind == SyntaxKind.DoubleKeyword || kind == SyntaxKind.FloatKeyword) { condition = SyntaxFactory.BinaryExpression(SyntaxKind.LogicalOrExpression, condition, SyntaxFactory.InvocationExpression(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, elementType, SyntaxFactory.IdentifierName("IsNaN")), CreateArguments(x))); } return SyntaxFactory.IfStatement(SyntaxFactory.IdentifierName("found_"), SyntaxFactory.Block(SyntaxFactory.IfStatement(condition, SyntaxFactory.ExpressionStatement(assignmentExpressionSyntax))), SyntaxFactory.ElseClause(SyntaxFactory.Block(SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName("found_"), SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression))), SyntaxFactory.ExpressionStatement(assignmentExpressionSyntax)))); }); })); } if (aggregationMethod.Contains(".Average")) { var elementType = ((returnType as NullableTypeSyntax)?.ElementType ?? returnType); var primitive = ((PredefinedTypeSyntax)elementType).Keyword.Kind(); ExpressionSyntax sumIdentifier = SyntaxFactory.IdentifierName("sum_"); ExpressionSyntax countIdentifier = SyntaxFactory.IdentifierName("count_"); if (primitive != SyntaxKind.DecimalKeyword) { sumIdentifier = SyntaxFactory.CastExpression(CreatePrimitiveType(SyntaxKind.DoubleKeyword), sumIdentifier); countIdentifier = SyntaxFactory.CastExpression(CreatePrimitiveType(SyntaxKind.DoubleKeyword), countIdentifier); } ExpressionSyntax division = SyntaxFactory.BinaryExpression(SyntaxKind.DivideExpression, sumIdentifier, countIdentifier); if (primitive != SyntaxKind.DoubleKeyword && primitive != SyntaxKind.DecimalKeyword) { division = SyntaxFactory.CastExpression(elementType, SyntaxFactory.ParenthesizedExpression(division)); } return(RewriteAsLoop( returnType, new[] { CreateLocalVariableDeclaration("sum_", SyntaxFactory.CastExpression(primitive == SyntaxKind.IntKeyword || primitive == SyntaxKind.LongKeyword ? CreatePrimitiveType(SyntaxKind.LongKeyword) : primitive == SyntaxKind.DecimalKeyword ? CreatePrimitiveType(SyntaxKind.DecimalKeyword) : CreatePrimitiveType(SyntaxKind.DoubleKeyword), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(0)))), CreateLocalVariableDeclaration("count_", SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.ParseToken("0L"))) }, new[] { SyntaxFactory.Block( SyntaxFactory.IfStatement(SyntaxFactory.BinaryExpression(SyntaxKind.EqualsExpression, SyntaxFactory.IdentifierName("count_"), SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.ParseToken("0"))), returnType == elementType ? (StatementSyntax)CreateThrowException("System.InvalidOperationException", "The sequence did not contain any elements.") : SyntaxFactory.ReturnStatement(SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression)) ), SyntaxFactory.ReturnStatement(division) ) }, collection, MaybeAddSelect(chain, node.ArgumentList.Arguments.Count != 0), (inv, arguments, param) => { var currentValue = SyntaxFactory.IdentifierName(param.Identifier.ValueText); return IfNullableIsNotNull(elementType != returnType, currentValue, x => { return SyntaxFactory.CheckedStatement(SyntaxKind.CheckedStatement, SyntaxFactory.Block( SyntaxFactory.ExpressionStatement(SyntaxFactory.PostfixUnaryExpression(SyntaxKind.PostIncrementExpression, SyntaxFactory.IdentifierName("count_"))), SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.AddAssignmentExpression, SyntaxFactory.IdentifierName("sum_"), x)) )); }); } )); } if (aggregationMethod == AnyMethod || aggregationMethod == AnyWithConditionMethod) { return(RewriteAsLoop( CreatePrimitiveType(SyntaxKind.BoolKeyword), Enumerable.Empty <StatementSyntax>(), new[] { SyntaxFactory.ReturnStatement(SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression)) }, collection, MaybeAddFilter(chain, aggregationMethod == AnyWithConditionMethod), (inv, arguments, param) => { return SyntaxFactory.ReturnStatement(SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression)); } )); } if (aggregationMethod == ListForEachMethod || aggregationMethod == IEnumerableForEachMethod) { return(RewriteAsLoop( CreatePrimitiveType(SyntaxKind.VoidKeyword), Enumerable.Empty <StatementSyntax>(), Enumerable.Empty <StatementSyntax>(), collection, chain, (inv, arguments, param) => { var lambda = inv.Lambda ?? new Lambda((AnonymousFunctionExpressionSyntax)inv.Arguments.First()); return SyntaxFactory.ExpressionStatement(InlineOrCreateMethod(lambda, CreatePrimitiveType(SyntaxKind.VoidKeyword), arguments, param)); } )); } if (aggregationMethod == ContainsMethod) { var elementType = SyntaxFactory.ParseTypeName(semantic.GetTypeInfo(node.ArgumentList.Arguments.First().Expression).ConvertedType.ToDisplayString()); var comparerIdentifier = ((elementType as NullableTypeSyntax)?.ElementType ?? elementType) is PredefinedTypeSyntax ? null : SyntaxFactory.IdentifierName("comparer_"); return(RewriteAsLoop( CreatePrimitiveType(SyntaxKind.BoolKeyword), comparerIdentifier != null ? new StatementSyntax[] { CreateLocalVariableDeclaration("comparer_", SyntaxFactory.ParseExpression("System.Collections.Generic.EqualityComparer<" + elementType.ToString() + ">.Default")) } : Enumerable.Empty <StatementSyntax>(), new[] { SyntaxFactory.ReturnStatement(SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression)) }, collection, chain, (inv, arguments, param) => { var target = SyntaxFactory.IdentifierName("_target"); var current = SyntaxFactory.IdentifierName(param.Identifier.ValueText); var condition = comparerIdentifier != null ? SyntaxFactory.InvocationExpression(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, comparerIdentifier, SyntaxFactory.IdentifierName("Equals")), CreateArguments(current, target)) : (ExpressionSyntax)SyntaxFactory.BinaryExpression(SyntaxKind.EqualsExpression, current, target); return SyntaxFactory.IfStatement(condition, SyntaxFactory.ReturnStatement(SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression))); }, additionalParameters: new[] { Tuple.Create(CreateParameter("_target", elementType), node.ArgumentList.Arguments.First().Expression) } )); } if (aggregationMethod == AllWithConditionMethod) // All alone does not exist { return(RewriteAsLoop( CreatePrimitiveType(SyntaxKind.BoolKeyword), Enumerable.Empty <StatementSyntax>(), new[] { SyntaxFactory.ReturnStatement(SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression)) }, collection, chain, (inv, arguments, param) => { var lambda = (LambdaExpressionSyntax)inv.Arguments.First(); return SyntaxFactory.IfStatement(SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, SyntaxFactory.ParenthesizedExpression(InlineOrCreateMethod(new Lambda(lambda), CreatePrimitiveType(SyntaxKind.BoolKeyword), arguments, param))), SyntaxFactory.ReturnStatement(SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression) )); } )); } if (aggregationMethod == CountMethod || aggregationMethod == CountWithConditionMethod || aggregationMethod == LongCountMethod || aggregationMethod == LongCountWithConditionMethod) { return(RewriteAsLoop( returnType, new[] { CreateLocalVariableDeclaration("_count", SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.ParseToken(aggregationMethod == LongCountMethod || aggregationMethod == LongCountWithConditionMethod ? "0L" : "0"))) }, new[] { SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName("_count")) }, collection, MaybeAddFilter(chain, aggregationMethod == CountWithConditionMethod || aggregationMethod == LongCountWithConditionMethod), (inv, arguments, param) => { return SyntaxFactory.ExpressionStatement(SyntaxFactory.PostfixUnaryExpression(SyntaxKind.PostIncrementExpression, SyntaxFactory.IdentifierName("_count"))); } )); } if (aggregationMethod == ElementAtMethod || aggregationMethod == ElementAtOrDefaultMethod) { return(RewriteAsLoop( returnType, new[] { CreateLocalVariableDeclaration("_count", SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.ParseToken(aggregationMethod == LongCountMethod || aggregationMethod == LongCountWithConditionMethod ? "0L" : "0"))) }, new[] { aggregationMethod == ElementAtMethod ? (StatementSyntax)CreateThrowException("System.InvalidOperationException", "The specified index is not included in the sequence.") : SyntaxFactory.ReturnStatement(SyntaxFactory.DefaultExpression(returnType)) }, collection, MaybeAddFilter(chain, aggregationMethod == CountWithConditionMethod || aggregationMethod == LongCountWithConditionMethod), (inv, arguments, param) => { return SyntaxFactory.IfStatement(SyntaxFactory.BinaryExpression(SyntaxKind.EqualsExpression, SyntaxFactory.IdentifierName("_requestedPosition"), SyntaxFactory.PostfixUnaryExpression(SyntaxKind.PostIncrementExpression, SyntaxFactory.IdentifierName("_count"))), SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName(param.Identifier.ValueText))); }, additionalParameters: new[] { Tuple.Create(CreateParameter("_requestedPosition", CreatePrimitiveType(SyntaxKind.IntKeyword)), node.ArgumentList.Arguments.First().Expression) } )); } if (aggregationMethod == FirstMethod || aggregationMethod == FirstWithConditionMethod) { return(RewriteAsLoop( returnType, Enumerable.Empty <StatementSyntax>(), new[] { CreateThrowException("System.InvalidOperationException", "The sequence did not contain any elements.") }, collection, MaybeAddFilter(chain, aggregationMethod == FirstWithConditionMethod), (inv, arguments, param) => { return SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName(param.Identifier.ValueText)); } )); } if (aggregationMethod == FirstOrDefaultMethod || aggregationMethod == FirstOrDefaultWithConditionMethod) { return(RewriteAsLoop( returnType, Enumerable.Empty <StatementSyntax>(), new[] { SyntaxFactory.ReturnStatement(SyntaxFactory.DefaultExpression(returnType)) }, collection, MaybeAddFilter(chain, aggregationMethod == FirstOrDefaultWithConditionMethod), (inv, arguments, param) => { return SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName(param.Identifier.ValueText)); } )); } if (aggregationMethod == LastOrDefaultMethod || aggregationMethod == LastOrDefaultWithConditionMethod) { return(RewriteAsLoop( returnType, new[] { CreateLocalVariableDeclaration("_last", SyntaxFactory.DefaultExpression(returnType)) }, new[] { SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName("_last")) }, collection, MaybeAddFilter(chain, aggregationMethod == LastOrDefaultWithConditionMethod), (inv, arguments, param) => { return SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName("_last"), SyntaxFactory.IdentifierName(param.Identifier.ValueText))); } )); } if (aggregationMethod == LastMethod || aggregationMethod == LastWithConditionMethod) { return(RewriteAsLoop( returnType, new[] { CreateLocalVariableDeclaration("_last", SyntaxFactory.DefaultExpression(returnType)), CreateLocalVariableDeclaration("_found", SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression)) }, new StatementSyntax[] { SyntaxFactory.IfStatement(SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, SyntaxFactory.IdentifierName("_found")), CreateThrowException("System.InvalidOperationException", "The sequence did not contain any elements.")), SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName("_last")) }, collection, MaybeAddFilter(chain, aggregationMethod == LastWithConditionMethod), (inv, arguments, param) => { return SyntaxFactory.Block( SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName("_found"), SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression))), SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName("_last"), SyntaxFactory.IdentifierName(param.Identifier.ValueText)))); } )); } if (aggregationMethod == SingleMethod || aggregationMethod == SingleWithConditionMethod) { return(RewriteAsLoop( returnType, new[] { CreateLocalVariableDeclaration("_last", SyntaxFactory.DefaultExpression(returnType)), CreateLocalVariableDeclaration("_found", SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression)) }, new StatementSyntax[] { SyntaxFactory.IfStatement(SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, SyntaxFactory.IdentifierName("_found")), CreateThrowException("System.InvalidOperationException", "The sequence did not contain any elements.")), SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName("_last")) }, collection, MaybeAddFilter(chain, aggregationMethod == SingleWithConditionMethod), (inv, arguments, param) => { return SyntaxFactory.Block( SyntaxFactory.IfStatement(SyntaxFactory.IdentifierName("_found"), CreateThrowException("System.InvalidOperationException", "The sequence contains more than one element.")), SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName("_found"), SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression))), SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName("_last"), SyntaxFactory.IdentifierName(param.Identifier.ValueText)))); } )); } if (aggregationMethod == SingleOrDefaultMethod || aggregationMethod == SingleOrDefaultWithConditionMethod) { return(RewriteAsLoop( returnType, new[] { CreateLocalVariableDeclaration("_last", SyntaxFactory.DefaultExpression(returnType)), CreateLocalVariableDeclaration("_found", SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression)) }, new StatementSyntax[] { SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName("_last")) }, collection, MaybeAddFilter(chain, aggregationMethod == SingleOrDefaultWithConditionMethod), (inv, arguments, param) => { return SyntaxFactory.Block( SyntaxFactory.IfStatement(SyntaxFactory.IdentifierName("_found"), CreateThrowException("System.InvalidOperationException", "The sequence contains more than one element.")), SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName("_found"), SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression))), SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName("_last"), SyntaxFactory.IdentifierName(param.Identifier.ValueText)))); } )); } if (aggregationMethod == ToListMethod || aggregationMethod == ReverseMethod) { var count = chain.All(x => MethodsThatPreserveCount.Contains(x.MethodName)) ? GetCollectionCount(collection, true) : null; var listIdentifier = SyntaxFactory.IdentifierName("_list"); return(RewriteAsLoop( returnType, new[] { CreateLocalVariableDeclaration("_list", SyntaxFactory.ObjectCreationExpression(SyntaxFactory.ParseTypeName("System.Collections.Generic.List<" + GetItemType(semanticReturnType).ToDisplayString() + ">"), CreateArguments(count != null ? new[] { count } : Enumerable.Empty <ExpressionSyntax>()), null)) }, aggregationMethod == ReverseMethod ? new StatementSyntax[] { SyntaxFactory.ExpressionStatement(SyntaxFactory.InvocationExpression(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName("_list"), SyntaxFactory.IdentifierName("Reverse")))), SyntaxFactory.ReturnStatement(listIdentifier) } : new[] { SyntaxFactory.ReturnStatement(listIdentifier) }, collection, chain, (inv, arguments, param) => { return CreateStatement(SyntaxFactory.InvocationExpression(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, listIdentifier, SyntaxFactory.IdentifierName("Add")), CreateArguments(new[] { SyntaxFactory.IdentifierName(param.Identifier.ValueText) }))); } )); } if (/*aggregationMethod == ToDictionaryWithKeyMethod || */ aggregationMethod == ToDictionaryWithKeyValueMethod) { var dictIdentifier = SyntaxFactory.IdentifierName("_dict"); return(RewriteAsLoop( returnType, new[] { CreateLocalVariableDeclaration("_dict", SyntaxFactory.ObjectCreationExpression(returnType, CreateArguments(Enumerable.Empty <ArgumentSyntax>()), null)) }, new[] { SyntaxFactory.ReturnStatement(dictIdentifier) }, collection, chain, (inv, arguments, param) => { var keyLambda = (AnonymousFunctionExpressionSyntax)node.ArgumentList.Arguments.First().Expression; var valueLambda = (AnonymousFunctionExpressionSyntax)node.ArgumentList.Arguments.ElementAtOrDefault(1)?.Expression; return CreateStatement(SyntaxFactory.InvocationExpression(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, dictIdentifier, SyntaxFactory.IdentifierName("Add")), CreateArguments(new[] { InlineOrCreateMethod(new Lambda(keyLambda), SyntaxFactory.ParseTypeName(GetLambdaReturnType(keyLambda).ToDisplayString()), arguments, param), aggregationMethod == ToDictionaryWithKeyValueMethod ? InlineOrCreateMethod(new Lambda(valueLambda), SyntaxFactory.ParseTypeName(GetLambdaReturnType(valueLambda).ToDisplayString()), arguments, param): SyntaxFactory.IdentifierName(param.Identifier.ValueText), }))); } )); } if (aggregationMethod == ToArrayMethod) { var count = chain.All(x => MethodsThatPreserveCount.Contains(x.MethodName)) ? GetCollectionCount(collection, false) : null; if (count != null) { var arrayIdentifier = SyntaxFactory.IdentifierName("_array"); return(RewriteAsLoop( returnType, new[] { CreateLocalVariableDeclaration("_array", SyntaxFactory.ArrayCreationExpression(SyntaxFactory.ArrayType(((ArrayTypeSyntax)returnType).ElementType, SyntaxFactory.List(new[] { SyntaxFactory.ArrayRankSpecifier(CreateSeparatedList(new[] { count })) })))) }, new[] { SyntaxFactory.ReturnStatement(arrayIdentifier) }, collection, chain, (inv, arguments, param) => { return CreateStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.ElementAccessExpression(arrayIdentifier, SyntaxFactory.BracketedArgumentList(CreateSeparatedList(new[] { SyntaxFactory.Argument(SyntaxFactory.IdentifierName("_index")) }))), SyntaxFactory.IdentifierName(param.Identifier.ValueText))); } )); } else { var listIdentifier = SyntaxFactory.IdentifierName("_list"); var listType = SyntaxFactory.ParseTypeName("System.Collections.Generic.List<" + ((ArrayTypeSyntax)returnType).ElementType + ">"); return(RewriteAsLoop( returnType, new[] { CreateLocalVariableDeclaration("_list", SyntaxFactory.ObjectCreationExpression(listType, CreateArguments(Enumerable.Empty <ArgumentSyntax>()), null)) }, new[] { SyntaxFactory.ReturnStatement(SyntaxFactory.InvocationExpression(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, listIdentifier, SyntaxFactory.IdentifierName("ToArray")))) }, collection, chain, (inv, arguments, param) => { return CreateStatement(SyntaxFactory.InvocationExpression(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, listIdentifier, SyntaxFactory.IdentifierName("Add")), CreateArguments(new[] { SyntaxFactory.IdentifierName(param.Identifier.ValueText) }))); } )); } } #if false if (GetMethodFullName(node) == SumWithSelectorMethod) { string itemArg = null; return(RewriteAsLoop( CreatePrimitiveType(SyntaxKind.IntKeyword), new[] { CreateLocalVariableDeclaration("sum_", SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(0))) }, arguments => { return SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.AddAssignmentExpression, SyntaxFactory.IdentifierName("sum_"), InlineOrCreateMethod((CSharpSyntaxNode)Visit(lambda.Body), arguments, CreateParameter(arg.Identifier, itemType), out itemArg))); }, new[] { SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName("sum_")) }, () => itemArg, collection )); } if (GetMethodFullName(node) == SumIntsMethod) { string itemArg = null; return(RewriteAsLoop( CreatePrimitiveType(SyntaxKind.IntKeyword), new[] { CreateLocalVariableDeclaration("sum_", SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(0))) }, arguments => { return SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.AddAssignmentExpression, SyntaxFactory.IdentifierName("sum_"), InlineOrCreateMethod(SyntaxFactory.IdentifierName(ItemName), arguments, CreateParameter(ItemName, itemType), out itemArg))); }, new[] { SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName("sum_")) }, () => itemArg, collection )); } #endif return(null); }