IDefinitionsAndReferencesFactory.cs 7.7 KB
Newer Older
1 2 3 4
// 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.Collections.Generic;
using System.Composition;
C
CyrusNajmabadi 已提交
5
using System.Diagnostics;
6
using System.Threading;
7 8
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.FindSymbols;
9
using Microsoft.CodeAnalysis.FindUsages;
10 11 12 13
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Shared.Extensions;

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

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

36 37 38 39
    internal static class DefinitionItemExtensions
    {
        public static DefinitionItem ToDefinitionItem(
            this ISymbol definition,
40
            Solution solution,
41
            bool includeHiddenLocations,
C
CyrusNajmabadi 已提交
42
            HashSet<DocumentSpan> uniqueSpans = null)
43
        {
44 45 46 47 48 49 50 51
            // 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;

52
            var displayParts = definition.ToDisplayParts(GetFormat(definition)).ToTaggedText();
53
            var nameDisplayParts = definition.ToDisplayParts(s_namePartsFormat).ToTaggedText();
54

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

59
            var sourceLocations = ArrayBuilder<DocumentSpan>.GetInstance();
60
            ImmutableDictionary<string, string> properties = null;
61

62
            // If it's a namespace, don't create any normal location.  Namespaces
C
CyrusNajmabadi 已提交
63 64 65
            // 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)
66
            {
C
CyrusNajmabadi 已提交
67
                foreach (var location in definition.Locations)
68
                {
C
CyrusNajmabadi 已提交
69
                    if (location.IsInMetadata)
70
                    {
71
                        return DefinitionItem.CreateMetadataDefinition(
72
                            tags, displayParts, nameDisplayParts, solution, 
73
                            definition, properties, displayIfNoReferences);
74
                    }
75
                    else if (location.IsInSource)
76
                    {
77 78 79 80 81 82
                        if (!location.IsVisibleSourceLocation() &&
                            !includeHiddenLocations)
                        {
                            continue;
                        }

C
CyrusNajmabadi 已提交
83 84
                        var document = solution.GetDocument(location.SourceTree);
                        if (document != null)
85
                        {
C
CyrusNajmabadi 已提交
86
                            var documentLocation = new DocumentSpan(document, location.SourceSpan);
87
                            if (sourceLocations.Count == 0)
88
                            {
89
                                sourceLocations.Add(documentLocation);
90 91 92
                            }
                            else
                            {
C
CyrusNajmabadi 已提交
93 94
                                if (uniqueSpans == null ||
                                    uniqueSpans.Add(documentLocation))
95
                                {
96
                                    sourceLocations.Add(documentLocation);
97
                                }
98
                            }
99 100 101 102 103
                        }
                    }
                }
            }

104
            if (sourceLocations.Count == 0)
105 106 107
            {
                // If we got no definition locations, then create a sentinel one
                // that we can display but which will not allow navigation.
108
                return DefinitionItem.CreateNonNavigableItem(
109
                    tags, displayParts,
110
                    DefinitionItem.GetOriginationParts(definition),
111
                    properties, displayIfNoReferences);
112 113
            }

114
            return DefinitionItem.Create(
115
                tags, displayParts, sourceLocations.ToImmutableAndFree(),
116
                nameDisplayParts, properties, displayIfNoReferences);
117 118
        }

119 120
        public static SourceReferenceItem TryCreateSourceReferenceItem(
            this ReferenceLocation referenceLocation,
121 122
            DefinitionItem definitionItem,
            bool includeHiddenLocations)
123
        {
124
            var location = referenceLocation.Location;
125

C
CyrusNajmabadi 已提交
126
            Debug.Assert(location.IsInSource);
127 128
            if (!location.IsVisibleSourceLocation() &&
                !includeHiddenLocations)
129 130
            {
                return null;
131
            }
132

133 134 135 136
            return new SourceReferenceItem(
                definitionItem, 
                new DocumentSpan(referenceLocation.Document, location.SourceSpan),
                referenceLocation.IsWrittenTo);
137
        }
C
CyrusNajmabadi 已提交
138

139 140 141 142 143 144 145
        private static SymbolDisplayFormat GetFormat(ISymbol definition)
        {
            return definition.Kind == SymbolKind.Parameter
                ? s_parameterDefinitionFormat
                : s_definitionFormat;
        }

146 147
        private static readonly SymbolDisplayFormat s_namePartsFormat = new SymbolDisplayFormat(
            memberOptions: SymbolDisplayMemberOptions.IncludeContainingType);
148

149
        private static readonly SymbolDisplayFormat s_definitionFormat =
C
CyrusNajmabadi 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
            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);
167 168 169

        private static SymbolDisplayFormat s_parameterDefinitionFormat = s_definitionFormat
            .AddParameterOptions(SymbolDisplayParameterOptions.IncludeName);
170 171
    }
}