IDefinitionsAndReferencesFactory.cs 8.6 KB
Newer Older
1 2
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

3
using System.Collections.Immutable;
4
using System.Composition;
C
CyrusNajmabadi 已提交
5
using System.Diagnostics;
6
using System.Threading;
7
using System.Threading.Tasks;
8
using Microsoft.CodeAnalysis.Completion;
9
using Microsoft.CodeAnalysis.Features.RQName;
10
using Microsoft.CodeAnalysis.FindSymbols;
11
using Microsoft.CodeAnalysis.FindUsages;
12 13 14 15
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Shared.Extensions;

16
namespace Microsoft.CodeAnalysis.Editor.FindUsages
17 18 19
{
    internal interface IDefinitionsAndReferencesFactory : IWorkspaceService
    {
20
        DefinitionItem GetThirdPartyDefinitionItem(
21
            Solution solution, DefinitionItem definitionItem, CancellationToken cancellationToken);
22 23 24 25 26
    }

    [ExportWorkspaceService(typeof(IDefinitionsAndReferencesFactory)), Shared]
    internal class DefaultDefinitionsAndReferencesFactory : IDefinitionsAndReferencesFactory
    {
C
CyrusNajmabadi 已提交
27 28 29 30
        /// <summary>
        /// Provides an extension point that allows for other workspace layers to add additional
        /// results to the results found by the FindReferences engine.
        /// </summary>
31
        public virtual DefinitionItem GetThirdPartyDefinitionItem(
32
            Solution solution, DefinitionItem definitionItem, CancellationToken cancellationToken)
33 34 35
        {
            return null;
        }
36
    }
37

38 39
    internal static class DefinitionItemExtensions
    {
40
        public static async Task<DefinitionItem> ToDefinitionItemAsync(
41
            this ISymbol definition,
42
            Solution solution,
43
            bool includeHiddenLocations,
C
CyrusNajmabadi 已提交
44
            CancellationToken cancellationToken)
45
        {
46 47 48 49 50 51 52 53
            // Ensure we're working with the original definition for the symbol. I.e. When we're 
            // creating definition items, we want to create them for types like Dictionary<TKey,TValue>
            // not some random instantiation of that type.  
            //
            // This ensures that the type will both display properly to the user, as well as ensuring
            // that we can accurately resolve the type later on when we try to navigate to it.
            definition = definition.OriginalDefinition;

54
            var displayParts = definition.ToDisplayParts(GetFormat(definition)).ToTaggedText();
55
            var nameDisplayParts = definition.ToDisplayParts(s_namePartsFormat).ToTaggedText();
56

57
            var tags = GlyphTags.GetTags(definition.GetGlyph());
58 59
            var displayIfNoReferences = definition.ShouldShowWithNoReferenceLocations(
                showMetadataSymbolsWithoutReferences: false);
60

61
            var sourceLocations = ArrayBuilder<DocumentSpan>.GetInstance();
62 63

            var properties = GetProperties(definition);
64

65
            // If it's a namespace, don't create any normal location.  Namespaces
C
CyrusNajmabadi 已提交
66 67 68
            // come from many different sources, but we'll only show a single 
            // root definition node for it.  That node won't be navigable.
            if (definition.Kind != SymbolKind.Namespace)
69
            {
C
CyrusNajmabadi 已提交
70
                foreach (var location in definition.Locations)
71
                {
C
CyrusNajmabadi 已提交
72
                    if (location.IsInMetadata)
73
                    {
74
                        return DefinitionItem.CreateMetadataDefinition(
75
                            tags, displayParts, nameDisplayParts, solution, 
76
                            definition, properties, displayIfNoReferences);
77
                    }
78
                    else if (location.IsInSource)
79
                    {
80 81 82 83 84 85
                        if (!location.IsVisibleSourceLocation() &&
                            !includeHiddenLocations)
                        {
                            continue;
                        }

C
CyrusNajmabadi 已提交
86 87
                        var document = solution.GetDocument(location.SourceTree);
                        if (document != null)
88
                        {
89 90
                            var documentLocation = await ClassifiedSpansAndHighlightSpan.GetClassifiedDocumentSpanAsync(
                                document, location.SourceSpan, cancellationToken).ConfigureAwait(false);
C
CyrusNajmabadi 已提交
91 92

                            sourceLocations.Add(documentLocation);
93 94 95 96 97
                        }
                    }
                }
            }

98
            if (sourceLocations.Count == 0)
99 100 101
            {
                // If we got no definition locations, then create a sentinel one
                // that we can display but which will not allow navigation.
102
                return DefinitionItem.CreateNonNavigableItem(
103
                    tags, displayParts,
104
                    DefinitionItem.GetOriginationParts(definition),
105
                    properties, displayIfNoReferences);
106 107
            }

108
            return DefinitionItem.Create(
109
                tags, displayParts, sourceLocations.ToImmutableAndFree(),
110
                nameDisplayParts, properties, displayIfNoReferences);
111 112
        }

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
        private static ImmutableDictionary<string, string> GetProperties(ISymbol definition)
        {
            var properties = ImmutableDictionary<string, string>.Empty;

            var rqName = RQNameInternal.From(definition);
            if (rqName != null)
            {
                properties = properties.Add(DefinitionItem.RQNameKey1, rqName);
            }

            if (definition?.IsConstructor() == true)
            {
                // If the symbol being considered is a constructor include the containing type in case
                // a third party wants to navigate to that.
                rqName = RQNameInternal.From(definition.ContainingType);
                if (rqName != null)
                {
                    properties = properties.Add(DefinitionItem.RQNameKey2, rqName);
                }
            }

            return properties;
        }

137
        public static async Task<SourceReferenceItem> TryCreateSourceReferenceItemAsync(
138
            this ReferenceLocation referenceLocation,
139
            DefinitionItem definitionItem,
140 141
            bool includeHiddenLocations,
            CancellationToken cancellationToken)
142
        {
143
            var location = referenceLocation.Location;
144

C
CyrusNajmabadi 已提交
145
            Debug.Assert(location.IsInSource);
146 147
            if (!location.IsVisibleSourceLocation() &&
                !includeHiddenLocations)
148 149
            {
                return null;
150
            }
151

152 153 154 155 156 157 158
            var document = referenceLocation.Document;
            var sourceSpan = location.SourceSpan;

            var documentSpan = await ClassifiedSpansAndHighlightSpan.GetClassifiedDocumentSpanAsync(
                document, sourceSpan, cancellationToken).ConfigureAwait(false);

            return new SourceReferenceItem(definitionItem, documentSpan, referenceLocation.IsWrittenTo);
159
        }
C
CyrusNajmabadi 已提交
160

161 162 163 164 165 166 167
        private static SymbolDisplayFormat GetFormat(ISymbol definition)
        {
            return definition.Kind == SymbolKind.Parameter
                ? s_parameterDefinitionFormat
                : s_definitionFormat;
        }

168 169
        private static readonly SymbolDisplayFormat s_namePartsFormat = new SymbolDisplayFormat(
            memberOptions: SymbolDisplayMemberOptions.IncludeContainingType);
170

171
        private static readonly SymbolDisplayFormat s_definitionFormat =
C
CyrusNajmabadi 已提交
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
            new SymbolDisplayFormat(
                typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameOnly,
                genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
                parameterOptions: SymbolDisplayParameterOptions.IncludeType,
                propertyStyle: SymbolDisplayPropertyStyle.ShowReadWriteDescriptor,
                delegateStyle: SymbolDisplayDelegateStyle.NameAndSignature,
                kindOptions: SymbolDisplayKindOptions.IncludeMemberKeyword | SymbolDisplayKindOptions.IncludeNamespaceKeyword | SymbolDisplayKindOptions.IncludeTypeKeyword,
                localOptions: SymbolDisplayLocalOptions.IncludeType,
                memberOptions:
                    SymbolDisplayMemberOptions.IncludeContainingType |
                    SymbolDisplayMemberOptions.IncludeExplicitInterface |
                    SymbolDisplayMemberOptions.IncludeModifiers |
                    SymbolDisplayMemberOptions.IncludeParameters |
                    SymbolDisplayMemberOptions.IncludeType,
                miscellaneousOptions:
                    SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers |
                    SymbolDisplayMiscellaneousOptions.UseSpecialTypes);
189 190 191

        private static SymbolDisplayFormat s_parameterDefinitionFormat = s_definitionFormat
            .AddParameterOptions(SymbolDisplayParameterOptions.IncludeName);
192 193
    }
}