private static bool IsElseIfOrElseClauseEquivalent(
            ISyntaxFactsService syntaxFacts,
            IIfLikeStatementGenerator ifGenerator,
            SyntaxNode elseIfOrElseClause1,
            SyntaxNode elseIfOrElseClause2)
        {
            // Compare Else/ElseIf clauses for equality.

            var isIfStatement = ifGenerator.IsIfOrElseIf(elseIfOrElseClause1);

            if (isIfStatement != ifGenerator.IsIfOrElseIf(elseIfOrElseClause2))
            {
                // If we have one Else and one ElseIf, they're not equal.
                return(false);
            }

            if (isIfStatement)
            {
                // If we have two ElseIf blocks, their conditions have to match.
                var condition1 = ifGenerator.GetCondition(elseIfOrElseClause1);
                var condition2 = ifGenerator.GetCondition(elseIfOrElseClause2);

                if (!syntaxFacts.AreEquivalent(condition1, condition2))
                {
                    return(false);
                }
            }

            var statements1 = WalkDownScopeBlocks(syntaxFacts, syntaxFacts.GetStatementContainerStatements(elseIfOrElseClause1));
            var statements2 = WalkDownScopeBlocks(syntaxFacts, syntaxFacts.GetStatementContainerStatements(elseIfOrElseClause2));

            return(statements1.SequenceEqual(statements2, syntaxFacts.AreEquivalent));
        }
        private static bool IsFirstStatementOfIfOrElseIf(
            ISyntaxFactsService syntaxFacts,
            IIfLikeStatementGenerator ifGenerator,
            SyntaxNode statement,
            out SyntaxNode ifOrElseIf)
        {
            // Check whether the statement is a first statement inside an if or else if.
            // If it's inside a block, it has to be the first statement of the block.

            // We can't assume that a statement will always be in a statement container, because an if statement
            // in top level code will be in a GlobalStatement.
            if (syntaxFacts.IsStatementContainer(statement.Parent))
            {
                var statements = syntaxFacts.GetStatementContainerStatements(statement.Parent);
                if (statements.Count > 0 && statements[0] == statement)
                {
                    var rootStatements = WalkUpScopeBlocks(syntaxFacts, statements);
                    if (rootStatements.Count > 0 && ifGenerator.IsIfOrElseIf(rootStatements[0].Parent))
                    {
                        ifOrElseIf = rootStatements[0].Parent;
                        return(true);
                    }
                }
            }

            ifOrElseIf = null;
            return(false);
        }
        private static bool IsFirstStatementIfStatement(
            ISyntaxFactsService syntaxFacts,
            IIfLikeStatementGenerator ifGenerator,
            SyntaxNode ifOrElseIf,
            out SyntaxNode ifStatement)
        {
            // Check whether the first statement inside an if or else if is an if statement.
            // If the if statement is inside a block, it has to be the first statement of the block.

            // An if or else if should always be a statement container, but we'll do a defensive check anyway.
            Debug.Assert(syntaxFacts.IsStatementContainer(ifOrElseIf));
            if (syntaxFacts.IsStatementContainer(ifOrElseIf))
            {
                var rootStatements = syntaxFacts.GetStatementContainerStatements(ifOrElseIf);

                var statements = WalkDownScopeBlocks(syntaxFacts, rootStatements);
                if (statements.Count > 0 && ifGenerator.IsIfOrElseIf(statements[0]))
                {
                    ifStatement = statements[0];
                    return(true);
                }
            }

            ifStatement = null;
            return(false);
        }
            static SyntaxNode FindIfOrElseIf(TextSpan span, IIfLikeStatementGenerator ifGenerator, SyntaxNode root)
            {
                var innerMatch = root.FindNode(span, getInnermostNodeForTie: true);

                return(innerMatch?.FirstAncestorOrSelf <SyntaxNode>(
                           node => ifGenerator.IsIfOrElseIf(node) && node.Span == span));
            }
        private static bool IsFirstStatementOfIfOrElseIf(
            ISyntaxFactsService syntaxFacts,
            IIfLikeStatementGenerator ifGenerator,
            SyntaxNode statement,
            out SyntaxNode ifOrElseIf)
        {
            // Check whether the statement is a first statement inside an if or else if.
            // If it's inside a block, it has to be the first statement of the block.

            // A statement should always be in a statement container, but we'll do a defensive check anyway so that
            // we don't crash if the helper is missing some cases or there's a new language feature it didn't account for.
            Debug.Assert(syntaxFacts.IsStatementContainer(statement.Parent));
            if (syntaxFacts.IsStatementContainer(statement.Parent))
            {
                var statements = syntaxFacts.GetStatementContainerStatements(statement.Parent);
                if (statements.Count > 0 && statements[0] == statement)
                {
                    var rootStatements = WalkUpScopeBlocks(syntaxFacts, statements);
                    if (rootStatements.Count > 0 && ifGenerator.IsIfOrElseIf(rootStatements[0].Parent))
                    {
                        ifOrElseIf = rootStatements[0].Parent;
                        return(true);
                    }
                }
            }

            ifOrElseIf = null;
            return(false);
        }
        private static async Task <bool> CanStatementsBeMergedAsync(
            Document document,
            ISyntaxFactsService syntaxFacts,
            IBlockFactsService blockFacts,
            IIfLikeStatementGenerator ifGenerator,
            SyntaxNode firstStatement,
            SyntaxNode secondStatement,
            CancellationToken cancellationToken)
        {
            // We don't support cases where the previous if statement has any else-if or else clauses. In order for that
            // to be mergable, the control flow would have to quit from inside every branch, which is getting a little complex.
            if (!ifGenerator.IsIfOrElseIf(firstStatement) || ifGenerator.GetElseIfAndElseClauses(firstStatement).Length > 0)
            {
                return(false);
            }

            if (!ifGenerator.IsIfOrElseIf(secondStatement))
            {
                return(false);
            }

            if (!ContainEquivalentStatements(syntaxFacts, blockFacts, firstStatement, secondStatement, out var insideStatements))
            {
                return(false);
            }

            if (insideStatements.Count == 0)
            {
                // Even though there are no statements inside, we still can't merge these into one statement
                // because it would change the semantics from always evaluating the second condition to short-circuiting.
                return(false);
            }
            else
            {
                // There are statements inside. We can merge these into one statement if
                // control flow can't reach the end of these statements (otherwise, it would change from running
                // the second 'if' in the case that both conditions are true to only running the statements once).
                // This will typically look like a single return, break, continue or a throw statement.

                var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                var controlFlow = semanticModel.AnalyzeControlFlow(insideStatements[0], insideStatements[insideStatements.Count - 1]);

                return(!controlFlow.EndPointIsReachable);
            }
        }