AbstractRemoveUnusedVariableCodeFixProvider.cs 5.3 KB
Newer Older
S
Stefan Nikolei 已提交
1 2 3 4 5 6 7 8
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
C
CyrusNajmabadi 已提交
9
using Microsoft.CodeAnalysis.CodeFixes;
S
Stefan Nikolei 已提交
10
using Microsoft.CodeAnalysis.Editing;
11
using Microsoft.CodeAnalysis.Formatting;
12
using Microsoft.CodeAnalysis.LanguageServices;
S
Stefan Nikolei 已提交
13 14 15
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;

C
CyrusNajmabadi 已提交
16
namespace Microsoft.CodeAnalysis.RemoveUnusedVariable
S
Stefan Nikolei 已提交
17 18
{
    internal abstract class AbstractRemoveUnusedVariableCodeFixProvider<TLocalDeclarationStatement, TVariableDeclarator, TVariableDeclaration> : SyntaxEditorBasedCodeFixProvider
19 20 21
        where TLocalDeclarationStatement : SyntaxNode
        where TVariableDeclarator : SyntaxNode
        where TVariableDeclaration : SyntaxNode
S
Stefan Nikolei 已提交
22
    {
23 24
        protected abstract bool IsCatchDeclarationIdentifier(SyntaxToken token);

S
Stefan Nikolei 已提交
25 26 27 28
        public async override Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            foreach (var diagnostic in context.Diagnostics)
            {
29
                var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
S
Stefan Nikolei 已提交
30
                var token = root.FindToken(diagnostic.Location.SourceSpan.Start);
31
                if (!IsCatchDeclarationIdentifier(token))
S
Stefan Nikolei 已提交
32
                {
33 34 35 36 37 38
                    var ancestor = token.GetAncestor<TLocalDeclarationStatement>();

                    if (ancestor == null)
                    {
                        return;
                    }
S
Stefan Nikolei 已提交
39 40 41 42 43 44 45 46 47 48
                }
            }

            context.RegisterCodeFix(
                new MyCodeAction(c => FixAsync(context.Document, context.Diagnostics.First(), c)),
                context.Diagnostics);
        }

        protected override Task FixAllAsync(Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken)
        {
49
            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
S
Stefan Nikolei 已提交
50 51 52
            var root = editor.OriginalRoot;
            foreach (var diagnostic in diagnostics)
            {
53 54
                var token = diagnostic.Location.FindToken(cancellationToken);
                if (IsCatchDeclarationIdentifier(token))
S
Stefan Nikolei 已提交
55
                {
56 57 58
                    editor.ReplaceNode(
                        token.Parent,
                        token.Parent.ReplaceToken(token, default(SyntaxToken)).WithAdditionalAnnotations(Formatter.Annotation));
S
Stefan Nikolei 已提交
59
                }
60
                else
S
Stefan Nikolei 已提交
61
                {
62 63 64 65 66
                    var variableDeclarator = token.GetAncestor<TVariableDeclarator>();
                    var variableDeclarators = token.GetAncestor<TVariableDeclaration>().ChildNodes().Where(x => x is TVariableDeclarator);

                    if (variableDeclarators.Count() == 1)
                    {
67 68 69 70 71 72 73
                        var localDeclaration = token.GetAncestor<TLocalDeclarationStatement>();
                        var removeOptions = SyntaxGenerator.DefaultRemoveOptions;

                        if (localDeclaration.GetLeadingTrivia().Contains(t => t.IsDirective))
                        {
                            removeOptions |= SyntaxRemoveOptions.KeepLeadingTrivia;
                        }
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
                        else
                        {
                            var statementParent = localDeclaration.Parent;
                            if (syntaxFacts.IsExecutableBlock(statementParent))
                            {
                                var siblings = syntaxFacts.GetExecutableBlockStatements(statementParent);
                                var localDeclarationIndex = siblings.IndexOf(localDeclaration);
                                if (localDeclarationIndex != 0)
                                {
                                    // if we're removing hte first statement in a block, then we
                                    // want to have the elastic marker on it so that the next statement
                                    // properly formats with the space left behind.  But if it's
                                    // not the first statement then just keep the trivia as is
                                    // so that the statement before and after it stay appropriately
                                    // spaced apart.
                                    removeOptions &= ~SyntaxRemoveOptions.AddElasticMarker;
                                }
                            }
                        }
93 94

                        editor.RemoveNode(localDeclaration, removeOptions);
95 96 97 98 99
                    }
                    else if (variableDeclarators.Count() > 1)
                    {
                        editor.RemoveNode(variableDeclarator);
                    }
S
Stefan Nikolei 已提交
100 101
                }
            }
C
CyrusNajmabadi 已提交
102

S
Stefan Nikolei 已提交
103 104 105 106 107 108
            return SpecializedTasks.EmptyTask;
        }

        private class MyCodeAction : CodeAction.DocumentChangeAction
        {
            public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument) :
S
Stefan Nikolei 已提交
109
                base(FeaturesResources.Remove_unused_variable, createChangedDocument, FeaturesResources.Remove_unused_variable)
S
Stefan Nikolei 已提交
110 111 112 113
            {
            }
        }
    }
114
}