IDefinitionsAndReferencesFactory.cs 10.0 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;
4 5 6
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
C
CyrusNajmabadi 已提交
7
using System.Diagnostics;
8 9 10 11 12 13
using System.Linq;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Shared.Extensions;
C
CyrusNajmabadi 已提交
14
using Microsoft.CodeAnalysis.Text;
15 16
using Roslyn.Utilities;

17
namespace Microsoft.CodeAnalysis.FindReferences
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
{
    internal interface IDefinitionsAndReferencesFactory : IWorkspaceService
    {
        DefinitionsAndReferences CreateDefinitionsAndReferences(
            Solution solution, IEnumerable<ReferencedSymbol> referencedSymbols);
    }

    [ExportWorkspaceService(typeof(IDefinitionsAndReferencesFactory)), Shared]
    internal class DefaultDefinitionsAndReferencesFactory : IDefinitionsAndReferencesFactory
    {
        public DefinitionsAndReferences CreateDefinitionsAndReferences(
            Solution solution, IEnumerable<ReferencedSymbol> referencedSymbols)
        {
            var definitions = ImmutableArray.CreateBuilder<DefinitionItem>();
            var references = ImmutableArray.CreateBuilder<SourceReferenceItem>();

34
            var uniqueLocations = new HashSet<DocumentLocation>();
C
CyrusNajmabadi 已提交
35

36 37 38
            // Order the symbols by precedence, then create the appropriate
            // definition item per symbol and all refernece items for its
            // reference locations.
39 40
            foreach (var referencedSymbol in referencedSymbols.OrderBy(GetPrecedence))
            {
C
CyrusNajmabadi 已提交
41 42
                ProcessReferencedSymbol(
                    solution, referencedSymbol, definitions, references, uniqueLocations);
43 44 45 46 47
            }

            return new DefinitionsAndReferences(definitions.ToImmutable(), references.ToImmutable());
        }

48 49 50 51 52 53 54 55 56
        /// <summary>
        /// Reference locations are deduplicated across the entire find references result set
        /// Order the definitions so that references to multiple definitions appear under the
        /// desired definition (e.g. constructor references should prefer the constructor method
        /// over the type definition). Note that this does not change the order in which
        /// definitions are displayed in Find Symbol Results, it only changes which definition
        /// a given reference should appear under when its location is a reference to multiple
        /// definitions.
        /// </summary>
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
        private static int GetPrecedence(ReferencedSymbol referencedSymbol)
        {
            switch (referencedSymbol.Definition.Kind)
            {
                case SymbolKind.Event:
                case SymbolKind.Field:
                case SymbolKind.Label:
                case SymbolKind.Local:
                case SymbolKind.Method:
                case SymbolKind.Parameter:
                case SymbolKind.Property:
                case SymbolKind.RangeVariable:
                    return 0;

                case SymbolKind.ArrayType:
                case SymbolKind.DynamicType:
                case SymbolKind.ErrorType:
                case SymbolKind.NamedType:
                case SymbolKind.PointerType:
                    return 1;

                default:
                    return 2;
            }
        }

        private void ProcessReferencedSymbol(
            Solution solution,
            ReferencedSymbol referencedSymbol,
            ImmutableArray<DefinitionItem>.Builder definitions,
C
CyrusNajmabadi 已提交
87
            ImmutableArray<SourceReferenceItem>.Builder references,
88
            HashSet<DocumentLocation> uniqueLocations)
89
        {
90 91
            // See if this is a symbol we even want to present to the user.  If not,
            // ignore it entirely (including all its reference locations).
92 93 94 95 96
            if (!referencedSymbol.ShouldShow())
            {
                return;
            }

97
            // Try to create an item for this definition.  If we can't,
C
CyrusNajmabadi 已提交
98
            // ignore it entirely (including all its reference locations).
99 100 101 102 103 104 105
            var definitionItem = CreateDefinitionItem(solution, referencedSymbol);
            if (definitionItem == null)
            {
                return;
            }

            definitions.Add(definitionItem);
106 107 108

            // Now, create the SourceReferenceItems for all the reference locations
            // for this definition.
C
CyrusNajmabadi 已提交
109
            CreateReferences(referencedSymbol, references, definitionItem, uniqueLocations);
110

111 112
            // Finally, see if there are any third parties that want to add their
            // own result to our collection.
113 114 115 116 117 118 119
            var thirdPartyItem = GetThirdPartyDefinitionItem(solution, referencedSymbol.Definition);
            if (thirdPartyItem != null)
            {
                definitions.Add(thirdPartyItem);
            }
        }

C
CyrusNajmabadi 已提交
120 121 122 123
        /// <summary>
        /// Provides an extension point that allows for other workspace layers to add additional
        /// results to the results found by the FindReferences engine.
        /// </summary>
124 125 126 127 128 129 130 131 132 133 134
        protected virtual DefinitionItem GetThirdPartyDefinitionItem(
            Solution solution, ISymbol definition)
        {
            return null;
        }

        private static DefinitionItem CreateDefinitionItem(
            Solution solution, ReferencedSymbol referencedSymbol)
        {
            var definition = referencedSymbol.Definition;

135
            var definitionLocations = ConvertDefinitionLocations(solution, definition);
C
CyrusNajmabadi 已提交
136
            var displayParts = definition.ToDisplayParts(s_definitionDisplayFormat).ToTaggedText();
137 138 139

            return new DefinitionItem(
                GlyphTags.GetTags(definition.GetGlyph()),
140
                displayParts,
141 142 143 144
                definitionLocations,
                definition.ShouldShowWithNoReferenceLocations());
        }

145 146
        private static ImmutableArray<DefinitionLocation> ConvertDefinitionLocations(
            Solution solution, ISymbol definition)
147 148 149
        {
            var result = ImmutableArray.CreateBuilder<DefinitionLocation>();

C
CyrusNajmabadi 已提交
150 151 152 153
            // If it's a namespace, don't create any normal lcoation.  Namespaces
            // 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)
154
            {
C
CyrusNajmabadi 已提交
155
                foreach (var location in definition.Locations)
156
                {
C
CyrusNajmabadi 已提交
157
                    if (location.IsInMetadata)
158
                    {
159
                        result.Add(DefinitionLocation.CreateSymbolLocation(solution, definition));
160
                    }
C
CyrusNajmabadi 已提交
161
                    else if (location.IsInSource)
162
                    {
C
CyrusNajmabadi 已提交
163 164
                        var document = solution.GetDocument(location.SourceTree);
                        if (document != null)
165
                        {
C
CyrusNajmabadi 已提交
166 167 168 169 170
                            var documentLocation = new DocumentLocation(document, location.SourceSpan);
                            if (documentLocation.CanNavigateTo())
                            {
                                result.Add(DefinitionLocation.CreateDocumentLocation(documentLocation));
                            }
171 172 173 174 175
                        }
                    }
                }
            }

176 177 178 179 180 181 182 183
            if (result.Count == 0)
            {
                // If we got no definition locations, then create a sentinel one
                // that we can display but which will not allow navigation.
                result.Add(DefinitionLocation.CreateNonNavigatingLocation(
                    DefinitionLocation.GetOriginationParts(definition)));
            }

184 185 186 187 188 189
            return result.ToImmutable();
        }

        private static void CreateReferences(
            ReferencedSymbol referencedSymbol,
            ImmutableArray<SourceReferenceItem>.Builder references,
C
CyrusNajmabadi 已提交
190
            DefinitionItem definitionItem,
191
            HashSet<DocumentLocation> uniqueLocations)
192 193 194 195
        {
            foreach (var referenceLocation in referencedSymbol.Locations)
            {
                var location = referenceLocation.Location;
C
CyrusNajmabadi 已提交
196
                Debug.Assert(location.IsInSource);
197

C
CyrusNajmabadi 已提交
198 199 200
                var document = referenceLocation.Document;
                var sourceSpan = location.SourceSpan;

201 202
                var documentLocation = new DocumentLocation(document, sourceSpan);
                if (!documentLocation.CanNavigateTo())
203
                {
204 205
                    continue;
                }
206

207 208
                if (uniqueLocations.Add(documentLocation))
                {
C
CyrusNajmabadi 已提交
209 210
                    references.Add(new SourceReferenceItem(definitionItem, documentLocation));
                }
211 212
            }
        }
C
CyrusNajmabadi 已提交
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231

        public static readonly SymbolDisplayFormat s_definitionDisplayFormat =
            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);
232 233
    }
}