public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out BinaryExpressionSyntax binaryExpression)) { return; } Document document = context.Document; foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case DiagnosticIdentifiers.SimplifyBooleanComparison: { CodeAction codeAction = CodeAction.Create( "Simplify boolean comparison", cancellationToken => SimplifyBooleanComparisonRefactoring.RefactorAsync(document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.CallSkipAndAnyInsteadOfCount: { CodeAction codeAction = CodeAction.Create( "Call 'Skip' and 'Any' instead of 'Count'", cancellationToken => CallSkipAndAnyInsteadOfCountRefactoring.RefactorAsync(document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.ConstantValuesShouldBePlacedOnRightSideOfComparisons: { CodeAction codeAction = CodeAction.Create( "Swap operands", cancellationToken => document.ReplaceNodeAsync(binaryExpression, SyntaxRefactorings.SwapBinaryOperands(binaryExpression), cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod: { CodeAction codeAction = CodeAction.Create( "Use 'string.IsNullOrEmpty' method", cancellationToken => UseStringIsNullOrEmptyMethodAsync(document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.SimplifyCoalesceExpression: { ExpressionSyntax expression = binaryExpression.Left; if (expression == null || !context.Span.Contains(expression.Span)) { expression = binaryExpression.Right; } CodeAction codeAction = CodeAction.Create( "Simplify coalesce expression", cancellationToken => SimplifyCoalesceExpressionRefactoring.RefactorAsync(document, binaryExpression, expression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.RemoveRedundantAsOperator: { CodeAction codeAction = CodeAction.Create( "Remove redundant 'as' operator", cancellationToken => RemoveRedundantAsOperatorRefactoring.RefactorAsync(document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseStringLengthInsteadOfComparisonWithEmptyString: { CodeAction codeAction = CodeAction.Create( "Use string.Length", cancellationToken => UseStringLengthInsteadOfComparisonWithEmptyStringAsync(document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UnconstrainedTypeParameterCheckedForNull: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken); CodeAction codeAction = CodeAction.Create( $"Use EqualityComparer<{typeSymbol.Name}>.Default", cancellationToken => UnconstrainedTypeParameterCheckedForNullRefactoring.RefactorAsync(document, binaryExpression, typeSymbol, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.ValueTypeObjectIsNeverEqualToNull: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken); string title; if (CSharpFacts.IsSimpleType(typeSymbol.SpecialType) || typeSymbol.ContainsMember <IMethodSymbol>(WellKnownMemberNames.EqualityOperatorName)) { ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(document.GetDefaultSyntaxOptions()); title = $"Replace 'null' with '{expression}'"; } else { title = $"Use EqualityComparer<{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, binaryExpression.Right.SpanStart, SymbolDisplayFormats.DisplayName)}>.Default"; } CodeAction codeAction = CodeAction.Create( title, cancellationToken => ValueTypeObjectIsNeverEqualToNullRefactoring.RefactorAsync(document, binaryExpression, typeSymbol, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.JoinStringExpressions: { CodeAction codeAction = CodeAction.Create( "Join string expressions", cancellationToken => JoinStringExpressionsRefactoring.RefactorAsync(document, binaryExpression, context.Span, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseExclusiveOrOperator: { CodeAction codeAction = CodeAction.Create( "Use ^ operator", cancellationToken => UseExclusiveOrOperatorRefactoring.RefactorAsync(document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.SimplifyBooleanExpression: { CodeAction codeAction = CodeAction.Create( "Simplify boolean expression", cancellationToken => SimplifyBooleanExpressionRefactoring.RefactorAsync(document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseShortCircuitingOperator: { SyntaxToken operatorToken = binaryExpression.OperatorToken; SyntaxKind kind = binaryExpression.Kind(); SyntaxToken newToken = default; if (kind == SyntaxKind.BitwiseAndExpression) { newToken = Token(operatorToken.LeadingTrivia, SyntaxKind.AmpersandAmpersandToken, operatorToken.TrailingTrivia); } else if (kind == SyntaxKind.BitwiseOrExpression) { newToken = Token(operatorToken.LeadingTrivia, SyntaxKind.BarBarToken, operatorToken.TrailingTrivia); } CodeAction codeAction = CodeAction.Create( $"Use '{newToken.ToString()}' operator", ct => { BinaryExpressionSyntax newBinaryExpression = null; if (kind == SyntaxKind.BitwiseAndExpression) { newBinaryExpression = LogicalAndExpression(binaryExpression.Left, newToken, binaryExpression.Right); } else if (kind == SyntaxKind.BitwiseOrExpression) { newBinaryExpression = LogicalOrExpression(binaryExpression.Left, newToken, binaryExpression.Right); } return(document.ReplaceNodeAsync(binaryExpression, newBinaryExpression, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UnnecessaryOperator: { CodeAction codeAction = CodeAction.Create( "Use '==' operator", ct => { SyntaxToken operatorToken = binaryExpression.OperatorToken; BinaryExpressionSyntax newBinaryExpression = EqualsExpression( binaryExpression.Left, Token(operatorToken.LeadingTrivia, SyntaxKind.EqualsEqualsToken, operatorToken.TrailingTrivia), binaryExpression.Right); return(document.ReplaceNodeAsync(binaryExpression, newBinaryExpression, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out BinaryExpressionSyntax binaryExpression)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case DiagnosticIdentifiers.SimplifyBooleanComparison: { CodeAction codeAction = CodeAction.Create( "Simplify boolean comparison", cancellationToken => SimplifyBooleanComparisonRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseAnyMethodInsteadOfCountMethod: { CodeAction codeAction = CodeAction.Create( "Call 'Any' instead of 'Count'", cancellationToken => CallAnyInsteadOfCountRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.AvoidNullLiteralExpressionOnLeftSideOfBinaryExpression: { CodeAction codeAction = CodeAction.Create( $"Swap '{binaryExpression.Left}' and '{binaryExpression.Right}'", cancellationToken => SwapExpressionsInBinaryExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod: { CodeAction codeAction = CodeAction.Create( "Use 'string.IsNullOrEmpty' method", cancellationToken => UseStringIsNullOrEmptyMethodRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.SimplifyCoalesceExpression: { ExpressionSyntax expression = binaryExpression.Left; if (expression == null || !context.Span.Contains(expression.Span)) { expression = binaryExpression.Right; } CodeAction codeAction = CodeAction.Create( "Simplify coalesce expression", cancellationToken => SimplifyCoalesceExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, expression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.RemoveRedundantAsOperator: { CodeAction codeAction = CodeAction.Create( "Remove redundant 'as' operator", cancellationToken => RemoveRedundantAsOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseStringLengthInsteadOfComparisonWithEmptyString: { CodeAction codeAction = CodeAction.Create( "Use string.Length", cancellationToken => UseStringLengthInsteadOfComparisonWithEmptyStringRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UnconstrainedTypeParameterCheckedForNull: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken); CodeAction codeAction = CodeAction.Create( $"Use EqualityComparer<{typeSymbol.Name}>.Default", cancellationToken => UnconstrainedTypeParameterCheckedForNullRefactoring.RefactorAsync(context.Document, binaryExpression, typeSymbol, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.ValueTypeObjectIsNeverEqualToNull: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken); string title = null; if (typeSymbol.IsPredefinedValueType() || typeSymbol.ExistsMethod(WellKnownMemberNames.EqualityOperatorName)) { ExpressionSyntax expression = typeSymbol.ToDefaultValueSyntax(semanticModel, binaryExpression.Right.SpanStart); title = $"Replace 'null' with '{expression}'"; } else { title = $"Use EqualityComparer<{SymbolDisplay.GetMinimalString(typeSymbol, semanticModel, binaryExpression.Right.SpanStart)}>.Default"; } CodeAction codeAction = CodeAction.Create( title, cancellationToken => ValueTypeObjectIsNeverEqualToNullRefactoring.RefactorAsync(context.Document, binaryExpression, typeSymbol, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseIsOperatorInsteadOfAsOperator: { CodeAction codeAction = CodeAction.Create( "Use is operator", cancellationToken => UseIsOperatorInsteadOfAsOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.JoinStringExpressions: { CodeAction codeAction = CodeAction.Create( "Join string expressions", cancellationToken => JoinStringExpressionsRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseExclusiveOrOperator: { CodeAction codeAction = CodeAction.Create( "Use ^ operator", cancellationToken => UseExclusiveOrOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.SimplifyBooleanExpression: { CodeAction codeAction = CodeAction.Create( "Simplify boolean expression", cancellationToken => SimplifyBooleanExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out BinaryExpressionSyntax binaryExpression)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case DiagnosticIdentifiers.SimplifyBooleanComparison: { CodeAction codeAction = CodeAction.Create( "Simplify boolean comparison", cancellationToken => SimplifyBooleanComparisonRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.CallSkipAndAnyInsteadOfCount: { CodeAction codeAction = CodeAction.Create( "Call 'Skip' and 'Any' instead of 'Count'", cancellationToken => CallSkipAndAnyInsteadOfCountRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.AvoidNullLiteralExpressionOnLeftSideOfBinaryExpression: { CodeAction codeAction = CodeAction.Create( "Swap operands", cancellationToken => CommonRefactorings.SwapBinaryOperandsAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod: { CodeAction codeAction = CodeAction.Create( "Use 'string.IsNullOrEmpty' method", cancellationToken => UseStringIsNullOrEmptyMethodRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.SimplifyCoalesceExpression: { ExpressionSyntax expression = binaryExpression.Left; if (expression == null || !context.Span.Contains(expression.Span)) { expression = binaryExpression.Right; } CodeAction codeAction = CodeAction.Create( "Simplify coalesce expression", cancellationToken => SimplifyCoalesceExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, expression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.RemoveRedundantAsOperator: { CodeAction codeAction = CodeAction.Create( "Remove redundant 'as' operator", cancellationToken => RemoveRedundantAsOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseStringLengthInsteadOfComparisonWithEmptyString: { CodeAction codeAction = CodeAction.Create( "Use string.Length", cancellationToken => UseStringLengthInsteadOfComparisonWithEmptyStringRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UnconstrainedTypeParameterCheckedForNull: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken); CodeAction codeAction = CodeAction.Create( $"Use EqualityComparer<{typeSymbol.Name}>.Default", cancellationToken => UnconstrainedTypeParameterCheckedForNullRefactoring.RefactorAsync(context.Document, binaryExpression, typeSymbol, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.ValueTypeObjectIsNeverEqualToNull: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken); string title; if (CSharpFacts.IsSimpleType(typeSymbol.SpecialType) || typeSymbol.ContainsMember <IMethodSymbol>(WellKnownMemberNames.EqualityOperatorName)) { ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(semanticModel, binaryExpression.Right.SpanStart); title = $"Replace 'null' with '{expression}'"; } else { title = $"Use EqualityComparer<{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, binaryExpression.Right.SpanStart, SymbolDisplayFormats.Default)}>.Default"; } CodeAction codeAction = CodeAction.Create( title, cancellationToken => ValueTypeObjectIsNeverEqualToNullRefactoring.RefactorAsync(context.Document, binaryExpression, typeSymbol, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.JoinStringExpressions: { CodeAction codeAction = CodeAction.Create( "Join string expressions", cancellationToken => JoinStringExpressionsRefactoring.RefactorAsync(context.Document, binaryExpression, context.Span, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseExclusiveOrOperator: { CodeAction codeAction = CodeAction.Create( "Use ^ operator", cancellationToken => UseExclusiveOrOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.SimplifyBooleanExpression: { CodeAction codeAction = CodeAction.Create( "Simplify boolean expression", cancellationToken => SimplifyBooleanExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.ExpressionIsAlwaysEqualToTrueOrFalse: { LiteralExpressionSyntax newNode = BooleanLiteralExpression(binaryExpression.IsKind(SyntaxKind.GreaterThanOrEqualExpression, SyntaxKind.LessThanOrEqualExpression)); CodeAction codeAction = CodeAction.Create( $"Replace expression with '{newNode}'", cancellationToken => context.Document.ReplaceNodeAsync(binaryExpression, newNode.WithTriviaFrom(binaryExpression), cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }