Пример #1
0
        public static CompletionItem Create(INamedTypeSymbol typeSymbol, string containingNamespace, string genericTypeSuffix)
        {
            PooledDictionary <string, string> propertyBuilder = null;

            if (typeSymbol.Arity > 0)
            {
                propertyBuilder = PooledDictionary <string, string> .GetInstance();

                propertyBuilder.Add(TypeAritySuffixName, GetAritySuffix(typeSymbol.Arity));
            }

            // Add tildes (ASCII: 126) to name and namespace as sort text:
            // 1. '~' before type name makes import items show after in-scope items
            // 2. ' ' before namespace makes types with identical type name but from different namespace all show up in the list,
            //    it also makes sure type with shorter name shows first, e.g. 'SomeType` before 'SomeTypeWithLongerName'.
            var sortTextBuilder = PooledStringBuilder.GetInstance();

            sortTextBuilder.Builder.AppendFormat(SortTextFormat, typeSymbol.Name, containingNamespace);

            return(CompletionItem.Create(
                       displayText: typeSymbol.Name,
                       filterText: typeSymbol.Name,
                       sortText: sortTextBuilder.ToStringAndFree(),
                       properties: propertyBuilder?.ToImmutableDictionaryAndFree(),
                       tags: GlyphTags.GetTags(typeSymbol.GetGlyph()),
                       rules: CompletionItemRules.Default,
                       displayTextPrefix: null,
                       displayTextSuffix: typeSymbol.Arity == 0 ? string.Empty : genericTypeSuffix,
                       inlineDescription: containingNamespace));
        }
Пример #2
0
        public static CompletionItem Create(INamedTypeSymbol typeSymbol, string containingNamespace)
        {
            PooledDictionary <string, string> propertyBuilder = null;

            if (typeSymbol.Arity > 0)
            {
                propertyBuilder = PooledDictionary <string, string> .GetInstance();

                propertyBuilder.Add(TypeAritySuffixName, GetAritySuffix(typeSymbol.Arity));
            }

            // Hack: add tildes (ASCII: 126) to name and namespace as sort text:
            // 1. '~' before type name makes import items show after in-scope items
            // 2. ' ' before namespace makes types with identical type name but from different namespace all show up in the list,
            //    it also makes sure type with shorter name shows first, e.g. 'SomeType` before 'SomeTypeWithLongerName'.
            var sortTextBuilder = PooledStringBuilder.GetInstance();

            sortTextBuilder.Builder.AppendFormat(SortTextFormat, typeSymbol.Name, containingNamespace);

            // TODO:
            // 1. Suffix should be language specific, i.e. `(Of ...)` if triggered from VB.
            // 2. Sort the import items to be after in-scope symbols in a less hacky way.
            // 3. Editor support for resolving item text conflicts?
            return(CompletionItem.Create(
                       displayText: typeSymbol.Name,
                       filterText: typeSymbol.Name,
                       sortText: sortTextBuilder.ToStringAndFree(),
                       properties: propertyBuilder?.ToImmutableDictionaryAndFree(),
                       tags: GlyphTags.GetTags(typeSymbol.GetGlyph()),
                       rules: CompletionItemRules.Default,
                       displayTextPrefix: null,
                       displayTextSuffix: typeSymbol.Arity == 0 ? string.Empty : "<>",
                       inlineDescription: containingNamespace));
        }
        protected async Task CheckResultsAsync(
            Document document, int position, string expectedItemOrNull,
            string expectedDescriptionOrNull, bool usePreviousCharAsTrigger,
            bool checkForAbsence, int?glyph, int?matchPriority,
            bool?hasSuggestionModeItem, string displayTextSuffix)
        {
            var code = (await document.GetTextAsync()).ToString();

            var trigger = CompletionTrigger.Invoke;

            if (usePreviousCharAsTrigger)
            {
                trigger = CompletionTrigger.CreateInsertionTrigger(insertedCharacter: code.ElementAt(position - 1));
            }

            var completionService = GetCompletionService(document.Project.Solution.Workspace);
            var completionList    = await GetCompletionListAsync(completionService, document, position, trigger);

            var items = completionList == null ? ImmutableArray <CompletionItem> .Empty : completionList.Items;

            if (hasSuggestionModeItem != null)
            {
                Assert.Equal(hasSuggestionModeItem.Value, completionList.SuggestionModeItem != null);
            }

            if (checkForAbsence)
            {
                if (items == null)
                {
                    return;
                }

                if (expectedItemOrNull == null)
                {
                    Assert.Empty(items);
                }
                else
                {
                    AssertEx.None(
                        items,
                        c => CompareItems(c.DisplayText, expectedItemOrNull) &&
                        (expectedDescriptionOrNull != null ? completionService.GetDescriptionAsync(document, c).Result.Text == expectedDescriptionOrNull : true));
                }
            }
            else
            {
                if (expectedItemOrNull == null)
                {
                    Assert.NotEmpty(items);
                }
                else
                {
                    AssertEx.Any(items, c => CompareItems(c.DisplayText, expectedItemOrNull) &&
                                 CompareItems(c.DisplayTextSuffix, displayTextSuffix ?? "") &&
                                 (expectedDescriptionOrNull != null ? completionService.GetDescriptionAsync(document, c).Result.Text == expectedDescriptionOrNull : true) &&
                                 (glyph.HasValue ? c.Tags.SequenceEqual(GlyphTags.GetTags((Glyph)glyph.Value)) : true) &&
                                 (matchPriority.HasValue ? (int)c.Rules.MatchPriority == matchPriority.Value : true));
                }
            }
        }
Пример #4
0
        private static ImmutableDictionary <string, ImmutableDictionary <string, Glyph> > InitializeDictionary()
        {
            var builder = ImmutableDictionary.CreateBuilder <string, ImmutableDictionary <string, Glyph> >();

            foreach (var glyph in (Glyph[])Enum.GetValues(typeof(Glyph)))
            {
                var tags = GlyphTags.GetTags((Microsoft.CodeAnalysis.Glyph)glyph);
                if (tags.IsDefaultOrEmpty)
                {
                    continue;
                }

                var firstTag  = tags[0];
                var secondTag = tags.Length == 2 ? tags[1] : string.Empty;
                var inner     = builder.GetValueOrDefault(firstTag);
                if (inner == null)
                {
                    inner = ImmutableDictionary <string, Glyph> .Empty.Add(secondTag, glyph);
                }

                builder[firstTag] = inner.SetItem(secondTag, glyph);
            }

            return(builder.ToImmutable());
        }
Пример #5
0
        public override DefinitionItem GetThirdPartyDefinitionItem(
            Solution solution, ISymbol definition)
        {
            var symbolNavigationService = solution.Workspace.Services.GetService <ISymbolNavigationService>();

            if (!symbolNavigationService.WouldNavigateToSymbol(definition, solution, out var filePath, out var lineNumber, out var charOffset))
            {
                return(null);
            }

            var displayParts = GetDisplayParts(filePath, lineNumber, charOffset);

            return(new ExternalDefinitionItem(
                       GlyphTags.GetTags(definition.GetGlyph()),
                       displayParts, _serviceProvider, filePath, lineNumber, charOffset));
        }
Пример #6
0
        private static DefinitionItem CreateDefinitionItem(
            Solution solution,
            ReferencedSymbol referencedSymbol,
            HashSet <DocumentLocation> uniqueLocations)
        {
            var definition   = referencedSymbol.Definition;
            var displayParts = definition.ToDisplayParts(s_definitionDisplayFormat).ToTaggedText();

            return(CreateDefinitionItem(
                       GlyphTags.GetTags(definition.GetGlyph()),
                       displayParts,
                       definition.ShouldShowWithNoReferenceLocations(),
                       solution,
                       definition,
                       uniqueLocations));
        }
        private static async Task FindSymbolMonikerReferencesAsync(
            IFindSymbolMonikerUsagesService monikerUsagesService,
            ISymbol definition,
            IFindUsagesContext context,
            CancellationToken cancellationToken)
        {
            var moniker = SymbolMoniker.TryCreate(definition);

            if (moniker == null)
            {
                return;
            }

            // Let the find-refs window know we have outstanding work
            await using var _ = await context.ProgressTracker.AddSingleItemAsync().ConfigureAwait(false);

            var displayParts = GetDisplayParts(definition).AddRange(new[]
            {
                new TaggedText(TextTags.Space, " "),
                new TaggedText(TextTags.Text, EditorFeaturesResources.external),
            });

            var definitionItem = DefinitionItem.CreateNonNavigableItem(
                tags: GlyphTags.GetTags(definition.GetGlyph()),
                displayParts,
                originationParts: DefinitionItem.GetOriginationParts(definition));

            var monikers = ImmutableArray.Create(moniker);

            var first = true;

            await foreach (var referenceItem in monikerUsagesService.FindReferencesByMoniker(
                               definitionItem, monikers, context.ProgressTracker, cancellationToken))
            {
                if (first)
                {
                    // found some results.  Add the definition item to the context.
                    first = false;
                    await context.OnDefinitionFoundAsync(definitionItem).ConfigureAwait(false);
                }

                await context.OnExternalReferenceFoundAsync(referenceItem).ConfigureAwait(false);
            }
        }
Пример #8
0
        public static CompletionItem Create(string name, int arity, string containingNamespace, Glyph glyph, string genericTypeSuffix, CompletionItemFlags flags, string?symbolKeyData)
        {
            ImmutableDictionary <string, string>?properties = null;

            if (symbolKeyData != null || arity > 0)
            {
                var builder = PooledDictionary <string, string> .GetInstance();

                if (symbolKeyData != null)
                {
                    builder.Add(SymbolKeyData, symbolKeyData);
                }
                else
                {
                    // We don't need arity to recover symbol if we already have SymbolKeyData or it's 0.
                    // (but it still needed below to decide whether to show generic suffix)
                    builder.Add(TypeAritySuffixName, AbstractDeclaredSymbolInfoFactoryService.GetMetadataAritySuffix(arity));
                }

                properties = builder.ToImmutableDictionaryAndFree();
            }

            // Add tildes (ASCII: 126) to name and namespace as sort text:
            // 1. '~' before type name makes import items show after in-scope items
            // 2. ' ' before namespace makes types with identical type name but from different namespace all show up in the list,
            //    it also makes sure type with shorter name shows first, e.g. 'SomeType` before 'SomeTypeWithLongerName'.
            var sortTextBuilder = PooledStringBuilder.GetInstance();

            sortTextBuilder.Builder.AppendFormat(SortTextFormat, name, containingNamespace);

            var item = CompletionItem.Create(
                displayText: name,
                sortText: sortTextBuilder.ToStringAndFree(),
                properties: properties,
                tags: GlyphTags.GetTags(glyph),
                rules: CompletionItemRules.Default,
                displayTextPrefix: null,
                displayTextSuffix: arity == 0 ? string.Empty : genericTypeSuffix,
                inlineDescription: containingNamespace);

            item.Flags = flags;
            return(item);
        }
Пример #9
0
        public static CompletionItem Create(
            string displayText,
            string displayTextSuffix,
            CompletionItemRules rules,
            Glyph?glyph = null,
            ImmutableArray <SymbolDisplayPart> description = default,
            string sortText       = null,
            string filterText     = null,
            bool showsWarningIcon = false,
            ImmutableDictionary <string, string> properties = null,
            ImmutableArray <string> tags = default)
        {
            tags = tags.NullToEmpty();

            if (glyph != null)
            {
                // put glyph tags first
                tags = GlyphTags.GetTags(glyph.Value).AddRange(tags);
            }

            if (showsWarningIcon)
            {
                tags = tags.Add(WellKnownTags.Warning);
            }

            properties = properties ?? ImmutableDictionary <string, string> .Empty;
            if (!description.IsDefault && description.Length > 0)
            {
                properties = properties.Add("Description", EncodeDescription(description));
            }

            return(CompletionItem.Create(
                       displayText: displayText,
                       displayTextSuffix: displayTextSuffix,
                       filterText: filterText,
                       sortText: sortText,
                       properties: properties,
                       tags: tags,
                       rules: rules));
        }
Пример #10
0
 public static ImmutableArray <string> GetTags(FSharpGlyph glyph)
 {
     return(GlyphTags.GetTags(FSharpGlyphHelpers.ConvertTo(glyph)));
 }
        public static DefinitionItem ToDefinitionItem(
            this ISymbol definition,
            Solution solution,
            bool includeHiddenLocations,
            HashSet <DocumentSpan> uniqueSpans = null)
        {
            // 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;

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

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

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

            // If it's a namespace, don't create any normal location.  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)
            {
                foreach (var location in definition.Locations)
                {
                    if (location.IsInMetadata)
                    {
                        return(DefinitionItem.CreateMetadataDefinition(
                                   tags, displayParts, nameDisplayParts, solution,
                                   definition, displayIfNoReferences));
                    }
                    else if (location.IsInSource)
                    {
                        if (!location.IsVisibleSourceLocation() &&
                            !includeHiddenLocations)
                        {
                            continue;
                        }

                        var document = solution.GetDocument(location.SourceTree);
                        if (document != null)
                        {
                            var documentLocation = new DocumentSpan(document, location.SourceSpan);
                            if (sourceLocations.Count == 0)
                            {
                                sourceLocations.Add(documentLocation);
                            }
                            else
                            {
                                if (uniqueSpans == null ||
                                    uniqueSpans.Add(documentLocation))
                                {
                                    sourceLocations.Add(documentLocation);
                                }
                            }
                        }
                    }
                }
            }

            if (sourceLocations.Count == 0)
            {
                // If we got no definition locations, then create a sentinel one
                // that we can display but which will not allow navigation.
                return(DefinitionItem.CreateNonNavigableItem(
                           tags, displayParts,
                           DefinitionItem.GetOriginationParts(definition),
                           displayIfNoReferences));
            }

            return(DefinitionItem.Create(
                       tags, displayParts, sourceLocations.ToImmutableAndFree(),
                       nameDisplayParts, displayIfNoReferences));
        }
Пример #12
0
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            try
            {
                var document          = context.Document;
                var position          = context.Position;
                var cancellationToken = context.CancellationToken;

                var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                if (syntaxTree.IsInNonUserCode(position, cancellationToken))
                {
                    return;
                }

                var token = syntaxTree
                            .FindTokenOnLeftOfPosition(position, cancellationToken)
                            .GetPreviousTokenIfTouchingWord(position);

                if (!token.IsKind(SyntaxKind.OpenBracketToken, SyntaxKind.CommaToken))
                {
                    return;
                }

                if (token.Parent is not FunctionPointerUnmanagedCallingConventionListSyntax callingConventionList)
                {
                    return;
                }

                var contextPosition = token.SpanStart;
                var semanticModel   = await document.ReuseExistingSpeculativeModelAsync(callingConventionList, cancellationToken).ConfigureAwait(false);

                var completionItems = new HashSet <CompletionItem>(CompletionItemComparer.Instance);
                AddTypes(completionItems, contextPosition, semanticModel, cancellationToken);

                // Even if we didn't have types, there are four magic calling conventions recognized regardless.
                // We add these after doing the type lookup so if we had types we can show that instead
                foreach (var callingConvention in s_predefinedCallingConventions)
                {
                    completionItems.Add(CompletionItem.Create(callingConvention, tags: GlyphTags.GetTags(Glyph.Keyword)));
                }

                context.AddItems(completionItems);
            }
            catch (Exception e) when(FatalError.ReportWithoutCrashUnlessCanceled(e))
            {
                // nop
            }
        }
        public static DefinitionItem ToDefinitionItem(
            this ISymbol definition,
            Solution solution,
            HashSet <DocumentSpan> uniqueSpans = null)
        {
            var displayParts = definition.ToDisplayParts(GetFormat(definition)).ToTaggedText();

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

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

            // 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)
            {
                foreach (var location in definition.Locations)
                {
                    if (location.IsInMetadata)
                    {
                        return(DefinitionItem.CreateMetadataDefinition(
                                   tags, displayParts, solution, definition, displayIfNoReferences));
                    }
                    else if (location.IsVisibleSourceLocation())
                    {
                        var document = solution.GetDocument(location.SourceTree);
                        if (document != null)
                        {
                            var documentLocation = new DocumentSpan(document, location.SourceSpan);
                            if (sourceLocations.Count == 0)
                            {
                                sourceLocations.Add(documentLocation);
                            }
                            else
                            {
                                if (uniqueSpans == null ||
                                    uniqueSpans.Add(documentLocation))
                                {
                                    sourceLocations.Add(documentLocation);
                                }
                            }
                        }
                    }
                }
            }

            if (sourceLocations.Count == 0)
            {
                // If we got no definition locations, then create a sentinel one
                // that we can display but which will not allow navigation.
                return(DefinitionItem.CreateNonNavigableItem(
                           tags, displayParts,
                           DefinitionItem.GetOriginationParts(definition),
                           displayIfNoReferences));
            }

            return(DefinitionItem.Create(
                       tags, displayParts, sourceLocations.ToImmutableAndFree(), displayIfNoReferences));
        }
Пример #14
0
        private async Task CheckResultsAsync(
            Document document, int position, string expectedItemOrNull, string expectedDescriptionOrNull, bool usePreviousCharAsTrigger, bool checkForAbsence, Glyph?glyph)
        {
            var code = (await document.GetTextAsync()).ToString();

            CompletionTrigger trigger = CompletionTrigger.Default;

            if (usePreviousCharAsTrigger)
            {
                trigger = CompletionTrigger.CreateInsertionTrigger(insertedCharacter: code.ElementAt(position - 1));
            }

            var completionService = GetCompletionService(document.Project.Solution.Workspace);
            var completionList    = await GetCompletionListAsync(completionService, document, position, trigger);

            var items = completionList == null ? default(ImmutableArray <CompletionItem>) : completionList.Items;

            if (checkForAbsence)
            {
                if (items == null)
                {
                    return;
                }

                if (expectedItemOrNull == null)
                {
                    Assert.Empty(items);
                }
                else
                {
                    AssertEx.None(
                        items,
                        c => CompareItems(c.DisplayText, expectedItemOrNull) &&
                        (expectedDescriptionOrNull != null ? completionService.GetDescriptionAsync(document, c).Result.Text == expectedDescriptionOrNull : true));
                }
            }
            else
            {
                if (expectedItemOrNull == null)
                {
                    Assert.NotEmpty(items);
                }
                else
                {
                    AssertEx.Any(items, c => CompareItems(c.DisplayText, expectedItemOrNull) &&
                                 (expectedDescriptionOrNull != null ? completionService.GetDescriptionAsync(document, c).Result.Text == expectedDescriptionOrNull : true) &&
                                 (glyph.HasValue ? CompletionHelper.TagsEqual(c.Tags, GlyphTags.GetTags(glyph.Value)) : true));
                }
            }
        }
Пример #15
0
        private static async Task <DefinitionItem> ToDefinitionItemAsync(
            this ISymbol definition,
            Project project,
            bool includeHiddenLocations,
            bool includeClassifiedSpans,
            FindReferencesSearchOptions options,
            CancellationToken cancellationToken)
        {
            // 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;

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

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

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

            var properties = GetProperties(definition);

            var displayableProperties = AbstractReferenceFinder.GetAdditionalFindUsagesProperties(definition);

            // If it's a namespace, don't create any normal location.  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)
            {
                foreach (var location in definition.Locations)
                {
                    if (location.IsInMetadata)
                    {
                        return(DefinitionItem.CreateMetadataDefinition(
                                   tags, displayParts, nameDisplayParts, project,
                                   definition, properties, displayIfNoReferences));
                    }
                    else if (location.IsInSource)
                    {
                        if (!location.IsVisibleSourceLocation() &&
                            !includeHiddenLocations)
                        {
                            continue;
                        }

                        var document = project.Solution.GetDocument(location.SourceTree);
                        if (document != null)
                        {
                            var documentLocation = !includeClassifiedSpans
                                ? new DocumentSpan(document, location.SourceSpan)
                                : await ClassifiedSpansAndHighlightSpanFactory.GetClassifiedDocumentSpanAsync(
                                document, location.SourceSpan, cancellationToken).ConfigureAwait(false);

                            sourceLocations.Add(documentLocation);
                        }
                    }
                }
            }

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

            return(DefinitionItem.Create(
                       tags, displayParts, sourceLocations.ToImmutable(),
                       nameDisplayParts, properties, displayableProperties, displayIfNoReferences));
        }
Пример #16
0
        public override async Task ProvideCompletionsAsync(CompletionContext context)
        {
            // This provider is exported for all workspaces - so limit it to just our workspace & the debugger's intellisense workspace
            if (context.Document.Project.Solution.Workspace.Kind != WorkspaceKind.AnyCodeRoslynWorkspace &&
                context.Document.Project.Solution.Workspace.Kind != StringConstants.DebuggerIntellisenseWorkspaceKind)
            {
                return;
            }

            var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient;

            if (lspClient == null)
            {
                return;
            }

            var text = await context.Document.GetTextAsync(context.CancellationToken).ConfigureAwait(false);

            var completionParams = new LSP.CompletionParams
            {
                TextDocument = ProtocolConversions.DocumentToTextDocumentIdentifier(context.Document),
                Position     = ProtocolConversions.LinePositionToPosition(text.Lines.GetLinePosition(context.Position)),
                Context      = new LSP.CompletionContext {
                    TriggerCharacter = context.Trigger.Character.ToString(), TriggerKind = GetTriggerKind(context.Trigger)
                }
            };

            var completionObject = await lspClient.RequestAsync(LSP.Methods.TextDocumentCompletion.ToLSRequest(), completionParams, context.CancellationToken).ConfigureAwait(false);

            if (completionObject == null)
            {
                return;
            }

            var completionList = ((JToken)completionObject).ToObject <RoslynCompletionItem[]>();

            foreach (var item in completionList)
            {
                ImmutableArray <string> tags;
                if (item.Tags != null)
                {
                    tags = item.Tags.AsImmutable();
                }
                else
                {
                    var glyph = ProtocolConversions.CompletionItemKindToGlyph(item.Kind);
                    tags = GlyphTags.GetTags(glyph);
                }

                var properties = ImmutableDictionary.CreateBuilder <string, string>();
                if (!string.IsNullOrEmpty(item.Detail))
                {
                    // The display text is encoded as TaggedText | value
                    properties.Add("Description", $"Text|{item.Detail}");
                }

                properties.Add("InsertionText", item.InsertText);
                properties.Add("ResolveData", JToken.FromObject(item).ToString());
                var completionItem = CompletionItem.Create(item.Label, item.FilterText, item.SortText, properties: properties.ToImmutable(), tags: tags);
                context.AddItem(completionItem);
            }
        }
        private static async Task <DefinitionItem> ToDefinitionItemAsync(
            this ISymbol definition,
            Solution solution,
            bool isPrimary,
            bool includeHiddenLocations,
            bool includeClassifiedSpans,
            FindReferencesSearchOptions options,
            CancellationToken cancellationToken)
        {
            // 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.
            if (!definition.IsTupleField())
            {
                // In an earlier implementation of the compiler APIs, tuples and tuple fields symbols were definitions
                // We pretend this is still the case
                definition = definition.OriginalDefinition;
            }

            var displayParts     = GetDisplayParts(definition);
            var nameDisplayParts = definition.ToDisplayParts(s_namePartsFormat).ToTaggedText();

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

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

            var properties = GetProperties(definition, isPrimary);

            // If it's a namespace, don't create any normal location.  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)
            {
                foreach (var location in definition.Locations)
                {
                    if (location.IsInMetadata)
                    {
                        return(DefinitionItem.CreateMetadataDefinition(
                                   tags, displayParts, nameDisplayParts, solution,
                                   definition, properties, displayIfNoReferences));
                    }
                    else if (location.IsInSource)
                    {
                        if (!location.IsVisibleSourceLocation() &&
                            !includeHiddenLocations)
                        {
                            continue;
                        }

                        var document = solution.GetDocument(location.SourceTree);
                        if (document != null)
                        {
                            var documentLocation = !includeClassifiedSpans
                                ? new DocumentSpan(document, location.SourceSpan)
                                : await ClassifiedSpansAndHighlightSpanFactory.GetClassifiedDocumentSpanAsync(
                                document, location.SourceSpan, cancellationToken).ConfigureAwait(false);

                            sourceLocations.Add(documentLocation);
                        }
                        else
                        {
                            // Was this a source generated tree? If so, we don't have a document representaion (yet) so
                            // we'll create a metadata symbol which will later be handled by the symbol navigation service
                            // that way. Once we represent generated source trees as propery documents, we'll update the code above
                            // to correctly make this item.
                            var project            = solution.GetOriginatingProject(definition);
                            var generatorRunResult = await project.GetGeneratorDriverRunResultAsync(cancellationToken).ConfigureAwait(false);

                            if (generatorRunResult.TryGetGeneratorAndHint(location.SourceTree, out _, out _))
                            {
                                return(DefinitionItem.CreateMetadataDefinition(
                                           tags, displayParts, nameDisplayParts, solution,
                                           definition, properties, displayIfNoReferences));
                            }
                        }
                    }
                }
            }

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

            var displayableProperties = AbstractReferenceFinder.GetAdditionalFindUsagesProperties(definition);

            return(DefinitionItem.Create(
                       tags, displayParts, sourceLocations.ToImmutable(),
                       nameDisplayParts, properties, displayableProperties, displayIfNoReferences));
        }