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));
        }
        private static async Task <bool> TryFindLiteralReferencesAsync(
            IFindUsagesContext context, Document document, int position, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

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

            var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>();

            // Currently we only support FAR for numbers, strings and characters.  We don't
            // bother with true/false/null as those are likely to have way too many results
            // to be useful.
            var token = await syntaxTree.GetTouchingTokenAsync(
                position,
                t => syntaxFacts.IsNumericLiteral(t) ||
                syntaxFacts.IsCharacterLiteral(t) ||
                syntaxFacts.IsStringLiteral(t),
                cancellationToken).ConfigureAwait(false);

            if (token.RawKind == 0)
            {
                return(false);
            }

            // Searching for decimals not supported currently.  Our index can only store 64bits
            // for numeric values, and a decimal won't fit within that.
            var tokenValue = token.Value;

            if (tokenValue is null or decimal)
            {
                return(false);
            }

            if (token.Parent is null)
            {
                return(false);
            }

            var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var symbol = semanticModel.GetSymbolInfo(token.Parent, cancellationToken).Symbol ?? semanticModel.GetDeclaredSymbol(token.Parent, cancellationToken);

            // Numeric labels are available in VB.  In that case we want the normal FAR engine to
            // do the searching.  For these literals we want to find symbolic results and not
            // numeric matches.
            if (symbol is ILabelSymbol)
            {
                return(false);
            }

            // Use the literal to make the title.  Trim literal if it's too long.
            var title = syntaxFacts.ConvertToSingleLine(token.Parent).ToString();

            if (title.Length >= 10)
            {
                title = title.Substring(0, 10) + "...";
            }

            var searchTitle = string.Format(FeaturesResources._0_references, title);
            await context.SetSearchTitleAsync(searchTitle, cancellationToken).ConfigureAwait(false);

            var solution = document.Project.Solution;

            // There will only be one 'definition' that all matching literal reference.
            // So just create it now and report to the context what it is.
            var definition = DefinitionItem.CreateNonNavigableItem(
                ImmutableArray.Create(TextTags.StringLiteral),
                ImmutableArray.Create(new TaggedText(TextTags.Text, searchTitle)));

            await context.OnDefinitionFoundAsync(definition, cancellationToken).ConfigureAwait(false);

            var progressAdapter = new FindLiteralsProgressAdapter(context, definition);

            // Now call into the underlying FAR engine to find reference.  The FAR
            // engine will push results into the 'progress' instance passed into it.
            // We'll take those results, massage them, and forward them along to the
            // FindUsagesContext instance we were given.
            await SymbolFinder.FindLiteralReferencesAsync(
                tokenValue, Type.GetTypeCode(tokenValue.GetType()), solution, progressAdapter, cancellationToken).ConfigureAwait(false);

            return(true);
        }