// Internal for testing public async Task <DiagnosticReport[]> HandleRequestAsync(DocumentDiagnosticsParams 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.LogWarning($"Failed to find document {request.TextDocument.Uri}."); return(null); } 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 DiagnosticReport[] { new DiagnosticReport() { ResultId = request.PreviousResultId, Diagnostics = null } }); } var referenceParams = new DocumentDiagnosticsParams() { TextDocument = new TextDocumentIdentifier() { Uri = csharpDoc.Uri }, PreviousResultId = request.PreviousResultId }; _logger.LogInformation($"Requesting diagnostics for {csharpDoc.Uri} with previous result Id of {request.PreviousResultId}."); // End goal is to transition this from ReinvokeRequestOnMultipleServersAsync -> ReinvokeRequestOnServerAsync // We can't do this right now as we don't have the ability to specify the language client name we'd like to make the call out to // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1246135 var resultsFromAllLanguageServers = await _requestInvoker.ReinvokeRequestOnMultipleServersAsync <DocumentDiagnosticsParams, DiagnosticReport[]>( MSLSPMethods.DocumentPullDiagnosticName, RazorLSPConstants.CSharpContentTypeName, referenceParams, cancellationToken).ConfigureAwait(false); var results = resultsFromAllLanguageServers.SelectMany(l => l).ToArray(); _logger.LogInformation($"Received {results?.Length} diagnostic reports."); var processedResults = await RemapDocumentDiagnosticsAsync( results, 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); }
// 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); }