IDefinitionsAndReferencesFactory.cs 10.4 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.Classification;
9
using Microsoft.CodeAnalysis.Completion;
10
using Microsoft.CodeAnalysis.Features.RQName;
11
using Microsoft.CodeAnalysis.FindSymbols;
12
using Microsoft.CodeAnalysis.FindUsages;
13 14
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
T
Tomas Matousek 已提交
15
using Microsoft.CodeAnalysis.PooledObjects;
16
using Microsoft.CodeAnalysis.Shared.Extensions;
C
CyrusNajmabadi 已提交
17
using Roslyn.Utilities;
18

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

    [ExportWorkspaceService(typeof(IDefinitionsAndReferencesFactory)), Shared]
    internal class DefaultDefinitionsAndReferencesFactory : IDefinitionsAndReferencesFactory
    {
30 31 32 33 34
        [ImportingConstructor]
        public DefaultDefinitionsAndReferencesFactory()
        {
        }

C
CyrusNajmabadi 已提交
35 36 37 38
        /// <summary>
        /// Provides an extension point that allows for other workspace layers to add additional
        /// results to the results found by the FindReferences engine.
        /// </summary>
39
        public virtual DefinitionItem GetThirdPartyDefinitionItem(
40
            Solution solution, DefinitionItem definitionItem, CancellationToken cancellationToken)
41 42 43
        {
            return null;
        }
44
    }
45

46 47
    internal static class DefinitionItemExtensions
    {
48 49
        public static DefinitionItem ToNonClassifiedDefinitionItem(
            this ISymbol definition,
50
            Project project,
51 52 53 54 55 56
            bool includeHiddenLocations)
        {
            // Because we're passing in 'false' for 'includeClassifiedSpans', this won't ever have
            // to actually do async work.  This is because the only asynchrony is when we are trying
            // to compute the classified spans for the locations of the definition.  So it's totally 
            // fine to pass in CancellationToken.None and block on the result.
57
            return ToDefinitionItemAsync(
D
dotnet-bot 已提交
58
                definition, project, includeHiddenLocations, includeClassifiedSpans: false,
59
                options: FindReferencesSearchOptions.Default, cancellationToken: CancellationToken.None).WaitAndGetResult_CanCallOnBackground(CancellationToken.None);
60 61 62 63
        }

        public static Task<DefinitionItem> ToClassifiedDefinitionItemAsync(
            this ISymbol definition,
64
            Project project,
65
            bool includeHiddenLocations,
66
            FindReferencesSearchOptions options,
67 68
            CancellationToken cancellationToken)
        {
69
            return ToDefinitionItemAsync(definition, project,
D
dotnet-bot 已提交
70
                includeHiddenLocations, includeClassifiedSpans: true,
71
                options, cancellationToken);
72 73 74
        }

        private static async Task<DefinitionItem> ToDefinitionItemAsync(
75
            this ISymbol definition,
76
            Project project,
77
            bool includeHiddenLocations,
78
            bool includeClassifiedSpans,
79
            FindReferencesSearchOptions options,
C
CyrusNajmabadi 已提交
80
            CancellationToken cancellationToken)
81
        {
82 83 84 85 86 87 88 89
            // 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;

90
            var displayParts = definition.ToDisplayParts(GetFormat(definition)).ToTaggedText();
91
            var nameDisplayParts = definition.ToDisplayParts(s_namePartsFormat).ToTaggedText();
92

93
            var tags = GlyphTags.GetTags(definition.GetGlyph());
94
            var displayIfNoReferences = definition.ShouldShowWithNoReferenceLocations(
95
                options, showMetadataSymbolsWithoutReferences: false);
96

97
            using var sourceLocationsDisposer = ArrayBuilder<DocumentSpan>.GetInstance(out var sourceLocations);
98 99

            var properties = GetProperties(definition);
100

101
            // If it's a namespace, don't create any normal location.  Namespaces
C
CyrusNajmabadi 已提交
102 103 104
            // 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)
105
            {
C
CyrusNajmabadi 已提交
106
                foreach (var location in definition.Locations)
107
                {
C
CyrusNajmabadi 已提交
108
                    if (location.IsInMetadata)
109
                    {
110
                        return DefinitionItem.CreateMetadataDefinition(
D
dotnet-bot 已提交
111
                            tags, displayParts, nameDisplayParts, project,
112
                            definition, properties, displayIfNoReferences);
113
                    }
114
                    else if (location.IsInSource)
115
                    {
116 117 118 119 120 121
                        if (!location.IsVisibleSourceLocation() &&
                            !includeHiddenLocations)
                        {
                            continue;
                        }

122
                        var document = project.Solution.GetDocument(location.SourceTree);
C
CyrusNajmabadi 已提交
123
                        if (document != null)
124
                        {
125 126
                            var documentLocation = !includeClassifiedSpans
                                ? new DocumentSpan(document, location.SourceSpan)
127
                                : await ClassifiedSpansAndHighlightSpanFactory.GetClassifiedDocumentSpanAsync(
128
                                    document, location.SourceSpan, cancellationToken).ConfigureAwait(false);
C
CyrusNajmabadi 已提交
129 130

                            sourceLocations.Add(documentLocation);
131 132 133 134 135
                        }
                    }
                }
            }

136
            if (sourceLocations.Count == 0)
137 138 139
            {
                // If we got no definition locations, then create a sentinel one
                // that we can display but which will not allow navigation.
140
                return DefinitionItem.CreateNonNavigableItem(
141
                    tags, displayParts,
142
                    DefinitionItem.GetOriginationParts(definition),
143
                    properties, displayIfNoReferences);
144 145
            }

146
            return DefinitionItem.Create(
147
                tags, displayParts, sourceLocations.ToImmutable(),
148
                nameDisplayParts, properties, displayIfNoReferences);
149 150
        }

151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
        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;
        }

175
        public static async Task<SourceReferenceItem> TryCreateSourceReferenceItemAsync(
176
            this ReferenceLocation referenceLocation,
177
            DefinitionItem definitionItem,
178 179
            bool includeHiddenLocations,
            CancellationToken cancellationToken)
180
        {
181
            var location = referenceLocation.Location;
182

C
CyrusNajmabadi 已提交
183
            Debug.Assert(location.IsInSource);
184 185
            if (!location.IsVisibleSourceLocation() &&
                !includeHiddenLocations)
186 187
            {
                return null;
188
            }
189

190 191 192
            var document = referenceLocation.Document;
            var sourceSpan = location.SourceSpan;

193
            var documentSpan = await ClassifiedSpansAndHighlightSpanFactory.GetClassifiedDocumentSpanAsync(
194 195
                document, sourceSpan, cancellationToken).ConfigureAwait(false);

196
            return new SourceReferenceItem(definitionItem, documentSpan, referenceLocation.SymbolUsageInfo);
197
        }
C
CyrusNajmabadi 已提交
198

199 200 201 202 203 204 205
        private static SymbolDisplayFormat GetFormat(ISymbol definition)
        {
            return definition.Kind == SymbolKind.Parameter
                ? s_parameterDefinitionFormat
                : s_definitionFormat;
        }

206 207
        private static readonly SymbolDisplayFormat s_namePartsFormat = new SymbolDisplayFormat(
            memberOptions: SymbolDisplayMemberOptions.IncludeContainingType);
208

209
        private static readonly SymbolDisplayFormat s_definitionFormat =
C
CyrusNajmabadi 已提交
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
            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);
227

C
Cyrus Najmabadi 已提交
228
        private static readonly SymbolDisplayFormat s_parameterDefinitionFormat = s_definitionFormat
229
            .AddParameterOptions(SymbolDisplayParameterOptions.IncludeName);
230
    }
T
Tomas Matousek 已提交
231
}