private static string GetUniqueVariableNameForNewScope(SyntaxBase syntax, string name)
        {
            var variableAccesses = new HashSet <string>(LanguageConstants.IdentifierComparer);

            CallbackVisitor.Visit(syntax, child =>
            {
                if (child is VariableAccessSyntax variableAccess)
                {
                    variableAccesses.Add(variableAccess.Name.IdentifierName);
                }

                return(true);
            });

            if (!variableAccesses.Contains(name))
            {
                return(name);
            }

            var index = 1;

            while (true)
            {
                var newName = $"{name}_{index}";

                if (!variableAccesses.Contains(newName))
                {
                    return(newName);
                }
            }
        }
        protected override SyntaxBase ReplaceForSyntax(ForSyntax syntax)
        {
            syntax = (ForSyntax)base.ReplaceForSyntax(syntax);

            // look for range(0, length(<variable>))
            if (!IsLoopIteratorExpression(semanticModel, syntax.Expression, out var arrayVariable))
            {
                return(syntax);
            }

            if (syntax.VariableSection is not LocalVariableSyntax indexVariable)
            {
                return(syntax);
            }

            var arraySymbol      = semanticModel.GetSymbolInfo(arrayVariable);
            var arrayIndexSymbol = semanticModel.GetSymbolInfo(indexVariable);

            if (arraySymbol is null || arrayIndexSymbol is null)
            {
                return(syntax);
            }

            var arrayAccesses            = new HashSet <ArrayAccessSyntax>();
            var independentIndexAccesses = new HashSet <VariableAccessSyntax>();

            CallbackVisitor.Visit(syntax, child =>
            {
                if (child is ArrayAccessSyntax arrayAccess)
                {
                    if (semanticModel.GetSymbolInfo(arrayAccess.BaseExpression) == arraySymbol &&
                        semanticModel.GetSymbolInfo(arrayAccess.IndexExpression) == arrayIndexSymbol)
                    {
                        arrayAccesses.Add(arrayAccess);

                        // we don't want to count the VariableAccessSyntax under this particular node,
                        // so return false to skip visiting children.
                        return(false);
                    }
                }

                if (child is VariableAccessSyntax variableAccess)
                {
                    var accessSymbol = semanticModel.GetSymbolInfo(variableAccess);
                    if (accessSymbol == arrayIndexSymbol)
                    {
                        independentIndexAccesses.Add(variableAccess);
                    }
                }

                return(true);
            });

            if (!arrayAccesses.Any())
            {
                // nothing to really simplify here
                return(syntax);
            }

            var itemVarName = GetUniqueVariableNameForNewScope(syntax, "item");
            var forBody     = CallbackRewriter.Rewrite(syntax.Body, child =>
            {
                if (arrayAccesses.Contains(child))
                {
                    return(new VariableAccessSyntax(SyntaxFactory.CreateIdentifier(itemVarName)));
                }

                return(child);
            });

            SyntaxBase forVariableBlockSyntax;

            if (independentIndexAccesses.Any())
            {
                forVariableBlockSyntax = new ForVariableBlockSyntax(
                    SyntaxFactory.LeftParenToken,
                    new LocalVariableSyntax(SyntaxFactory.CreateIdentifier(itemVarName)),
                    SyntaxFactory.CommaToken,
                    new LocalVariableSyntax(SyntaxFactory.CreateIdentifier(arrayIndexSymbol.Name)),
                    SyntaxFactory.RightParenToken);
            }
            else
            {
                forVariableBlockSyntax = new LocalVariableSyntax(SyntaxFactory.CreateIdentifier(itemVarName));
            }

            var forExpression = new VariableAccessSyntax(SyntaxFactory.CreateIdentifier(arraySymbol.Name));

            return(new ForSyntax(
                       syntax.OpenSquare,
                       syntax.ForKeyword,
                       forVariableBlockSyntax,
                       syntax.InKeyword,
                       forExpression,
                       syntax.Colon,
                       forBody,
                       syntax.CloseSquare));
        }