From 413b6b66ce8edcb435f1e5ac68f4f5247cfac027 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Mon, 29 Apr 2019 17:22:31 -0700 Subject: [PATCH] Address review feedback. --- .../Extensions/ProtocolConversions.cs | 43 ++++++++++++++++++ .../Handler/Completion/CompletionHandler.cs | 17 +------ .../Definitions/GoToTypeDefinitionHandler.cs | 3 +- .../FoldingRanges/FoldingRangesHandler.cs | 3 +- .../Formatting/FormatDocumentHandler.cs | 23 +++------- .../Formatting/FormatDocumentHandlerBase.cs | 40 +++++++++++++++++ .../Formatting/FormatDocumentOnTypeHandler.cs | 13 ++++-- .../Formatting/FormatDocumentRangeHandler.cs | 20 +-------- .../Protocol/Handler/IRequestHandler.cs | 4 +- .../Handler/IRequestHandlerMetadata.cs | 8 +--- .../Handler/Initialize/InitializeHandler.cs | 44 +++++++++---------- .../SignatureHelp/SignatureHelpHandler.cs | 9 ++-- .../Handler/Symbols/DocumentSymbolsHandler.cs | 4 +- .../Protocol/LanguageServerProtocol.cs | 16 +------ ...odeAnalysis.LanguageServer.Protocol.csproj | 1 + .../AbstractLanguageServerProtocolTests.cs | 12 ----- .../CodeActions/CodeActionsTests.cs | 7 ++- ...osoft.VisualStudio.LanguageServices.csproj | 1 - ...dio.LanguageServices.Implementation.csproj | 9 ---- .../Impl}/CustomProtocol/RoslynMethods.cs | 0 .../Impl/FindAllReferencesHandler.cs | 4 +- .../Impl}/PreviewCodeActionsHandler.cs | 18 ++++---- .../LiveShare/Impl/ProjectsHandler.cs | 9 ++-- .../LiveShare/Impl/RenameHandler.cs | 5 ++- .../Shims/PreviewCodeActionsHandlerShim.cs | 21 --------- .../LiveShare/Test/DiagnosticsHandlerTests.cs | 23 +--------- .../Test}/PreviewCodeActionsTests.cs | 17 ++++--- src/VisualStudio/Setup/AssemblyRedirects.cs | 1 + .../Setup/Roslyn.VisualStudio.Setup.csproj | 5 +++ 29 files changed, 183 insertions(+), 197 deletions(-) create mode 100644 src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentHandlerBase.cs rename src/{Features/LanguageServer/Protocol => VisualStudio/LiveShare/Impl}/CustomProtocol/RoslynMethods.cs (100%) rename src/{Features/LanguageServer/Protocol/Handler/CodeActions => VisualStudio/LiveShare/Impl}/PreviewCodeActionsHandler.cs (78%) delete mode 100644 src/VisualStudio/LiveShare/Impl/Shims/PreviewCodeActionsHandlerShim.cs rename src/{Features/LanguageServer/ProtocolUnitTests/CodeActions => VisualStudio/LiveShare/Test}/PreviewCodeActionsTests.cs (57%) diff --git a/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs b/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs index 2ceba010809..a9a15ed6352 100644 --- a/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs +++ b/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs @@ -1,10 +1,12 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.DocumentHighlighting; using Microsoft.CodeAnalysis.NavigateTo; +using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text.Adornments; using Roslyn.Utilities; @@ -14,6 +16,47 @@ namespace Microsoft.CodeAnalysis.LanguageServer { internal static class ProtocolConversions { + public static readonly Dictionary RoslynTagToCompletionItemKind = new Dictionary() + { + { WellKnownTags.Public, LSP.CompletionItemKind.Keyword }, + { WellKnownTags.Protected, LSP.CompletionItemKind.Keyword }, + { WellKnownTags.Private, LSP.CompletionItemKind.Keyword }, + { WellKnownTags.Internal, LSP.CompletionItemKind.Keyword }, + { WellKnownTags.File, LSP.CompletionItemKind.File }, + { WellKnownTags.Project, LSP.CompletionItemKind.File }, + { WellKnownTags.Folder, LSP.CompletionItemKind.Folder }, + { WellKnownTags.Assembly, LSP.CompletionItemKind.File }, + { WellKnownTags.Class, LSP.CompletionItemKind.Class }, + { WellKnownTags.Constant, LSP.CompletionItemKind.Constant }, + { WellKnownTags.Delegate, LSP.CompletionItemKind.Function }, + { WellKnownTags.Enum, LSP.CompletionItemKind.Enum }, + { WellKnownTags.EnumMember, LSP.CompletionItemKind.EnumMember }, + { WellKnownTags.Event, LSP.CompletionItemKind.Event }, + { WellKnownTags.ExtensionMethod, LSP.CompletionItemKind.Method }, + { WellKnownTags.Field, LSP.CompletionItemKind.Field }, + { WellKnownTags.Interface, LSP.CompletionItemKind.Interface }, + { WellKnownTags.Intrinsic, LSP.CompletionItemKind.Text }, + { WellKnownTags.Keyword, LSP.CompletionItemKind.Keyword }, + { WellKnownTags.Label, LSP.CompletionItemKind.Text }, + { WellKnownTags.Local, LSP.CompletionItemKind.Variable }, + { WellKnownTags.Namespace, LSP.CompletionItemKind.Text }, + { WellKnownTags.Method, LSP.CompletionItemKind.Method }, + { WellKnownTags.Module, LSP.CompletionItemKind.Module }, + { WellKnownTags.Operator, LSP.CompletionItemKind.Operator }, + { WellKnownTags.Parameter, LSP.CompletionItemKind.Value }, + { WellKnownTags.Property, LSP.CompletionItemKind.Property }, + { WellKnownTags.RangeVariable, LSP.CompletionItemKind.Variable }, + { WellKnownTags.Reference, LSP.CompletionItemKind.Reference }, + { WellKnownTags.Structure, LSP.CompletionItemKind.Struct }, + { WellKnownTags.TypeParameter, LSP.CompletionItemKind.TypeParameter }, + { WellKnownTags.Snippet, LSP.CompletionItemKind.Snippet }, + { WellKnownTags.Error, LSP.CompletionItemKind.Text }, + { WellKnownTags.Warning, LSP.CompletionItemKind.Text }, + { WellKnownTags.StatusInformation, LSP.CompletionItemKind.Text }, + { WellKnownTags.AddReference, LSP.CompletionItemKind.Text }, + { WellKnownTags.NuGet, LSP.CompletionItemKind.Text } + }; + public static LinePosition PositionToLinePosition(LSP.Position position) { return new LinePosition(position.Line, position.Character); diff --git a/src/Features/LanguageServer/Protocol/Handler/Completion/CompletionHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Completion/CompletionHandler.cs index d61c3eea61c..cc6d95b873b 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Completion/CompletionHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Completion/CompletionHandler.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Tags; using Microsoft.VisualStudio.Text.Adornments; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; @@ -60,21 +59,9 @@ private static LSP.CompletionItemKind GetCompletionKind(ImmutableArray t { foreach (var tag in tags) { - if (Enum.TryParse(tag, out var kind)) + if (ProtocolConversions.RoslynTagToCompletionItemKind.TryGetValue(tag, out var completionItemKind)) { - return kind; - } - else if (tag == WellKnownTags.Local || tag == WellKnownTags.Parameter) - { - return LSP.CompletionItemKind.Variable; - } - else if (tag == WellKnownTags.Structure) - { - return LSP.CompletionItemKind.Struct; - } - else if (tag == WellKnownTags.Delegate) - { - return LSP.CompletionItemKind.Function; + return completionItemKind; } } diff --git a/src/Features/LanguageServer/Protocol/Handler/Definitions/GoToTypeDefinitionHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Definitions/GoToTypeDefinitionHandler.cs index 90442bf760d..6e6b22b55a9 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Definitions/GoToTypeDefinitionHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Definitions/GoToTypeDefinitionHandler.cs @@ -9,8 +9,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler { [Shared] - // TODO - Use method name from VS language server package once updated. - [ExportLspMethod("textDocument/typeDefinition")] + [ExportLspMethod(LSP.Methods.TextDocumentTypeDefinitionName)] internal class GoToTypeDefinitionHandler : GoToDefinitionHandlerBase, IRequestHandler { [ImportingConstructor] diff --git a/src/Features/LanguageServer/Protocol/Handler/FoldingRanges/FoldingRangesHandler.cs b/src/Features/LanguageServer/Protocol/Handler/FoldingRanges/FoldingRangesHandler.cs index d653e8b7204..334e7f1dc7d 100644 --- a/src/Features/LanguageServer/Protocol/Handler/FoldingRanges/FoldingRangesHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/FoldingRanges/FoldingRangesHandler.cs @@ -10,8 +10,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler { [Shared] - // TODO - Use method name from VS language server package once updated. - [ExportLspMethod("textDocument/foldingRange")] + [ExportLspMethod(Methods.TextDocumentFoldingRangeName)] internal class FoldingRangesHandler : IRequestHandler { public async Task HandleRequestAsync(Solution solution, FoldingRangeParams request, diff --git a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentHandler.cs index 7b7e6bc18d9..0b3007c7a0f 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentHandler.cs @@ -1,32 +1,19 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Collections.Generic; using System.Composition; -using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor; -using Microsoft.VisualStudio.LanguageServer.Protocol; +using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler { [Shared] - [ExportLspMethod(Methods.TextDocumentFormattingName)] - internal class FormatDocumentHandler : IRequestHandler + [ExportLspMethod(LSP.Methods.TextDocumentFormattingName)] + internal class FormatDocumentHandler : FormatDocumentHandlerBase, IRequestHandler { - public async Task HandleRequestAsync(Solution solution, DocumentFormattingParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) + public async Task HandleRequestAsync(Solution solution, LSP.DocumentFormattingParams request, LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { - var edits = new List(); - var document = solution.GetDocumentFromURI(request.TextDocument.Uri); - if (document != null) - { - var formattingService = document.Project.LanguageServices.GetService(); - var textChanges = await formattingService.GetFormattingChangesAsync(document, null, cancellationToken).ConfigureAwait(false); - var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text))); - } - - return edits.ToArray(); + return await GetTextEdits(solution, request.TextDocument.Uri, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentHandlerBase.cs b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentHandlerBase.cs new file mode 100644 index 00000000000..fda38125b46 --- /dev/null +++ b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentHandlerBase.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Text; +using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.Handler +{ + internal class FormatDocumentHandlerBase + { + protected async Task GetTextEdits(Solution solution, Uri documentUri, CancellationToken cancellationToken, LSP.Range range = null) + { + var edits = new ArrayBuilder(); + var document = solution.GetDocumentFromURI(documentUri); + + if (document != null) + { + var formattingService = document.Project.LanguageServices.GetService(); + var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + TextSpan? textSpan = null; + if (range != null) + { + textSpan = ProtocolConversions.RangeToTextSpan(range, text); + } + + var textChanges = await formattingService.GetFormattingChangesAsync(document, textSpan, cancellationToken).ConfigureAwait(false); + edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text))); + } + + return edits.ToArrayAndFree(); + } + } +} diff --git a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs index 70d9418ea25..4c41dcac8bb 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs @@ -5,7 +5,9 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -17,16 +19,21 @@ internal class FormatDocumentOnTypeHandler : IRequestHandler HandleRequestAsync(Solution solution, DocumentOnTypeFormattingParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { - var edits = new List(); + var edits = new ArrayBuilder(); var document = solution.GetDocumentFromURI(request.TextDocument.Uri); if (document != null) { var formattingService = document.Project.LanguageServices.GetService(); var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); + if (string.IsNullOrEmpty(request.Character)) + { + return edits.ToArrayAndFree(); + } + IList textChanges; // Formatting on new lines must be handled differently. - if (request.Character == "\n") + if (SyntaxFacts.IsNewLine(request.Character[0])) { textChanges = await formattingService.GetFormattingChangesOnReturnAsync(document, position, cancellationToken).ConfigureAwait(false); } @@ -42,7 +49,7 @@ public async Task HandleRequestAsync(Solution solution, DocumentOnTy } } - return edits.ToArray(); + return edits.ToArrayAndFree(); } } } diff --git a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentRangeHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentRangeHandler.cs index b34366d8895..c5ad891d494 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentRangeHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Formatting/FormatDocumentRangeHandler.cs @@ -1,35 +1,19 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Collections.Generic; using System.Composition; -using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler { [Shared] [ExportLspMethod(Methods.TextDocumentRangeFormattingName)] - internal class FormatDocumentRangeHandler : IRequestHandler + internal class FormatDocumentRangeHandler : FormatDocumentHandlerBase, IRequestHandler { public async Task HandleRequestAsync(Solution solution, DocumentRangeFormattingParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { - var edits = new List(); - var document = solution.GetDocumentFromURI(request.TextDocument.Uri); - if (document != null) - { - var formattingService = document.Project.LanguageServices.GetService(); - - var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - var textSpan = ProtocolConversions.RangeToTextSpan(request.Range, text); - - var textChanges = await formattingService.GetFormattingChangesAsync(document, textSpan, cancellationToken).ConfigureAwait(false); - edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text))); - } - - return edits.ToArray(); + return await GetTextEdits(solution, request.TextDocument.Uri, cancellationToken, range: request.Range).ConfigureAwait(false); } } } diff --git a/src/Features/LanguageServer/Protocol/Handler/IRequestHandler.cs b/src/Features/LanguageServer/Protocol/Handler/IRequestHandler.cs index fb600dcf91f..07d822e5463 100644 --- a/src/Features/LanguageServer/Protocol/Handler/IRequestHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/IRequestHandler.cs @@ -9,11 +9,11 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler /// /// Top level type for LSP request handler. /// - interface IRequestHandler + internal interface IRequestHandler { } - interface IRequestHandler : IRequestHandler + internal interface IRequestHandler : IRequestHandler { Task HandleRequestAsync(Solution solution, RequestType request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken); } diff --git a/src/Features/LanguageServer/Protocol/Handler/IRequestHandlerMetadata.cs b/src/Features/LanguageServer/Protocol/Handler/IRequestHandlerMetadata.cs index eb46709ff3d..0a97211eb5a 100644 --- a/src/Features/LanguageServer/Protocol/Handler/IRequestHandlerMetadata.cs +++ b/src/Features/LanguageServer/Protocol/Handler/IRequestHandlerMetadata.cs @@ -1,12 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace Microsoft.CodeAnalysis.LanguageServer.Handler { - interface IRequestHandlerMetadata + internal interface IRequestHandlerMetadata { /// /// Name of the LSP method to handle. diff --git a/src/Features/LanguageServer/Protocol/Handler/Initialize/InitializeHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Initialize/InitializeHandler.cs index 4fd35d05c09..07aba33d2a8 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Initialize/InitializeHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Initialize/InitializeHandler.cs @@ -11,31 +11,29 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler [ExportLspMethod(Methods.InitializeName)] internal class InitializeHandler : IRequestHandler { - public Task HandleRequestAsync(Solution solution, InitializeParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) + private static readonly InitializeResult s_initializeResult = new InitializeResult { - var result = new InitializeResult + Capabilities = new ServerCapabilities { - Capabilities = new ServerCapabilities - { - DefinitionProvider = true, - ReferencesProvider = true, - ImplementationProvider = true, - CompletionProvider = new CompletionOptions { ResolveProvider = true, TriggerCharacters = new[] { "." } }, - HoverProvider = true, - SignatureHelpProvider = new SignatureHelpOptions { TriggerCharacters = new[] { "(", "," } }, - CodeActionProvider = true, - DocumentSymbolProvider = true, - WorkspaceSymbolProvider = true, - DocumentFormattingProvider = true, - DocumentRangeFormattingProvider = true, - DocumentOnTypeFormattingProvider = new DocumentOnTypeFormattingOptions { FirstTriggerCharacter = "}", MoreTriggerCharacter = new[] { ";", "\n" } }, - DocumentHighlightProvider = true, - RenameProvider = true, - ExecuteCommandProvider = new ExecuteCommandOptions() - } - }; + DefinitionProvider = true, + ReferencesProvider = true, + ImplementationProvider = true, + CompletionProvider = new CompletionOptions { ResolveProvider = true, TriggerCharacters = new[] { "." } }, + HoverProvider = true, + SignatureHelpProvider = new SignatureHelpOptions { TriggerCharacters = new[] { "(", "," } }, + CodeActionProvider = true, + DocumentSymbolProvider = true, + WorkspaceSymbolProvider = true, + DocumentFormattingProvider = true, + DocumentRangeFormattingProvider = true, + DocumentOnTypeFormattingProvider = new DocumentOnTypeFormattingOptions { FirstTriggerCharacter = "}", MoreTriggerCharacter = new[] { ";", "\n" } }, + DocumentHighlightProvider = true, + RenameProvider = true, + ExecuteCommandProvider = new ExecuteCommandOptions() + } + }; - return Task.FromResult(result); - } + public Task HandleRequestAsync(Solution solution, InitializeParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) + => Task.FromResult(s_initializeResult); } } diff --git a/src/Features/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs b/src/Features/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs index 66bd30e5937..add7f521fd4 100644 --- a/src/Features/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.VisualStudio.Text.Adornments; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; @@ -46,7 +47,7 @@ public SignatureHelpHandler([ImportMany] IEnumerable(); + var sigInfos = new ArrayBuilder(); foreach (var item in items.Items) { @@ -77,7 +78,7 @@ public SignatureHelpHandler([ImportMany] IEnumerable(); + var taggedTexts = new ArrayBuilder(); taggedTexts.AddRange(item.PrefixDisplayParts); @@ -160,7 +161,7 @@ private ClassifiedTextElement GetSignatureClassifiedText(SignatureHelpItem item) taggedTexts.AddRange(item.SuffixDisplayParts); taggedTexts.AddRange(item.DescriptionParts); - return new ClassifiedTextElement(taggedTexts.Select(part => new ClassifiedTextRun(part.Tag.ToClassificationTypeName(), part.Text))); + return new ClassifiedTextElement(taggedTexts.ToArrayAndFree().Select(part => new ClassifiedTextRun(part.Tag.ToClassificationTypeName(), part.Text))); } } } diff --git a/src/Features/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs index a99d4bb41ae..4a49da1ec7f 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs @@ -139,13 +139,13 @@ static SymbolInformation Create(NavigationBarItem item, TextSpan span, string co static async Task GetChildrenAsync(IEnumerable items, Compilation compilation, SyntaxTree tree, SourceText text, CancellationToken cancellationToken) { - var list = new List(); + var list = new ArrayBuilder(); foreach (var item in items) { list.Add(await GetDocumentSymbolAsync(item, compilation, tree, text, cancellationToken).ConfigureAwait(false)); } - return list.ToArray(); + return list.ToArrayAndFree(); } static async Task GetSymbolAsync(Location location, Compilation compilation, CancellationToken cancellationToken) diff --git a/src/Features/LanguageServer/Protocol/LanguageServerProtocol.cs b/src/Features/LanguageServer/Protocol/LanguageServerProtocol.cs index 8cf54ff5e0f..b823810251c 100644 --- a/src/Features/LanguageServer/Protocol/LanguageServerProtocol.cs +++ b/src/Features/LanguageServer/Protocol/LanguageServerProtocol.cs @@ -6,7 +6,6 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.LanguageServer.CustomProtocol; using Microsoft.CodeAnalysis.LanguageServer.Handler; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; @@ -28,7 +27,7 @@ public LanguageServerProtocol([ImportMany] IEnumerable> CreateMethodToHandlerMap(IEnumerable> requestHandlers) + private static ImmutableDictionary> CreateMethodToHandlerMap(IEnumerable> requestHandlers) { var requestHandlerDictionary = new Dictionary>(); foreach (var lazyHandler in requestHandlers) @@ -256,19 +255,6 @@ public async Task InitializeAsync(Solution solution, LSP.I .ConfigureAwait(false); } - /// - /// Answers a preview code action request by returning the text edits for a specific code action. - /// - /// the solution containing the document. - /// the code action location and title to preview. - /// a cancellation token. - /// a list of text edits for the code action result. - public async Task PreviewCodeActionsAsync(Solution solution, RunCodeActionParams request, LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken) - { - return await ExecuteRequestAsync(RoslynMethods.CodeActionPreviewName, solution, request, clientCapabilities, cancellationToken) - .ConfigureAwait(false); - } - /// /// Answers a request to resolve a completion item. /// https://microsoft.github.io/language-server-protocol/specification#completionItem_resolve diff --git a/src/Features/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj b/src/Features/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj index 429cb5674db..9ffa7ae0361 100644 --- a/src/Features/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj +++ b/src/Features/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj @@ -14,6 +14,7 @@ + diff --git a/src/Features/LanguageServer/ProtocolUnitTests/AbstractLanguageServerProtocolTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/AbstractLanguageServerProtocolTests.cs index 1401ee90678..c8635a67e6c 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/AbstractLanguageServerProtocolTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/AbstractLanguageServerProtocolTests.cs @@ -4,11 +4,9 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; -using Microsoft.CodeAnalysis.LanguageServer.CustomProtocol; using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; @@ -220,16 +218,6 @@ protected static LSP.VSCompletionItem CreateCompletionItem(string text, LSP.Comp Icon = tags != null ? new ImageElement(tags.ToImmutableArray().GetFirstGlyph().GetImageId()) : null }; - // Private procted because RunCodeActionParams is internal. - private protected static RunCodeActionParams CreateRunCodeActionParams(LSP.Location location, string title) - => new RunCodeActionParams() - { - Range = location.Range, - TextDocument = CreateTextDocumentIdentifier(location.Uri), - Title = title - }; - - /// /// Creates a solution with a document. /// diff --git a/src/Features/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs index 73a99806bf6..415937c0550 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs @@ -83,7 +83,12 @@ private static LSP.Command CreateCommand(string title, LSP.Location location) CommandIdentifier = "Roslyn.RunCodeAction", Arguments = new object[] { - CreateRunCodeActionParams(location, title) + new RunCodeActionParams() + { + Range = location.Range, + TextDocument = CreateTextDocumentIdentifier(location.Uri), + Title = title + } } } } diff --git a/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj b/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj index b8d932a3530..8b140af63a6 100644 --- a/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj +++ b/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj @@ -78,7 +78,6 @@ - diff --git a/src/VisualStudio/Core/Impl/Microsoft.VisualStudio.LanguageServices.Implementation.csproj b/src/VisualStudio/Core/Impl/Microsoft.VisualStudio.LanguageServices.Implementation.csproj index a86767c33b4..59177738100 100644 --- a/src/VisualStudio/Core/Impl/Microsoft.VisualStudio.LanguageServices.Implementation.csproj +++ b/src/VisualStudio/Core/Impl/Microsoft.VisualStudio.LanguageServices.Implementation.csproj @@ -70,19 +70,11 @@ - - Code - - - Code - GridOptionPreviewControl.xaml - Code OptionPreviewControl.xaml - Code ManageNamingStylesInfoDialog.xaml @@ -92,7 +84,6 @@ NamingStyleOptionPageControl.xaml - Code SymbolSpecificationDialog.xaml diff --git a/src/Features/LanguageServer/Protocol/CustomProtocol/RoslynMethods.cs b/src/VisualStudio/LiveShare/Impl/CustomProtocol/RoslynMethods.cs similarity index 100% rename from src/Features/LanguageServer/Protocol/CustomProtocol/RoslynMethods.cs rename to src/VisualStudio/LiveShare/Impl/CustomProtocol/RoslynMethods.cs diff --git a/src/VisualStudio/LiveShare/Impl/FindAllReferencesHandler.cs b/src/VisualStudio/LiveShare/Impl/FindAllReferencesHandler.cs index 833271c835e..d4312e78e4e 100644 --- a/src/VisualStudio/LiveShare/Impl/FindAllReferencesHandler.cs +++ b/src/VisualStudio/LiveShare/Impl/FindAllReferencesHandler.cs @@ -86,7 +86,7 @@ private async Task GetReferenceGroupsAsync(LSP.ReferencePa referenceGroup.Definition = await ProtocolConversions.DocumentSpanToLocationWithTextAsync(definition.SourceSpans.First(), text, cancellationToken).ConfigureAwait(false); referenceGroup.DefinitionIcon = new ImageElement(definition.Tags.GetFirstGlyph().GetImageId()); - var locationWithTexts = new List(); + var locationWithTexts = new ArrayBuilder(); foreach (var reference in references) { var classifiedSpansAndHighlightSpan = await ClassifiedSpansAndHighlightSpanFactory.ClassifyAsync(reference.SourceSpan, context.CancellationToken).ConfigureAwait(false); @@ -98,7 +98,7 @@ private async Task GetReferenceGroupsAsync(LSP.ReferencePa locationWithTexts.Add(locationWithText); } - referenceGroup.References = locationWithTexts.ToArray(); + referenceGroup.References = locationWithTexts.ToArrayAndFree(); referenceGroups.Add(referenceGroup); } diff --git a/src/Features/LanguageServer/Protocol/Handler/CodeActions/PreviewCodeActionsHandler.cs b/src/VisualStudio/LiveShare/Impl/PreviewCodeActionsHandler.cs similarity index 78% rename from src/Features/LanguageServer/Protocol/Handler/CodeActions/PreviewCodeActionsHandler.cs rename to src/VisualStudio/LiveShare/Impl/PreviewCodeActionsHandler.cs index a69413d4d4c..12b6c0480c8 100644 --- a/src/Features/LanguageServer/Protocol/Handler/CodeActions/PreviewCodeActionsHandler.cs +++ b/src/VisualStudio/LiveShare/Impl/PreviewCodeActionsHandler.cs @@ -1,21 +1,24 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Composition; +using System.ComponentModel.Composition; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.LanguageServer.CustomProtocol; +using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.VisualStudio.LiveShare.LanguageServices; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; -namespace Microsoft.CodeAnalysis.LanguageServer.Handler +namespace Microsoft.VisualStudio.LanguageServices.LiveShare { - [Shared] - [ExportLspMethod(RoslynMethods.CodeActionPreviewName)] - internal class PreviewCodeActionsHandler : CodeActionsHandlerBase, IRequestHandler + [ExportLspRequestHandler(LiveShareConstants.RoslynContractName, RoslynMethods.CodeActionPreviewName)] + internal class PreviewCodeActionsHandler : CodeActionsHandlerBase, ILspRequestHandler { [ImportingConstructor] public PreviewCodeActionsHandler(ICodeFixService codeFixService, ICodeRefactoringService codeRefactoringService) @@ -23,11 +26,10 @@ public PreviewCodeActionsHandler(ICodeFixService codeFixService, ICodeRefactorin { } - public async Task HandleRequestAsync(Solution solution, RunCodeActionParams request, - LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken) + public async Task HandleAsync(RunCodeActionParams request, RequestContext requestContext, CancellationToken cancellationToken) { var edits = ArrayBuilder.GetInstance(); - + var solution = requestContext.Context; var codeActions = await GetCodeActionsAsync(solution, request.TextDocument.Uri, request.Range, diff --git a/src/VisualStudio/LiveShare/Impl/ProjectsHandler.cs b/src/VisualStudio/LiveShare/Impl/ProjectsHandler.cs index 026b4d7f8a2..33bb0b080de 100644 --- a/src/VisualStudio/LiveShare/Impl/ProjectsHandler.cs +++ b/src/VisualStudio/LiveShare/Impl/ProjectsHandler.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.LanguageServer.CustomProtocol; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.VisualStudio.LiveShare.LanguageServices; namespace Microsoft.VisualStudio.LanguageServices.LiveShare @@ -19,11 +20,11 @@ internal class ProjectsHandler : ILspRequestHandler HandleAsync(object param, RequestContext requestContext, CancellationToken cancellationToken) { - var projects = new List(); + var projects = new ArrayBuilder(); var solution = requestContext.Context; foreach (var project in solution.Projects) { - var externalUris = new List(); + var externalUris = new ArrayBuilder(); foreach (var sourceFile in project.Documents) { var uri = new Uri(sourceFile.FilePath); @@ -32,7 +33,7 @@ public async Task HandleAsync(object param, RequestCon externalUris.Add(uri); } } - await requestContext.ProtocolConverter.RegisterExternalFilesAsync(externalUris.ToArray()).ConfigureAwait(false); + await requestContext.ProtocolConverter.RegisterExternalFilesAsync(externalUris.ToArrayAndFree()).ConfigureAwait(false); var lspProject = new CustomProtocol.Project { @@ -44,7 +45,7 @@ public async Task HandleAsync(object param, RequestCon projects.Add(lspProject); } - return projects.ToArray(); + return projects.ToArrayAndFree(); } } } diff --git a/src/VisualStudio/LiveShare/Impl/RenameHandler.cs b/src/VisualStudio/LiveShare/Impl/RenameHandler.cs index 17e36bdeeec..4a245f0da4a 100644 --- a/src/VisualStudio/LiveShare/Impl/RenameHandler.cs +++ b/src/VisualStudio/LiveShare/Impl/RenameHandler.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.LanguageServer; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.LiveShare.LanguageServices; @@ -55,7 +56,7 @@ public async Task HandleAsync(RenameParams request, RequestContex .GetProjectChanges() .SelectMany(p => p.GetChangedDocuments()); - var documentEdits = new List(); + var documentEdits = new ArrayBuilder(); foreach (var docId in changedDocuments) { var oldDoc = solution.GetDocument(docId); @@ -71,7 +72,7 @@ public async Task HandleAsync(RenameParams request, RequestContex documentEdits.Add(textDocumentEdit); } - workspaceEdit = new WorkspaceEdit { DocumentChanges = documentEdits.ToArray() }; + workspaceEdit = new WorkspaceEdit { DocumentChanges = documentEdits.ToArrayAndFree() }; } return workspaceEdit; diff --git a/src/VisualStudio/LiveShare/Impl/Shims/PreviewCodeActionsHandlerShim.cs b/src/VisualStudio/LiveShare/Impl/Shims/PreviewCodeActionsHandlerShim.cs deleted file mode 100644 index 58f0394855b..00000000000 --- a/src/VisualStudio/LiveShare/Impl/Shims/PreviewCodeActionsHandlerShim.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using Microsoft.CodeAnalysis.LanguageServer.CustomProtocol; -using Microsoft.CodeAnalysis.LanguageServer.Handler; -using Microsoft.VisualStudio.LanguageServer.Protocol; -using Microsoft.VisualStudio.LiveShare.LanguageServices; - -namespace Microsoft.VisualStudio.LanguageServices.LiveShare -{ - [ExportLspRequestHandler(LiveShareConstants.RoslynContractName, RoslynMethods.CodeActionPreviewName)] - internal class PreviewCodeActionsHandlerShim : AbstractLiveShareHandlerShim - { - [ImportingConstructor] - public PreviewCodeActionsHandlerShim([ImportMany] IEnumerable> requestHandlers) : base(requestHandlers, RoslynMethods.CodeActionPreviewName) - { - } - } -} diff --git a/src/VisualStudio/LiveShare/Test/DiagnosticsHandlerTests.cs b/src/VisualStudio/LiveShare/Test/DiagnosticsHandlerTests.cs index e286ec848ba..d68c22ddf9a 100644 --- a/src/VisualStudio/LiveShare/Test/DiagnosticsHandlerTests.cs +++ b/src/VisualStudio/LiveShare/Test/DiagnosticsHandlerTests.cs @@ -1,15 +1,9 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Linq; -using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Common; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; -using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.VisualStudio.LanguageServices.LiveShare.CustomProtocol; using Xunit; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; @@ -18,7 +12,7 @@ namespace Microsoft.VisualStudio.LanguageServices.LiveShare.UnitTests { public class DiagnosticsHandlerTests : AbstractLiveShareRequestHandlerTests { - [Fact] + [Fact(Skip = "Need easy way to export analyzers for testing.")] public async Task TestDiagnosticsAsync() { var markup = @@ -31,23 +25,10 @@ void M() }"; var (solution, ranges) = CreateTestSolution(markup); var workspace = (TestWorkspace)solution.Workspace; - var diagnosticService = (DiagnosticService)workspace.ExportProvider.GetExportedValue(); - - var miscService = new DefaultDiagnosticAnalyzerService(new TestDiagnosticAnalyzerService(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap()), diagnosticService); - - DiagnosticProvider.Enable(workspace, DiagnosticProvider.Options.Syntax); - - var document = solution.Projects.First().Documents.First(); - var analyzer = miscService.CreateIncrementalAnalyzer(workspace); - - await analyzer.AnalyzeSyntaxAsync(document, InvocationReasons.Empty, CancellationToken.None); - await analyzer.AnalyzeDocumentAsync(document, null, InvocationReasons.Empty, CancellationToken.None); var diagnosticLocation = ranges["diagnostic"].First(); - var results = await TestHandleAsync(solution, CreateTestDocumentParams(diagnosticLocation.Uri)); - var i = 1; - //AssertCollectionsEqual(new ClassificationSpan[] { CreateClassificationSpan("keyword", classifyLocation.Range) }, results, AssertClassificationsEqual); + var _ = await TestHandleAsync(solution, CreateTestDocumentParams(diagnosticLocation.Uri)); } private static TextDocumentParams CreateTestDocumentParams(Uri uri) diff --git a/src/Features/LanguageServer/ProtocolUnitTests/CodeActions/PreviewCodeActionsTests.cs b/src/VisualStudio/LiveShare/Test/PreviewCodeActionsTests.cs similarity index 57% rename from src/Features/LanguageServer/ProtocolUnitTests/CodeActions/PreviewCodeActionsTests.cs rename to src/VisualStudio/LiveShare/Test/PreviewCodeActionsTests.cs index c2329af3a64..c4c413570c3 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/CodeActions/PreviewCodeActionsTests.cs +++ b/src/VisualStudio/LiveShare/Test/PreviewCodeActionsTests.cs @@ -1,14 +1,14 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Linq; -using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer.CustomProtocol; using Xunit; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; -namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.CodeActions +namespace Microsoft.VisualStudio.LanguageServices.LiveShare.UnitTests { - public class PreviewCodeActionsTests : AbstractLanguageServerProtocolTests + public class PreviewCodeActionsTests : AbstractLiveShareRequestHandlerTests { [Fact] public async Task TestPreviewCodeActionsAsync() @@ -24,12 +24,17 @@ void M() var (solution, locations) = CreateTestSolution(markup); var expected = CreateTextEdit("var", locations["edit"].First().Range); - var results = await RunPreviewCodeActionsAsync(solution, locations["caret"].First(), "Use implicit type"); + var results = await TestHandleAsync(solution, CreateRunCodeActionParams(locations["caret"].First(), "Use implicit type")); AssertCollectionsEqual(new LSP.TextEdit[] { expected }, results, AssertTextEditsEqual); } - private static async Task RunPreviewCodeActionsAsync(Solution solution, LSP.Location caret, string title) - => await GetLanguageServer(solution).PreviewCodeActionsAsync(solution, CreateRunCodeActionParams(caret, title), new LSP.ClientCapabilities(), CancellationToken.None); + private static RunCodeActionParams CreateRunCodeActionParams(LSP.Location location, string title) + => new RunCodeActionParams() + { + Range = location.Range, + TextDocument = CreateTextDocumentIdentifier(location.Uri), + Title = title + }; private static LSP.TextEdit CreateTextEdit(string text, LSP.Range range) => new LSP.TextEdit() diff --git a/src/VisualStudio/Setup/AssemblyRedirects.cs b/src/VisualStudio/Setup/AssemblyRedirects.cs index 1739b233b97..c34440b1298 100644 --- a/src/VisualStudio/Setup/AssemblyRedirects.cs +++ b/src/VisualStudio/Setup/AssemblyRedirects.cs @@ -29,6 +29,7 @@ [assembly: ProvideRoslynBindingRedirection("Microsoft.VisualStudio.LanguageServices.Implementation.dll")] [assembly: ProvideRoslynBindingRedirection("Microsoft.VisualStudio.LanguageServices.VisualBasic.dll")] [assembly: ProvideRoslynBindingRedirection("Microsoft.VisualStudio.LanguageServices.CSharp.dll")] +[assembly: ProvideRoslynBindingRedirection("Microsoft.VisualStudio.LanguageServices.LiveShare.dll")] [assembly: ProvideRoslynBindingRedirection("Microsoft.VisualStudio.LanguageServices.SolutionExplorer.dll")] [assembly: ProvideRoslynBindingRedirection("Microsoft.VisualStudio.LanguageServices.Xaml.dll")] [assembly: ProvideRoslynBindingRedirection("Microsoft.VisualStudio.LanguageServices.Razor.RemoteClient.dll")] diff --git a/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj b/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj index ad153f0d6e5..302db4a4591 100644 --- a/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj +++ b/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj @@ -114,6 +114,11 @@ BuiltProjectOutputGroup;SatelliteDllsProjectOutputGroup true + + LiveShareLanguageServices + BuiltProjectOutputGroup;SatelliteDllsProjectOutputGroup + true + TextEditorFeatures BuiltProjectOutputGroup;SatelliteDllsProjectOutputGroup -- GitLab