public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(
                    root,
                    context.Span,
                    out SyntaxNode node,
                    findInsideTrivia: true,
                    predicate: f => f.IsKind(SyntaxKind.UsingDirective, SyntaxKind.RegionDirectiveTrivia, SyntaxKind.EndRegionDirectiveTrivia)))
            {
                return;
            }

            Document   document   = context.Document;
            Diagnostic diagnostic = context.Diagnostics[0];

            switch (node)
            {
            case UsingDirectiveSyntax usingDirective:
            {
                if (context.Span.Start == usingDirective.SpanStart)
                {
                    CodeAction codeAction = CodeAction.Create(
                        CodeFixTitles.AddEmptyLine,
                        ct => AddEmptyLineBeforeUsingDirectiveAsync(document, usingDirective, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }
                else
                {
                    CodeAction codeAction = CodeAction.Create(
                        CodeFixTitles.AddEmptyLine,
                        ct => CodeFixHelpers.AppendEndOfLineAsync(document, usingDirective, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }

                break;
            }

            case RegionDirectiveTriviaSyntax regionDirective:
            {
                CodeAction codeAction = CodeAction.Create(
                    CodeFixTitles.AddEmptyLine,
                    ct => CodeFixHelpers.AddEmptyLineBeforeDirectiveAsync(document, regionDirective, ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case EndRegionDirectiveTriviaSyntax endRegionDirective:
            {
                CodeAction codeAction = CodeAction.Create(
                    CodeFixTitles.AddEmptyLine,
                    ct => CodeFixHelpers.AddEmptyLineAfterDirectiveAsync(document, endRegionDirective, 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 SyntaxNode node, predicate: f => f.IsKind(
                                                SyntaxKind.InvocationExpression,
                                                SyntaxKind.EqualsExpression,
                                                SyntaxKind.NotEqualsExpression,
                                                SyntaxKind.IsPatternExpression,
                                                SyntaxKind.ConditionalExpression)))
            {
                return;
            }

            Diagnostic        diagnostic        = context.Diagnostics[0];
            Document          document          = context.Document;
            CancellationToken cancellationToken = context.CancellationToken;

            SyntaxKind kind = node.Kind();

            if (kind == SyntaxKind.InvocationExpression)
            {
                var invocation = (InvocationExpressionSyntax)node;

                SimpleMemberInvocationExpressionInfo invocationInfo = SimpleMemberInvocationExpressionInfo(invocation);

                if (diagnostic.Properties.TryGetValue("Name", out string name) &&
                    name == "SimplifyLinqMethodChain")
                {
                    SimpleMemberInvocationExpressionInfo invocationInfo2 = SimpleMemberInvocationExpressionInfo(invocationInfo.Expression);

                    CodeAction codeAction = CodeAction.Create(
                        $"Combine '{invocationInfo2.NameText}' and '{invocationInfo.NameText}'",
                        ct => SimplifyLinqMethodChainAsync(document, invocationInfo, ct),
                        GetEquivalenceKey(diagnostic, "SimplifyLinqMethodChain"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }

                switch (invocationInfo.NameText)
                {
                case "Cast":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'OfType' instead of 'Where' and 'Cast'",
                        ct => CallOfTypeInsteadOfWhereAndCastAsync(document, invocationInfo, ct),
                        GetEquivalenceKey(diagnostic, "CallOfTypeInsteadOfWhereAndCast"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }

                case "Any":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Combine 'Where' and 'Any'",
                        ct => CombineWhereAndAnyAsync(document, invocationInfo, ct),
                        GetEquivalenceKey(diagnostic, "CombineWhereAndAny"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }

                case "OfType":
                {
                    TypeSyntax typeArgument = ((GenericNameSyntax)invocationInfo.Name).TypeArgumentList.Arguments.Single();

                    SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                    if (semanticModel.GetTypeSymbol(typeArgument, cancellationToken).IsValueType)
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Remove redundant 'OfType' call",
                            ct =>
                            {
                                ExpressionSyntax newNode = invocationInfo.Expression.WithTrailingTrivia(invocation.GetTrailingTrivia());
                                return(document.ReplaceNodeAsync(invocation, newNode, ct));
                            },
                            GetEquivalenceKey(diagnostic, "RemoveRedundantOfTypeCall"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }
                    else
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Call 'Where' instead of 'OfType'",
                            ct => CallWhereInsteadOfOfTypeAsync(document, invocationInfo, ct),
                            GetEquivalenceKey(diagnostic, "CallWhereInsteadOfOfType"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    return;
                }

                case "Select":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Cast' instead of 'Select'",
                        ct => CallCastInsteadOfSelectAsync(document, invocation, ct),
                        GetEquivalenceKey(diagnostic, "CallCastInsteadOfSelect"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }

                case "FirstOrDefault":
                {
                    SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Find' instead of 'FirstOrDefault'",
                        ct => CallFindInsteadOfFirstOrDefaultAsync(document, invocationInfo, semanticModel, ct),
                        GetEquivalenceKey(diagnostic, "CallFindInsteadOfFirstOrDefault"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }

                case "First":
                {
                    if (diagnostic.Properties.TryGetValue("MethodName", out string methodName) &&
                        methodName == "Peek")
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Call 'Peek' instead of 'First'",
                            ct => document.ReplaceNodeAsync(invocation, ChangeInvokedMethodName(invocation, "Peek"), ct),
                            GetEquivalenceKey(diagnostic, "CallPeekInsteadOfFirst"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }
                    else
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Use [] instead of calling 'First'",
                            ct => UseElementAccessInsteadOfEnumerableMethodRefactoring.UseElementAccessInsteadOfFirstAsync(context.Document, invocation, ct),
                            GetEquivalenceKey(diagnostic, "UseElementAccessInsteadOfFirst"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    return;
                }

                case "Count":
                {
                    if (diagnostic.Properties.TryGetValue("PropertyName", out string propertyName))
                    {
                        CodeAction codeAction = CodeAction.Create(
                            $"Use '{propertyName}' property instead of calling 'Count'",
                            ct => UseCountOrLengthPropertyInsteadOfCountMethodAsync(document, invocation, diagnostic.Properties["PropertyName"], ct),
                            GetEquivalenceKey(diagnostic, "UseCountOrLengthPropertyInsteadOfCountMethod"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }
                    else if (invocation.Parent is BinaryExpressionSyntax binaryExpression)
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Call 'Any' instead of 'Count'",
                            ct => CallAnyInsteadOfCountAsync(document, invocation, binaryExpression, ct),
                            GetEquivalenceKey(diagnostic, "CallAnyInsteadOfCount"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    return;
                }

                case "ElementAt":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use [] instead of calling 'ElementAt'",
                        ct => UseElementAccessInsteadOfEnumerableMethodRefactoring.UseElementAccessInsteadOfElementAtAsync(document, invocation, ct),
                        GetEquivalenceKey(diagnostic, "UseElementAccessInsteadOfElementAt"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }
                }
            }
            else if (kind == SyntaxKind.ConditionalExpression)
            {
                CodeAction codeAction = CodeAction.Create(
                    "Call 'FirstOrDefault' instead of ?:",
                    ct => CallFirstOrDeafultInsteadOfConditionalExpressionAsync(document, (ConditionalExpressionSyntax)node, ct),
                    GetEquivalenceKey(diagnostic, "CallFirstOrDefaultInsteadOfConditionalExpression"));

                context.RegisterCodeFix(codeAction, diagnostic);
            }
            else if (kind.Is(
                         SyntaxKind.EqualsExpression,
                         SyntaxKind.NotEqualsExpression,
                         SyntaxKind.IsPatternExpression))
            {
                CodeAction codeAction = CodeAction.Create(
                    "Call 'Any' instead of 'FirstOrDefault'",
                    ct => CallAnyInsteadOfFirstOrDefaultAsync(document, node, ct),
                    GetEquivalenceKey(diagnostic, "CallAnyInsteadOfFirstOrDefault"));

                context.RegisterCodeFix(codeAction, diagnostic);
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassNonStatic) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveOutModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveRefModifier))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindToken(root, context.Span.Start, out SyntaxToken token))
            {
                return;
            }

            SyntaxNode node = token.Parent;

            if (!node.SupportsModifiers())
            {
                node = node.FirstAncestor(f => f.SupportsModifiers());
            }

            Debug.Assert(node != null, $"{nameof(node)} is null");

            if (node == null)
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.ModifierIsNotValidForThisItem:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    SyntaxTokenList modifiers = node.GetModifiers();

                    if (modifiers.Contains(token))
                    {
                        RemoveModifier(context, diagnostic, node, token);
                        break;
                    }

                    if (IsInterfaceMemberOrExplicitInterfaceImplementation(node))
                    {
                        RemoveModifiers(context, diagnostic, node, modifiers, f =>
                            {
                                switch (f.Kind())
                                {
                                case SyntaxKind.PublicKeyword:
                                case SyntaxKind.ProtectedKeyword:
                                case SyntaxKind.InternalKeyword:
                                case SyntaxKind.PrivateKeyword:
                                case SyntaxKind.StaticKeyword:
                                case SyntaxKind.VirtualKeyword:
                                case SyntaxKind.OverrideKeyword:
                                case SyntaxKind.AbstractKeyword:
                                    {
                                        return(true);
                                    }
                                }

                                return(false);
                            });
                    }
                    else if (node.IsKind(SyntaxKind.IndexerDeclaration))
                    {
                        RemoveModifier(context, diagnostic, node, modifiers, SyntaxKind.StaticKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.MoreThanOneProtectionModifier:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        RemoveModifier(context, diagnostic, node, token);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.AccessibilityModifiersMayNotBeUsedOnAccessorsInInterface:
                case CompilerDiagnosticIdentifiers.AccessModifiersAreNotAllowedOnStaticConstructors:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        RemoveAccessModifiers(context, diagnostic, node);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ModifiersCannotBePlacedOnEventAccessorDeclarations:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        RemoveModifiers(context, diagnostic, node);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.OnlyMethodsClassesStructsOrInterfacesMayBePartial:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        RemoveModifier(context, diagnostic, node, SyntaxKind.PartialKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ClassCannotBeBothStaticAndSealed:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    SyntaxTokenList modifiers = node.GetModifiers();

                    RemoveModifier(context, diagnostic, node, modifiers, SyntaxKind.StaticKeyword);
                    RemoveModifier(context, diagnostic, node, modifiers, SyntaxKind.SealedKeyword);
                    break;
                }

                case CompilerDiagnosticIdentifiers.FieldCanNotBeBothVolatileAndReadOnly:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    var fieldDeclaration = (FieldDeclarationSyntax)node;

                    SyntaxTokenList modifiers = fieldDeclaration.Modifiers;

                    RemoveModifier(context, diagnostic, fieldDeclaration, modifiers, SyntaxKind.VolatileKeyword);
                    RemoveModifier(context, diagnostic, fieldDeclaration, modifiers, SyntaxKind.ReadOnlyKeyword);
                    break;
                }

                case CompilerDiagnosticIdentifiers.NewProtectedMemberDeclaredInSealedClass:
                case CompilerDiagnosticIdentifiers.StaticClassesCannotContainProtectedMembers:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrPrivate);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.VirtualOrAbstractmembersCannotBePrivate:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrProtected);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.AbstractPropertiesCannotHavePrivateAccessors:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        RemoveAccessModifiers(context, diagnostic, node);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrProtected);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.StaticMemberCannotBeMarkedOverrideVirtualOrAbstract:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    SyntaxTokenList modifiers = node.GetModifiers();

                    if (!node.IsParentKind(SyntaxKind.ClassDeclaration) ||
                        !((ClassDeclarationSyntax)node.Parent).Modifiers.Contains(SyntaxKind.StaticKeyword))
                    {
                        RemoveModifier(context, diagnostic, node, modifiers, SyntaxKind.StaticKeyword);
                    }

                    RemoveModifier(context, diagnostic, node, modifiers, SyntaxKind.OverrideKeyword);
                    RemoveModifier(context, diagnostic, node, modifiers, SyntaxKind.VirtualKeyword);
                    RemoveModifier(context, diagnostic, node, modifiers, SyntaxKind.AbstractKeyword);
                    break;
                }

                case CompilerDiagnosticIdentifiers.AsyncModifierCanOnlyBeUsedInMethodsThatHaveBody:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        RemoveModifier(context, diagnostic, node, SyntaxKind.AsyncKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.PartialMethodCannotHaveAccessModifiersOrVirtualAbstractOverrideNewSealedOrExternModifiers:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    RemoveModifiers(context, diagnostic, node, f =>
                        {
                            switch (f.Kind())
                            {
                            case SyntaxKind.PublicKeyword:
                            case SyntaxKind.ProtectedKeyword:
                            case SyntaxKind.InternalKeyword:
                            case SyntaxKind.PrivateKeyword:
                            case SyntaxKind.VirtualKeyword:
                            case SyntaxKind.AbstractKeyword:
                            case SyntaxKind.OverrideKeyword:
                            case SyntaxKind.NewKeyword:
                            case SyntaxKind.SealedKeyword:
                            case SyntaxKind.ExternKeyword:
                                {
                                    return(true);
                                }
                            }

                            return(false);
                        });

                    break;
                }

                case CompilerDiagnosticIdentifiers.ExtensionMethodMustBeStatic:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier))
                    {
                        AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier))
                    {
                        RemoveThisModifier(context, diagnostic, (MethodDeclarationSyntax)node, CodeFixIdentifiers.RemoveThisModifier);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ExtensionMethodMustBeDefinedInNonGenericStaticClass:
                {
                    if (!node.IsKind(SyntaxKind.ClassDeclaration))
                    {
                        return;
                    }

                    var classDeclaration = (ClassDeclarationSyntax)node;

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier) &&
                        !classDeclaration.IsStatic())
                    {
                        AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier))
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Remove 'this' modifier from extension methods",
                            cancellationToken =>
                            {
                                IEnumerable <ParameterSyntax> thisParameters = classDeclaration.Members
                                                                               .Where(f => f.IsKind(SyntaxKind.MethodDeclaration))
                                                                               .Cast <MethodDeclarationSyntax>()
                                                                               .Select(f => f.ParameterList?.Parameters.FirstOrDefault())
                                                                               .Where(f => f?.Modifiers.Contains(SyntaxKind.ThisKeyword) == true);

                                return(context.Document.ReplaceNodesAsync(
                                           thisParameters,
                                           (f, g) => f.RemoveModifier(f.Modifiers.Find(SyntaxKind.ThisKeyword)),
                                           cancellationToken));
                            },
                            GetEquivalenceKey(diagnostic, CodeFixIdentifiers.RemoveThisModifier));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NoDefiningDeclarationFoundForImplementingDeclarationOfPartialMethod:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        RemoveModifier(context, diagnostic, node, SyntaxKind.PartialKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.MethodHasParameterModifierThisWhichIsNotOnFirstParameter:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier))
                    {
                        RemoveModifier(context, diagnostic, token.Parent, token);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotDeclareInstanceMembersInStaticClass:
                case CompilerDiagnosticIdentifiers.StaticClassesCannotHaveInstanceConstructors:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier))
                    {
                        AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassNonStatic))
                    {
                        var classDeclaration = (ClassDeclarationSyntax)node.Parent;

                        SyntaxToken staticModifier = classDeclaration.Modifiers.Find(SyntaxKind.StaticKeyword);

                        RemoveModifier(context, diagnostic, classDeclaration, staticModifier, CodeFixIdentifiers.MakeContainingClassNonStatic, "Make containing class non-static");
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ElementsDefinedInNamespaceCannotBeExplicitlyDeclaredAsPrivateProtectedOrProtectedInternal:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ChangeAccessibility(context, diagnostic, node, _publicOrInternal);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NamespaceAlreadyContainsDefinition:
                case CompilerDiagnosticIdentifiers.TypeAlreadyContainsDefinition:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier))
                    {
                        break;
                    }

                    if (!node.IsKind(
                            SyntaxKind.ClassDeclaration,
                            SyntaxKind.StructDeclaration,
                            SyntaxKind.InterfaceDeclaration,
                            SyntaxKind.MethodDeclaration))
                    {
                        return;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ISymbol symbol = semanticModel.GetDeclaredSymbol(node, context.CancellationToken);

                    ImmutableArray <SyntaxReference> syntaxReferences = symbol.DeclaringSyntaxReferences;

                    if (syntaxReferences.Length > 1)
                    {
                        AddPartialModifier(context, diagnostic, ImmutableArray.CreateRange(syntaxReferences, f => f.GetSyntax(context.CancellationToken)));
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NoSuitableMethodFoundToOverride:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        RemoveModifier(context, diagnostic, node, SyntaxKind.OverrideKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.AsyncMethodsCannotHaveRefOrOutParameters:
                case CompilerDiagnosticIdentifiers.IteratorsCannotHaveRefOrOutParameters:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveRefModifier))
                    {
                        RemoveModifier(context, diagnostic, node, SyntaxKind.RefKeyword);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveOutModifier))
                    {
                        RemoveModifier(context, diagnostic, node, SyntaxKind.OutKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotHaveInstancePropertyOrFieldInitializersInStruct:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier))
                    {
                        AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier);
                    }

                    break;
                }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsAnyEnabled(
                    CodeFixIdentifiers.ChangeTypeOfParamsParameter,
                    CodeFixIdentifiers.RemoveDefaultValueFromParameter))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out ParameterSyntax parameter))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.ParamsParameterMustBeSingleDimensionalArray:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.ChangeTypeOfParamsParameter))
                    {
                        break;
                    }

                    TypeSyntax type = parameter.Type;

                    if (type?.IsMissing == false)
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(type, context.CancellationToken);

                        if (typeSymbol?.Kind == SymbolKind.NamedType)
                        {
                            ArrayTypeSyntax newType = ArrayType(
                                typeSymbol.ToMinimalTypeSyntax(semanticModel, parameter.SpanStart),
                                SingletonList(ArrayRankSpecifier()));

                            CodeAction codeAction = CodeAction.Create(
                                $"Change parameter type to '{newType}'",
                                cancellationToken => context.Document.ReplaceNodeAsync(type, newType.WithTriviaFrom(type), cancellationToken),
                                GetEquivalenceKey(diagnostic));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotSpecifyDefaultValueForParameterArray:
                case CompilerDiagnosticIdentifiers.CannotSpecifyDefaultValueForThisParameter:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.RemoveDefaultValueFromParameter))
                    {
                        break;
                    }

                    EqualsValueClauseSyntax defaultValue = parameter.Default;

                    CodeAction codeAction = CodeAction.Create(
                        "Remove default value from parameter",
                        cancellationToken =>
                        {
                            ParameterSyntax newParameter = parameter
                                                           .RemoveNode(defaultValue)
                                                           .WithFormatterAnnotation();

                            return(context.Document.ReplaceNodeAsync(parameter, newParameter, 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 AssignmentExpressionSyntax assignment))
            {
                return;
            }

            Document document = context.Document;

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.UseCompoundAssignment:
                {
                    var binaryExpression = (BinaryExpressionSyntax)assignment.Right.WalkDownParentheses();

                    string operatorText = UseCompoundAssignmentAnalyzer.GetCompoundAssignmentOperatorText(binaryExpression);

                    CodeAction codeAction = CodeAction.Create(
                        $"Use {operatorText} operator",
                        cancellationToken => UseCompoundAssignmentRefactoring.RefactorAsync(document, assignment, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseUnaryOperatorInsteadOfAssignment:
                {
                    string operatorText = UseUnaryOperatorInsteadOfAssignmentAnalyzer.GetOperatorText(assignment);

                    CodeAction codeAction = CodeAction.Create(
                        $"Use {operatorText} operator",
                        ct => UseUnaryOperatorInsteadOfAssignmentAsync(document, assignment, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.RemoveRedundantDelegateCreation:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove redundant delegate creation",
                        cancellationToken =>
                        {
                            return(RemoveRedundantDelegateCreationRefactoring.RefactorAsync(
                                       document,
                                       (ObjectCreationExpressionSyntax)assignment.Right,
                                       cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.RemoveRedundantAssignment:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove redundant assignment",
                        cancellationToken =>
                        {
                            return(RemoveRedundantAssignmentRefactoring.RefactorAsync(
                                       document,
                                       assignment,
                                       cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsAnyEnabled(
                    CodeFixIdentifiers.UseYieldReturnInsteadOfReturn,
                    CodeFixIdentifiers.RemoveReturnKeyword,
                    CodeFixIdentifiers.RemoveReturnExpression,
                    CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out ReturnStatementSyntax returnStatement))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.CannotReturnValueFromIterator:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.UseYieldReturnInsteadOfReturn))
                    {
                        break;
                    }

                    ExpressionSyntax expression = returnStatement.Expression;

                    if (expression != null)
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ISymbol containingSymbol = semanticModel.GetEnclosingSymbol(returnStatement.SpanStart, context.CancellationToken);

                        if (containingSymbol?.Kind == SymbolKind.Method)
                        {
                            var methodSymbol = (IMethodSymbol)containingSymbol;

                            ITypeSymbol returnType = methodSymbol.ReturnType;

                            var replacementKind = SyntaxKind.None;

                            if (returnType.SpecialType == SpecialType.System_Collections_IEnumerable)
                            {
                                if (semanticModel
                                    .GetTypeSymbol(expression, context.CancellationToken)
                                    .OriginalDefinition
                                    .IsIEnumerableOrIEnumerableOfT())
                                {
                                    replacementKind = SyntaxKind.ForEachStatement;
                                }
                                else
                                {
                                    replacementKind = SyntaxKind.YieldReturnStatement;
                                }
                            }
                            else if (returnType.Kind == SymbolKind.NamedType)
                            {
                                var namedTypeSymbol = (INamedTypeSymbol)returnType;

                                if (namedTypeSymbol.OriginalDefinition.IsIEnumerableOfT())
                                {
                                    if (semanticModel.IsImplicitConversion(expression, namedTypeSymbol.TypeArguments[0]))
                                    {
                                        replacementKind = SyntaxKind.YieldReturnStatement;
                                    }
                                    else
                                    {
                                        replacementKind = SyntaxKind.ForEachStatement;
                                    }
                                }
                            }

                            if (replacementKind == SyntaxKind.YieldReturnStatement ||
                                (replacementKind == SyntaxKind.ForEachStatement && !returnStatement.SpanContainsDirectives()))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Use yield return instead of return",
                                    cancellationToken => UseYieldReturnInsteadOfReturnRefactoring.RefactorAsync(context.Document, returnStatement, replacementKind, semanticModel, cancellationToken),
                                    GetEquivalenceKey(diagnostic));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.SinceMethodReturnsVoidReturnKeywordMustNotBeFollowedByObjectExpression:
                case CompilerDiagnosticIdentifiers.SinceMethodIsAsyncMethodThatReturnsTaskReturnKeywordMustNotBeFollowedByObjectExpression:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    if (Settings.IsEnabled(CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression))
                    {
                        ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, returnStatement.Expression, semanticModel);
                    }

                    if (Settings.IsEnabled(CodeFixIdentifiers.RemoveReturnExpression))
                    {
                        ISymbol symbol = semanticModel.GetEnclosingSymbol(returnStatement.SpanStart, context.CancellationToken);

                        if (symbol?.Kind == SymbolKind.Method)
                        {
                            var methodSymbol = (IMethodSymbol)symbol;

                            if (methodSymbol.ReturnsVoid ||
                                methodSymbol.ReturnType.HasMetadataName(MetadataNames.System_Threading_Tasks_Task))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Remove return expression",
                                    cancellationToken =>
                                    {
                                        ReturnStatementSyntax newNode = returnStatement
                                                                        .WithExpression(null)
                                                                        .WithFormatterAnnotation();

                                        return(context.Document.ReplaceNodeAsync(returnStatement, newNode, cancellationToken));
                                    },
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.RemoveReturnExpression));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }
                    }

                    if (Settings.IsEnabled(CodeFixIdentifiers.RemoveReturnKeyword))
                    {
                        ExpressionSyntax expression = returnStatement.Expression;

                        if (expression.IsKind(
                                SyntaxKind.InvocationExpression,
                                SyntaxKind.ObjectCreationExpression,
                                SyntaxKind.PreDecrementExpression,
                                SyntaxKind.PreIncrementExpression,
                                SyntaxKind.PostDecrementExpression,
                                SyntaxKind.PostIncrementExpression) ||
                            expression is AssignmentExpressionSyntax)
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Remove 'return'",
                                cancellationToken =>
                                {
                                    SyntaxTriviaList leadingTrivia = returnStatement
                                                                     .GetLeadingTrivia()
                                                                     .AddRange(returnStatement.ReturnKeyword.TrailingTrivia.EmptyIfWhitespace())
                                                                     .AddRange(expression.GetLeadingTrivia().EmptyIfWhitespace());

                                    ExpressionStatementSyntax newNode = SyntaxFactory.ExpressionStatement(
                                        expression.WithLeadingTrivia(leadingTrivia),
                                        returnStatement.SemicolonToken);

                                    return(context.Document.ReplaceNodeAsync(returnStatement, newNode, cancellationToken));
                                },
                                GetEquivalenceKey(diagnostic, CodeFixIdentifiers.RemoveReturnKeyword));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }
                }
            }
        }
Example #7
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(
                    root,
                    context.Span,
                    out SyntaxNode node,
                    predicate: f =>
            {
                switch (f.Kind())
                {
                case SyntaxKind.TypeArgumentList:
                case SyntaxKind.ArgumentList:
                case SyntaxKind.BracketedArgumentList:
                case SyntaxKind.AttributeList:
                case SyntaxKind.AttributeArgumentList:
                case SyntaxKind.BaseList:
                case SyntaxKind.ParameterList:
                case SyntaxKind.BracketedParameterList:
                case SyntaxKind.TypeParameterList:
                    return(true);
                }

                return(false);
            }))
            {
                return;
            }

            Document   document   = context.Document;
            Diagnostic diagnostic = context.Diagnostics[0];

            CodeAction codeAction = CodeAction.Create(
                $"Wrap and indent each {GetTitle()}",
                ct => WrapAndIndentEachNodeInListAsync(document, node, ct),
                GetEquivalenceKey(diagnostic));

            context.RegisterCodeFix(codeAction, diagnostic);

            string GetTitle()
            {
                switch (node.Kind())
                {
                case SyntaxKind.TypeArgumentList:
                    return("type argument");

                case SyntaxKind.ArgumentList:
                case SyntaxKind.BracketedArgumentList:
                case SyntaxKind.AttributeArgumentList:
                    return("argument");

                case SyntaxKind.AttributeList:
                    return("attribute");

                case SyntaxKind.BaseList:
                    return("type");

                case SyntaxKind.ParameterList:
                case SyntaxKind.BracketedParameterList:
                    return("parameter");

                case SyntaxKind.TypeParameterList:
                    return("type parameter");

                default:
                    throw new InvalidOperationException();
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            StatementSyntax statement = root
                                        .FindNode(context.Span, getInnermostNodeForTie: true)?
                                        .FirstAncestorOrSelf <StatementSyntax>();

            Debug.Assert(statement != null, $"{nameof(statement)} is null");

            if (statement == null)
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.AddEmptyLineAfterLastStatementInDoStatement:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Add empty line",
                        cancellationToken =>
                        {
                            return(AddEmptyLineAfterLastStatementInDoStatementRefactoring.RefactorAsync(
                                       context.Document,
                                       statement,
                                       cancellationToken));
                        },
                        diagnostic.Id + EquivalenceKeySuffix);

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.ReplaceReturnStatementWithExpressionStatement:
                {
                    switch (statement.Kind())
                    {
                    case SyntaxKind.ReturnStatement:
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Remove 'return'",
                            cancellationToken => ReplaceReturnStatementWithExpressionStatementRefactoring.RefactorAsync(context.Document, (ReturnStatementSyntax)statement, cancellationToken),
                            diagnostic.Id + EquivalenceKeySuffix);

                        context.RegisterCodeFix(codeAction, diagnostic);
                        break;
                    }

                    case SyntaxKind.YieldReturnStatement:
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Remove 'yield return'",
                            cancellationToken => ReplaceReturnStatementWithExpressionStatementRefactoring.RefactorAsync(context.Document, (YieldStatementSyntax)statement, cancellationToken),
                            diagnostic.Id + EquivalenceKeySuffix);

                        context.RegisterCodeFix(codeAction, diagnostic);
                        break;
                    }

                    default:
                    {
                        Debug.Assert(false, statement.Kind().ToString());
                        break;
                    }
                    }

                    break;
                }

                case DiagnosticIdentifiers.UseCoalesceExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use coalesce expression",
                        cancellationToken =>
                        {
                            return(UseCoalesceExpressionRefactoring.RefactorAsync(
                                       context.Document,
                                       statement,
                                       cancellationToken));
                        },
                        diagnostic.Id + EquivalenceKeySuffix);

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.RemoveRedundantDisposeOrCloseCall:
                {
                    var expressionStatement = (ExpressionStatementSyntax)statement;
                    var invocation          = (InvocationExpressionSyntax)expressionStatement.Expression;
                    var memberAccess        = (MemberAccessExpressionSyntax)invocation.Expression;

                    CodeAction codeAction = CodeAction.Create(
                        $"Remove redundant '{memberAccess.Name?.Identifier.ValueText}' call",
                        cancellationToken => RemoveRedundantDisposeOrCloseCallRefactoring.RefactorAsync(context.Document, expressionStatement, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.RemoveRedundantContinueStatement:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove continue;",
                        cancellationToken => RemoveRedundantContinueStatementRefactoring.RefactorAsync(context.Document, (ContinueStatementSyntax)statement, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            Diagnostic diagnostic = context.Diagnostics[0];

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemovePropertyOrFieldInitializer, context.Document, root.SyntaxTree))
            {
                return;
            }

            if (!TryFindToken(root, context.Span.Start, out SyntaxToken token))
            {
                return;
            }

            SyntaxDebug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token);

            if (!token.IsKind(SyntaxKind.IdentifierToken))
            {
                return;
            }

            switch (token.Parent)
            {
            case PropertyDeclarationSyntax propertyDeclaration:
            {
                EqualsValueClauseSyntax initializer = propertyDeclaration.Initializer;

                CodeAction codeAction = CodeAction.Create(
                    Title,
                    ct =>
                    {
                        PropertyDeclarationSyntax newNode = propertyDeclaration
                                                            .RemoveNode(initializer)
                                                            .WithSemicolonToken(default(SyntaxToken))
                                                            .AppendToTrailingTrivia(propertyDeclaration.SemicolonToken.GetAllTrivia())
                                                            .WithFormatterAnnotation();

                        return(context.Document.ReplaceNodeAsync(propertyDeclaration, newNode, ct));
                    },
                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.RemovePropertyOrFieldInitializer));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case VariableDeclaratorSyntax variableDeclarator:
            {
                EqualsValueClauseSyntax initializer = variableDeclarator.Initializer;

                CodeAction codeAction = CodeAction.Create(
                    Title,
                    ct =>
                    {
                        VariableDeclaratorSyntax newNode = variableDeclarator
                                                           .RemoveNode(initializer)
                                                           .WithFormatterAnnotation();

                        return(context.Document.ReplaceNodeAsync(variableDeclarator, newNode, ct));
                    },
                    GetEquivalenceKey(CompilerDiagnosticIdentifiers.CS0573_CannotHaveInstancePropertyOrFieldInitializersInStruct, CodeFixIdentifiers.RemovePropertyOrFieldInitializer));

                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 ClassDeclarationSyntax classDeclaration))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.MakeClassStatic:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ISymbol symbol = semanticModel.GetDeclaredSymbol(classDeclaration, context.CancellationToken);

                    ImmutableArray <SyntaxReference> syntaxReferences = symbol.DeclaringSyntaxReferences;

                    if (!syntaxReferences.Any())
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.AddModifier(
                        context,
                        diagnostic,
                        ImmutableArray.CreateRange(syntaxReferences, f => f.GetSyntax()),
                        SyntaxKind.StaticKeyword,
                        title: "Make class static");

                    break;
                }

                case DiagnosticIdentifiers.AddStaticModifierToAllPartialClassDeclarations:
                {
                    ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, classDeclaration, SyntaxKind.StaticKeyword);
                    break;
                }

                case DiagnosticIdentifiers.ImplementExceptionConstructors:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Generate exception constructors",
                        cancellationToken =>
                        {
                            return(ImplementExceptionConstructorsAsync(
                                       context.Document,
                                       classDeclaration,
                                       cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseAttributeUsageAttribute:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use AttributeUsageAttribute",
                        cancellationToken => UseAttributeUsageAttributeAsync(context.Document, classDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.MakeClassSealed:
                {
                    ModifiersCodeFixRegistrator.AddModifier(
                        context,
                        diagnostic,
                        classDeclaration,
                        SyntaxKind.SealedKeyword);

                    break;
                }
                }
            }
        }
Example #11
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out ExpressionSyntax expression, predicate: f => f.IsKind(SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression)))
            {
                return;
            }

            if (IsPartOfLeftSideOfAssignment())
            {
                return;
            }

            if (expression
                .WalkUp(f => f.IsKind(SyntaxKind.InvocationExpression, SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression, SyntaxKind.ParenthesizedExpression))
                .IsParentKind(SyntaxKind.AwaitExpression))
            {
                return;
            }

            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

            if (expression.IsInExpressionTree(semanticModel, context.CancellationToken))
            {
                return;
            }

            SyntaxKind kind = expression.Kind();

            if (kind == SyntaxKind.SimpleMemberAccessExpression)
            {
                expression = ((MemberAccessExpressionSyntax)expression).Expression;
            }
            else if (kind == SyntaxKind.ElementAccessExpression)
            {
                expression = ((ElementAccessExpressionSyntax)expression).Expression;
            }

            CodeAction codeAction = CodeAction.Create(
                "Use conditional access",
                cancellationToken => RefactorAsync(context.Document, expression, cancellationToken),
                GetEquivalenceKey(DiagnosticIdentifiers.AvoidNullReferenceException));

            context.RegisterCodeFix(codeAction, context.Diagnostics);

            bool IsPartOfLeftSideOfAssignment()
            {
                for (SyntaxNode node = expression; node != null; node = node.Parent)
                {
                    var assignmentExpression = node.Parent as AssignmentExpressionSyntax;

                    if (assignmentExpression?.Left == node)
                    {
                        return(true);
                    }
                }

                return(false);
            }
        }
Example #12
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsAnyCodeFixEnabled(
                    CodeFixIdentifiers.RemoveEmptySwitchStatement,
                    CodeFixIdentifiers.IntroduceLocalVariable,
                    CodeFixIdentifiers.RemoveJumpStatement))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out StatementSyntax statement))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.EmptySwitchBlock:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveEmptySwitchStatement))
                    {
                        break;
                    }

                    if (!statement.IsKind(SyntaxKind.SwitchStatement))
                    {
                        break;
                    }

                    var switchStatement = (SwitchStatementSyntax)statement;

                    CodeAction codeAction = CodeAction.Create(
                        "Remove switch statement",
                        cancellationToken => context.Document.RemoveStatementAsync(switchStatement, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.OnlyAssignmentCallIncrementDecrementAndNewObjectExpressionsCanBeUsedAsStatement:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceLocalVariable))
                    {
                        break;
                    }

                    if (!statement.IsKind(SyntaxKind.ExpressionStatement))
                    {
                        break;
                    }

                    var expressionStatement = (ExpressionStatementSyntax)statement;

                    ExpressionSyntax expression = expressionStatement.Expression;

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    if (semanticModel.GetSymbol(expression, context.CancellationToken)?.IsErrorType() == false)
                    {
                        ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken);

                        if (typeSymbol?.IsErrorType() == false)
                        {
                            bool addAwait = typeSymbol.IsConstructedFromTaskOfT(semanticModel) &&
                                            semanticModel.GetEnclosingSymbol(expressionStatement.SpanStart, context.CancellationToken).IsAsyncMethod();

                            CodeAction codeAction = CodeAction.Create(
                                IntroduceLocalVariableRefactoring.GetTitle(expression),
                                cancellationToken => IntroduceLocalVariableRefactoring.RefactorAsync(context.Document, expressionStatement, typeSymbol, addAwait, semanticModel, cancellationToken),
                                GetEquivalenceKey(diagnostic));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NoEnclosingLoopOutOfWhichToBreakOrContinue:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveJumpStatement))
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        $"Remove {statement.GetTitle()}",
                        cancellationToken => context.Document.RemoveStatementAsync(statement, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsAnyCodeFixEnabled(
                    CodeFixIdentifiers.AddOutModifierToArgument,
                    CodeFixIdentifiers.RemoveRefModifier,
                    CodeFixIdentifiers.CreateSingletonArray,
                    CodeFixIdentifiers.AddArgumentList,
                    CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out ArgumentSyntax argument))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.ArgumentMustBePassedWithRefOrOutKeyword:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddOutModifierToArgument))
                    {
                        return;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    IParameterSymbol parameter = semanticModel.DetermineParameter(argument, allowCandidate: true, cancellationToken: context.CancellationToken);

                    if (parameter == null)
                    {
                        return;
                    }

                    SyntaxToken refOrOutKeyword = default;

                    if (parameter.RefKind == RefKind.Out)
                    {
                        refOrOutKeyword = Token(SyntaxKind.OutKeyword);
                    }
                    else if (parameter.RefKind == RefKind.Ref)
                    {
                        refOrOutKeyword = Token(SyntaxKind.RefKeyword);
                    }
                    else
                    {
                        return;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        $"Add '{SyntaxFacts.GetText(refOrOutKeyword.Kind())}' modifier",
                        cancellationToken =>
                        {
                            ArgumentSyntax newArgument = argument
                                                         .WithRefOrOutKeyword(refOrOutKeyword)
                                                         .WithFormatterAnnotation();

                            return(context.Document.ReplaceNodeAsync(argument, newArgument, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.ArgumentShouldNotBePassedWithRefOrOutKeyword:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveRefModifier))
                    {
                        return;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Remove 'ref' modifier",
                        cancellationToken =>
                        {
                            ArgumentSyntax newArgument = argument
                                                         .WithRefOrOutKeyword(default(SyntaxToken))
                                                         .PrependToLeadingTrivia(argument.RefOrOutKeyword.GetAllTrivia())
                                                         .WithFormatterAnnotation();

                            return(context.Document.ReplaceNodeAsync(argument, newArgument, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotConvertArgumentType:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue))
                    {
                        ExpressionSyntax expression = argument.Expression;

                        if (expression.Kind() == SyntaxKind.NullLiteralExpression &&
                            argument.Parent is ArgumentListSyntax argumentList)
                        {
                            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                            ImmutableArray <IParameterSymbol> parameterSymbols = FindParameters(argumentList, semanticModel, context.CancellationToken);

                            if (!parameterSymbols.IsDefault)
                            {
                                int index = argumentList.Arguments.IndexOf(argument);

                                IParameterSymbol parameterSymbol = parameterSymbols[index];

                                ITypeSymbol typeSymbol = parameterSymbol.Type;

                                if (typeSymbol.IsValueType)
                                {
                                    CodeFixRegistrator.ReplaceNullWithDefaultValue(
                                        context,
                                        diagnostic,
                                        expression,
                                        typeSymbol,
                                        semanticModel,
                                        CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue);
                                }
                            }
                        }
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddArgumentList))
                    {
                        ExpressionSyntax expression = argument.Expression;

                        if (expression.IsKind(
                                SyntaxKind.IdentifierName,
                                SyntaxKind.GenericName,
                                SyntaxKind.SimpleMemberAccessExpression))
                        {
                            InvocationExpressionSyntax invocationExpression = InvocationExpression(
                                expression.WithoutTrailingTrivia(),
                                ArgumentList().WithTrailingTrivia(expression.GetTrailingTrivia()));

                            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                            if (semanticModel.GetSpeculativeMethodSymbol(expression.SpanStart, invocationExpression) != null)
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Add argument list",
                                    cancellationToken =>
                                    {
                                        ArgumentSyntax newNode = argument.WithExpression(invocationExpression);

                                        return(context.Document.ReplaceNodeAsync(argument, newNode, cancellationToken));
                                    },
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.AddArgumentList));

                                context.RegisterCodeFix(codeAction, diagnostic);
                                break;
                            }
                        }
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.CreateSingletonArray))
                    {
                        ExpressionSyntax expression = argument.Expression;

                        if (expression?.IsMissing == false)
                        {
                            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                            ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression);

                            if (typeSymbol?.IsErrorType() == false)
                            {
                                foreach (ITypeSymbol typeSymbol2 in DetermineParameterTypeHelper.DetermineParameterTypes(argument, semanticModel, context.CancellationToken))
                                {
                                    if (!typeSymbol.Equals(typeSymbol2) &&
                                        typeSymbol2 is IArrayTypeSymbol arrayType &&
                                        semanticModel.IsImplicitConversion(expression, arrayType.ElementType))
                                    {
                                        CodeAction codeAction = CodeAction.Create(
                                            "Create singleton array",
                                            cancellationToken => CreateSingletonArrayRefactoring.RefactorAsync(context.Document, expression, arrayType.ElementType, semanticModel, cancellationToken),
                                            GetEquivalenceKey(diagnostic, CodeFixIdentifiers.CreateSingletonArray));

                                        context.RegisterCodeFix(codeAction, diagnostic);
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    break;
                }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveUnreachableCode))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out StatementSyntax statement))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.UnreachableCodeDetected:
                {
                    Debug.Assert(context.Span.Start == statement.SpanStart, statement.ToString());

                    if (context.Span.Start != statement.SpanStart)
                    {
                        break;
                    }

                    CodeAction codeAction = CreateCodeActionForIfElse(context.Document, diagnostic, statement.Parent);

                    if (codeAction != null)
                    {
                        context.RegisterCodeFix(codeAction, diagnostic);
                        break;
                    }

                    if (StatementContainer.TryCreate(statement, out StatementContainer container))
                    {
                        codeAction = CodeAction.Create(
                            Title,
                            cancellationToken =>
                            {
                                SyntaxList <StatementSyntax> statements = container.Statements;

                                int index = statements.IndexOf(statement);

                                if (index == statements.Count - 1)
                                {
                                    return(context.Document.RemoveStatementAsync(statement, cancellationToken));
                                }
                                else
                                {
                                    SyntaxRemoveOptions removeOptions = RemoveHelper.DefaultRemoveOptions;

                                    if (statement.GetLeadingTrivia().IsEmptyOrWhitespace())
                                    {
                                        removeOptions &= ~SyntaxRemoveOptions.KeepLeadingTrivia;
                                    }

                                    if (statements.Last().GetTrailingTrivia().IsEmptyOrWhitespace())
                                    {
                                        removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
                                    }

                                    return(context.Document.RemoveNodesAsync(statements.Skip(index), removeOptions, cancellationToken));
                                }
                            },
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MarkOperatorAsPublicAndStatic))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            MemberDeclarationSyntax memberDeclaration = root
                                                        .FindNode(context.Span, getInnermostNodeForTie: true)?
                                                        .FirstAncestorOrSelf <MemberDeclarationSyntax>();

            Debug.Assert(memberDeclaration != null, $"{nameof(memberDeclaration)} is null");

            if (memberDeclaration == null)
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.UserDefinedOperatorMustBeDeclaredStaticAndPublic:
                {
                    SyntaxTokenList modifiers = memberDeclaration.GetModifiers();

                    string title = "Add ";

                    if (modifiers.Contains(SyntaxKind.PublicKeyword))
                    {
                        title += "'static' modifier";
                    }
                    else if (modifiers.Contains(SyntaxKind.StaticKeyword))
                    {
                        title += "'public' modifier";
                    }
                    else
                    {
                        title += "'public static' modifiers";
                    }

                    CodeAction codeAction = CodeAction.Create(
                        title,
                        cancellationToken =>
                        {
                            SyntaxTokenList newModifiers = modifiers;

                            if (!modifiers.Contains(SyntaxKind.PublicKeyword))
                            {
                                newModifiers = newModifiers.InsertModifier(SyntaxKind.PublicKeyword, ModifierComparer.Instance);
                            }

                            if (!modifiers.Contains(SyntaxKind.StaticKeyword))
                            {
                                newModifiers = newModifiers.InsertModifier(SyntaxKind.StaticKeyword, ModifierComparer.Instance);
                            }

                            MemberDeclarationSyntax newMemberDeclaration = memberDeclaration.WithModifiers(newModifiers);

                            return(context.Document.ReplaceNodeAsync(memberDeclaration, newMemberDeclaration, 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 IfStatementSyntax ifStatement))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.MergeIfStatementWithNestedIfStatement:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Merge if with nested if",
                        cancellationToken =>
                        {
                            return(MergeIfStatementWithNestedIfStatementRefactoring.RefactorAsync(
                                       context.Document,
                                       ifStatement,
                                       cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.ReplaceIfStatementWithAssignment:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Replace if with assignment",
                        cancellationToken =>
                        {
                            return(ReplaceIfStatementWithAssignmentRefactoring.RefactorAsync(
                                       context.Document,
                                       ifStatement,
                                       cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseCoalesceExpressionInsteadOfIf:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    IfRefactoring refactoring = IfRefactoring.Analyze(
                        ifStatement,
                        UseCoalesceExpressionInsteadOfIfDiagnosticAnalyzer.AnalysisOptions,
                        semanticModel,
                        context.CancellationToken).First();

                    CodeAction codeAction = CodeAction.Create(
                        refactoring.Title,
                        cancellationToken => refactoring.RefactorAsync(context.Document, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.ReduceIfNesting:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Reduce if nesting",
                        cancellationToken =>
                        {
                            return(ReduceIfNestingRefactoring.RefactorAsync(
                                       context.Document,
                                       ifStatement,
                                       recursive: true,
                                       cancellationToken: cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddComparisonWithBooleanLiteral) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.CreateSingletonArray) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseUncheckedExpression) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConstModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseCoalesceExpression) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConditionThatIsAlwaysEqualToTrueOrFalse) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceLocalVariable) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceField) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceStringLiteralWithCharacterLiteral) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseYieldReturnInsteadOfReturn) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression)
                )
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindNode(root, context.Span, out ExpressionSyntax expression))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.CannotImplicitlyConvertTypeExplicitConversionExists:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    TypeInfo typeInfo = semanticModel.GetTypeInfo(expression, context.CancellationToken);

                    ITypeSymbol type          = typeInfo.Type;
                    ITypeSymbol convertedType = typeInfo.ConvertedType;

                    if ((type is INamedTypeSymbol namedType) &&
                        namedType.ConstructedFrom.SpecialType == SpecialType.System_Nullable_T)
                    {
                        if (convertedType?.IsBoolean() == true ||
                            AddComparisonWithBooleanLiteralRefactoring.IsCondition(expression))
                        {
                            if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddComparisonWithBooleanLiteral))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    AddComparisonWithBooleanLiteralRefactoring.GetTitle(expression),
                                    cancellationToken => AddComparisonWithBooleanLiteralRefactoring.RefactorAsync(context.Document, expression, cancellationToken),
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.AddComparisonWithBooleanLiteral));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }
                        else if (namedType.TypeArguments[0].Equals(convertedType))
                        {
                            if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseCoalesceExpression))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Use coalesce expression",
                                    cancellationToken =>
                                    {
                                        ExpressionSyntax defaultValue = convertedType.ToDefaultValueSyntax(semanticModel, expression.SpanStart);

                                        ExpressionSyntax newNode = CoalesceExpression(expression.WithoutTrivia(), defaultValue)
                                                                   .WithTriviaFrom(expression)
                                                                   .Parenthesize()
                                                                   .WithFormatterAnnotation();

                                        return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken));
                                    },
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.UseCoalesceExpression));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression))
                    {
                        ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddCastExpression))
                    {
                        CodeFixRegistrator.AddCastExpression(context, diagnostic, expression, convertedType, semanticModel);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.CreateSingletonArray) &&
                        type?.IsErrorType() == false &&
                        !type.Equals(convertedType) &&
                        (convertedType is IArrayTypeSymbol arrayType) &&
                        semanticModel.IsImplicitConversion(expression, arrayType.ElementType))
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Create singleton array",
                            cancellationToken => CreateSingletonArrayRefactoring.RefactorAsync(context.Document, expression, arrayType.ElementType, semanticModel, cancellationToken),
                            GetEquivalenceKey(diagnostic, CodeFixIdentifiers.CreateSingletonArray));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ConstantValueCannotBeConverted:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseUncheckedExpression))
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Use 'unchecked'",
                        cancellationToken =>
                        {
                            CheckedExpressionSyntax newNode = CSharpFactory.UncheckedExpression(expression.WithoutTrivia());

                            newNode = newNode.WithTriviaFrom(expression);

                            return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.ExpressionBeingAssignedMustBeConstant:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConstModifier))
                    {
                        break;
                    }

                    LocalDeclarationStatementSyntax localDeclarationStatement = GetLocalDeclarationStatement(expression);

                    if (localDeclarationStatement == null)
                    {
                        break;
                    }

                    SyntaxTokenList modifiers = localDeclarationStatement.Modifiers;

                    if (!modifiers.Contains(SyntaxKind.ConstKeyword))
                    {
                        break;
                    }

                    ModifiersCodeFixes.RemoveModifier(context, diagnostic, localDeclarationStatement, SyntaxKind.ConstKeyword);

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotConvertNullToTypeBecauseItIsNonNullableValueType:
                case CompilerDiagnosticIdentifiers.CannotConvertNullToTypeParameterBecauseItCouldBeNonNullableValueType:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = semanticModel.GetTypeInfo(expression, context.CancellationToken).ConvertedType;

                    if (typeSymbol?.SupportsExplicitDeclaration() != true)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Replace 'null' with default value",
                        cancellationToken =>
                        {
                            ExpressionSyntax newNode = typeSymbol.ToDefaultValueSyntax(semanticModel, expression.SpanStart);

                            return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.ResultOfExpressionIsAlwaysConstantSinceValueIsNeverEqualToNull:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConditionThatIsAlwaysEqualToTrueOrFalse))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    if (!NullCheckExpression.TryCreate(expression, semanticModel, out NullCheckExpression nullCheck, context.CancellationToken))
                    {
                        break;
                    }

                    if (nullCheck.Kind != NullCheckKind.EqualsToNull &&
                        nullCheck.Kind != NullCheckKind.NotEqualsToNull)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Remove condition",
                        cancellationToken =>
                        {
                            SyntaxNode newRoot = RemoveHelper.RemoveCondition(root, expression, nullCheck.Kind == NullCheckKind.NotEqualsToNull);

                            return(Task.FromResult(context.Document.WithSyntaxRoot(newRoot)));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);

                    break;
                }

                case CompilerDiagnosticIdentifiers.OnlyAssignmentCallIncrementDecrementAndNewObjectExpressionsCanBeUsedAsStatement:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    if (expression.Parent is ArrowExpressionClauseSyntax arrowExpresssionClause)
                    {
                        if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression))
                        {
                            break;
                        }

                        ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                    }
                    else if (expression.Parent is ExpressionStatementSyntax expressionStatement)
                    {
                        if (!Settings.IsAnyCodeFixEnabled(
                                CodeFixIdentifiers.IntroduceLocalVariable,
                                CodeFixIdentifiers.IntroduceField))
                        {
                            break;
                        }

                        if (semanticModel.GetSymbol(expression, context.CancellationToken)?.IsErrorType() != false)
                        {
                            break;
                        }

                        ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken);

                        if (typeSymbol?.IsErrorType() != false)
                        {
                            break;
                        }

                        if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceLocalVariable) &&
                            !expressionStatement.IsEmbedded())
                        {
                            bool addAwait = typeSymbol.IsConstructedFromTaskOfT(semanticModel) &&
                                            semanticModel.GetEnclosingSymbol(expressionStatement.SpanStart, context.CancellationToken).IsAsyncMethod();

                            CodeAction codeAction = CodeAction.Create(
                                IntroduceLocalVariableRefactoring.GetTitle(expression),
                                cancellationToken => IntroduceLocalVariableRefactoring.RefactorAsync(context.Document, expressionStatement, typeSymbol, addAwait, semanticModel, cancellationToken),
                                GetEquivalenceKey(diagnostic, CodeFixIdentifiers.IntroduceLocalVariable));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }

                        if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceField))
                        {
                            CodeAction codeAction = CodeAction.Create(
                                $"Introduce field for '{expression}'",
                                cancellationToken => IntroduceFieldRefactoring.RefactorAsync(context.Document, expressionStatement, typeSymbol, semanticModel, cancellationToken),
                                GetEquivalenceKey(diagnostic, CodeFixIdentifiers.IntroduceField));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotImplicitlyConvertType:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression))
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                        break;
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceStringLiteralWithCharacterLiteral) &&
                        expression?.IsKind(SyntaxKind.StringLiteralExpression) == true)
                    {
                        var literalExpression = (LiteralExpressionSyntax)expression;

                        if (literalExpression.Token.ValueText.Length == 1)
                        {
                            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                            if (semanticModel.GetTypeInfo(expression, context.CancellationToken).ConvertedType?.IsChar() == true)
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Replace string literal with character literal",
                                    cancellationToken => ReplaceStringLiteralWithCharacterLiteralRefactoring.RefactorAsync(context.Document, literalExpression, cancellationToken),
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.ReplaceStringLiteralWithCharacterLiteral));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseYieldReturnInsteadOfReturn) &&
                        expression.IsParentKind(SyntaxKind.ReturnStatement))
                    {
                        var returnStatement = (ReturnStatementSyntax)expression.Parent;

                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ISymbol containingSymbol = semanticModel.GetEnclosingSymbol(returnStatement.SpanStart, context.CancellationToken);

                        if (containingSymbol?.IsKind(SymbolKind.Method) == true &&
                            ((IMethodSymbol)containingSymbol).ReturnType?.IsIEnumerableOrConstructedFromIEnumerableOfT() == true)
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Use yield return instead of return",
                                cancellationToken => UseYieldReturnInsteadOfReturnRefactoring.RefactorAsync(context.Document, returnStatement, SyntaxKind.YieldReturnStatement, semanticModel, cancellationToken),
                                GetEquivalenceKey(diagnostic, CodeFixIdentifiers.UseYieldReturnInsteadOfReturn));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }
                }
            }
        }
Example #18
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsAnyCodeFixEnabled(
                    CodeFixIdentifiers.AddArgumentList,
                    CodeFixIdentifiers.ChangeArrayType))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out SimpleNameSyntax simpleName))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.CannotConvertMethodGroupToNonDelegateType:
                case CompilerDiagnosticIdentifiers.NameIsNotValidInGivenContext:
                {
                    if (!simpleName.IsParentKind(SyntaxKind.SimpleMemberAccessExpression))
                    {
                        break;
                    }

                    var memberAccess = (MemberAccessExpressionSyntax)simpleName.Parent;

                    CodeAction codeAction = CodeAction.Create(
                        "Add argument list",
                        cancellationToken =>
                        {
                            InvocationExpressionSyntax invocationExpression = InvocationExpression(
                                memberAccess.WithoutTrailingTrivia(),
                                ArgumentList().WithTrailingTrivia(memberAccess.GetTrailingTrivia()));

                            return(context.Document.ReplaceNodeAsync(memberAccess, invocationExpression, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.TypeOrNamespaceNameCouldNotBeFound:
                {
                    if (!(simpleName.Parent is ArrayTypeSyntax arrayType))
                    {
                        break;
                    }

                    if (!(arrayType.Parent is ArrayCreationExpressionSyntax arrayCreation))
                    {
                        break;
                    }

                    if (!object.ReferenceEquals(simpleName, arrayType.ElementType))
                    {
                        break;
                    }

                    ExpressionSyntax expression = arrayCreation.Initializer?.Expressions.FirstOrDefault();

                    if (expression == null)
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken);

                    if (typeSymbol?.SupportsExplicitDeclaration() != true)
                    {
                        break;
                    }

                    TypeSyntax newType = typeSymbol.ToMinimalTypeSyntax(semanticModel, simpleName.SpanStart);

                    CodeAction codeAction = CodeAction.Create(
                        $"Change element type to '{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, simpleName.SpanStart, SymbolDisplayFormats.Default)}'",
                        cancellationToken => context.Document.ReplaceNodeAsync(simpleName, newType.WithTriviaFrom(simpleName), cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Example #19
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            Diagnostic diagnostic = context.Diagnostics[0];

            if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveUnreachableCode))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out StatementSyntax statement))
            {
                return;
            }

            Debug.Assert(context.Span.Start == statement.SpanStart, statement.ToString());

            if (context.Span.Start != statement.SpanStart)
            {
                return;
            }

            CodeAction codeAction = CreateCodeActionForIfElse(context.Document, diagnostic, statement.Parent);

            if (codeAction != null)
            {
                context.RegisterCodeFix(codeAction, diagnostic);
                return;
            }

            StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(statement);

            if (statementsInfo.Success)
            {
                codeAction = CodeAction.Create(
                    Title,
                    cancellationToken =>
                {
                    SyntaxList <StatementSyntax> statements = statementsInfo.Statements;

                    int index = statements.IndexOf(statement);

                    if (index == statements.Count - 1)
                    {
                        return(context.Document.RemoveStatementAsync(statement, cancellationToken));
                    }
                    else
                    {
                        int lastIndex = statements.LastIndexOf(f => !f.IsKind(SyntaxKind.LocalFunctionStatement));

                        SyntaxList <StatementSyntax> nodes = RemoveRange(statements, index, lastIndex - index + 1, f => !f.IsKind(SyntaxKind.LocalFunctionStatement));

                        return(context.Document.ReplaceStatementsAsync(
                                   statementsInfo,
                                   nodes,
                                   cancellationToken));
                    }
                },
                    base.GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
            }
        }
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(
                    root,
                    context.Span,
                    out SyntaxNode node,
                    predicate: f => f.IsKind(SyntaxKind.EqualsValueClause, SyntaxKind.SuppressNullableWarningExpression)))
            {
                return;
            }

            Diagnostic diagnostic = context.Diagnostics[0];
            Document   document   = context.Document;

            switch (diagnostic.Id)
            {
            case DiagnosticIdentifiers.UnnecessaryNullForgivingOperator:
            {
                CodeAction codeAction = CodeAction.Create(
                    "Remove null-forgiving operator",
                    ct =>
                    {
                        if (node.Parent is PropertyDeclarationSyntax propertyDeclaration)
                        {
                            SyntaxToken semicolonToken = propertyDeclaration.SemicolonToken;

                            SyntaxToken token = propertyDeclaration.Initializer.GetFirstToken().GetPreviousToken();

                            SyntaxTriviaList newTrivia = token.TrailingTrivia
                                                         .AddRange(node.GetLeadingAndTrailingTrivia())
                                                         .AddRange(semicolonToken.LeadingTrivia)
                                                         .EmptyIfWhitespace()
                                                         .AddRange(semicolonToken.TrailingTrivia);

                            PropertyDeclarationSyntax newNode = propertyDeclaration
                                                                .ReplaceToken(token, token.WithTrailingTrivia(newTrivia))
                                                                .WithInitializer(null)
                                                                .WithSemicolonToken(default);

                            return(document.ReplaceNodeAsync(propertyDeclaration, newNode, ct));
                        }
                        else if (node.Parent.Parent.IsParentKind(SyntaxKind.FieldDeclaration))
                        {
                            var variableDeclarator = (VariableDeclaratorSyntax)node.Parent;

                            SyntaxToken token = variableDeclarator.Initializer.GetFirstToken().GetPreviousToken();

                            SyntaxTriviaList newTrivia = token.TrailingTrivia
                                                         .AddRange(node.GetLeadingAndTrailingTrivia())
                                                         .EmptyIfWhitespace();

                            VariableDeclaratorSyntax newNode = variableDeclarator
                                                               .ReplaceToken(token, token.WithTrailingTrivia(newTrivia))
                                                               .WithInitializer(null);

                            return(document.ReplaceNodeAsync(variableDeclarator, newNode, ct));
                        }
                        else
                        {
                            var expression = (PostfixUnaryExpressionSyntax)node;

                            ExpressionSyntax newExpression = expression.Operand
                                                             .AppendToTrailingTrivia(expression.OperatorToken.LeadingAndTrailingTrivia());

                            return(document.ReplaceNodeAsync(expression, newExpression, ct));
                        }
                    },
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddDocumentationComment) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMethodReturnType) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassAbstract) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveParametersFromStaticConstructor) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveMemberDeclaration) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RenameDestructorToMatchClassName))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.MissingXmlCommentForPubliclyVisibleTypeOrMember:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddDocumentationComment))
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Add documentation comment",
                        cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, false, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);

                    CodeAction codeAction2 = CodeAction.Create(
                        "Add documentation comment (copy from base if available)",
                        cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, true, cancellationToken),
                        GetEquivalenceKey(diagnostic, "CopyFromBaseIfAvailable"));

                    context.RegisterCodeFix(codeAction2, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.MethodReturnTypeMustMatchOverriddenMethodReturnType:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMethodReturnType))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken);

                    ITypeSymbol typeSymbol = methodSymbol.OverriddenMethod.ReturnType;

                    if (typeSymbol?.IsErrorType() == false)
                    {
                        CodeAction codeAction = CodeAction.Create(
                            $"Change return type to '{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, memberDeclaration.SpanStart, SymbolDisplayFormats.Default)}'",
                            cancellationToken => MemberTypeMustMatchOverriddenMemberTypeRefactoring.RefactorAsync(context.Document, memberDeclaration, typeSymbol, semanticModel, cancellationToken),
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.PartialMethodsMustHaveVoidReturnType:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMethodReturnType))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration;

                    MethodDeclarationSyntax otherPart = semanticModel.GetOtherPart(methodDeclaration, context.CancellationToken);

                    if (otherPart == null)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Change return type to 'void'",
                        cancellationToken =>
                        {
                            return(context.Document.Solution().ReplaceNodesAsync(
                                       new MethodDeclarationSyntax[] { methodDeclaration, otherPart },
                                       (node, _) => node.WithReturnType(CSharpFactory.VoidType().WithTriviaFrom(node.ReturnType)),
                                       cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.MemberTypeMustMatchOverriddenMemberType:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = null;

                    switch (memberDeclaration.Kind())
                    {
                    case SyntaxKind.PropertyDeclaration:
                    case SyntaxKind.IndexerDeclaration:
                    {
                        var propertySymbol = (IPropertySymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken);

                        typeSymbol = propertySymbol.OverriddenProperty.Type;
                        break;
                    }

                    case SyntaxKind.EventDeclaration:
                    {
                        var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken);

                        typeSymbol = eventSymbol.OverriddenEvent.Type;
                        break;
                    }

                    case SyntaxKind.EventFieldDeclaration:
                    {
                        VariableDeclaratorSyntax declarator = ((EventFieldDeclarationSyntax)memberDeclaration).Declaration.Variables.First();

                        var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(declarator, context.CancellationToken);

                        typeSymbol = eventSymbol.OverriddenEvent.Type;
                        break;
                    }
                    }

                    if (typeSymbol?.IsErrorType() == false)
                    {
                        string title = $"Change type to '{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, memberDeclaration.SpanStart, SymbolDisplayFormats.Default)}'";

                        CodeAction codeAction = CodeAction.Create(
                            title,
                            cancellationToken => MemberTypeMustMatchOverriddenMemberTypeRefactoring.RefactorAsync(context.Document, memberDeclaration, typeSymbol, semanticModel, cancellationToken),
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.MissingPartialModifier:
                case CompilerDiagnosticIdentifiers.PartialMethodMustBeDeclaredInPartialClassOrPartialStruct:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier))
                    {
                        break;
                    }

                    SyntaxNode node = null;

                    switch (memberDeclaration.Kind())
                    {
                    case SyntaxKind.MethodDeclaration:
                    {
                        if (memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration))
                        {
                            node = memberDeclaration.Parent;
                        }

                        break;
                    }

                    case SyntaxKind.ClassDeclaration:
                    case SyntaxKind.StructDeclaration:
                    case SyntaxKind.InterfaceDeclaration:
                    {
                        node = memberDeclaration;
                        break;
                    }
                    }

                    Debug.Assert(node != null, memberDeclaration.ToString());

                    if (node == null)
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.PartialKeyword);
                    break;
                }

                case CompilerDiagnosticIdentifiers.MemberIsAbstractButItIsContainedInNonAbstractClass:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassAbstract))
                    {
                        break;
                    }

                    if (!memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration))
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.AddModifier(
                        context,
                        diagnostic,
                        memberDeclaration.Parent,
                        SyntaxKind.AbstractKeyword,
                        title: "Make containing class abstract");

                    break;
                }

                case CompilerDiagnosticIdentifiers.StaticConstructorMustBeParameterless:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveParametersFromStaticConstructor))
                    {
                        break;
                    }

                    var constructorDeclaration = (ConstructorDeclarationSyntax)memberDeclaration;

                    CodeAction codeAction = CodeAction.Create(
                        "Remove parameters",
                        cancellationToken =>
                        {
                            ParameterListSyntax parameterList = constructorDeclaration.ParameterList;

                            ParameterListSyntax newParameterList = parameterList
                                                                   .WithParameters(default(SeparatedSyntaxList <ParameterSyntax>))
                                                                   .WithOpenParenToken(parameterList.OpenParenToken.WithoutTrailingTrivia())
                                                                   .WithCloseParenToken(parameterList.CloseParenToken.WithoutLeadingTrivia());

                            ConstructorDeclarationSyntax newNode = constructorDeclaration.WithParameterList(newParameterList);

                            return(context.Document.ReplaceNodeAsync(constructorDeclaration, newNode, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.ExplicitInterfaceDeclarationCanOnlyBeDeclaredInClassOrStruct:
                case CompilerDiagnosticIdentifiers.InterfacesCannotContainFields:
                case CompilerDiagnosticIdentifiers.InterfacesCannotContainOperators:
                case CompilerDiagnosticIdentifiers.InterfacesCannotDeclareTypes:
                case CompilerDiagnosticIdentifiers.OnlyClassTypesCanContainDestructors:
                case CompilerDiagnosticIdentifiers.StructsCannotContainExplicitParameterlessConstructors:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveMemberDeclaration))
                    {
                        break;
                    }

                    CodeFixRegistrator.RemoveMember(context, diagnostic, memberDeclaration);
                    break;
                }

                case CompilerDiagnosticIdentifiers.NameOfDestructorMustMatchNameOfClass:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RenameDestructorToMatchClassName))
                    {
                        break;
                    }

                    if (!(memberDeclaration is DestructorDeclarationSyntax destructorDeclaration))
                    {
                        break;
                    }

                    if (!(memberDeclaration.Parent is ClassDeclarationSyntax classDeclaration))
                    {
                        break;
                    }

                    if (classDeclaration.Identifier.ValueText.Length == 0)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Rename destructor to match class name",
                        cancellationToken =>
                        {
                            DestructorDeclarationSyntax newNode = destructorDeclaration.WithIdentifier(classDeclaration.Identifier.WithTriviaFrom(destructorDeclaration.Identifier));

                            return(context.Document.ReplaceNodeAsync(destructorDeclaration, newNode, 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 SyntaxNode node, predicate: f => f.IsKind(
                                                SyntaxKind.EqualsExpression,
                                                SyntaxKind.NotEqualsExpression,
                                                SyntaxKind.InvocationExpression)))
            {
                return;
            }

            Diagnostic diagnostic = context.Diagnostics[0];

            switch (node.Kind())
            {
            case SyntaxKind.EqualsExpression:
            case SyntaxKind.NotEqualsExpression:
            {
                var binaryExpression = (BinaryExpressionSyntax)node;

                SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(binaryExpression.Left.WalkDownParentheses());

                if (!invocationInfo.Success)
                {
                    invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo((InvocationExpressionSyntax)binaryExpression.Right.WalkDownParentheses());
                }

                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                INamedTypeSymbol comparisonSymbol = semanticModel.GetTypeByMetadataName(MetadataNames.System_StringComparison);

                if (!invocationInfo.NameText.EndsWith("Invariant", StringComparison.Ordinal) ||
                    !RegisterCodeFix(context, diagnostic, binaryExpression, comparisonSymbol, "InvariantCultureIgnoreCase"))
                {
                    RegisterCodeFix(context, diagnostic, binaryExpression, comparisonSymbol, "OrdinalIgnoreCase");
                    RegisterCodeFix(context, diagnostic, binaryExpression, comparisonSymbol, "CurrentCultureIgnoreCase");
                }

                break;
            }

            case SyntaxKind.InvocationExpression:
            {
                var invocationExpression = (InvocationExpressionSyntax)node;

                SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationExpression);

                SeparatedSyntaxList <ArgumentSyntax> arguments = invocationInfo.Arguments;

                InvocationExpressionSyntax invocationExpression2;

                if (arguments.Count == 1)
                {
                    invocationExpression2 = (InvocationExpressionSyntax)invocationInfo.Expression;
                }
                else
                {
                    invocationExpression2 = (arguments[0].Expression.WalkDownParentheses() as InvocationExpressionSyntax)
                                            ?? (InvocationExpressionSyntax)arguments[1].Expression.WalkDownParentheses();
                }

                SimpleMemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationExpression2);

                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                INamedTypeSymbol comparisonSymbol = semanticModel.GetTypeByMetadataName(MetadataNames.System_StringComparison);

                if (!invocationInfo2.NameText.EndsWith("Invariant", StringComparison.Ordinal) ||
                    !RegisterCodeFix(context, diagnostic, invocationInfo, comparisonSymbol, "InvariantCultureIgnoreCase"))
                {
                    RegisterCodeFix(context, diagnostic, invocationInfo, comparisonSymbol, "OrdinalIgnoreCase");
                    RegisterCodeFix(context, diagnostic, invocationInfo, comparisonSymbol, "CurrentCultureIgnoreCase");
                }

                break;
            }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            Document   document   = context.Document;
            Diagnostic diagnostic = context.Diagnostics[0];

            if (!TryFindTrivia(root, context.Span.Start, out SyntaxTrivia trivia, findInsideTrivia: false))
            {
                return;
            }

            switch (diagnostic.Id)
            {
            case DiagnosticIdentifiers.AddEmptyLineAfterTopComment:
            {
                CodeAction codeAction = CodeAction.Create(
                    CodeFixTitles.AddEmptyLine,
                    ct => document.ReplaceTokenAsync(trivia.Token, trivia.Token.AppendEndOfLineToLeadingTrivia(), ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case DiagnosticIdentifiers.AddEmptyLineBeforeTopDeclaration:
            case DiagnosticIdentifiers.AddEmptyLineBetweenAccessors:
            {
                CodeAction codeAction = CodeAction.Create(
                    CodeFixTitles.AddEmptyLine,
                    ct => CodeFixHelpers.AppendEndOfLineAsync(document, trivia.Token, ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case DiagnosticIdentifiers.AddEmptyLineBetweenSingleLineAccessorsOrViceVersa:
            case DiagnosticIdentifiers.AddEmptyLineBetweenUsingDirectivesWithDifferentRootNamespaceOrViceVersa:
            {
                if (DiagnosticProperties.ContainsInvert(diagnostic.Properties))
                {
                    CodeAction codeAction = CodeAction.Create(
                        CodeFixTitles.RemoveEmptyLine,
                        ct => CodeFixHelpers.RemoveEmptyLinesBeforeAsync(document, trivia.Token, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }
                else
                {
                    CodeAction codeAction = CodeAction.Create(
                        CodeFixTitles.AddEmptyLine,
                        ct => CodeFixHelpers.AppendEndOfLineAsync(document, trivia.Token, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }

                break;
            }

            case DiagnosticIdentifiers.RemoveEmptyLineBetweenUsingDirectivesWithSameRootNamespace:
            {
                CodeAction codeAction = CodeAction.Create(
                    CodeFixTitles.RemoveEmptyLine,
                    ct => CodeFixHelpers.RemoveEmptyLinesBeforeAsync(document, trivia.Token, ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case DiagnosticIdentifiers.RemoveNewLineBeforeBaseList:
            case DiagnosticIdentifiers.RemoveNewLineBetweenIfKeywordAndElseKeyword:
            {
                CodeAction codeAction = CodeAction.Create(
                    CodeFixTitles.RemoveNewLine,
                    ct => CodeFixHelpers.ReplaceTriviaBetweenAsync(document, trivia.Token, trivia.Token.GetNextToken(), cancellationToken: ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }
            }
        }
Example #24
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.MissingXmlCommentForPubliclyVisibleTypeOrMember:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddDocumentationComment))
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Add documentation comment",
                        cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, false, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);

                    CodeAction codeAction2 = CodeAction.Create(
                        "Add documentation comment (copy from base if available)",
                        cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, true, cancellationToken),
                        GetEquivalenceKey(diagnostic, "CopyFromBaseIfAvailable"));

                    context.RegisterCodeFix(codeAction2, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.MethodReturnTypeMustMatchOverriddenMethodReturnType:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMethodReturnType))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken);

                    ITypeSymbol typeSymbol = methodSymbol.OverriddenMethod.ReturnType;

                    CodeFixRegistrator.ChangeTypeOrReturnType(context, diagnostic, memberDeclaration, typeSymbol, semanticModel);

                    break;
                }

                case CompilerDiagnosticIdentifiers.PartialMethodsMustHaveVoidReturnType:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMethodReturnType))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration;

                    MethodDeclarationSyntax otherPart = semanticModel.GetOtherPart(methodDeclaration, context.CancellationToken);

                    if (otherPart == null)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Change return type to 'void'",
                        cancellationToken =>
                        {
                            return(context.Document.Solution().ReplaceNodesAsync(
                                       new MethodDeclarationSyntax[] { methodDeclaration, otherPart },
                                       (node, _) => node.WithReturnType(CSharpFactory.VoidType().WithTriviaFrom(node.ReturnType)),
                                       cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.MemberTypeMustMatchOverriddenMemberType:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = null;

                    switch (memberDeclaration.Kind())
                    {
                    case SyntaxKind.PropertyDeclaration:
                    case SyntaxKind.IndexerDeclaration:
                    {
                        var propertySymbol = (IPropertySymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken);

                        typeSymbol = propertySymbol.OverriddenProperty.Type;
                        break;
                    }

                    case SyntaxKind.EventDeclaration:
                    {
                        var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken);

                        typeSymbol = eventSymbol.OverriddenEvent.Type;
                        break;
                    }

                    case SyntaxKind.EventFieldDeclaration:
                    {
                        VariableDeclaratorSyntax declarator = ((EventFieldDeclarationSyntax)memberDeclaration).Declaration.Variables[0];

                        var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(declarator, context.CancellationToken);

                        typeSymbol = eventSymbol.OverriddenEvent.Type;
                        break;
                    }
                    }

                    CodeFixRegistrator.ChangeTypeOrReturnType(context, diagnostic, memberDeclaration, typeSymbol, semanticModel);

                    break;
                }

                case CompilerDiagnosticIdentifiers.MissingPartialModifier:
                case CompilerDiagnosticIdentifiers.PartialMethodMustBeDeclaredInPartialClassOrPartialStruct:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddPartialModifier))
                    {
                        break;
                    }

                    SyntaxNode node = null;

                    switch (memberDeclaration.Kind())
                    {
                    case SyntaxKind.MethodDeclaration:
                    {
                        if (memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration))
                        {
                            node = memberDeclaration.Parent;
                        }

                        break;
                    }

                    case SyntaxKind.ClassDeclaration:
                    case SyntaxKind.StructDeclaration:
                    case SyntaxKind.InterfaceDeclaration:
                    case SyntaxKind.RecordDeclaration:
                    {
                        node = memberDeclaration;
                        break;
                    }
                    }

                    Debug.Assert(node != null, memberDeclaration.ToString());

                    if (node == null)
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.PartialKeyword, title: $"Make {CSharpFacts.GetTitle(node)} partial");
                    break;
                }

                case CompilerDiagnosticIdentifiers.MemberIsAbstractButItIsContainedInNonAbstractClass:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MakeContainingClassAbstract))
                    {
                        break;
                    }

                    if (!memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration))
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.AddModifier(
                        context,
                        diagnostic,
                        memberDeclaration.Parent,
                        SyntaxKind.AbstractKeyword,
                        title: "Make containing class abstract");

                    break;
                }

                case CompilerDiagnosticIdentifiers.StaticConstructorMustBeParameterless:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveParametersFromStaticConstructor))
                    {
                        break;
                    }

                    var constructorDeclaration = (ConstructorDeclarationSyntax)memberDeclaration;

                    CodeAction codeAction = CodeAction.Create(
                        "Remove parameters",
                        cancellationToken =>
                        {
                            ParameterListSyntax parameterList = constructorDeclaration.ParameterList;

                            ParameterListSyntax newParameterList = parameterList
                                                                   .WithParameters(default(SeparatedSyntaxList <ParameterSyntax>))
                                                                   .WithOpenParenToken(parameterList.OpenParenToken.WithoutTrailingTrivia())
                                                                   .WithCloseParenToken(parameterList.CloseParenToken.WithoutLeadingTrivia());

                            ConstructorDeclarationSyntax newNode = constructorDeclaration.WithParameterList(newParameterList);

                            return(context.Document.ReplaceNodeAsync(constructorDeclaration, newNode, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.ExplicitInterfaceDeclarationCanOnlyBeDeclaredInClassOrStruct:
                case CompilerDiagnosticIdentifiers.InterfacesCannotContainFields:
                case CompilerDiagnosticIdentifiers.InterfacesCannotContainOperators:
                case CompilerDiagnosticIdentifiers.InterfacesCannotDeclareTypes:
                case CompilerDiagnosticIdentifiers.OnlyClassTypesCanContainDestructors:
                case CompilerDiagnosticIdentifiers.StructsCannotContainExplicitParameterlessConstructors:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveMemberDeclaration))
                    {
                        break;
                    }

                    CodeFixRegistrator.RemoveMemberDeclaration(context, diagnostic, memberDeclaration);
                    break;
                }

                case CompilerDiagnosticIdentifiers.NameOfDestructorMustMatchNameOfClass:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RenameDestructorToMatchClassName))
                    {
                        break;
                    }

                    if (!(memberDeclaration is DestructorDeclarationSyntax destructorDeclaration))
                    {
                        break;
                    }

                    if (!(memberDeclaration.Parent is ClassDeclarationSyntax classDeclaration))
                    {
                        break;
                    }

                    if (classDeclaration.Identifier.ValueText.Length == 0)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Rename destructor to match class name",
                        cancellationToken =>
                        {
                            DestructorDeclarationSyntax newNode = destructorDeclaration.WithIdentifier(classDeclaration.Identifier.WithTriviaFrom(destructorDeclaration.Identifier));

                            return(context.Document.ReplaceNodeAsync(destructorDeclaration, newNode, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotChangeTupleElementNameWhenOverridingInheritedMember:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RenameTupleElement))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    if (memberDeclaration is MethodDeclarationSyntax methodDeclaration)
                    {
                        IMethodSymbol methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration, context.CancellationToken);

                        if (!(methodSymbol.ReturnType is INamedTypeSymbol tupleType))
                        {
                            break;
                        }

                        if (!tupleType.IsTupleType)
                        {
                            break;
                        }

                        if (!(methodSymbol.OverriddenMethod?.ReturnType is INamedTypeSymbol baseTupleType))
                        {
                            break;
                        }

                        if (!baseTupleType.IsTupleType)
                        {
                            break;
                        }

                        ImmutableArray <IFieldSymbol> elements     = tupleType.TupleElements;
                        ImmutableArray <IFieldSymbol> baseElements = baseTupleType.TupleElements;

                        if (elements.Length != baseElements.Length)
                        {
                            break;
                        }

                        int i = 0;
                        while (i < elements.Length)
                        {
                            if (elements[i].Name != baseElements[i].Name)
                            {
                                break;
                            }

                            i++;
                        }

                        if (i == elements.Length)
                        {
                            break;
                        }

                        TupleElementSyntax tupleElement = ((TupleTypeSyntax)methodDeclaration.ReturnType).Elements[i];

                        CodeAction codeAction = CodeAction.Create(
                            $"Rename '{elements[i].Name}' to '{baseElements[i].Name}'",
                            ct => RenameTupleElementAsync(context.Document, methodDeclaration, tupleElement, elements[i], baseElements[i].Name, semanticModel, ct),
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }
                    else if (memberDeclaration is PropertyDeclarationSyntax propertyDeclaration)
                    {
                        IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, context.CancellationToken);

                        if (!(propertySymbol.Type is INamedTypeSymbol tupleType))
                        {
                            break;
                        }

                        if (!tupleType.IsTupleType)
                        {
                            break;
                        }

                        if (!(propertySymbol.OverriddenProperty?.Type is INamedTypeSymbol baseTupleType))
                        {
                            break;
                        }

                        if (!baseTupleType.IsTupleType)
                        {
                            break;
                        }

                        ImmutableArray <IFieldSymbol> elements     = tupleType.TupleElements;
                        ImmutableArray <IFieldSymbol> baseElements = baseTupleType.TupleElements;

                        if (elements.Length != baseElements.Length)
                        {
                            break;
                        }

                        int i = 0;
                        while (i < elements.Length)
                        {
                            if (elements[i].Name != baseElements[i].Name)
                            {
                                break;
                            }

                            i++;
                        }

                        if (i == elements.Length)
                        {
                            break;
                        }

                        TupleElementSyntax tupleElement = ((TupleTypeSyntax)propertyDeclaration.Type).Elements[i];

                        CodeAction codeAction = CodeAction.Create(
                            $"Rename '{elements[i].Name}' to '{baseElements[i].Name}'",
                            ct => RenameTupleElementAsync(context.Document, propertyDeclaration, tupleElement, elements[i], baseElements[i].Name, semanticModel, ct),
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.MethodsWithVariableArgumentsAreNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.ArgumentTypeIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.ReturnTypeIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.TypeOfVariableIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.IdentifierDifferingOnlyInCaseIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.OverloadedMethodDifferingOnlyInRefOrOutOrInArrayRankIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.OverloadedMethodDifferingOnlyByUnnamedArrayTypesIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.IdentifierIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.BaseTypeIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.ArraysAsAttributeArgumentsIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.ConstraintTypeIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.TypeIsNotCLSCompliantBecauseBaseInterfaceIsNotCLSCompliant:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MarkDeclarationAsNonCLSCompliant))
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        $"Mark {CSharpFacts.GetTitle(memberDeclaration)} as non-CLS-compliant",
                        ct => MarkDeclarationAsNonCLSCompliantAsync(context.Document, memberDeclaration, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.ExplicitInterfaceDeclarationIsNotMemberOfInterface:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddParameterToExplicitlyImplementedInterfaceMember))
                    {
                        break;
                    }

                    var context2 = new CommonFixContext(
                        context.Document,
                        GetEquivalenceKey(diagnostic),
                        await context.GetSemanticModelAsync().ConfigureAwait(false),
                        context.CancellationToken);

                    CodeAction codeAction = AddParameterToInterfaceMemberRefactoring.ComputeRefactoringForExplicitImplementation(context2, memberDeclaration);

                    if (codeAction != null)
                    {
                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }
                }
            }
        }
Example #25
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindToken(root, context.Span.Start, out SyntaxToken token))
            {
                return;
            }

            SyntaxKind kind = token.Kind();

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.OperatorCannotBeAppliedToOperand:
                {
                    if (kind == SyntaxKind.QuestionToken &&
                        token.Parent is ConditionalAccessExpressionSyntax conditionalAccess)
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(conditionalAccess.Expression, context.CancellationToken);

                        if (typeSymbol?.IsErrorType() == false &&
                            !typeSymbol.IsNullableType())
                        {
                            if (typeSymbol.IsValueType)
                            {
                                if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveConditionalAccess))
                                {
                                    CodeAction codeAction = CodeAction.Create(
                                        "Remove '?' operator",
                                        ct => context.Document.WithTextChangeAsync(token.Span, "", ct),
                                        GetEquivalenceKey(diagnostic));

                                    context.RegisterCodeFix(codeAction, diagnostic);
                                }
                            }
                            else if (typeSymbol.IsReferenceType)
                            {
                                if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddArgumentList) &&
                                    conditionalAccess.WhenNotNull is MemberBindingExpressionSyntax memberBindingExpression)
                                {
                                    ConditionalAccessExpressionSyntax newNode = conditionalAccess.WithWhenNotNull(
                                        InvocationExpression(
                                            memberBindingExpression.WithoutTrailingTrivia(),
                                            ArgumentList().WithTrailingTrivia(memberBindingExpression.GetTrailingTrivia())));

                                    CodeAction codeAction = CodeAction.Create(
                                        "Add argument list",
                                        cancellationToken => context.Document.ReplaceNodeAsync(conditionalAccess, newNode, cancellationToken),
                                        GetEquivalenceKey(diagnostic));

                                    context.RegisterCodeFix(codeAction, diagnostic);
                                }
                            }
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.PartialModifierCanOnlyAppearImmediatelyBeforeClassStructInterfaceOrVoid:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.OrderModifiers))
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.MoveModifier(context, diagnostic, token.Parent, token);
                    break;
                }

                case CompilerDiagnosticIdentifiers.ValueCannotBeUsedAsDefaultParameter:
                {
                    if (!(token.Parent is ParameterSyntax parameter))
                    {
                        break;
                    }

                    ExpressionSyntax value = parameter.Default?.Value;

                    if (value == null)
                    {
                        break;
                    }

                    if (value.IsKind(SyntaxKind.NullLiteralExpression))
                    {
                        if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue))
                        {
                            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                            CodeFixRegistrator.ReplaceNullWithDefaultValue(context, diagnostic, value, semanticModel);
                        }
                    }
                    else if (!value.IsKind(SyntaxKind.DefaultExpression, SyntaxKind.DefaultLiteralExpression))
                    {
                        if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeParameterType))
                        {
                            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                            ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(value, context.CancellationToken);

                            if (!typeSymbol.IsKind(SymbolKind.ErrorType))
                            {
                                CodeFixRegistrator.ChangeType(context, diagnostic, parameter.Type, typeSymbol, semanticModel);
                            }
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ObjectOfTypeConvertibleToTypeIsRequired:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReturnDefaultValue))
                    {
                        break;
                    }

                    if (token.Kind() != SyntaxKind.ReturnKeyword)
                    {
                        break;
                    }

                    if (!token.IsParentKind(SyntaxKind.ReturnStatement))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ISymbol symbol = semanticModel.GetEnclosingSymbol(token.SpanStart, context.CancellationToken);

                    if (symbol == null)
                    {
                        break;
                    }

                    SymbolKind symbolKind = symbol.Kind;

                    ITypeSymbol typeSymbol = null;

                    if (symbolKind == SymbolKind.Method)
                    {
                        var methodSymbol = (IMethodSymbol)symbol;

                        typeSymbol = methodSymbol.ReturnType;

                        if (methodSymbol.IsAsync &&
                            (typeSymbol is INamedTypeSymbol namedTypeSymbol))
                        {
                            ImmutableArray <ITypeSymbol> typeArguments = namedTypeSymbol.TypeArguments;

                            if (typeArguments.Any())
                            {
                                typeSymbol = typeArguments[0];
                            }
                        }
                    }
                    else if (symbolKind == SymbolKind.Property)
                    {
                        typeSymbol = ((IPropertySymbol)symbol).Type;
                    }
                    else
                    {
                        Debug.Fail(symbolKind.ToString());
                    }

                    if (typeSymbol == null)
                    {
                        break;
                    }

                    if (typeSymbol.Kind == SymbolKind.ErrorType)
                    {
                        break;
                    }

                    if (!typeSymbol.SupportsExplicitDeclaration())
                    {
                        break;
                    }

                    var returnStatement = (ReturnStatementSyntax)token.Parent;

                    CodeAction codeAction = CodeAction.Create(
                        "Return default value",
                        cancellationToken =>
                        {
                            ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(context.Document.GetDefaultSyntaxOptions());

                            if (expression.IsKind(SyntaxKind.DefaultExpression) &&
                                context.Document.SupportsLanguageFeature(CSharpLanguageFeature.DefaultLiteral))
                            {
                                expression = CSharpFactory.DefaultLiteralExpression().WithTriviaFrom(expression);
                            }

                            ReturnStatementSyntax newNode = returnStatement.WithExpression(expression);

                            return(context.Document.ReplaceNodeAsync(returnStatement, newNode, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.TypeExpected:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddMissingType))
                    {
                        break;
                    }

                    if (token.Kind() != SyntaxKind.CloseParenToken)
                    {
                        break;
                    }

                    if (!(token.Parent is DefaultExpressionSyntax defaultExpression))
                    {
                        break;
                    }

                    if (!(defaultExpression.Type is IdentifierNameSyntax identifierName))
                    {
                        break;
                    }

                    if (!identifierName.IsMissing)
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    TypeInfo typeInfo = semanticModel.GetTypeInfo(defaultExpression, context.CancellationToken);

                    ITypeSymbol convertedType = typeInfo.ConvertedType;

                    if (convertedType?.SupportsExplicitDeclaration() != true)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        $"Add type '{SymbolDisplay.ToMinimalDisplayString(convertedType, semanticModel, defaultExpression.SpanStart, SymbolDisplayFormats.DisplayName)}'",
                        ct =>
                        {
                            TypeSyntax newType = convertedType.ToTypeSyntax()
                                                 .WithTriviaFrom(identifierName)
                                                 .WithFormatterAndSimplifierAnnotation();

                            return(context.Document.ReplaceNodeAsync(identifierName, newType, ct));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.SemicolonAfterMethodOrAccessorBlockIsNotValid:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveSemicolon))
                    {
                        break;
                    }

                    if (token.Kind() != SyntaxKind.SemicolonToken)
                    {
                        break;
                    }

                    switch (token.Parent)
                    {
                    case MethodDeclarationSyntax methodDeclaration:
                    {
                        BlockSyntax body = methodDeclaration.Body;

                        if (body == null)
                        {
                            break;
                        }

                        CodeAction codeAction = CodeAction.Create(
                            "Remove semicolon",
                            cancellationToken =>
                                {
                                    SyntaxTriviaList trivia = body
                                                              .GetTrailingTrivia()
                                                              .EmptyIfWhitespace()
                                                              .AddRange(token.LeadingTrivia.EmptyIfWhitespace())
                                                              .AddRange(token.TrailingTrivia);

                                    MethodDeclarationSyntax newNode = methodDeclaration
                                                                      .WithBody(body.WithTrailingTrivia(trivia))
                                                                      .WithSemicolonToken(default(SyntaxToken));

                                    return(context.Document.ReplaceNodeAsync(methodDeclaration, newNode, cancellationToken));
                                },
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                        break;
                    }

                    case PropertyDeclarationSyntax propertyDeclaration:
                    {
                        AccessorListSyntax accessorList = propertyDeclaration.AccessorList;

                        if (accessorList == null)
                        {
                            break;
                        }

                        CodeAction codeAction = CodeAction.Create(
                            "Remove semicolon",
                            cancellationToken =>
                                {
                                    SyntaxTriviaList trivia = accessorList
                                                              .GetTrailingTrivia()
                                                              .EmptyIfWhitespace()
                                                              .AddRange(token.LeadingTrivia.EmptyIfWhitespace())
                                                              .AddRange(token.TrailingTrivia);

                                    PropertyDeclarationSyntax newNode = propertyDeclaration
                                                                        .WithAccessorList(accessorList.WithTrailingTrivia(trivia))
                                                                        .WithSemicolonToken(default(SyntaxToken));

                                    return(context.Document.ReplaceNodeAsync(propertyDeclaration, newNode, cancellationToken));
                                },
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                        break;
                    }

                    case AccessorDeclarationSyntax accessorDeclaration:
                    {
                        BlockSyntax body = accessorDeclaration.Body;

                        if (body == null)
                        {
                            break;
                        }

                        CodeAction codeAction = CodeAction.Create(
                            "Remove semicolon",
                            cancellationToken =>
                                {
                                    SyntaxTriviaList trivia = body
                                                              .GetTrailingTrivia()
                                                              .EmptyIfWhitespace()
                                                              .AddRange(token.LeadingTrivia.EmptyIfWhitespace())
                                                              .AddRange(token.TrailingTrivia);

                                    AccessorDeclarationSyntax newNode = accessorDeclaration
                                                                        .WithBody(body.WithTrailingTrivia(trivia))
                                                                        .WithSemicolonToken(default(SyntaxToken));

                                    return(context.Document.ReplaceNodeAsync(accessorDeclaration, newNode, cancellationToken));
                                },
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                        break;
                    }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotConvertType:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeForEachType))
                    {
                        break;
                    }

                    if (token.Kind() != SyntaxKind.ForEachKeyword)
                    {
                        break;
                    }

                    if (!(token.Parent is ForEachStatementSyntax forEachStatement))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ForEachStatementInfo info = semanticModel.GetForEachStatementInfo(forEachStatement);

                    ITypeSymbol typeSymbol = info.ElementType;

                    if (typeSymbol.SupportsExplicitDeclaration())
                    {
                        CodeFixRegistrator.ChangeType(context, diagnostic, forEachStatement.Type, typeSymbol, semanticModel, CodeFixIdentifiers.ChangeForEachType);
                    }

                    CodeFixRegistrator.ChangeTypeToVar(context, diagnostic, forEachStatement.Type, CodeFixIdentifiers.ChangeTypeToVar);
                    break;
                }

                case CompilerDiagnosticIdentifiers.OptionalParametersMustAppearAfterAllRequiredParameters:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddDefaultValueToParameter))
                    {
                        break;
                    }

                    if (!(token.Parent is BaseParameterListSyntax parameterList))
                    {
                        break;
                    }

                    SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters;

                    ParameterSyntax parameter = null;

                    for (int i = 0; i < parameters.Count; i++)
                    {
                        ParameterSyntax p = parameters[i];

                        if (p.FullSpan.End <= token.SpanStart)
                        {
                            parameter = p;
                        }
                        else
                        {
                            break;
                        }
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    IParameterSymbol parameterSymbol = semanticModel.GetDeclaredSymbol(parameter, context.CancellationToken);

                    ITypeSymbol typeSymbol = parameterSymbol.Type;

                    if (typeSymbol.Kind == SymbolKind.ErrorType)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Add default value",
                        cancellationToken =>
                        {
                            ExpressionSyntax defaultValue = typeSymbol.GetDefaultValueSyntax(context.Document.GetDefaultSyntaxOptions());

                            ParameterSyntax newParameter = parameter
                                                           .WithDefault(EqualsValueClause(defaultValue).WithTrailingTrivia(parameter.GetTrailingTrivia()))
                                                           .WithoutTrailingTrivia()
                                                           .WithFormatterAnnotation();

                            return(context.Document.ReplaceNodeAsync(parameter, newParameter, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.AnnotationForNullableReferenceTypesShouldOnlyBeUsedWithinNullableAnnotationsContext:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveAnnotationForNullableReferenceTypes))
                    {
                        break;
                    }

                    if (!token.IsKind(SyntaxKind.QuestionToken))
                    {
                        return;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Remove 'nullable' annotation",
                        ct =>
                        {
                            var textChange = new TextChange(token.Span, "");

                            return(context.Document.WithTextChangeAsync(textChange, ct));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Example #26
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            IfStatementSyntax ifStatement = root
                                            .FindNode(context.Span, getInnermostNodeForTie: true)?
                                            .FirstAncestorOrSelf <IfStatementSyntax>();

            Debug.Assert(ifStatement != null, $"{nameof(ifStatement)} is null");

            if (ifStatement == null)
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.MergeIfStatementWithNestedIfStatement:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Merge if with nested if",
                        cancellationToken =>
                        {
                            return(MergeIfStatementWithNestedIfStatementRefactoring.RefactorAsync(
                                       context.Document,
                                       ifStatement,
                                       cancellationToken));
                        },
                        diagnostic.Id + EquivalenceKeySuffix);

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.ReplaceIfStatementWithAssignment:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Replace if with assignment",
                        cancellationToken =>
                        {
                            return(ReplaceIfStatementWithAssignmentRefactoring.RefactorAsync(
                                       context.Document,
                                       ifStatement,
                                       cancellationToken));
                        },
                        diagnostic.Id + EquivalenceKeySuffix);

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseCoalesceExpressionInsteadOfIf:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    IfRefactoring refactoring = IfRefactoring.Analyze(
                        ifStatement,
                        UseCoalesceExpressionInsteadOfIfDiagnosticAnalyzer.AnalysisOptions,
                        semanticModel,
                        context.CancellationToken).First();

                    CodeAction codeAction = CodeAction.Create(
                        refactoring.Title,
                        cancellationToken => refactoring.RefactorAsync(context.Document, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Example #27
0
        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.AvoidNullLiteralExpressionOnLeftSideOfBinaryExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Swap operands",
                        cancellationToken => DocumentRefactorings.SwapBinaryOperandsAsync(document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use 'string.IsNullOrEmpty' method",
                        ct => UseStringIsNullOrEmptyMethodAsync(document, binaryExpression, ct),
                        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.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.Default)}>.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;
                }
                }
            }
        }
Example #28
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out TypeDeclarationSyntax typeDeclaration))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.TypeDefinesEqualityOperatorButDoesNotOverrideObjectEquals:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.DefineObjectEquals))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    var typeSymbol = semanticModel.GetDeclaredSymbol(typeDeclaration, context.CancellationToken) as ITypeSymbol;

                    if (typeSymbol?.IsErrorType() != false)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Override object.Equals",
                        cancellationToken =>
                        {
                            TypeSyntax type = typeSymbol.ToMinimalTypeSyntax(semanticModel, typeDeclaration.Identifier.SpanStart);

                            MethodDeclarationSyntax methodDeclaration = ObjectEqualsMethodDeclaration(type);

                            TypeDeclarationSyntax newNode = MemberDeclarationInserter.Default.Insert(typeDeclaration, methodDeclaration);

                            return(context.Document.ReplaceNodeAsync(typeDeclaration, newNode, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.TypeDefinesEqualityOperatorButDoesNotOverrideObjectGetHashCode:
                case CompilerDiagnosticIdentifiers.TypeOverridesObjectEqualsButDoesNotOverrideObjectGetHashCode:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.DefineObjectGetHashCode))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    MethodDeclarationSyntax methodDeclaration = ObjectGetHashCodeMethodDeclaration();

                    CodeAction codeAction = CodeAction.Create(
                        "Override object.GetHashCode",
                        cancellationToken =>
                        {
                            TypeDeclarationSyntax newNode = MemberDeclarationInserter.Default.Insert(typeDeclaration, methodDeclaration);

                            return(context.Document.ReplaceNodeAsync(typeDeclaration, newNode, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Example #29
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(
                    root,
                    context.Span,
                    out SyntaxNode node,
                    predicate: f =>
            {
                switch (f.Kind())
                {
                case SyntaxKind.ParameterList:
                case SyntaxKind.BracketedParameterList:
                case SyntaxKind.TypeParameterList:
                case SyntaxKind.ArgumentList:
                case SyntaxKind.BracketedArgumentList:
                case SyntaxKind.AttributeArgumentList:
                case SyntaxKind.TypeArgumentList:
                case SyntaxKind.AttributeList:
                case SyntaxKind.BaseList:
                case SyntaxKind.TupleType:
                case SyntaxKind.TupleExpression:
                case SyntaxKind.ArrayInitializerExpression:
                case SyntaxKind.CollectionInitializerExpression:
                case SyntaxKind.ComplexElementInitializerExpression:
                case SyntaxKind.ObjectInitializerExpression:
                    return(true);

                default:
                    return(false);
                }
            }))
            {
                return;
            }

            Document   document   = context.Document;
            Diagnostic diagnostic = context.Diagnostics[0];
            CodeAction codeAction = CreateCodeAction();

            context.RegisterCodeFix(codeAction, diagnostic);

            CodeAction CreateCodeAction()
            {
                switch (node)
                {
                case ParameterListSyntax parameterList:
                {
                    return(CodeAction.Create(
                               Title,
                               ct => FixAsync(document, parameterList, parameterList.OpenParenToken, parameterList.Parameters, ct),
                               GetEquivalenceKey(diagnostic)));
                }

                case BracketedParameterListSyntax bracketedParameterList:
                {
                    return(CodeAction.Create(
                               Title,
                               ct => FixAsync(document, bracketedParameterList, bracketedParameterList.OpenBracketToken, bracketedParameterList.Parameters, ct),
                               GetEquivalenceKey(diagnostic)));
                }

                case TypeParameterListSyntax typeParameterList:
                {
                    return(CodeAction.Create(
                               Title,
                               ct => FixAsync(document, typeParameterList, typeParameterList.LessThanToken, typeParameterList.Parameters, ct),
                               GetEquivalenceKey(diagnostic)));
                }

                case ArgumentListSyntax argumentList:
                {
                    return(CodeAction.Create(
                               Title,
                               ct => FixAsync(document, argumentList, argumentList.OpenParenToken, argumentList.Arguments, ct),
                               GetEquivalenceKey(diagnostic)));
                }

                case BracketedArgumentListSyntax bracketedArgumentList:
                {
                    return(CodeAction.Create(
                               Title,
                               ct => FixAsync(document, bracketedArgumentList, bracketedArgumentList.OpenBracketToken, bracketedArgumentList.Arguments, ct),
                               GetEquivalenceKey(diagnostic)));
                }

                case AttributeArgumentListSyntax attributeArgumentList:
                {
                    return(CodeAction.Create(
                               Title,
                               ct => FixAsync(document, attributeArgumentList, attributeArgumentList.OpenParenToken, attributeArgumentList.Arguments, ct),
                               GetEquivalenceKey(diagnostic)));
                }

                case TypeArgumentListSyntax typeArgumentList:
                {
                    return(CodeAction.Create(
                               Title,
                               ct => FixAsync(document, typeArgumentList, typeArgumentList.LessThanToken, typeArgumentList.Arguments, ct),
                               GetEquivalenceKey(diagnostic)));
                }

                case AttributeListSyntax attributeList:
                {
                    return(CodeAction.Create(
                               Title,
                               ct => FixAsync(document, attributeList, attributeList.OpenBracketToken, attributeList.Attributes, ct),
                               GetEquivalenceKey(diagnostic)));
                }

                case BaseListSyntax baseList:
                {
                    return(CodeAction.Create(
                               Title,
                               ct => FixAsync(document, baseList, baseList.ColonToken, baseList.Types, ct),
                               GetEquivalenceKey(diagnostic)));
                }

                case TupleTypeSyntax tupleType:
                {
                    return(CodeAction.Create(
                               Title,
                               ct => FixAsync(document, tupleType, tupleType.OpenParenToken, tupleType.Elements, ct),
                               GetEquivalenceKey(diagnostic)));
                }

                case TupleExpressionSyntax tupleExpression:
                {
                    return(CodeAction.Create(
                               Title,
                               ct => FixAsync(document, tupleExpression, tupleExpression.OpenParenToken, tupleExpression.Arguments, ct),
                               GetEquivalenceKey(diagnostic)));
                }

                case InitializerExpressionSyntax initializerExpression:
                {
                    return(CodeAction.Create(
                               Title,
                               ct => FixAsync(document, initializerExpression, initializerExpression.OpenBraceToken, initializerExpression.Expressions, ct),
                               GetEquivalenceKey(diagnostic)));
                }

                default:
                {
                    throw new InvalidOperationException();
                }
                }
            }
        }
Example #30
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindToken(root, context.Span.Start, out SyntaxToken token))
            {
                return;
            }

            SyntaxNode node = token.Parent;

            if (!CSharpFacts.CanHaveModifiers(node.Kind()))
            {
                node = node.FirstAncestor(f => CSharpFacts.CanHaveModifiers(f.Kind()));
            }

            Debug.Assert(node != null, $"{nameof(node)} is null");

            if (node == null)
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.ModifierIsNotValidForThisItem:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    SyntaxTokenList modifiers = SyntaxInfo.ModifierListInfo(node).Modifiers;

                    if (modifiers.Contains(token))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, token);
                        break;
                    }
                    else if (IsInterfaceMemberOrExplicitInterfaceImplementation(node))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifiers(
                            context,
                            diagnostic,
                            node,
                            modifiers,
                            f =>
                            {
                                switch (f.Kind())
                                {
                                case SyntaxKind.PublicKeyword:
                                case SyntaxKind.ProtectedKeyword:
                                case SyntaxKind.InternalKeyword:
                                case SyntaxKind.PrivateKeyword:
                                case SyntaxKind.StaticKeyword:
                                case SyntaxKind.VirtualKeyword:
                                case SyntaxKind.OverrideKeyword:
                                case SyntaxKind.AbstractKeyword:
                                    {
                                        return(true);
                                    }
                                }

                                return(false);
                            });
                    }
                    else if (node.IsKind(SyntaxKind.MethodDeclaration, SyntaxKind.PropertyDeclaration, SyntaxKind.IndexerDeclaration, SyntaxKind.EventDeclaration, SyntaxKind.EventFieldDeclaration) &&
                             node.IsParentKind(SyntaxKind.StructDeclaration) &&
                             modifiers.Contains(SyntaxKind.VirtualKeyword))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.VirtualKeyword);
                    }
                    else if (node.IsKind(SyntaxKind.IndexerDeclaration) &&
                             modifiers.Contains(SyntaxKind.StaticKeyword))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword);
                    }
                    else if (node.IsKind(SyntaxKind.PropertyDeclaration, SyntaxKind.IndexerDeclaration, SyntaxKind.EventDeclaration, SyntaxKind.EventFieldDeclaration) &&
                             modifiers.Contains(SyntaxKind.AsyncKeyword))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AsyncKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.MoreThanOneProtectionModifier:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, token);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.AccessibilityModifiersMayNotBeUsedOnAccessorsInInterface:
                case CompilerDiagnosticIdentifiers.AccessModifiersAreNotAllowedOnStaticConstructors:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveAccessibility(context, diagnostic, node);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ModifiersCannotBePlacedOnEventAccessorDeclarations:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifiers(context, diagnostic, node);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.OnlyMethodsClassesStructsOrInterfacesMayBePartial:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.PartialKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ClassCannotBeBothStaticAndSealed:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword, additionalKey: nameof(SyntaxKind.StaticKeyword));
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.SealedKeyword, additionalKey: nameof(SyntaxKind.SealedKeyword));
                    break;
                }

                case CompilerDiagnosticIdentifiers.FieldCanNotBeBothVolatileAndReadOnly:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    var fieldDeclaration = (FieldDeclarationSyntax)node;

                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, fieldDeclaration, SyntaxKind.VolatileKeyword, additionalKey: nameof(SyntaxKind.VolatileKeyword));
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, fieldDeclaration, SyntaxKind.ReadOnlyKeyword, additionalKey: nameof(SyntaxKind.ReadOnlyKeyword));
                    break;
                }

                case CompilerDiagnosticIdentifiers.NewProtectedMemberDeclaredInSealedClass:
                case CompilerDiagnosticIdentifiers.StaticClassesCannotContainProtectedMembers:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrPrivate);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.VirtualOrAbstractMembersCannotBePrivate:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveVirtualModifier))
                    {
                        ModifierListInfo modifierInfo = SyntaxInfo.ModifierListInfo(node);

                        if (modifierInfo.IsVirtual)
                        {
                            ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.VirtualKeyword, additionalKey: nameof(SyntaxKind.VirtualKeyword));
                        }
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrProtected);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.AbstractPropertiesCannotHavePrivateAccessors:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveAccessibility(context, diagnostic, node, additionalKey: CodeFixIdentifiers.RemoveInvalidModifier);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrProtected);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.StaticMemberCannotBeMarkedOverrideVirtualOrAbstract:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    if (!node.IsParentKind(SyntaxKind.ClassDeclaration) ||
                        !((ClassDeclarationSyntax)node.Parent).Modifiers.Contains(SyntaxKind.StaticKeyword))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword, additionalKey: nameof(SyntaxKind.StaticKeyword));
                    }

                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OverrideKeyword, additionalKey: nameof(SyntaxKind.OverrideKeyword));
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.VirtualKeyword, additionalKey: nameof(SyntaxKind.VirtualKeyword));
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AbstractKeyword, additionalKey: nameof(SyntaxKind.AbstractKeyword));
                    break;
                }

                case CompilerDiagnosticIdentifiers.AsyncModifierCanOnlyBeUsedInMethodsThatHaveBody:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AsyncKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.PartialMethodCannotHaveAccessModifiersOrVirtualAbstractOverrideNewSealedOrExternModifiers:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.RemoveModifiers(
                        context,
                        diagnostic,
                        node,
                        f =>
                        {
                            switch (f.Kind())
                            {
                            case SyntaxKind.PublicKeyword:
                            case SyntaxKind.ProtectedKeyword:
                            case SyntaxKind.InternalKeyword:
                            case SyntaxKind.PrivateKeyword:
                            case SyntaxKind.VirtualKeyword:
                            case SyntaxKind.AbstractKeyword:
                            case SyntaxKind.OverrideKeyword:
                            case SyntaxKind.NewKeyword:
                            case SyntaxKind.SealedKeyword:
                            case SyntaxKind.ExternKeyword:
                                {
                                    return(true);
                                }
                            }

                            return(false);
                        });

                    break;
                }

                case CompilerDiagnosticIdentifiers.ExtensionMethodMustBeStatic:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddStaticModifier))
                    {
                        AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveThisModifier))
                    {
                        var methodDeclaration = (MethodDeclarationSyntax)node;

                        ParameterSyntax parameter = methodDeclaration.ParameterList.Parameters[0];

                        SyntaxToken modifier = parameter.Modifiers.Find(SyntaxKind.ThisKeyword);

                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, parameter, modifier, additionalKey: CodeFixIdentifiers.RemoveThisModifier);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ExtensionMethodMustBeDefinedInNonGenericStaticClass:
                {
                    if (!(node is ClassDeclarationSyntax classDeclaration))
                    {
                        return;
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddStaticModifier) &&
                        !classDeclaration.Modifiers.Contains(SyntaxKind.StaticKeyword))
                    {
                        AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveThisModifier))
                    {
                        IEnumerable <ParameterSyntax> thisParameters = classDeclaration.Members
                                                                       .Where(f => f.IsKind(SyntaxKind.MethodDeclaration))
                                                                       .Cast <MethodDeclarationSyntax>()
                                                                       .Select(f => f.ParameterList?.Parameters.FirstOrDefault())
                                                                       .Where(f => f?.Modifiers.Contains(SyntaxKind.ThisKeyword) == true);

                        ModifiersCodeFixRegistrator.RemoveModifier(
                            context,
                            diagnostic,
                            thisParameters,
                            SyntaxKind.ThisKeyword,
                            title: "Remove 'this' modifier from extension methods",
                            additionalKey: CodeFixIdentifiers.RemoveThisModifier);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NoDefiningDeclarationFoundForImplementingDeclarationOfPartialMethod:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.PartialKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.MethodHasParameterModifierThisWhichIsNotOnFirstParameter:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveThisModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, token.Parent, token);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotDeclareInstanceMembersInStaticClass:
                case CompilerDiagnosticIdentifiers.StaticClassesCannotHaveInstanceConstructors:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddStaticModifier))
                    {
                        AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MakeContainingClassNonStatic))
                    {
                        var classDeclaration = (ClassDeclarationSyntax)node.Parent;

                        ModifiersCodeFixRegistrator.RemoveModifier(
                            context,
                            diagnostic,
                            classDeclaration,
                            classDeclaration.Modifiers.Find(SyntaxKind.StaticKeyword),
                            title: "Make containing class non-static",
                            additionalKey: CodeFixIdentifiers.MakeContainingClassNonStatic);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ElementsDefinedInNamespaceCannotBeExplicitlyDeclaredAsPrivateProtectedOrProtectedInternal:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternal);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NamespaceAlreadyContainsDefinition:
                case CompilerDiagnosticIdentifiers.TypeAlreadyContainsDefinition:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddPartialModifier))
                    {
                        break;
                    }

                    if (!node.IsKind(
                            SyntaxKind.ClassDeclaration,
                            SyntaxKind.StructDeclaration,
                            SyntaxKind.InterfaceDeclaration,
                            SyntaxKind.MethodDeclaration))
                    {
                        return;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ISymbol symbol = semanticModel.GetDeclaredSymbol(node, context.CancellationToken);

                    ImmutableArray <SyntaxReference> syntaxReferences = symbol.DeclaringSyntaxReferences;

                    if (syntaxReferences.Length <= 1)
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.AddModifier(
                        context,
                        diagnostic,
                        ImmutableArray.CreateRange(syntaxReferences, f => f.GetSyntax(context.CancellationToken)),
                        SyntaxKind.PartialKeyword,
                        title: $"Make {CSharpFacts.GetTitle(node)} partial");

                    break;
                }

                case CompilerDiagnosticIdentifiers.NoSuitableMethodFoundToOverride:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OverrideKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.AsyncMethodsCannotHaveRefOrOutParameters:
                case CompilerDiagnosticIdentifiers.IteratorsCannotHaveRefOrOutParameters:
                case CompilerDiagnosticIdentifiers.ReadOnlyFieldCannotBePassedAsRefOrOutValue:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveRefModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.RefKeyword, additionalKey: nameof(SyntaxKind.RefKeyword));
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveOutModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OutKeyword, additionalKey: nameof(SyntaxKind.OutKeyword));
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotHaveInstancePropertyOrFieldInitializersInStruct:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddStaticModifier))
                    {
                        AddStaticModifier(context, diagnostic, node);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.MemberMustDeclareBodyBecauseItIsNotMarkedAbstractExternOrPartial:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddModifierAbstract) &&
                        node.Kind() == SyntaxKind.MethodDeclaration &&
                        (node.Parent as ClassDeclarationSyntax)?.Modifiers.Contains(SyntaxKind.AbstractKeyword) == true)
                    {
                        ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.AbstractKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NewVirtualMemberInSealedClass:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveVirtualModifier))
                    {
                        if (node is AccessorDeclarationSyntax &&
                            SyntaxInfo.ModifierListInfo(node.Parent.Parent).IsVirtual)
                        {
                            node = node.Parent.Parent;
                        }

                        ModifiersCodeFixRegistrator.RemoveModifier(
                            context,
                            diagnostic,
                            node,
                            SyntaxKind.VirtualKeyword,
                            additionalKey: CodeFixIdentifiers.RemoveVirtualModifier);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MakeContainingClassUnsealed) &&
                        node.Parent is ClassDeclarationSyntax classDeclaration)
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(
                            context,
                            diagnostic,
                            classDeclaration,
                            SyntaxKind.SealedKeyword,
                            title: "Make containing class unsealed",
                            additionalKey: CodeFixIdentifiers.MakeContainingClassUnsealed);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.InstanceFieldsOfReadOnlyStructsMustBeReadOnly:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MakeMemberReadOnly))
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.ReadOnlyKeyword);
                    break;
                }

                case CompilerDiagnosticIdentifiers.MemberCannotBeSealedBecauseItIsNotOverride:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveSealedModifier))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    if (semanticModel.GetDiagnostic(
                            CompilerDiagnosticIdentifiers.MemberHidesInheritedMemberToMakeCurrentMethodOverrideThatImplementationAddOverrideKeyword,
                            CSharpUtility.GetIdentifier(node).Span,
                            context.CancellationToken) != null)
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.SealedKeyword);
                    break;
                }
                }
            }
        }