SymbolReference.cs 5.1 KB
Newer Older
C
Cyrus Najmabadi 已提交
1 2 3
// 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;
4
using System.Collections.Immutable;
5 6 7
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
8
using Microsoft.CodeAnalysis.Text;
9
using Roslyn.Utilities;
10

11
namespace Microsoft.CodeAnalysis.AddImport
12
{
13
    internal abstract partial class AbstractAddImportCodeFixProvider<TSimpleNameSyntax>
14
    {
15
        private abstract partial class SymbolReference : Reference
16
        {
17
            public readonly SymbolResult<INamespaceOrTypeSymbol> SymbolResult;
18

19 20 21 22 23
            protected abstract bool ShouldAddWithExistingImport(Document document);

            public SymbolReference(
                AbstractAddImportCodeFixProvider<TSimpleNameSyntax> provider,
                SymbolResult<INamespaceOrTypeSymbol> symbolResult)
24
                : base(provider, new SearchResult(symbolResult))
25
            {
26
                this.SymbolResult = symbolResult;
27 28
            }

29
            protected abstract ImmutableArray<string> GetTags(Document document);
30

31 32
            public override bool Equals(object obj)
            {
33 34 35 36 37
                var equals = base.Equals(obj);
                if (!equals)
                {
                    return false;
                }
38

39 40 41
                var name1 = this.SymbolResult.DesiredName;
                var name2 = (obj as SymbolReference)?.SymbolResult.DesiredName;
                return StringComparer.Ordinal.Equals(name1, name2);
42 43 44
            }

            public override int GetHashCode()
45
                => Hash.Combine(this.SymbolResult.DesiredName, base.GetHashCode());
C
CyrusNajmabadi 已提交
46

47
            private async Task<ImmutableArray<TextChange>> GetTextChangesAsync(
48 49 50
                Document document, SyntaxNode contextNode, 
                bool placeSystemNamespaceFirst, bool hasExistingImport,
                CancellationToken cancellationToken)
51
            {
52
                // Defer to the language to add the actual import/using.
53 54
                if (hasExistingImport)
                {
55
                    return ImmutableArray<TextChange>.Empty;
56 57
                }

58 59 60
                (var newContextNode, var newDocument) = await ReplaceNameNodeAsync(
                    contextNode, document, cancellationToken).ConfigureAwait(false);

61
                var updatedDocument = await provider.AddImportAsync(
62 63
                    newContextNode, this.SymbolResult.Symbol, newDocument, 
                    placeSystemNamespaceFirst, cancellationToken).ConfigureAwait(false);
64 65 66 67 68 69 70 71

                var cleanedDocument = await CodeAction.CleanupDocumentAsync(
                    updatedDocument, cancellationToken).ConfigureAwait(false);

                var textChanges = await cleanedDocument.GetTextChangesAsync(
                    document, cancellationToken).ConfigureAwait(false);

                return textChanges.ToImmutableArray();
72
            }
73

74
            public sealed override async Task<AddImportFixData> GetFixDataAsync(
C
CyrusNajmabadi 已提交
75 76
                Document document, SyntaxNode node,
                bool placeSystemNamespaceFirst, CancellationToken cancellationToken)
77
            {
78
                var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
79
                var (description, hasExistingImport) = GetDescription(document, node, semanticModel, cancellationToken);
80
                if (description == null)
81 82 83 84
                {
                    return null;
                }

85 86 87 88 89
                if (hasExistingImport && !this.ShouldAddWithExistingImport(document))
                {
                    return null;
                }

90 91 92 93 94 95 96
                if (!this.SearchResult.DesiredNameMatchesSourceName(document))
                {
                    // The name is going to change.  Make it clear in the description that 
                    // this is going to happen.
                    description = $"{this.SearchResult.DesiredName} - {description}";
                }

97
                var textChanges = await GetTextChangesAsync(
98
                    document, node, placeSystemNamespaceFirst, hasExistingImport, cancellationToken).ConfigureAwait(false);
99

100
                return GetFixData(
101 102
                    document, textChanges.ToImmutableArray(), description,
                    GetTags(document), GetPriority(document));
103 104
            }

105
            protected abstract AddImportFixData GetFixData(
106 107 108 109 110
                Document document, ImmutableArray<TextChange> textChanges, 
                string description, ImmutableArray<string> tags, CodeActionPriority priority);

            protected abstract CodeActionPriority GetPriority(Document document);

111 112
            protected virtual (string description, bool hasExistingImport) GetDescription(
                Document document, SyntaxNode node,
C
CyrusNajmabadi 已提交
113
                SemanticModel semanticModel, CancellationToken cancellationToken)
114
            {
115 116
                return provider.GetDescription(
                    document, SymbolResult.Symbol, semanticModel, node, cancellationToken);
117 118
            }
        }
119
    }
C
CyrusNajmabadi 已提交
120
}