private async Task <Document> IntroduceLocalDeclarationIntoBlockAsync(
            SemanticDocument document,
            BlockSyntax block,
            ExpressionSyntax expression,
            NameSyntax newLocalName,
            LocalDeclarationStatementSyntax declarationStatement,
            bool allOccurrences,
            CancellationToken cancellationToken)
        {
            declarationStatement = declarationStatement.WithAdditionalAnnotations(Formatter.Annotation);

            SyntaxNode scope = block;

            // If we're within a non-static local function, our scope for the new local declaration is expanded to include the enclosing member.
            var localFunction = block.GetAncestor <LocalFunctionStatementSyntax>();

            if (localFunction != null && !localFunction.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.StaticKeyword)))
            {
                scope = block.GetAncestor <MemberDeclarationSyntax>();
            }

            var matches = FindMatches(document, expression, document, scope, allOccurrences, cancellationToken);

            Debug.Assert(matches.Contains(expression));

            (document, matches) = await ComplexifyParentingStatementsAsync(document, matches, cancellationToken).ConfigureAwait(false);

            // Our original expression should have been one of the matches, which were tracked as part
            // of complexification, so we can retrieve the latest version of the expression here.
            expression = document.Root.GetCurrentNode(expression);

            var root = document.Root;
            ISet <StatementSyntax> allAffectedStatements = new HashSet <StatementSyntax>(matches.SelectMany(expr => GetApplicableStatementAncestors(expr)));

            SyntaxNode innermostCommonBlock;

            var innermostStatements = new HashSet <StatementSyntax>(matches.Select(expr => GetApplicableStatementAncestors(expr).First()));

            if (innermostStatements.Count == 1)
            {
                // if there was only one match, or all the matches came from the same statement
                var statement = innermostStatements.Single();

                // and the statement is an embedded statement without a block, we want to generate one
                // around this statement rather than continue going up to find an actual block
                if (!IsBlockLike(statement.Parent))
                {
                    root = root.TrackNodes(allAffectedStatements.Concat(new SyntaxNode[] { expression, statement }));
                    root = root.ReplaceNode(root.GetCurrentNode(statement),
                                            SyntaxFactory.Block(root.GetCurrentNode(statement)).WithAdditionalAnnotations(Formatter.Annotation));

                    expression            = root.GetCurrentNode(expression);
                    allAffectedStatements = allAffectedStatements.Select(root.GetCurrentNode).ToSet();

                    statement = root.GetCurrentNode(statement);
                }

                innermostCommonBlock = statement.Parent;
            }
            else
            {
                innermostCommonBlock = innermostStatements.FindInnermostCommonNode(IsBlockLike);
            }

            var firstStatementAffectedIndex = GetFirstStatementAffectedIndex(innermostCommonBlock, matches, GetStatements(innermostCommonBlock).IndexOf(allAffectedStatements.Contains));

            var newInnerMostBlock = Rewrite(
                document, expression, newLocalName, document, innermostCommonBlock, allOccurrences, cancellationToken);

            var statements          = InsertWithinTriviaOfNext(GetStatements(newInnerMostBlock), declarationStatement, firstStatementAffectedIndex);
            var finalInnerMostBlock = WithStatements(newInnerMostBlock, statements);

            var newRoot = root.ReplaceNode(innermostCommonBlock, finalInnerMostBlock);

            return(document.Document.WithSyntaxRoot(newRoot));
        }