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);
        }