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)); }
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)); }
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)); }