public static bool TryMatchPattern(
            ISyntaxFacts syntaxFacts,
            IConditionalOperation ifOperation,
            [NotNullWhen(true)] out IOperation trueStatement,
            [NotNullWhen(true)] out IOperation falseStatement,
            out ISimpleAssignmentOperation?trueAssignment,
            out ISimpleAssignmentOperation?falseAssignment)
        {
            trueAssignment  = null;
            falseAssignment = null;

            trueStatement  = ifOperation.WhenTrue;
            falseStatement = ifOperation.WhenFalse;

            trueStatement  = UseConditionalExpressionHelpers.UnwrapSingleStatementBlock(trueStatement);
            falseStatement = UseConditionalExpressionHelpers.UnwrapSingleStatementBlock(falseStatement);

            if (!TryGetAssignmentOrThrow(trueStatement, out trueAssignment, out var trueThrow) ||
                !TryGetAssignmentOrThrow(falseStatement, out falseAssignment, out var falseThrow))
            {
                return(false);
            }

            var anyAssignment = trueAssignment ?? falseAssignment;

            if (UseConditionalExpressionHelpers.HasInconvertibleThrowStatement(
                    syntaxFacts, anyAssignment?.IsRef == true, trueThrow, falseThrow))
            {
                return(false);
            }

            // The left side of both assignment statements has to be syntactically identical (modulo
            // trivia differences).
            if (trueAssignment != null && falseAssignment != null &&
                !syntaxFacts.AreEquivalent(trueAssignment.Target.Syntax, falseAssignment.Target.Syntax))
            {
                return(false);
            }

            return(UseConditionalExpressionHelpers.CanConvert(
                       syntaxFacts, ifOperation, trueStatement, falseStatement));
        }
예제 #2
0
        public static bool TryMatchPattern(
            ISyntaxFacts syntaxFacts,
            IConditionalOperation ifOperation,
            ISymbol containingSymbol,
            [NotNullWhen(true)] out IOperation?trueStatement,
            [NotNullWhen(true)] out IOperation?falseStatement,
            out IReturnOperation?trueReturn,
            out IReturnOperation?falseReturn)
        {
            trueReturn  = null;
            falseReturn = null;

            trueStatement  = ifOperation.WhenTrue;
            falseStatement = ifOperation.WhenFalse;

            // we support:
            //
            //      if (expr)
            //          return a;
            //      else
            //          return b;
            //
            // and
            //
            //      if (expr)
            //          return a;
            //
            //      return b;
            //
            // note: either (but not both) of these statements can be throw-statements.

            if (falseStatement == null)
            {
                if (ifOperation.Parent is not IBlockOperation parentBlock)
                {
                    return(false);
                }

                var ifIndex = parentBlock.Operations.IndexOf(ifOperation);
                if (ifIndex < 0)
                {
                    return(false);
                }

                if (ifIndex + 1 >= parentBlock.Operations.Length)
                {
                    return(false);
                }

                falseStatement = parentBlock.Operations[ifIndex + 1];
                if (falseStatement.IsImplicit)
                {
                    return(false);
                }
            }

            trueStatement  = UseConditionalExpressionHelpers.UnwrapSingleStatementBlock(trueStatement);
            falseStatement = UseConditionalExpressionHelpers.UnwrapSingleStatementBlock(falseStatement);

            // Both return-statements must be of the form "return value"
            if (!IsReturnExprOrThrow(trueStatement) ||
                !IsReturnExprOrThrow(falseStatement))
            {
                return(false);
            }

            trueReturn  = trueStatement as IReturnOperation;
            falseReturn = falseStatement as IReturnOperation;
            var trueThrow  = trueStatement as IThrowOperation;
            var falseThrow = falseStatement as IThrowOperation;

            var anyReturn = trueReturn ?? falseReturn;

            if (UseConditionalExpressionHelpers.HasInconvertibleThrowStatement(
                    syntaxFacts, anyReturn.GetRefKind(containingSymbol) != RefKind.None,
                    trueThrow, falseThrow))
            {
                return(false);
            }

            if (trueReturn != null &&
                falseReturn != null &&
                trueReturn.Kind != falseReturn.Kind)
            {
                // Not allowed if these are different types of returns.  i.e.
                // "yield return ..." and "return ...".
                return(false);
            }

            if (trueReturn?.Kind == OperationKind.YieldBreak)
            {
                // This check is just paranoia.  We likely shouldn't get here since we already
                // checked if .ReturnedValue was null above.
                return(false);
            }

            if (trueReturn?.Kind == OperationKind.YieldReturn &&
                ifOperation.WhenFalse == null)
            {
                // we have the following:
                //
                //   if (...) {
                //       yield return ...
                //   }
                //
                //   yield return ...
                //
                // It is *not* correct to replace this with:
                //
                //      yield return ... ? ... ? ...
                //
                // as both yields need to be hit.
                return(false);
            }

            return(UseConditionalExpressionHelpers.CanConvert(
                       syntaxFacts, ifOperation, trueStatement, falseStatement));
        }