public async Task HandleRequestAsync_DocumentNotFound_ClearsDiagnostics()
        {
            // Arrange
            var documentManager            = new TestDocumentManager();
            var requestInvoker             = Mock.Of <LSPRequestInvoker>(MockBehavior.Strict);
            var diagnosticsProvider        = Mock.Of <LSPDiagnosticsTranslator>(MockBehavior.Strict);
            var documentSynchronizer       = Mock.Of <LSPDocumentSynchronizer>(MockBehavior.Strict);
            var documentDiagnosticsHandler = new DocumentPullDiagnosticsHandler(requestInvoker, documentManager, documentSynchronizer, diagnosticsProvider, LoggerProvider);
            var diagnosticRequest          = new VSInternalDocumentDiagnosticsParams()
            {
                TextDocument = new TextDocumentIdentifier()
                {
                    Uri = Uri
                },
                PreviousResultId = "4"
            };

            // Act
            var result = await documentDiagnosticsHandler.HandleRequestAsync(diagnosticRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false);

            // Assert
            var report = Assert.Single(result);

            Assert.Null(report.Diagnostics);
            Assert.Null(report.ResultId);
        }
        public Task <VSInternalDiagnosticReport[]?> GetDocumentPullDiagnosticsAsync(VSInternalDocumentDiagnosticsParams diagnosticsParams, CancellationToken cancellationToken)
        {
            Contract.ThrowIfNull(_clientCapabilities, $"{nameof(InitializeAsync)} has not been called.");

            return(RequestDispatcher.ExecuteRequestAsync <VSInternalDocumentDiagnosticsParams, VSInternalDiagnosticReport[]?>(
                       Queue, VSInternalMethods.DocumentPullDiagnosticName,
                       diagnosticsParams, _clientCapabilities, ClientName, cancellationToken));
        }
        public async Task HandleRequestAsync_RemapsDiagnosticRange()
        {
            // Arrange
            var called          = false;
            var documentManager = CreateDocumentManager();

            var requestInvoker = GetRequestInvoker <VSInternalDocumentDiagnosticsParams, VSInternalDiagnosticReport[]>(
                s_roslynDiagnosticResponse,
                (textBuffer, method, diagnosticParams, ct) =>
            {
                Assert.Equal(VSInternalMethods.DocumentPullDiagnosticName, method);
                called = true;
            });

            var diagnosticsProvider  = GetDiagnosticsProvider(s_validDiagnostic_UnknownName_MappedRange, s_validDiagnostic_InvalidExpression_MappedRange);
            var documentSynchronizer = CreateDocumentSynchronizer();

            var documentDiagnosticsHandler = new DocumentPullDiagnosticsHandler(requestInvoker, documentManager, documentSynchronizer, diagnosticsProvider, LoggerProvider);
            var diagnosticRequest          = new VSInternalDocumentDiagnosticsParams()
            {
                TextDocument = new TextDocumentIdentifier()
                {
                    Uri = Uri
                },
                PreviousResultId = "4"
            };

            // Act
            var result = await documentDiagnosticsHandler.HandleRequestAsync(diagnosticRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false);

            // Assert
            Assert.True(called);
            var diagnosticReport = Assert.Single(result);

            Assert.Equal(s_roslynDiagnosticResponse.First().ResultId, diagnosticReport.ResultId);
            Assert.Collection(diagnosticReport.Diagnostics,
                              d =>
            {
                Assert.Equal(s_validDiagnostic_UnknownName.Code, d.Code);
                Assert.Equal(s_validDiagnostic_UnknownName_MappedRange, d.Range);
            },
                              d =>
            {
                Assert.Equal(s_validDiagnostic_InvalidExpression.Code, d.Code);
                Assert.Equal(s_validDiagnostic_InvalidExpression_MappedRange, d.Range);
            });
        }
        public async Task HandleRequestAsync_DocumentSynchronizationFails_ReturnsNullDiagnostic()
        {
            // Arrange
            var called          = false;
            var documentManager = CreateDocumentManager();

            var requestInvoker = GetRequestInvoker <VSInternalDocumentDiagnosticsParams, VSInternalDiagnosticReport[]>(
                s_roslynDiagnosticResponse,
                (textBuffer, method, diagnosticParams, ct) =>
            {
                Assert.Equal(VSInternalMethods.DocumentPullDiagnosticName, method);
                called = true;
            });

            var diagnosticsProvider = GetDiagnosticsProvider(s_validDiagnostic_UnknownName_MappedRange, s_validDiagnostic_InvalidExpression_MappedRange);

            var documentSynchronizer = new Mock <LSPDocumentSynchronizer>(MockBehavior.Strict);

            documentSynchronizer
            .Setup(d => d.TrySynchronizeVirtualDocumentAsync(It.IsAny <int>(), It.IsAny <CSharpVirtualDocumentSnapshot>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(false));

            var documentDiagnosticsHandler = new DocumentPullDiagnosticsHandler(requestInvoker, documentManager, documentSynchronizer.Object, diagnosticsProvider, LoggerProvider);
            var diagnosticRequest          = new VSInternalDocumentDiagnosticsParams()
            {
                TextDocument = new TextDocumentIdentifier()
                {
                    Uri = Uri
                },
                PreviousResultId = "4"
            };

            // Act
            var result = await documentDiagnosticsHandler.HandleRequestAsync(diagnosticRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false);

            // Assert
            Assert.False(called);
            var diagnosticReport = Assert.Single(result);

            Assert.Equal(diagnosticRequest.PreviousResultId, diagnosticReport.ResultId);
            Assert.Null(diagnosticReport.Diagnostics);
        }
    public async Task TestRoslynTypeScriptHandlerInvoked()
    {
        var workspaceXml =
            @$ "<Workspace>
    <Project Language=" "TypeScript" " CommonReferences=" "true" " AssemblyName=" "TypeScriptProj" ">
        <Document FilePath=" "C:\T.ts" "></Document>
    </Project>
</Workspace>";

        using var testLspServer = await CreateTsTestLspServerAsync(workspaceXml);

        var document            = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single();
        var documentPullRequest = new VSInternalDocumentDiagnosticsParams
        {
            TextDocument = CreateTextDocumentIdentifier(document.GetURI(), document.Project.Id)
        };

        var response = await testLspServer.ExecuteRequestAsync <VSInternalDocumentDiagnosticsParams, VSInternalDiagnosticReport[]>(VSInternalMethods.DocumentPullDiagnosticName, documentPullRequest, CancellationToken.None);

        Assert.Empty(response);
    }
        public async Task HandleRequestAsync_VersionMismatch_DiscardsLocation()
        {
            // Arrange
            var called          = false;
            var documentManager = CreateDocumentManager(hostDocumentVersion: 1);

            var requestInvoker = GetRequestInvoker <VSInternalDocumentDiagnosticsParams, VSInternalDiagnosticReport[]>(
                s_roslynDiagnosticResponse,
                (textBuffer, method, diagnosticParams, ct) =>
            {
                Assert.Equal(VSInternalMethods.DocumentPullDiagnosticName, method);
                called = true;
            });

            // Note the HostDocumentVersion provided by the DiagnosticsProvider = 0,
            // which is different from document version (1) from the DocumentManager
            var diagnosticsProvider  = GetDiagnosticsProvider(s_validDiagnostic_UnknownName_MappedRange, s_validDiagnostic_InvalidExpression_MappedRange);
            var documentSynchronizer = CreateDocumentSynchronizer();

            var documentDiagnosticsHandler = new DocumentPullDiagnosticsHandler(requestInvoker, documentManager, documentSynchronizer, diagnosticsProvider, LoggerProvider);
            var diagnosticRequest          = new VSInternalDocumentDiagnosticsParams()
            {
                TextDocument = new TextDocumentIdentifier()
                {
                    Uri = Uri
                },
                PreviousResultId = "4"
            };

            // Act
            var result = await documentDiagnosticsHandler.HandleRequestAsync(diagnosticRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false);

            // Assert
            Assert.True(called);
            var returnedReport = Assert.Single(result);

            Assert.Equal(s_roslynDiagnosticResponse.First().ResultId, returnedReport.ResultId);
            Assert.Null(returnedReport.Diagnostics);
        }
        public async Task HandleRequestAsync_NoDiagnosticsAfterFiltering_ReturnsNullDiagnostic()
        {
            // Arrange
            var called          = false;
            var documentManager = CreateDocumentManager();

            var filteredDiagnostic = new Diagnostic()
            {
                Range = new Range()
                {
                    Start = new Position(159, 19),
                    End   = new Position(159, 23)
                },
                Code     = "RemoveUnnecessaryImportsFixable",
                Severity = DiagnosticSeverity.Warning
            };

            var filteredDiagnostic_mappedRange = new Range()
            {
                Start = new Position(49, 19),
                End   = new Position(49, 23)
            };

            var diagnosticReport = new VSInternalDiagnosticReport()
            {
                ResultId    = "6",
                Diagnostics = new Diagnostic[]
                {
                    filteredDiagnostic
                }
            };

            var requestInvoker = GetRequestInvoker <VSInternalDocumentDiagnosticsParams, VSInternalDiagnosticReport[]>(
                new[] { diagnosticReport },
                (textBuffer, method, diagnosticParams, ct) =>
            {
                Assert.Equal(VSInternalMethods.DocumentPullDiagnosticName, method);
                called = true;
            });

            var diagnosticsProvider  = GetDiagnosticsProvider(filteredDiagnostic_mappedRange);
            var documentSynchronizer = CreateDocumentSynchronizer();

            var documentDiagnosticsHandler = new DocumentPullDiagnosticsHandler(requestInvoker, documentManager, documentSynchronizer, diagnosticsProvider, LoggerProvider);
            var diagnosticRequest          = new VSInternalDocumentDiagnosticsParams()
            {
                TextDocument = new TextDocumentIdentifier()
                {
                    Uri = Uri
                },
                PreviousResultId = "4"
            };

            // Act
            var result = await documentDiagnosticsHandler.HandleRequestAsync(diagnosticRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false);

            // Assert
            Assert.True(called);
            var returnedReport = Assert.Single(result);

            Assert.Equal(diagnosticReport.ResultId, returnedReport.ResultId);
            Assert.Empty(returnedReport.Diagnostics);
        }
        public async Task HandleRequestAsync_RemapFailsButErrorDiagnosticIsShown()
        {
            // Arrange
            var called          = false;
            var documentManager = CreateDocumentManager();

            var unmappableDiagnostic_errorSeverity = new Diagnostic()
            {
                Range = new Range()
                {
                    Start = new Position(149, 19),
                    End   = new Position(149, 23)
                },
                Code     = "CS0103",
                Severity = DiagnosticSeverity.Error
            };

            var unmappableDiagnostic_warningSeverity = new Diagnostic()
            {
                Range = new Range()
                {
                    Start = new Position(159, 19),
                    End   = new Position(159, 23)
                },
                Code     = "IDE003",
                Severity = DiagnosticSeverity.Warning
            };

            var diagnosticReport = new VSInternalDiagnosticReport()
            {
                ResultId    = "6",
                Diagnostics = new Diagnostic[]
                {
                    unmappableDiagnostic_errorSeverity,
                    unmappableDiagnostic_warningSeverity
                }
            };

            var requestInvoker = GetRequestInvoker <VSInternalDocumentDiagnosticsParams, VSInternalDiagnosticReport[]>(
                new[] { diagnosticReport },
                (textBuffer, method, diagnosticParams, ct) =>
            {
                Assert.Equal(VSInternalMethods.DocumentPullDiagnosticName, method);
                called = true;
            });

            var undefinedRange = new Range()
            {
                Start = new Position(-1, -1), End = new Position(-1, -1)
            };
            var diagnosticsProvider = GetDiagnosticsProvider(undefinedRange, undefinedRange);

            var documentSynchronizer = CreateDocumentSynchronizer();

            var documentDiagnosticsHandler = new DocumentPullDiagnosticsHandler(requestInvoker, documentManager, documentSynchronizer, diagnosticsProvider, LoggerProvider);
            var diagnosticRequest          = new VSInternalDocumentDiagnosticsParams()
            {
                TextDocument = new TextDocumentIdentifier()
                {
                    Uri = Uri
                },
                PreviousResultId = "4"
            };

            // Act
            var result = await documentDiagnosticsHandler.HandleRequestAsync(diagnosticRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false);

            // Assert
            Assert.True(called);

            var diagnosticReportResult = Assert.Single(result);

            Assert.Equal(diagnosticReport.ResultId, diagnosticReportResult.ResultId);

            var returnedDiagnostic = Assert.Single(diagnosticReportResult.Diagnostics);

            Assert.Equal(unmappableDiagnostic_errorSeverity.Code, returnedDiagnostic.Code);
            Assert.True(returnedDiagnostic.Range.IsUndefined());
        }
        // Internal for testing
        public async Task <IReadOnlyList <VSInternalDiagnosticReport> > HandleRequestAsync(VSInternalDocumentDiagnosticsParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
        {
            if (request is null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (clientCapabilities is null)
            {
                throw new ArgumentNullException(nameof(clientCapabilities));
            }

            _logger.LogInformation($"Starting request for {request.TextDocument.Uri}.");

            if (!_documentManager.TryGetDocument(request.TextDocument.Uri, out var documentSnapshot))
            {
                _logger.LogInformation($"Document {request.TextDocument.Uri} closed or deleted, clearing diagnostics.");

                var clearedDiagnosticReport = new VSInternalDiagnosticReport[]
                {
                    new VSInternalDiagnosticReport()
                    {
                        ResultId    = null,
                        Diagnostics = null
                    }
                };
                return(clearedDiagnosticReport);
            }

            if (!documentSnapshot.TryGetVirtualDocument <CSharpVirtualDocumentSnapshot>(out var csharpDoc))
            {
                _logger.LogWarning($"Failed to find virtual C# document for {request.TextDocument.Uri}.");
                return(null);
            }

            var synchronized = await _documentSynchronizer.TrySynchronizeVirtualDocumentAsync(
                documentSnapshot.Version,
                csharpDoc,
                cancellationToken).ConfigureAwait(false);

            if (!synchronized)
            {
                _logger.LogInformation($"Failed to synchronize document {csharpDoc.Uri}.");

                // Could not synchronize, report nothing changed
                return(new VSInternalDiagnosticReport[]
                {
                    new VSInternalDiagnosticReport()
                    {
                        ResultId = request.PreviousResultId,
                        Diagnostics = null
                    }
                });
            }

            var referenceParams = new VSInternalDocumentDiagnosticsParams()
            {
                TextDocument = new TextDocumentIdentifier()
                {
                    Uri = csharpDoc.Uri
                },
                PreviousResultId = request.PreviousResultId
            };

            _logger.LogInformation($"Requesting diagnostics for {csharpDoc.Uri} with previous result Id of {request.PreviousResultId}.");

            var textBuffer = csharpDoc.Snapshot.TextBuffer;
            var requests   = _requestInvoker.ReinvokeRequestOnMultipleServersAsync <VSInternalDocumentDiagnosticsParams, VSInternalDiagnosticReport[]>(
                textBuffer,
                VSInternalMethods.DocumentPullDiagnosticName,
                referenceParams,
                cancellationToken).ConfigureAwait(false);

            var resultsFromAllLanguageServers = new List <VSInternalDiagnosticReport>();

            await foreach (var response in requests)
            {
                if (response.Response is not null)
                {
                    resultsFromAllLanguageServers.AddRange(response.Response);
                }
            }

            _logger.LogInformation($"Received {resultsFromAllLanguageServers.Count} diagnostic reports.");

            var processedResults = await RemapDocumentDiagnosticsAsync(
                resultsFromAllLanguageServers,
                request.TextDocument.Uri,
                cancellationToken).ConfigureAwait(false);

            // | ---------------------------------------------------------------------------------- |
            // |                       LSP Platform Expected Response Semantics                     |
            // | ---------------------------------------------------------------------------------- |
            // | DiagnosticReport.Diagnostics     | DiagnosticReport.ResultId | Meaning             |
            // | -------------------------------- | ------------------------- | ------------------- |
            // | `null`                           | `null`                    | document gone       |
            // | `null`                           | valid                     | nothing changed     |
            // | valid (non-null including empty) | valid                     | diagnostics changed |
            // | ---------------------------------------------------------------------------------- |
            return(processedResults);
        }
Esempio n. 10
0
        public Task <IReadOnlyList <VSInternalDiagnosticReport> > DocumentPullDiagnosticsAsync(VSInternalDocumentDiagnosticsParams documentDiagnosticsParams, CancellationToken cancellationToken)
        {
            if (documentDiagnosticsParams is null)
            {
                throw new ArgumentNullException(nameof(documentDiagnosticsParams));
            }

            return(ExecuteRequestAsync <VSInternalDocumentDiagnosticsParams, IReadOnlyList <VSInternalDiagnosticReport> >(VSInternalMethods.DocumentPullDiagnosticName, documentDiagnosticsParams, ClientCapabilities, cancellationToken));
        }