public sealed 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 DiagnosticIdentifiers.RemoveRedundantOverridingMember:
                {
                    CodeAction codeAction = CodeActionFactory.RemoveMemberDeclaration(context.Document, memberDeclaration, equivalenceKey: GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.AddAccessibilityModifiersOrViceVersa:
                {
                    if (diagnostic.Properties.TryGetValue(nameof(Accessibility), out string accessibilityText))
                    {
                        var accessibility = (Accessibility)Enum.Parse(typeof(Accessibility), accessibilityText);

                        CodeAction codeAction = CodeAction.Create(
                            "Add accessibility modifiers",
                            ct =>
                            {
                                MemberDeclarationSyntax newNode = SyntaxAccessibility.WithExplicitAccessibility(memberDeclaration, accessibility);

                                return(context.Document.ReplaceNodeAsync(memberDeclaration, newNode, ct));
                            },
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }
                    else
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Remove accessibility modifiers",
                            ct =>
                            {
                                MemberDeclarationSyntax newNode = SyntaxAccessibility.WithoutExplicitAccessibility(memberDeclaration);

                                return(context.Document.ReplaceNodeAsync(memberDeclaration, newNode, ct));
                            },
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }

                case DiagnosticIdentifiers.RemoveRedundantSealedModifier:
                {
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, memberDeclaration, SyntaxKind.SealedKeyword);
                    break;
                }

                case DiagnosticIdentifiers.AvoidSemicolonAtEndOfDeclaration:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove unnecessary semicolon",
                        cancellationToken => AvoidSemicolonAtEndOfDeclarationRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.OrderModifiers:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Order modifiers",
                        ct => OrderModifiersAsync(context.Document, memberDeclaration, ct),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.MakeFieldReadOnly:
                {
                    var fieldDeclaration = (FieldDeclarationSyntax)memberDeclaration;

                    SeparatedSyntaxList <VariableDeclaratorSyntax> declarators = fieldDeclaration.Declaration.Variables;

                    string title = (declarators.Count == 1)
                                ? $"Make '{declarators[0].Identifier.ValueText}' read-only"
                                : "Make fields read-only";

                    ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, fieldDeclaration, SyntaxKind.ReadOnlyKeyword, title: title);
                    break;
                }

                case DiagnosticIdentifiers.UseConstantInsteadOfField:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use constant instead of field",
                        cancellationToken => UseConstantInsteadOfFieldRefactoring.RefactorAsync(context.Document, (FieldDeclarationSyntax)memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseReadOnlyAutoProperty:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use read-only auto-property",
                        cancellationToken => UseReadOnlyAutoPropertyRefactoring.RefactorAsync(context.Document, (PropertyDeclarationSyntax)memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.ConvertCommentToDocumentationComment:
                {
                    CodeAction codeAction = CodeAction.Create(
                        ConvertCommentToDocumentationCommentRefactoring.Title,
                        cancellationToken => ConvertCommentToDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, context.Span, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.MakeMethodExtensionMethod:
                {
                    var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration;

                    CodeAction codeAction = CodeAction.Create(
                        "Make method an extension method",
                        cancellationToken =>
                        {
                            ParameterSyntax parameter = methodDeclaration.ParameterList.Parameters[0];

                            ParameterSyntax newParameter = ModifierList.Insert(parameter, SyntaxKind.ThisKeyword);

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

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Beispiel #2
0
        public sealed 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 DiagnosticIdentifiers.FormatDeclarationBraces:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Format braces",
                        cancellationToken => FormatDeclarationBracesRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.RemoveRedundantOverridingMember:
                {
                    CodeAction codeAction = CodeAction.Create(
                        $"Remove {memberDeclaration.GetTitle()}",
                        cancellationToken => context.Document.RemoveMemberAsync(memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.AddDefaultAccessModifier:
                {
                    var accessibility = (Accessibility)Enum.Parse(
                        typeof(Accessibility),
                        context.Diagnostics[0].Properties[nameof(Accessibility)]);

                    CodeAction codeAction = CodeAction.Create(
                        "Add default access modifier",
                        cancellationToken => AddDefaultAccessModifierRefactoring.RefactorAsync(context.Document, memberDeclaration, accessibility, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.AddEmptyLineBetweenDeclarations:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Add empty line",
                        cancellationToken => AddEmptyLineBetweenDeclarationsRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.RemoveRedundantSealedModifier:
                {
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, memberDeclaration, SyntaxKind.SealedKeyword);
                    break;
                }

                case DiagnosticIdentifiers.AvoidSemicolonAtEndOfDeclaration:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove unnecessary semicolon",
                        cancellationToken => AvoidSemicolonAtEndOfDeclarationRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.ReorderModifiers:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Reorder modifiers",
                        cancellationToken => ReorderModifiersRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.MarkFieldAsReadOnly:
                {
                    var fieldDeclaration = (FieldDeclarationSyntax)memberDeclaration;

                    SeparatedSyntaxList <VariableDeclaratorSyntax> declarators = fieldDeclaration.Declaration.Variables;

                    string title = (declarators.Count == 1)
                                ? $"Mark '{declarators[0].Identifier.ValueText}' as read-only"
                                : "Mark fields as read-only";

                    ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, fieldDeclaration, SyntaxKind.ReadOnlyKeyword, title: title);
                    break;
                }

                case DiagnosticIdentifiers.UseConstantInsteadOfField:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use constant instead of field",
                        cancellationToken => UseConstantInsteadOfFieldRefactoring.RefactorAsync(context.Document, (FieldDeclarationSyntax)memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseReadOnlyAutoProperty:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use read-only auto-property",
                        cancellationToken => UseReadOnlyAutoPropertyRefactoring.RefactorAsync(context.Document, (PropertyDeclarationSyntax)memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.ReplaceCommentWithDocumentationComment:
                {
                    CodeAction codeAction = CodeAction.Create(
                        ReplaceCommentWithDocumentationCommentRefactoring.Title,
                        cancellationToken => ReplaceCommentWithDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            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 DiagnosticIdentifiers.FormatDeclarationBraces:
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Format braces",
                                cancellationToken => FormatDeclarationBracesRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                                diagnostic.Id + EquivalenceKeySuffix);

                            context.RegisterCodeFix(codeAction, diagnostic);
                            break;
                        }
                    case DiagnosticIdentifiers.MarkMemberAsStatic:
                        {
                            CodeAction codeAction = CodeAction.Create(
                                $"Mark {memberDeclaration.GetTitle()} as static",
                                cancellationToken => MarkMemberAsStaticRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                                diagnostic.Id + EquivalenceKeySuffix);

                            context.RegisterCodeFix(codeAction, diagnostic);
                            break;
                        }
                    case DiagnosticIdentifiers.AddDocumentationComment:
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Add documentation comment",
                                cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, false, cancellationToken),
                                diagnostic.Id + EquivalenceKeySuffix);

                            context.RegisterCodeFix(codeAction, diagnostic);

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

                            context.RegisterCodeFix(codeAction2, diagnostic);
                            break;
                        }
                    case DiagnosticIdentifiers.RemoveRedundantOverridingMember:
                        {
                            CodeAction codeAction = CodeAction.Create(
                                $"Remove redundant overridding {memberDeclaration.GetTitle()}",
                                cancellationToken => Remover.RemoveMemberAsync(context.Document, memberDeclaration, cancellationToken),
                                diagnostic.Id + EquivalenceKeySuffix);

                            context.RegisterCodeFix(codeAction, diagnostic);
                            break;
                        }
                    case DiagnosticIdentifiers.MarkContainingClassAsAbstract:
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Mark containing class as abstract",
                                cancellationToken => MarkContainingClassAsAbstractRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                                diagnostic.Id + EquivalenceKeySuffix);

                            context.RegisterCodeFix(codeAction, diagnostic);
                            break;
                        }
                    case DiagnosticIdentifiers.MemberTypeMustMatchOverriddenMemberType:
                        {
                            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                            ITypeSymbol typeSymbol = null;

                            switch (memberDeclaration.Kind())
                            {
                                case SyntaxKind.MethodDeclaration:
                                    {
                                        var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken);
                                        typeSymbol = methodSymbol.OverriddenMethod.ReturnType;
                                        break;
                                    }
                                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;
                                    }
                            }

                            int position = memberDeclaration.SpanStart;

                            TypeSyntax newType = typeSymbol.ToMinimalTypeSyntax(semanticModel, position);

                            string title = (memberDeclaration.IsKind(SyntaxKind.MethodDeclaration))
                                ? "Change return type to "
                                : "Change type to ";

                            title += $"'{SymbolDisplay.GetMinimalString(typeSymbol, semanticModel, position)}'";

                            CodeAction codeAction = CodeAction.Create(
                                title,
                                cancellationToken => MemberTypeMustMatchOverriddenMemberTypeRefactoring.RefactorAsync(context.Document, memberDeclaration, newType, cancellationToken),
                                diagnostic.Id + EquivalenceKeySuffix);

                            context.RegisterCodeFix(codeAction, diagnostic);
                            break;
                        }
                    case DiagnosticIdentifiers.AddDefaultAccessModifier:
                        {
                            var accessibility = (Accessibility)Enum.Parse(
                                typeof(Accessibility),
                                context.Diagnostics[0].Properties[nameof(Accessibility)]);

                            CodeAction codeAction = CodeAction.Create(
                                "Add default access modifier",
                                cancellationToken => AddDefaultAccessModifierRefactoring.RefactorAsync(context.Document, memberDeclaration, accessibility, cancellationToken),
                                diagnostic.Id + EquivalenceKeySuffix);

                            context.RegisterCodeFix(codeAction, diagnostic);
                            break;
                        }
                    case DiagnosticIdentifiers.AddEmptyLineBetweenDeclarations:
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Add empty line",
                                cancellationToken => AddEmptyLineBetweenDeclarationsRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                                diagnostic.Id + EquivalenceKeySuffix);

                            context.RegisterCodeFix(codeAction, diagnostic);
                            break;
                        }
                    case DiagnosticIdentifiers.RemoveRedundantSealedModifier:
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Remove sealed modifier",
                                cancellationToken => RemoveRedundantSealedModifierRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                                diagnostic.Id + EquivalenceKeySuffix);

                            context.RegisterCodeFix(codeAction, diagnostic);
                            break;
                        }
                    case DiagnosticIdentifiers.AvoidSemicolonAtEndOfDeclaration:
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Remove unnecessary semicolon",
                                cancellationToken => AvoidSemicolonAtEndOfDeclarationRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                                diagnostic.Id + EquivalenceKeySuffix);

                            context.RegisterCodeFix(codeAction, diagnostic);
                            break;
                        }
                    case DiagnosticIdentifiers.ReorderModifiers:
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Reorder modifiers",
                                cancellationToken => ReorderModifiersRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                                diagnostic.Id + EquivalenceKeySuffix);

                            context.RegisterCodeFix(codeAction, diagnostic);
                            break;
                        }
                    case DiagnosticIdentifiers.OverridingMemberCannotChangeAccessModifiers:
                        {
                            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                            OverrideInfo overrideInfo = OverridingMemberCannotChangeAccessModifiersRefactoring.GetOverrideInfo(memberDeclaration, semanticModel, context.CancellationToken);

                            string title = $"Change accessibility to '{OverridingMemberCannotChangeAccessModifiersRefactoring.GetAccessibilityText(overrideInfo.OverridenSymbol.DeclaredAccessibility)}'";

                            CodeAction codeAction = CodeAction.Create(
                                title,
                                cancellationToken => OverridingMemberCannotChangeAccessModifiersRefactoring.RefactorAsync(context.Document, memberDeclaration, overrideInfo, cancellationToken),
                                diagnostic.Id + EquivalenceKeySuffix);

                            context.RegisterCodeFix(codeAction, diagnostic);
                            break;
                        }
                    case DiagnosticIdentifiers.MarkFieldAsReadOnly:
                        {
                            var fieldDeclaration = (FieldDeclarationSyntax)memberDeclaration;

                            SeparatedSyntaxList<VariableDeclaratorSyntax> declarators = fieldDeclaration.Declaration.Variables;

                            string title = (declarators.Count == 1)
                                ? $"Mark '{declarators[0].Identifier.ValueText}' as read-only"
                                : "Mark fields as read-only";

                            CodeAction codeAction = CodeAction.Create(
                                title,
                                cancellationToken => MarkFieldAsReadOnlyRefactoring.RefactorAsync(context.Document, fieldDeclaration, cancellationToken),
                                diagnostic.Id + EquivalenceKeySuffix);

                            context.RegisterCodeFix(codeAction, diagnostic);
                            break;
                        }
                    case DiagnosticIdentifiers.UseReadOnlyAutoProperty:
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Use read-only auto-property",
                                cancellationToken => UseReadOnlyAutoPropertyRefactoring.RefactorAsync(context.Document, (PropertyDeclarationSyntax)memberDeclaration, cancellationToken),
                                diagnostic.Id + EquivalenceKeySuffix);

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