public async Task TestDocumentDiagnosticsForRemovedDocument() { var markup = @"class A {"; using var testLspServer = CreateTestWorkspaceWithDiagnostics( markup, BackgroundAnalysisScope.OpenFilesAndProjects ); var workspace = testLspServer.TestWorkspace; // Calling GetTextBuffer will effectively open the file. workspace.Documents.Single().GetTextBuffer(); var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); // Get the diagnostics for the solution containing the doc. var solution = document.Project.Solution; await OpenDocumentAsync(testLspServer, document); await WaitForDiagnosticsAsync(workspace); var results = await testLspServer.ExecuteRequestAsync < DocumentDiagnosticsParams, DiagnosticReport[] >( MSLSPMethods.DocumentPullDiagnosticName, CreateDocumentDiagnosticParams(document), new LSP.ClientCapabilities(), clientName : null, CancellationToken.None ); Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); // Now remove the doc. workspace.OnDocumentRemoved(workspace.Documents.Single().Id); await CloseDocumentAsync(testLspServer, document); // And get diagnostic again, using the same doc-id as before. await WaitForDiagnosticsAsync(workspace); results = await testLspServer.ExecuteRequestAsync < DocumentDiagnosticsParams, DiagnosticReport[] >( MSLSPMethods.DocumentPullDiagnosticName, new DocumentDiagnosticsParams { PreviousResultId = results.Single().ResultId, TextDocument = ProtocolConversions.DocumentToTextDocumentIdentifier(document) }, new LSP.ClientCapabilities(), clientName : null, CancellationToken.None ); Assert.Null(results.Single().Diagnostics); Assert.Null(results.Single().ResultId); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { // This provider is exported for all workspaces - so limit it to just our workspace. var(document, span, cancellationToken) = context; if (document.Project.Solution.Workspace.Kind != WorkspaceKind.AnyCodeRoslynWorkspace) { return; } var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient; if (lspClient == null) { return; } var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var diagnostics = await _diagnosticAnalyzerService.GetDiagnosticsForSpanAsync(document, span, cancellationToken : cancellationToken).ConfigureAwait(false); var diagnostic = diagnostics?.FirstOrDefault(); if (diagnostic != null) { span = diagnostic.TextSpan; } var codeActionParams = new LSP.CodeActionParams { TextDocument = ProtocolConversions.DocumentToTextDocumentIdentifier(document), Range = ProtocolConversions.TextSpanToRange(span, text) }; var commands = await lspClient.RequestAsync(LSP.Methods.TextDocumentCodeAction.ToLSRequest(), codeActionParams, cancellationToken).ConfigureAwait(false); if (commands == null) { return; } foreach (var command in commands) { if (LanguageServicesUtils.TryParseJson(command, out LSP.Command lspCommand)) { // The command can either wrap a Command or a CodeAction. // If a Command, leave it unchanged; we want to dispatch it to the host to execute. // If a CodeAction, unwrap the CodeAction so the guest can run it locally. var commandArguments = lspCommand.Arguments.Single(); if (LanguageServicesUtils.TryParseJson(commandArguments, out LSP.CodeAction lspCodeAction)) { context.RegisterRefactoring(new RoslynRemoteCodeAction(document, lspCodeAction.Command, lspCodeAction.Edit, lspCodeAction.Title, lspClient)); } else { context.RegisterRefactoring(new RoslynRemoteCodeAction(document, lspCommand, lspCommand?.Title, lspClient)); } } } }
public async Task <TReport[]?> HandleRequestAsync(TDiagnosticsParams diagnosticsParams, RequestContext context, CancellationToken cancellationToken) { Contract.ThrowIfNull(context.Solution); using var progress = BufferedProgress.Create(GetProgress(diagnosticsParams)); // Get the set of results the request said were previously reported. var previousResults = GetPreviousResults(diagnosticsParams); var documentToPreviousResultId = new Dictionary <Document, string?>(); if (previousResults != null) { // Go through the previousResults and check if we need to remove diagnostic information for any documents foreach (var previousResult in previousResults) { if (previousResult.TextDocument != null) { var document = context.Solution.GetDocument(previousResult.TextDocument); if (document == null) { // We can no longer get this document, return null for both diagnostics and resultId progress.Report(CreateReport(previousResult.TextDocument, diagnostics: null, resultId: null)); } else { // Cache the document to previousResultId mapping so we can easily retrieve the resultId later. documentToPreviousResultId[document] = previousResult.PreviousResultId; } } } } // Go through the documents that we need to process and call XamlPullDiagnosticService to get the diagnostic report foreach (var document in GetDocuments(context)) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var documentId = ProtocolConversions.DocumentToTextDocumentIdentifier(document); // If we can get a previousId of the document, use it, // otherwise use null as the previousId to pass into the XamlPullDiagnosticService var previousResultId = documentToPreviousResultId.TryGetValue(document, out var id) ? id : null; // Call XamlPullDiagnosticService to get the diagnostic report for this document. // We will compute what to report inside XamlPullDiagnosticService, for example, whether we should keep using the previousId or use a new resultId, // and the handler here just return the result get from XamlPullDiagnosticService. var diagnosticReport = await _xamlDiagnosticService.GetDiagnosticReportAsync(document, previousResultId, cancellationToken).ConfigureAwait(false); progress.Report(CreateReport( documentId, ConvertToVSDiagnostics(diagnosticReport.Diagnostics, document, text), diagnosticReport.ResultId)); } return(progress.GetValues()); }
public async Task FindReferencesAsync(Document document, int position, IFindUsagesContext context) { var text = await document.GetTextAsync().ConfigureAwait(false); var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient; if (lspClient == null) { return; } var referenceParams = new LSP.ReferenceParams { Context = new LSP.ReferenceContext { IncludeDeclaration = false }, TextDocument = ProtocolConversions.DocumentToTextDocumentIdentifier(document), Position = ProtocolConversions.LinePositionToPosition(text.Lines.GetLinePosition(position)) }; var locations = await lspClient.RequestAsync(LSP.Methods.TextDocumentReferences, referenceParams, context.CancellationToken).ConfigureAwait(false); if (locations == null) { return; } // TODO: Need to get real definition data from the server. var dummyDef = DefinitionItem.CreateNonNavigableItem(ImmutableArray <string> .Empty, ImmutableArray <TaggedText> .Empty); await context.OnDefinitionFoundAsync(dummyDef).ConfigureAwait(false); foreach (var location in locations) { var documentSpan = await _remoteLanguageServiceWorkspace.GetDocumentSpanFromLocation(location, context.CancellationToken).ConfigureAwait(false); if (documentSpan == null) { continue; } #pragma warning disable CS0612 // Type or member is obsolete. TODO. await context.OnReferenceFoundAsync(new SourceReferenceItem(dummyDef, documentSpan.Value, isWrittenTo : false)).ConfigureAwait(false); #pragma warning restore CS0612 // Type or member is obsolete } }
public override async Task ProvideCompletionsAsync(CompletionContext context) { // This provider is exported for all workspaces - so limit it to just our workspace & the debugger's intellisense workspace if (context.Document.Project.Solution.Workspace.Kind != WorkspaceKind.AnyCodeRoslynWorkspace && context.Document.Project.Solution.Workspace.Kind != StringConstants.DebuggerIntellisenseWorkspaceKind) { return; } var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient; if (lspClient == null) { return; } var text = await context.Document.GetTextAsync(context.CancellationToken).ConfigureAwait(false); var completionParams = new LSP.CompletionParams { TextDocument = ProtocolConversions.DocumentToTextDocumentIdentifier(context.Document), Position = ProtocolConversions.LinePositionToPosition(text.Lines.GetLinePosition(context.Position)), Context = new LSP.CompletionContext { TriggerCharacter = context.Trigger.Character.ToString(), TriggerKind = GetTriggerKind(context.Trigger) } }; var completionObject = await lspClient.RequestAsync(LSP.Methods.TextDocumentCompletion.ToLSRequest(), completionParams, context.CancellationToken).ConfigureAwait(false); if (completionObject == null) { return; } var completionList = ((JToken)completionObject).ToObject <RoslynCompletionItem[]>(); foreach (var item in completionList) { ImmutableArray <string> tags; if (item.Tags != null) { tags = item.Tags.AsImmutable(); } else { var glyph = ProtocolConversions.CompletionItemKindToGlyph(item.Kind); tags = GlyphTags.GetTags(glyph); } var properties = ImmutableDictionary.CreateBuilder <string, string>(); if (!string.IsNullOrEmpty(item.Detail)) { // The display text is encoded as TaggedText | value properties.Add("Description", $"Text|{item.Detail}"); } properties.Add("InsertionText", item.InsertText); properties.Add("ResolveData", JToken.FromObject(item).ToString()); var completionItem = CompletionItem.Create(item.Label, item.FilterText, item.SortText, properties: properties.ToImmutable(), tags: tags); context.AddItem(completionItem); } }