private static bool CanBeMergedWithParent(
     ISyntaxFactsService syntaxFacts,
     IIfLikeStatementGenerator ifGenerator,
     SyntaxNode ifOrElseIf,
     out SyntaxNode parentIfOrElseIf)
 {
     return(ifGenerator.IsElseIfClause(ifOrElseIf, out parentIfOrElseIf) &&
            ContainEquivalentStatements(syntaxFacts, ifOrElseIf, parentIfOrElseIf, out _));
 }
Beispiel #2
0
        private static async Task <bool> CanBeSeparateStatementsAsync(
            Document document,
            ISyntaxFactsService syntaxFacts,
            IIfLikeStatementGenerator ifGenerator,
            SyntaxNode ifOrElseIf,
            CancellationToken cancellationToken
            )
        {
            // In order to make separate statements, ifOrElseIf must be an if statement, not an else-if clause.
            if (ifGenerator.IsElseIfClause(ifOrElseIf, out _))
            {
                return(false);
            }

            // If there is an else clause, we *could* in theory separate these and move the current else clause to the second
            // statement, but we won't. It would break the else-if chain in an odd way. We'll insert an else-if instead.
            if (ifGenerator.GetElseIfAndElseClauses(ifOrElseIf).Length > 0)
            {
                return(false);
            }

            var insideStatements = syntaxFacts.GetStatementContainerStatements(ifOrElseIf);

            if (insideStatements.Count == 0)
            {
                // Even though there are no statements inside, we still can't split this into separate statements
                // because it would change the semantics from short-circuiting to always evaluating the second condition,
                // breaking code like 'if (a == null || a.InstanceMethod())'.
                return(false);
            }
            else
            {
                // There are statements inside. We can split this into separate statements and leave out the 'else' if
                // control flow can't reach the end of these statements (otherwise, it would continue to the second 'if'
                // and in the case that both conditions are true, run the same statements twice).
                // 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);
            }
        }