diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/CodeActionsService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/CodeActionsService.cs index 66403209cdd..38ab48f9f44 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/CodeActionsService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/CodeActionsService.cs @@ -186,6 +186,15 @@ private RazorVSInternalCodeAction[] ExtractCSharpCodeActionNamesFromData(RazorVS continue; } + // In VS Code, Roslyn adds duplicate code actions for every code action, to implement Fix All functionality. + // Until we implement support for that in the C# Extension, we want to filter them out. + // https://github.com/dotnet/razor/issues/11832 + if (jsonData.TryGetProperty("FixAllFlavors", out var fixAllFlavours) && + fixAllFlavours.GetArrayLength() > 0) + { + continue; + } + actions.Add(codeAction); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Cohosting/CohostTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Cohosting/CohostTestBase.cs index 171cbcee949..6ca282c248f 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Cohosting/CohostTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Cohosting/CohostTestBase.cs @@ -118,7 +118,16 @@ private protected void UpdateClientLSPInitializationOptions(FuncShared\%(RecursiveDir)%(FileName)%(Extension) - + diff --git a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/CohostEndpointTestBase.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/CohostEndpointTestBase.cs index 0cdc84b48d8..7cf127581ee 100644 --- a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/CohostEndpointTestBase.cs +++ b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/CohostEndpointTestBase.cs @@ -2,17 +2,22 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; +using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.Test; +using Microsoft.AspNetCore.Razor.Test.Common.Mef; +using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.Remote; using Microsoft.CodeAnalysis.Razor.SemanticTokens; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Razor.Workspaces.Settings; using Microsoft.CodeAnalysis.Remote.Razor; -using Microsoft.VisualStudio.Composition; using Microsoft.VisualStudioCode.RazorExtension.Configuration; using Microsoft.VisualStudioCode.RazorExtension.Services; +using Xunit; using Xunit.Abstractions; namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost; @@ -23,16 +28,13 @@ public abstract class CohostEndpointTestBase(ITestOutputHelper testOutputHelper) private VSCodeRemoteServiceInvoker? _remoteServiceInvoker; private IFilePathService? _filePathService; private ISemanticTokensLegendService? _semanticTokensLegendService; + private Workspace? _workspace; private protected override IRemoteServiceInvoker RemoteServiceInvoker => _remoteServiceInvoker.AssumeNotNull(); private protected override IClientSettingsManager ClientSettingsManager => _clientSettingsManager.AssumeNotNull(); private protected override IFilePathService FilePathService => _filePathService.AssumeNotNull(); private protected ISemanticTokensLegendService SemanticTokensLegendService => _semanticTokensLegendService.AssumeNotNull(); - - /// - /// The export provider for Roslyn "devenv" services, if tests opt-in to using them - /// - private protected ExportProvider? RoslynDevenvExportProvider { get; private set; } + private protected Workspace Workspace => _workspace.AssumeNotNull(); protected override async Task InitializeAsync() { @@ -40,9 +42,10 @@ protected override async Task InitializeAsync() InProcServiceFactory.TestAccessor.SetExportProvider(OOPExportProvider); + _workspace = CreateWorkspace(); + var workspaceProvider = new VSCodeWorkspaceProvider(); - var remoteWorkspace = RemoteWorkspaceProvider.Instance.GetWorkspace(); - workspaceProvider.SetWorkspace(remoteWorkspace); + workspaceProvider.SetWorkspace(Workspace); _remoteServiceInvoker = new VSCodeRemoteServiceInvoker(workspaceProvider, LoggerFactory); AddDisposable(_remoteServiceInvoker); @@ -82,4 +85,32 @@ private protected override RemoteClientLSPInitializationOptions GetRemoteClientL TokenTypes = [] }; } + + protected override TextDocument CreateProjectAndRazorDocument( + string contents, + RazorFileKind? fileKind = null, + string? documentFilePath = null, + (string fileName, string contents)[]? additionalFiles = null, + bool inGlobalNamespace = false, + bool miscellaneousFile = false) + { + return CreateProjectAndRazorDocument(Workspace, contents, fileKind, documentFilePath, additionalFiles, inGlobalNamespace, miscellaneousFile); + } + + private AdhocWorkspace CreateWorkspace() + { + var composition = TestComposition.RoslynFeatures; + + // We can't enforce that the composition is entirely valid, because we don't have a full MEF catalog, but we + // can assume there should be no errors related to Razor, and having this array makes debugging failures a lot + // easier. + var errors = composition.GetCompositionErrors().ToArray(); + Assert.Empty(errors.Where(e => e.Contains("Razor"))); + + var roslynExportProvider = composition.ExportProviderFactory.CreateExportProvider(); + AddDisposable(roslynExportProvider); + var workspace = TestWorkspace.CreateWithDiagnosticAnalyzers(roslynExportProvider); + AddDisposable(workspace); + return workspace; + } } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/AddUsingTests.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/AddUsingTests.cs similarity index 95% rename from src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/AddUsingTests.cs rename to src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/AddUsingTests.cs index ba04d124c34..d371a075978 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/AddUsingTests.cs +++ b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/AddUsingTests.cs @@ -31,6 +31,9 @@ public async Task FullyQualify() await VerifyCodeActionAsync(input, expected, LanguageServerConstants.CodeActions.FullyQualify); } +#if !VSCODE + // This uses a nested code action in Roslyn which we don't support in VS Code + // https://github.com/dotnet/razor/issues/11832 [Fact] public async Task FullyQualify_Multiple() { @@ -58,6 +61,7 @@ public class StringBuilder codeActionName: LanguageServerConstants.CodeActions.FullyQualify, childActionIndex: 0); } +#endif [Fact] public async Task AddUsing() diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/CSharpCodeActionTests.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/CSharpCodeActionTests.cs similarity index 100% rename from src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/CSharpCodeActionTests.cs rename to src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/CSharpCodeActionTests.cs diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/CohostCodeActionsEndpointTestBase.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/CohostCodeActionsEndpointTestBase.cs similarity index 97% rename from src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/CohostCodeActionsEndpointTestBase.cs rename to src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/CohostCodeActionsEndpointTestBase.cs index be617d26f0e..4346d9bf3b5 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/CohostCodeActionsEndpointTestBase.cs +++ b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/CohostCodeActionsEndpointTestBase.cs @@ -20,8 +20,6 @@ using Microsoft.CodeAnalysis.Razor.Utilities; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Remote.Razor; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.Razor.Settings; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -220,8 +218,7 @@ private async Task VerifyCodeActionResultAsync(TextDocument document, WorkspaceE private async Task ResolveCodeActionAsync(CodeAnalysis.TextDocument document, CodeAction codeAction) { var requestInvoker = new TestHtmlRequestInvoker(); - var clientSettingsManager = new ClientSettingsManager(changeTriggers: []); - var endpoint = new CohostCodeActionsResolveEndpoint(IncompatibleProjectService, RemoteServiceInvoker, ClientCapabilitiesService, clientSettingsManager, requestInvoker); + var endpoint = new CohostCodeActionsResolveEndpoint(IncompatibleProjectService, RemoteServiceInvoker, ClientCapabilitiesService, ClientSettingsManager, requestInvoker); var result = await endpoint.GetTestAccessor().HandleRequestAsync(document, codeAction, DisposalToken); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/CreateComponentFromTagTests.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/CreateComponentFromTagTests.cs similarity index 100% rename from src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/CreateComponentFromTagTests.cs rename to src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/CreateComponentFromTagTests.cs diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/ExtractToCodeBehindTests.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/ExtractToCodeBehindTests.cs similarity index 100% rename from src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/ExtractToCodeBehindTests.cs rename to src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/ExtractToCodeBehindTests.cs diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/ExtractToComponentTests.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/ExtractToComponentTests.cs similarity index 100% rename from src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/ExtractToComponentTests.cs rename to src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/ExtractToComponentTests.cs diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/ExtractToCssTests.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/ExtractToCssTests.cs similarity index 100% rename from src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/ExtractToCssTests.cs rename to src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/ExtractToCssTests.cs diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/GenerateEventHandlerTests.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/GenerateEventHandlerTests.cs similarity index 100% rename from src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/GenerateEventHandlerTests.cs rename to src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/GenerateEventHandlerTests.cs diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/PromoteUsingDirectiveTests.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/PromoteUsingDirectiveTests.cs similarity index 82% rename from src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/PromoteUsingDirectiveTests.cs rename to src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/PromoteUsingDirectiveTests.cs index 94206c090be..6bbee233de4 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/PromoteUsingDirectiveTests.cs +++ b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/PromoteUsingDirectiveTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Threading.Tasks; +using System.IO; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.Protocol; using Xunit; @@ -30,7 +31,7 @@ Hello World """, codeActionName: LanguageServerConstants.CodeActions.PromoteUsingDirective, additionalExpectedFiles: [ - (FileUri(@"..\_Imports.razor"), """ + (FileUri(Path.Combine("..", "_Imports.razor")), """ @using System """)]); } @@ -58,7 +59,7 @@ Hello World """, codeActionName: LanguageServerConstants.CodeActions.PromoteUsingDirective, additionalExpectedFiles: [ - (FileUri(@"..\_Imports.razor"), """ + (FileUri(Path.Combine("..", "_Imports.razor")), """ @using System """)]); } @@ -83,7 +84,7 @@ Hello World codeActionName: LanguageServerConstants.CodeActions.PromoteUsingDirective, fileKind: RazorFileKind.Legacy, additionalExpectedFiles: [ - (FileUri(@"..\_ViewImports.cshtml"), """ + (FileUri(Path.Combine("..", "_ViewImports.cshtml")), """ @using System """)]); } @@ -99,9 +100,9 @@ @using [||]System Hello World """, - documentFilePath: FilePath(@"My\Deeply\Nested\File.razor"), + documentFilePath: FilePath(Path.Combine("My", "Deeply", "Nested", "File.razor")), additionalFiles: [ - (FilePath(@"My\Deeply\_Imports.razor"), """ + (FilePath(Path.Combine("My", "Deeply", "_Imports.razor")), """ @using System.Text @using Foo.Bar """)], @@ -113,7 +114,7 @@ Hello World """, codeActionName: LanguageServerConstants.CodeActions.PromoteUsingDirective, additionalExpectedFiles: [ - (FileUri(@"My\Deeply\_Imports.razor"), """ + (FileUri(Path.Combine("My", "Deeply", "_Imports.razor")), """ @using System.Text @using Foo.Bar @using System @@ -131,9 +132,9 @@ @using [||]System Hello World """, - documentFilePath: FilePath(@"My\Deeply\Nested\File.razor"), + documentFilePath: FilePath(Path.Combine("My", "Deeply", "Nested", "File.razor")), additionalFiles: [ - (FilePath(@"My\Deeply\_Imports.razor"), """ + (FilePath(Path.Combine("My", "Deeply", "_Imports.razor")), """ @using System.Text @using Foo.Bar @@ -146,7 +147,7 @@ Hello World """, codeActionName: LanguageServerConstants.CodeActions.PromoteUsingDirective, additionalExpectedFiles: [ - (FileUri(@"My\Deeply\_Imports.razor"), """ + (FileUri(Path.Combine("My", "Deeply", "_Imports.razor")), """ @using System.Text @using Foo.Bar @using System @@ -164,9 +165,9 @@ @using [||]System Hello World """, - documentFilePath: FilePath(@"My\Deeply\Nested\File.razor"), + documentFilePath: FilePath(Path.Combine("My", "Deeply", "Nested", "File.razor")), additionalFiles: [ - (FilePath(@"My\Deeply\_Imports.razor"), """ + (FilePath(Path.Combine("My", "Deeply", "_Imports.razor")), """ @using System.Text @using Foo.Bar @@ -179,7 +180,7 @@ Hello World """, codeActionName: LanguageServerConstants.CodeActions.PromoteUsingDirective, additionalExpectedFiles: [ - (FileUri(@"My\Deeply\_Imports.razor"), """ + (FileUri(Path.Combine("My", "Deeply", "_Imports.razor")), """ @using System.Text @using Foo.Bar @using System diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/SimplifyTagToSelfClosingTests.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/SimplifyTagToSelfClosingTests.cs similarity index 100% rename from src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/SimplifyTagToSelfClosingTests.cs rename to src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/SimplifyTagToSelfClosingTests.cs diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/TypeAccessibilityTests.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/TypeAccessibilityTests.cs similarity index 98% rename from src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/TypeAccessibilityTests.cs rename to src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/TypeAccessibilityTests.cs index 73d52469d91..14e2294d31b 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/TypeAccessibilityTests.cs +++ b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/TypeAccessibilityTests.cs @@ -93,6 +93,7 @@ public async Task AddUsingShouldBeFirst() var document = CreateRazorDocument(input); var codeActions = await GetCodeActionsAsync(document, input); + Assert.NotNull(codeActions); Assert.Equal(LanguageServerConstants.CodeActions.AddUsing, codeActions.Select(a => ((RazorVSInternalCodeAction)a.Value!).Name).First()); } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/WrapAttributeTests.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/WrapAttributeTests.cs similarity index 100% rename from src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CodeActions/WrapAttributeTests.cs rename to src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CodeActions/WrapAttributeTests.cs