Exemple #1
0
        /// <summary>
        ///  Using the find usages service is more expensive than using the definitions service because a lot of unnecessary information is computed. However, some languages
        /// don't provide an <see cref="IGoToDefinitionService"/> implementation that will return definitions so we must use <see cref="IFindUsagesService"/>.
        /// </summary>
        private async Task <List <LSP.Location> > GetDefinitionsWithFindUsagesService(Document document, int pos, CancellationToken cancellationToken)
        {
            var findUsagesService = document.Project.LanguageServices.GetService <IFindUsagesService>();

            var context = new SimpleFindUsagesContext(cancellationToken);

            // Roslyn calls into third party extensions to compute reference results and needs to be on the UI thread to compute results.
            // This is not great for us and ideally we should ask for a Roslyn API where we can make this call without blocking the UI.
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

            await findUsagesService.FindReferencesAsync(document, pos, context).ConfigureAwait(false);

            var locations = new List <LSP.Location>();

            var definitions = context.GetDefinitions();

            if (definitions != null)
            {
                foreach (var definition in definitions)
                {
                    foreach (var docSpan in definition.SourceSpans)
                    {
                        locations.Add(await ProtocolConversions.DocumentSpanToLocationAsync(docSpan, cancellationToken).ConfigureAwait(false));
                    }
                }
            }

            return(locations);
        }
Exemple #2
0
        public override async Task <LSP.Location[]> HandleRequestAsync(LSP.TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            Contract.ThrowIfNull(document);

            var locations = ArrayBuilder <LSP.Location> .GetInstance();

            var findUsagesService = document.GetRequiredLanguageService <IFindUsagesService>();
            var position          = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            var findUsagesContext = new SimpleFindUsagesContext();

            await FindImplementationsAsync(findUsagesService, document, position, findUsagesContext, cancellationToken).ConfigureAwait(false);

            foreach (var definition in findUsagesContext.GetDefinitions())
            {
                var text = definition.GetClassifiedText();
                foreach (var sourceSpan in definition.SourceSpans)
                {
                    if (context.ClientCapabilities?.HasVisualStudioLspCapability() == true)
                    {
                        locations.AddIfNotNull(await ProtocolConversions.DocumentSpanToLocationWithTextAsync(sourceSpan, text, cancellationToken).ConfigureAwait(false));
                    }
                    else
                    {
                        locations.AddIfNotNull(await ProtocolConversions.DocumentSpanToLocationAsync(sourceSpan, cancellationToken).ConfigureAwait(false));
                    }
                }
            }

            return(locations.ToArrayAndFree());
        }
Exemple #3
0
        private async Task <LSP.ReferenceGroup[]> GetReferenceGroupsAsync(LSP.ReferenceParams request, SimpleFindUsagesContext context, CancellationToken cancellationToken)
        {
            var definitionMap = new Dictionary <DefinitionItem, List <SourceReferenceItem> >();

            foreach (var reference in context.GetReferences())
            {
                if (!definitionMap.ContainsKey(reference.Definition))
                {
                    definitionMap.Add(reference.Definition, new List <SourceReferenceItem>());
                }

                definitionMap[reference.Definition].Add(reference);
            }

            var referenceGroups = ArrayBuilder <LSP.ReferenceGroup> .GetInstance();

            foreach (var keyValuePair in definitionMap)
            {
                var definition = keyValuePair.Key;
                var references = keyValuePair.Value;

                var referenceGroup = new LSP.ReferenceGroup();
                var text           = definition.GetClassifiedText();

                referenceGroup.Definition = await ProtocolConversions.DocumentSpanToLocationWithTextAsync(definition.SourceSpans.First(), text, cancellationToken).ConfigureAwait(false);

                referenceGroup.DefinitionIcon = new ImageElement(definition.Tags.GetFirstGlyph().GetImageId());

                var locationWithTexts = new ArrayBuilder <LSP.LocationWithText>();
                foreach (var reference in references)
                {
                    var classifiedSpansAndHighlightSpan = await ClassifiedSpansAndHighlightSpanFactory.ClassifyAsync(reference.SourceSpan, context.CancellationToken).ConfigureAwait(false);

                    var classifiedSpans   = classifiedSpansAndHighlightSpan.ClassifiedSpans;
                    var referenceLocation = await ProtocolConversions.DocumentSpanToLocationAsync(reference.SourceSpan, cancellationToken).ConfigureAwait(false);

                    var docText = await reference.SourceSpan.Document.GetTextAsync(context.CancellationToken).ConfigureAwait(false);

                    var classifiedText   = new ClassifiedTextElement(classifiedSpans.Select(cspan => new ClassifiedTextRun(cspan.ClassificationType, docText.ToString(cspan.TextSpan))));
                    var locationWithText = new LSP.LocationWithText {
                        Range = referenceLocation.Range, Uri = referenceLocation.Uri, Text = classifiedText
                    };
                    locationWithTexts.Add(locationWithText);
                }

                referenceGroup.References = locationWithTexts.ToArrayAndFree();
                referenceGroups.Add(referenceGroup);
            }

            return(referenceGroups.ToArrayAndFree());
        }
Exemple #4
0
            // Local functions
            static async Task <LSP.Location?> ComputeLocationAsync(
                Document document,
                int position,
                DocumentSpan documentSpan,
                IMetadataAsSourceFileService metadataAsSourceFileService,
                CancellationToken cancellationToken)
            {
                if (documentSpan != default)
                {
                    // We do have a document span, so compute location normally.
                    return(await ProtocolConversions.DocumentSpanToLocationAsync(documentSpan, cancellationToken).ConfigureAwait(false));
                }

                // If we have no document span, our location may be in metadata or may be a namespace.
                var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken).ConfigureAwait(false);

                if (symbol == null || symbol.Locations.IsEmpty || symbol.Kind == SymbolKind.Namespace)
                {
                    // Either:
                    // (1) We couldn't find the location in metadata and it's not in any of our known documents.
                    // (2) The symbol is a namespace (and therefore has no location).
                    return(null);
                }

                var declarationFile = await metadataAsSourceFileService.GetGeneratedFileAsync(
                    document.Project, symbol, allowDecompilation : false, cancellationToken).ConfigureAwait(false);

                var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span;

                if (string.IsNullOrEmpty(declarationFile.FilePath))
                {
                    return(null);
                }

                try
                {
                    return(new LSP.Location
                    {
                        Uri = ProtocolConversions.GetUriFromFilePath(declarationFile.FilePath),
                        Range = ProtocolConversions.LinePositionToRange(linePosSpan),
                    });
                }
                catch (UriFormatException e) when(FatalError.ReportAndCatch(e))
                {
                    // We might reach this point if the file path is formatted incorrectly.
                    return(null);
                }
            }
Exemple #5
0
        private static async Task <LSP.Location[]> GetLocationsAsync(LSP.ReferenceParams request, SimpleFindUsagesContext context, CancellationToken cancellationToken)
        {
            var locations = ArrayBuilder <LSP.Location> .GetInstance();

            if (request.Context.IncludeDeclaration)
            {
                foreach (var definition in context.GetDefinitions())
                {
                    foreach (var docSpan in definition.SourceSpans)
                    {
                        locations.Add(await ProtocolConversions.DocumentSpanToLocationAsync(docSpan, cancellationToken).ConfigureAwait(false));
                    }
                }
            }

            foreach (var reference in context.GetReferences())
            {
                locations.Add(await ProtocolConversions.DocumentSpanToLocationAsync(reference.SourceSpan, cancellationToken).ConfigureAwait(false));
            }

            return(locations.ToArrayAndFree());
        }
        public async Task <object> HandleRequestAsync(Solution solution, LSP.TextDocumentPositionParams request,
                                                      LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
        {
            var locations = ArrayBuilder <LSP.Location> .GetInstance();

            var document = solution.GetDocumentFromURI(request.TextDocument.Uri);

            if (document == null)
            {
                return(locations.ToArrayAndFree());
            }

            var findUsagesService = document.Project.LanguageServices.GetService <IFindUsagesService>();
            var position          = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            var context = new SimpleFindUsagesContext(cancellationToken);

            await FindImplementationsAsync(findUsagesService, document, position, context).ConfigureAwait(false);

            foreach (var definition in context.GetDefinitions())
            {
                var text = definition.GetClassifiedText();
                foreach (var sourceSpan in context.GetDefinitions().SelectMany(definition => definition.SourceSpans))
                {
                    if (clientCapabilities?.HasVisualStudioLspCapability() == true)
                    {
                        locations.Add(await ProtocolConversions.DocumentSpanToLocationWithTextAsync(sourceSpan, text, cancellationToken).ConfigureAwait(false));
                    }
                    else
                    {
                        locations.Add(await ProtocolConversions.DocumentSpanToLocationAsync(sourceSpan, cancellationToken).ConfigureAwait(false));
                    }
                }
            }

            return(locations.ToArrayAndFree());
        }