Пример #1
0
        private static SyntaxNode GetNegationOfIsPatternExpression(SyntaxNode isExpression, SyntaxGenerator generator, SyntaxGeneratorInternal generatorInternal, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            // Don't recurse into patterns if the language doesn't support negated patterns.
            // Just wrap with a normal '!' expression.
            var syntaxFacts = generatorInternal.SyntaxFacts;

            if (syntaxFacts.SupportsNotPattern(semanticModel.SyntaxTree.Options))
            {
                syntaxFacts.GetPartsOfIsPatternExpression(isExpression, out var left, out var isToken, out var pattern);
                var negated = generator.Negate(generatorInternal, pattern, semanticModel, cancellationToken);

                // Negating the pattern may have formed something illegal.  If so, just do a normal `!` negation.
                if (IsLegalPattern(syntaxFacts, negated, designatorsLegal: true))
                {
                    if (syntaxFacts.IsTypePattern(negated))
                    {
                        // We started with `x is not t`.  Unwrap the type pattern for 't' and create a simple `is` binary expr `x is t`.
                        var type = syntaxFacts.GetTypeOfTypePattern(negated);
                        return(generator.IsTypeExpression(left, type));
                    }
                    else
                    {
                        // Keep this as a normal `is-pattern`, just with the pattern portion negated.
                        return(generatorInternal.IsPatternExpression(left, isToken, negated));
                    }
                }
            }

            return(generator.LogicalNotExpression(isExpression));
        }
Пример #2
0
        private static SyntaxNode GetNegationOfBinaryExpression(
            SyntaxNode expressionNode,
            SyntaxGenerator generator,
            SyntaxGeneratorInternal generatorInternal,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            var syntaxFacts = generatorInternal.SyntaxFacts;

            syntaxFacts.GetPartsOfBinaryExpression(expressionNode, out var leftOperand, out var operatorToken, out var rightOperand);

            var operation = semanticModel.GetOperation(expressionNode, cancellationToken);

            if (operation is not IBinaryOperation binaryOperation)
            {
                // x is y   ->    x is not y
                if (syntaxFacts.IsIsExpression(expressionNode) && syntaxFacts.SupportsNotPattern(semanticModel.SyntaxTree.Options))
                {
                    return(generatorInternal.IsPatternExpression(leftOperand, operatorToken, generatorInternal.NotPattern(generatorInternal.TypePattern(rightOperand))));
                }

                // Apply the logical not operator if it is not a binary operation.
                return(generator.LogicalNotExpression(expressionNode));
            }

            if (!s_negatedBinaryMap.TryGetValue(binaryOperation.OperatorKind, out var negatedKind))
            {
                return(generator.LogicalNotExpression(expressionNode));
            }

            if (binaryOperation.OperatorKind is BinaryOperatorKind.Or or
                BinaryOperatorKind.And or
                BinaryOperatorKind.ConditionalAnd or
                BinaryOperatorKind.ConditionalOr)
            {
                leftOperand  = generator.Negate(generatorInternal, leftOperand, semanticModel, cancellationToken);
                rightOperand = generator.Negate(generatorInternal, rightOperand, semanticModel, cancellationToken);
            }

            var newBinaryExpressionSyntax = negatedKind is BinaryOperatorKind.Equals or BinaryOperatorKind.NotEquals
                ? generatorInternal.NegateEquality(generator, expressionNode, leftOperand, negatedKind, rightOperand)
                : NegateRelational(generator, binaryOperation, leftOperand, negatedKind, rightOperand);

            newBinaryExpressionSyntax = newBinaryExpressionSyntax.WithTriviaFrom(expressionNode);

            var newToken = syntaxFacts.GetOperatorTokenOfBinaryExpression(newBinaryExpressionSyntax);

            return(newBinaryExpressionSyntax.ReplaceToken(
                       newToken,
                       newToken.WithTriviaFrom(operatorToken)));
        }
        private static SyntaxNode GetNegationOfIsPatternExpression(SyntaxNode isExpression, SyntaxGenerator generator, SyntaxGeneratorInternal generatorInternal, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            // Don't recurse into patterns if the language doesn't support negated patterns.
            // Just wrap with a normal '!' expression.
            var syntaxFacts = generatorInternal.SyntaxFacts;

            syntaxFacts.GetPartsOfIsPatternExpression(isExpression, out var left, out var isToken, out var pattern);

            SyntaxNode?negatedPattern = null;

            if (syntaxFacts.SupportsNotPattern(semanticModel.SyntaxTree.Options))
            {
                // We do support 'not' patterns.  So attempt to push a 'not' pattern into the current is-pattern RHS.
                negatedPattern = generator.Negate(generatorInternal, pattern, semanticModel, cancellationToken);
            }
            else if (syntaxFacts.IsNotPattern(pattern))
            {
                // we don't support 'not' patterns, but we have a 'not' pattern in code.  Do a simple unwrapping of it.
                negatedPattern = GetNegationOfNotPattern(pattern, generator, generatorInternal, syntaxFacts);
            }

            // Negating the pattern may have formed something illegal.  If so, just do a normal `!` negation.
            if (negatedPattern != null && IsLegalPattern(syntaxFacts, negatedPattern, designatorsLegal: true))
            {
                if (syntaxFacts.IsTypePattern(negatedPattern))
                {
                    // We started with `x is not t`.  Unwrap the type pattern for 't' and create a simple `is` binary expr `x is t`.
                    var type = syntaxFacts.GetTypeOfTypePattern(negatedPattern);
                    return(generator.IsTypeExpression(left, type));
                }
                else
                {
                    // Keep this as a normal `is-pattern`, just with the pattern portion negated.
                    return(generatorInternal.IsPatternExpression(left, isToken, negatedPattern));
                }
            }

            return(generator.LogicalNotExpression(isExpression));
        }
Пример #4
0
        private static SyntaxNode GetNegationOfBinaryExpression(
            SyntaxNode expressionNode,
            SyntaxGenerator generator,
            SyntaxGeneratorInternal generatorInternal,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            var syntaxFacts = generatorInternal.SyntaxFacts;

            syntaxFacts.GetPartsOfBinaryExpression(expressionNode, out var leftOperand, out var operatorToken, out var rightOperand);

            var binaryOperation = semanticModel.GetOperation(expressionNode, cancellationToken) as IBinaryOperation;

            if (binaryOperation == null)
            {
                // x is y   ->    x is not y
                if (syntaxFacts.IsIsExpression(expressionNode) && syntaxFacts.SupportsNotPattern(semanticModel.SyntaxTree.Options))
                {
                    return(generatorInternal.IsPatternExpression(leftOperand, operatorToken, generatorInternal.NotPattern(generatorInternal.TypePattern(rightOperand))));
                }

                // Apply the logical not operator if it is not a binary operation.
                return(generator.LogicalNotExpression(expressionNode));
            }

            if (!s_negatedBinaryMap.TryGetValue(binaryOperation.OperatorKind, out var negatedKind))
            {
                return(generator.LogicalNotExpression(expressionNode));
            }
            else
            {
                var negateOperands = false;
                switch (binaryOperation.OperatorKind)
                {
                case BinaryOperatorKind.Or:
                case BinaryOperatorKind.And:
                case BinaryOperatorKind.ConditionalAnd:
                case BinaryOperatorKind.ConditionalOr:
                    negateOperands = true;
                    break;
                }

                //Workaround for https://github.com/dotnet/roslyn/issues/23956
                //Issue to remove this when above is merged
                if (binaryOperation.OperatorKind == BinaryOperatorKind.Or && syntaxFacts.IsLogicalOrExpression(expressionNode))
                {
                    negatedKind = BinaryOperatorKind.ConditionalAnd;
                }
                else if (binaryOperation.OperatorKind == BinaryOperatorKind.And && syntaxFacts.IsLogicalAndExpression(expressionNode))
                {
                    negatedKind = BinaryOperatorKind.ConditionalOr;
                }

                var newLeftOperand  = leftOperand;
                var newRightOperand = rightOperand;
                if (negateOperands)
                {
                    newLeftOperand  = generator.Negate(generatorInternal, leftOperand, semanticModel, cancellationToken);
                    newRightOperand = generator.Negate(generatorInternal, rightOperand, semanticModel, cancellationToken);
                }

                var newBinaryExpressionSyntax = NewBinaryOperation(binaryOperation, newLeftOperand, negatedKind, newRightOperand, generator)
                                                .WithTriviaFrom(expressionNode);

                var newToken           = syntaxFacts.GetOperatorTokenOfBinaryExpression(newBinaryExpressionSyntax);
                var newTokenWithTrivia = newToken.WithTriviaFrom(operatorToken);
                return(newBinaryExpressionSyntax.ReplaceToken(newToken, newTokenWithTrivia));
            }
        }
        public static SyntaxNode Negate(
            this SyntaxGenerator generator,
            SyntaxGeneratorInternal generatorInternal,
            SyntaxNode expressionOrPattern,
            SemanticModel semanticModel,
            bool negateBinary,
            CancellationToken cancellationToken)
        {
            var options     = semanticModel.SyntaxTree.Options;
            var syntaxFacts = generatorInternal.SyntaxFacts;

            if (syntaxFacts.IsParenthesizedExpression(expressionOrPattern))
            {
                return(generatorInternal.AddParentheses(
                           generator.Negate(
                               generatorInternal,
                               syntaxFacts.GetExpressionOfParenthesizedExpression(expressionOrPattern),
                               semanticModel,
                               negateBinary,
                               cancellationToken))
                       .WithTriviaFrom(expressionOrPattern));
            }

            if (negateBinary && syntaxFacts.IsBinaryExpression(expressionOrPattern))
            {
                return(GetNegationOfBinaryExpression(expressionOrPattern, generator, generatorInternal, semanticModel, cancellationToken));
            }

            if (syntaxFacts.IsLiteralExpression(expressionOrPattern))
            {
                return(GetNegationOfLiteralExpression(expressionOrPattern, generator, semanticModel));
            }

            if (syntaxFacts.IsLogicalNotExpression(expressionOrPattern))
            {
                return(GetNegationOfLogicalNotExpression(expressionOrPattern, syntaxFacts));
            }

            if (negateBinary && syntaxFacts.IsIsPatternExpression(expressionOrPattern))
            {
                return(GetNegationOfIsPatternExpression(expressionOrPattern, generator, generatorInternal, semanticModel, cancellationToken));
            }

            if (syntaxFacts.IsParenthesizedPattern(expressionOrPattern))
            {
                // Push the negation inside the parenthesized pattern.
                return(generatorInternal.AddParentheses(
                           generator.Negate(
                               generatorInternal,
                               syntaxFacts.GetPatternOfParenthesizedPattern(expressionOrPattern),
                               semanticModel,
                               negateBinary,
                               cancellationToken))
                       .WithTriviaFrom(expressionOrPattern));
            }

            if (negateBinary && syntaxFacts.IsBinaryPattern(expressionOrPattern))
            {
                return(GetNegationOfBinaryPattern(expressionOrPattern, generator, generatorInternal, semanticModel, cancellationToken));
            }

            if (syntaxFacts.IsConstantPattern(expressionOrPattern))
            {
                return(GetNegationOfConstantPattern(expressionOrPattern, generator, generatorInternal));
            }

            if (syntaxFacts.IsUnaryPattern(expressionOrPattern))
            {
                return(GetNegationOfUnaryPattern(expressionOrPattern, generator, generatorInternal, syntaxFacts));
            }

            if (syntaxFacts.IsIsTypeExpression(expressionOrPattern))
            {
                syntaxFacts.GetPartsOfAnyIsTypeExpression(expressionOrPattern, out var expression, out var type);
                if (syntaxFacts.SupportsNotPattern(options))
                {
                    return(generatorInternal.IsPatternExpression(expression, generatorInternal.NotPattern(type)));
                }

                if (syntaxFacts.SupportsIsNotTypeExpression(options))
                {
                    return(generatorInternal.IsNotTypeExpression(expression, type));
                }
            }

            if (syntaxFacts.IsIsNotTypeExpression(expressionOrPattern))
            {
                syntaxFacts.GetPartsOfAnyIsTypeExpression(expressionOrPattern, out var expression, out var type);
                return(generator.IsTypeExpression(expression, type));
            }

            // TODO(cyrusn): We could support negating relational patterns in the future.  i.e.
            //
            //      not >= 0   ->    < 0

            return(syntaxFacts.IsAnyPattern(expressionOrPattern)
                ? generatorInternal.NotPattern(expressionOrPattern)
                : generator.LogicalNotExpression(expressionOrPattern));
        }