protected async Task <LSP.Location[]?> GetDefinitionAsync(LSP.TextDocumentPositionParams request, bool typeOnly, RequestContext context, CancellationToken cancellationToken) { var document = context.Document; if (document == null) { return(null); } var locations = ArrayBuilder <LSP.Location> .GetInstance(); var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); var findDefinitionService = document.GetRequiredLanguageService <IFindDefinitionService>(); var definitions = await findDefinitionService.FindDefinitionsAsync(document, position, cancellationToken).ConfigureAwait(false); if (definitions.Any()) { foreach (var definition in definitions) { if (!ShouldInclude(definition, typeOnly)) { continue; } var location = await ProtocolConversions.TextSpanToLocationAsync( definition.Document, definition.SourceSpan, definition.IsStale, cancellationToken).ConfigureAwait(false); locations.AddIfNotNull(location); } } else if (document.SupportsSemanticModel && _metadataAsSourceFileService != null) { // No definition found - see if we can get metadata as source but that's only applicable for C#\VB. var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken).ConfigureAwait(false); if (symbol != null && _metadataAsSourceFileService.IsNavigableMetadataSymbol(symbol)) { if (!typeOnly || symbol is ITypeSymbol) { var options = _globalOptions.GetMetadataAsSourceOptions(document.Project.LanguageServices); var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(document.Project, symbol, signaturesOnly : false, options, cancellationToken).ConfigureAwait(false); var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; locations.Add(new LSP.Location { Uri = new Uri(declarationFile.FilePath), Range = ProtocolConversions.LinePositionToRange(linePosSpan), }); } } } return(locations.ToArrayAndFree());
private async Task <INavigableLocation?> GetNavigableLocationForMetadataAsync( Project project, ISymbol symbol, CancellationToken cancellationToken) { var masOptions = _globalOptions.GetMetadataAsSourceOptions(); var result = await _metadataAsSourceFileService.GetGeneratedFileAsync(project, symbol, signaturesOnly : false, masOptions, cancellationToken).ConfigureAwait(false); return(new NavigableLocation(async(options, cancellationToken) => { await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var vsRunningDocumentTable4 = _serviceProvider.GetServiceOnMainThread <SVsRunningDocumentTable, IVsRunningDocumentTable4>(); var fileAlreadyOpen = vsRunningDocumentTable4.IsMonikerValid(result.FilePath); var openDocumentService = _serviceProvider.GetServiceOnMainThread <SVsUIShellOpenDocument, IVsUIShellOpenDocument>(); openDocumentService.OpenDocumentViaProject(result.FilePath, VSConstants.LOGVIEWID.TextView_guid, out _, out _, out _, out var windowFrame); var documentCookie = vsRunningDocumentTable4.GetDocumentCookie(result.FilePath); var vsTextBuffer = (IVsTextBuffer)vsRunningDocumentTable4.GetDocumentData(documentCookie); // Set the buffer to read only, just in case the file isn't ErrorHandler.ThrowOnFailure(vsTextBuffer.GetStateFlags(out var flags)); flags |= (int)BUFFERSTATEFLAGS.BSF_USER_READONLY; ErrorHandler.ThrowOnFailure(vsTextBuffer.SetStateFlags(flags)); var textBuffer = _editorAdaptersFactory.GetDataBuffer(vsTextBuffer); if (!fileAlreadyOpen) { ErrorHandler.ThrowOnFailure(windowFrame.SetProperty((int)__VSFPROPID5.VSFPROPID_IsProvisional, true)); ErrorHandler.ThrowOnFailure(windowFrame.SetProperty((int)__VSFPROPID5.VSFPROPID_OverrideCaption, result.DocumentTitle)); ErrorHandler.ThrowOnFailure(windowFrame.SetProperty((int)__VSFPROPID5.VSFPROPID_OverrideToolTip, result.DocumentTooltip)); } windowFrame.Show(); var openedDocument = textBuffer?.AsTextContainer().GetRelatedDocuments().FirstOrDefault(); if (openedDocument != null) { var editorWorkspace = openedDocument.Project.Solution.Workspace; var navigationService = editorWorkspace.Services.GetRequiredService <IDocumentNavigationService>(); await navigationService.TryNavigateToSpanAsync( this.ThreadingContext, editorWorkspace, openedDocument.Id, result.IdentifierLocation.SourceSpan, options with { PreferProvisionalTab = true }, cancellationToken).ConfigureAwait(false); }
private static async Task <LSP.Location[]> GetSymbolDefinitionLocationsAsync(XamlSymbolDefinition symbolDefinition, RequestContext context, IMetadataAsSourceFileService metadataAsSourceFileService, IGlobalOptionService globalOptions, CancellationToken cancellationToken) { Contract.ThrowIfNull(symbolDefinition.Symbol); using var _ = ArrayBuilder <LSP.Location> .GetInstance(out var locations); var symbol = symbolDefinition.Symbol; var items = NavigableItemFactory.GetItemsFromPreferredSourceLocations(context.Solution, symbol, displayTaggedParts: null, cancellationToken); if (items.Any()) { foreach (var item in items) { var location = await ProtocolConversions.TextSpanToLocationAsync( item.Document, item.SourceSpan, item.IsStale, cancellationToken).ConfigureAwait(false); locations.AddIfNotNull(location); } } else { if (metadataAsSourceFileService.IsNavigableMetadataSymbol(symbol)) { var project = context.Document?.GetCodeProject(); if (project != null) { var options = globalOptions.GetMetadataAsSourceOptions(project.LanguageServices); var declarationFile = await metadataAsSourceFileService.GetGeneratedFileAsync(project, symbol, signaturesOnly : true, options, cancellationToken).ConfigureAwait(false); var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; locations.Add(new LSP.Location { Uri = new Uri(declarationFile.FilePath), Range = ProtocolConversions.LinePositionToRange(linePosSpan), }); } } } return(locations.ToArray()); }
/// <summary> /// Internal for testing purposes. /// </summary> internal async Task <ImmutableArray <CodeDefinitionWindowLocation> > GetContextFromPointAsync( Document document, int position, CancellationToken cancellationToken) { var workspace = document.Project.Solution.Workspace; var navigableItems = await GoToDefinitionHelpers.GetDefinitionsAsync(document, position, cancellationToken).ConfigureAwait(false); if (navigableItems?.Any() == true) { var navigationService = workspace.Services.GetRequiredService <IDocumentNavigationService>(); using var _ = PooledObjects.ArrayBuilder <CodeDefinitionWindowLocation> .GetInstance(out var builder); foreach (var item in navigableItems) { if (await navigationService.CanNavigateToSpanAsync(workspace, item.Document.Id, item.SourceSpan, cancellationToken).ConfigureAwait(false)) { var text = await item.Document.GetTextAsync(cancellationToken).ConfigureAwait(false); var linePositionSpan = text.Lines.GetLinePositionSpan(item.SourceSpan); if (item.Document.FilePath != null) { builder.Add(new CodeDefinitionWindowLocation(item.DisplayTaggedParts.JoinText(), item.Document.FilePath, linePositionSpan.Start)); } } } return(builder.ToImmutable()); } // We didn't have regular source references, but possibly: // 1. Another language (like XAML) will take over via ISymbolNavigationService // 2. There are no locations from source, so we'll try to generate a metadata as source file and use that var symbol = await SymbolFinder.FindSymbolAtPositionAsync( document, position, cancellationToken : cancellationToken).ConfigureAwait(false); if (symbol == null) { return(ImmutableArray <CodeDefinitionWindowLocation> .Empty); } var symbolNavigationService = workspace.Services.GetRequiredService <ISymbolNavigationService>(); var definitionItem = symbol.ToNonClassifiedDefinitionItem(document.Project.Solution, includeHiddenLocations: false); var result = await symbolNavigationService.GetExternalNavigationSymbolLocationAsync(definitionItem, cancellationToken).ConfigureAwait(false); if (result != null) { return(ImmutableArray.Create(new CodeDefinitionWindowLocation(symbol.ToDisplayString(), result.Value.filePath, result.Value.linePosition))); } else if (_metadataAsSourceFileService.IsNavigableMetadataSymbol(symbol)) { var options = _globalOptions.GetMetadataAsSourceOptions(document.Project.LanguageServices); var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(document.Project, symbol, signaturesOnly : false, options, cancellationToken).ConfigureAwait(false); var identifierSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; return(ImmutableArray.Create(new CodeDefinitionWindowLocation(symbol.ToDisplayString(), declarationFile.FilePath, identifierSpan.Start))); } return(ImmutableArray <CodeDefinitionWindowLocation> .Empty); }