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); }