From 8a80a1ec111d172c081b92530f05755980abe46f Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 24 Feb 2025 17:54:52 +1100 Subject: [PATCH 1/6] Unskip tests --- .../Cohost/CohostDocumentPullDiagnosticsTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentPullDiagnosticsTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentPullDiagnosticsTest.cs index 427efba455b..e43fd395207 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentPullDiagnosticsTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentPullDiagnosticsTest.cs @@ -17,7 +17,7 @@ namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost; public class CohostDocumentPullDiagnosticsTest(FuseTestContext context, ITestOutputHelper testOutputHelper) : CohostEndpointTestBase(testOutputHelper), IClassFixture { - [FuseFact(Skip = "Need to get generated C# doc without OOP")] + [FuseFact] public Task CSharp() => VerifyDiagnosticsAsync("""
@@ -107,7 +107,7 @@ public Task FilterEscapedAtFromCss() }]); } - [FuseFact(Skip = "Need to get generated C# doc without OOP")] + [FuseFact] public Task CombinedAndNestedDiagnostics() => VerifyDiagnosticsAsync(""" @using System.Threading.Tasks; From 45906d102a53c2b4a6f11f617f024ec0ae5c6ee0 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 24 Feb 2025 17:56:08 +1100 Subject: [PATCH 2/6] Don't use FilePathService in cohosting, it won't work --- .../Extensions/TextDocumentExtensions.cs | 34 +++++++++++++++++++ .../CohostDocumentPullDiagnosticsEndpoint.cs | 16 ++++----- 2 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Extensions/TextDocumentExtensions.cs diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Extensions/TextDocumentExtensions.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Extensions/TextDocumentExtensions.cs new file mode 100644 index 00000000000..344902721f5 --- /dev/null +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Extensions/TextDocumentExtensions.cs @@ -0,0 +1,34 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Diagnostics.CodeAnalysis; +using System.IO; +using Microsoft.CodeAnalysis; +using Microsoft.NET.Sdk.Razor.SourceGenerators; + +namespace Microsoft.VisualStudio.Razor.Extensions; + +internal static class TextDocumentExtensions +{ + /// + /// This method tries to compute the source generated hint name for a Razor document using only string manipulation + /// + /// + /// This should only be used in the devenv process. In OOP we can look at the actual generated run result to find this + /// information. + /// + public static bool TryComputeHintNameFromRazorDocument(this TextDocument razorDocument, [NotNullWhen(true)] out string? hintName) + { + if (razorDocument.FilePath is null) + { + hintName = null; + return false; + } + + var projectBasePath = Path.GetDirectoryName(razorDocument.Project.FilePath); + var relativeDocumentPath = razorDocument.FilePath[projectBasePath.Length..].TrimStart('/', '\\'); + hintName = RazorSourceGenerator.GetIdentifierFromPath(relativeDocumentPath); + + return hintName is not null; + } +} diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentPullDiagnosticsEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentPullDiagnosticsEndpoint.cs index 799c84de1ac..f66bac4ed87 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentPullDiagnosticsEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentPullDiagnosticsEndpoint.cs @@ -13,12 +13,12 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Remote; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; +using Microsoft.VisualStudio.Razor.Extensions; using ExternalHandlers = Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; using LspDiagnostic = Microsoft.VisualStudio.LanguageServer.Protocol.Diagnostic; using RoslynDiagnostic = Roslyn.LanguageServer.Protocol.Diagnostic; @@ -124,13 +124,13 @@ public ImmutableArray GetRegistrations(VSInternalClientCapabilitie private async Task GetCSharpDiagnosticsAsync(TextDocument razorDocument, CancellationToken cancellationToken) { - // TODO: This code will not work when the source generator is hooked up. - // How do we get the source generated C# document without OOP? Can we reverse engineer a file path? - var projectKey = razorDocument.Project.ToProjectKey(); - var csharpFilePath = _filePathService.GetRazorCSharpFilePath(projectKey, razorDocument.FilePath.AssumeNotNull()); - // We put the project Id in the generated document path, so there can only be one document - if (razorDocument.Project.Solution.GetDocumentIdsWithFilePath(csharpFilePath) is not [{ } generatedDocumentId] || - razorDocument.Project.GetDocument(generatedDocumentId) is not { } generatedDocument) + if (!razorDocument.TryComputeHintNameFromRazorDocument(out var hintName)) + { + return []; + } + + var generatedDocuments = await razorDocument.Project.GetSourceGeneratedDocumentsAsync(cancellationToken); + if (generatedDocuments.FirstOrDefault(d => d.HintName == hintName) is not { } generatedDocument) { return []; } From c9354efeb67bc255482620312abb3f8e3fa47863 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 24 Feb 2025 18:02:31 +1100 Subject: [PATCH 3/6] Prevent tests from doing bad things in cohosting I suspect this will make some of the skipped tests fail, which will help track down issues --- .../AbstractFilePathService.cs | 12 +++++++----- .../Remote/RemoteClientInitializationOptions.cs | 3 --- .../RemoteLanguageServerFeatureOptions.cs | 2 +- .../RemoteFilePathService.cs | 15 +++++++++++++++ .../Remote/RemoteServiceInvoker.cs | 1 - .../Cohost/CohostEndpointTestBase.cs | 2 -- 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/AbstractFilePathService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/AbstractFilePathService.cs index 6ced1313dcd..3da464e9c7a 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/AbstractFilePathService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/AbstractFilePathService.cs @@ -15,7 +15,7 @@ internal abstract class AbstractFilePathService(LanguageServerFeatureOptions lan public string GetRazorCSharpFilePath(ProjectKey projectKey, string razorFilePath) => GetGeneratedFilePath(projectKey, razorFilePath, _languageServerFeatureOptions.CSharpVirtualDocumentSuffix); - public Uri GetRazorDocumentUri(Uri virtualDocumentUri) + public virtual Uri GetRazorDocumentUri(Uri virtualDocumentUri) { var uriPath = virtualDocumentUri.AbsoluteUri; var razorFilePath = GetRazorFilePath(uriPath); @@ -23,7 +23,7 @@ public Uri GetRazorDocumentUri(Uri virtualDocumentUri) return uri; } - public bool IsVirtualCSharpFile(Uri uri) + public virtual bool IsVirtualCSharpFile(Uri uri) => CheckIfFileUriAndExtensionMatch(uri, _languageServerFeatureOptions.CSharpVirtualDocumentSuffix); public bool IsVirtualHtmlFile(Uri uri) @@ -37,10 +37,12 @@ private static bool CheckIfFileUriAndExtensionMatch(Uri uri, string extension) private string GetRazorFilePath(string filePath) { - var trimIndex = filePath.LastIndexOf(_languageServerFeatureOptions.CSharpVirtualDocumentSuffix); - if (trimIndex == -1) + var trimIndex = filePath.LastIndexOf(_languageServerFeatureOptions.HtmlVirtualDocumentSuffix); + // We don't check for C# in cohosting, as it will throw, and people might call this method on any + // random path. + if (trimIndex == -1 && !_languageServerFeatureOptions.UseRazorCohostServer) { - trimIndex = filePath.LastIndexOf(_languageServerFeatureOptions.HtmlVirtualDocumentSuffix); + trimIndex = filePath.LastIndexOf(_languageServerFeatureOptions.CSharpVirtualDocumentSuffix); } else if (_languageServerFeatureOptions.IncludeProjectKeyInGeneratedFilePath) { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/RemoteClientInitializationOptions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/RemoteClientInitializationOptions.cs index f599e8efa1c..c836720ad15 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/RemoteClientInitializationOptions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/RemoteClientInitializationOptions.cs @@ -13,9 +13,6 @@ internal struct RemoteClientInitializationOptions [JsonPropertyName("usePreciseSemanticTokenRanges")] public required bool UsePreciseSemanticTokenRanges { get; set; } - [JsonPropertyName("csharpVirtualDocumentSuffix")] - public required string CSharpVirtualDocumentSuffix { get; set; } - [JsonPropertyName("htmlVirtualDocumentSuffix")] public required string HtmlVirtualDocumentSuffix { get; set; } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Initialization/RemoteLanguageServerFeatureOptions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Initialization/RemoteLanguageServerFeatureOptions.cs index 15be2389f9a..66d2ec14771 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Initialization/RemoteLanguageServerFeatureOptions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Initialization/RemoteLanguageServerFeatureOptions.cs @@ -26,7 +26,7 @@ public void SetOptions(RemoteClientInitializationOptions options) public override bool SupportsFileManipulation => _options.SupportsFileManipulation; - public override string CSharpVirtualDocumentSuffix => _options.CSharpVirtualDocumentSuffix; + public override string CSharpVirtualDocumentSuffix => throw new InvalidOperationException("This property is not valid in OOP"); public override string HtmlVirtualDocumentSuffix => _options.HtmlVirtualDocumentSuffix; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteFilePathService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteFilePathService.cs index 587bc8b9e53..d73148a321d 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteFilePathService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/RemoteFilePathService.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. +using System; using System.Composition; using Microsoft.CodeAnalysis.Razor.Workspaces; @@ -10,4 +11,18 @@ namespace Microsoft.CodeAnalysis.Remote.Razor; [method: ImportingConstructor] internal sealed class RemoteFilePathService(LanguageServerFeatureOptions options) : AbstractFilePathService(options) { + public override Uri GetRazorDocumentUri(Uri virtualDocumentUri) + { + if (IsVirtualCSharpFile(virtualDocumentUri)) + { + throw new InvalidOperationException("Can not get a Razor document from a generated document Uri in cohosting"); + } + + return base.GetRazorDocumentUri(virtualDocumentUri); + } + + public override bool IsVirtualCSharpFile(Uri uri) + { + return uri.Scheme == "source-generated"; + } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/RemoteServiceInvoker.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/RemoteServiceInvoker.cs index 0698ed9c65f..693e4bc2f96 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/RemoteServiceInvoker.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/RemoteServiceInvoker.cs @@ -169,7 +169,6 @@ Task InitializeOOPAsync(RazorRemoteHostClient remoteClient) { UseRazorCohostServer = _languageServerFeatureOptions.UseRazorCohostServer, UsePreciseSemanticTokenRanges = _languageServerFeatureOptions.UsePreciseSemanticTokenRanges, - CSharpVirtualDocumentSuffix = _languageServerFeatureOptions.CSharpVirtualDocumentSuffix, HtmlVirtualDocumentSuffix = _languageServerFeatureOptions.HtmlVirtualDocumentSuffix, IncludeProjectKeyInGeneratedFilePath = _languageServerFeatureOptions.IncludeProjectKeyInGeneratedFilePath, ReturnCodeActionAndRenamePathsWithPrefixedSlash = _languageServerFeatureOptions.ReturnCodeActionAndRenamePathsWithPrefixedSlash, diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTestBase.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTestBase.cs index 575ea5b4cb3..c1fd7478cb2 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTestBase.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTestBase.cs @@ -32,7 +32,6 @@ namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost; public abstract class CohostEndpointTestBase(ITestOutputHelper testOutputHelper) : ToolingTestBase(testOutputHelper) { - private const string CSharpVirtualDocumentSuffix = ".g.cs"; private ExportProvider? _exportProvider; private TestRemoteServiceInvoker? _remoteServiceInvoker; private RemoteClientInitializationOptions _clientInitializationOptions; @@ -76,7 +75,6 @@ protected override async Task InitializeAsync() _clientInitializationOptions = new() { - CSharpVirtualDocumentSuffix = CSharpVirtualDocumentSuffix, HtmlVirtualDocumentSuffix = ".g.html", IncludeProjectKeyInGeneratedFilePath = false, UsePreciseSemanticTokenRanges = false, From 9a759197c3a5419eeb5f4c4bab3e236082bbab34 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 24 Feb 2025 18:02:44 +1100 Subject: [PATCH 4/6] Clean up --- .../Cohost/CohostDocumentPullDiagnosticsEndpoint.cs | 3 --- .../Cohost/CohostDocumentPullDiagnosticsTest.cs | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentPullDiagnosticsEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentPullDiagnosticsEndpoint.cs index f66bac4ed87..5c76ebc5952 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentPullDiagnosticsEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentPullDiagnosticsEndpoint.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Remote; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.Extensions; @@ -36,14 +35,12 @@ internal class CohostDocumentPullDiagnosticsEndpoint( IRemoteServiceInvoker remoteServiceInvoker, IHtmlDocumentSynchronizer htmlDocumentSynchronizer, LSPRequestInvoker requestInvoker, - IFilePathService filePathService, ILoggerFactory loggerFactory) : AbstractRazorCohostDocumentRequestHandler, IDynamicRegistrationProvider { private readonly IRemoteServiceInvoker _remoteServiceInvoker = remoteServiceInvoker; private readonly IHtmlDocumentSynchronizer _htmlDocumentSynchronizer = htmlDocumentSynchronizer; private readonly LSPRequestInvoker _requestInvoker = requestInvoker; - private readonly IFilePathService _filePathService = filePathService; private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); protected override bool MutatesSolutionState => false; diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentPullDiagnosticsTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentPullDiagnosticsTest.cs index e43fd395207..d811728f50f 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentPullDiagnosticsTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentPullDiagnosticsTest.cs @@ -144,7 +144,7 @@ private async Task VerifyDiagnosticsAsync(TestCode input, VSInternalDiagnosticRe var requestInvoker = new TestLSPRequestInvoker([(VSInternalMethods.DocumentPullDiagnosticName, htmlResponse)]); - var endpoint = new CohostDocumentPullDiagnosticsEndpoint(RemoteServiceInvoker, TestHtmlDocumentSynchronizer.Instance, requestInvoker, FilePathService, LoggerFactory); + var endpoint = new CohostDocumentPullDiagnosticsEndpoint(RemoteServiceInvoker, TestHtmlDocumentSynchronizer.Instance, requestInvoker, LoggerFactory); var result = await endpoint.GetTestAccessor().HandleRequestAsync(document, DisposalToken); From 59dd951d86411c58fe4c3e918e9185fbeff59d28 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Mon, 24 Feb 2025 19:58:56 +1100 Subject: [PATCH 5/6] Fix logic --- .../AbstractFilePathService.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/AbstractFilePathService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/AbstractFilePathService.cs index 3da464e9c7a..ee145aec387 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/AbstractFilePathService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/AbstractFilePathService.cs @@ -38,21 +38,22 @@ private static bool CheckIfFileUriAndExtensionMatch(Uri uri, string extension) private string GetRazorFilePath(string filePath) { var trimIndex = filePath.LastIndexOf(_languageServerFeatureOptions.HtmlVirtualDocumentSuffix); + // We don't check for C# in cohosting, as it will throw, and people might call this method on any // random path. if (trimIndex == -1 && !_languageServerFeatureOptions.UseRazorCohostServer) { trimIndex = filePath.LastIndexOf(_languageServerFeatureOptions.CSharpVirtualDocumentSuffix); - } - else if (_languageServerFeatureOptions.IncludeProjectKeyInGeneratedFilePath) - { + // If this is a C# generated file, and we're including the project suffix, then filename will be // .razor. - // This means we can remove the project key easily, by just looking for the last '.'. The project - // slug itself cannot a '.', enforced by the assert below in GetProjectSuffix - - trimIndex = filePath.LastIndexOf('.', trimIndex - 1); - Debug.Assert(trimIndex != -1, "There was no project element to the generated file name?"); + if (_languageServerFeatureOptions.IncludeProjectKeyInGeneratedFilePath) + { + // We can remove the project key easily, by just looking for the last '.'. The project + // slug itself cannot a '.', enforced by the assert below in GetProjectSuffix + trimIndex = filePath.LastIndexOf('.', trimIndex - 1); + Debug.Assert(trimIndex != -1, "There was no project element to the generated file name?"); + } } if (trimIndex != -1) From 6f5c1e48a9e0d191add8a18074fe6bcbb5c4b725 Mon Sep 17 00:00:00 2001 From: David Wengier Date: Tue, 25 Feb 2025 14:10:42 +1100 Subject: [PATCH 6/6] Unify logic --- .../Extensions/ProjectExtensions.cs | 17 +++++++++++++++++ .../ProjectSystem/RemoteProjectSnapshot.cs | 19 ++++++++++++------- .../CohostDocumentPullDiagnosticsEndpoint.cs | 9 ++------- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs index 4b3420f5c90..879059f3d9b 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs @@ -4,6 +4,8 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; namespace Microsoft.CodeAnalysis; @@ -34,4 +36,19 @@ public static bool TryGetCSharpDocument(this Project project, Uri csharpDocument return document is not null; } + + /// + /// Finds source generated documents by iterating through all of them. In OOP there are better options! + /// + public static async Task TryGetSourceGeneratedDocumentFromHintNameAsync(this Project project, string? hintName, CancellationToken cancellationToken) + { + // TODO: use this when the location is case-insensitive on windows (https://github.com/dotnet/roslyn/issues/76869) + //var generator = typeof(RazorSourceGenerator); + //var generatorAssembly = generator.Assembly; + //var generatorName = generatorAssembly.GetName(); + //var generatedDocuments = await _project.GetSourceGeneratedDocumentsForGeneratorAsync(generatorName.Name!, generatorAssembly.Location, generatorName.Version!, generator.Name, cancellationToken).ConfigureAwait(false); + + var generatedDocuments = await project.GetSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false); + return generatedDocuments.SingleOrDefault(d => d.HintName == hintName); + } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs index 07957a8d74d..5e5b9a82331 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs @@ -163,7 +163,9 @@ public bool TryGetDocument(string filePath, [NotNullWhen(true)] out IDocumentSna { var generatorResult = await GetRazorGeneratorResultAsync(cancellationToken).ConfigureAwait(false); if (generatorResult is null) + { return null; + } return generatorResult.GetCodeDocument(documentSnapshot.FilePath); } @@ -172,33 +174,36 @@ public bool TryGetDocument(string filePath, [NotNullWhen(true)] out IDocumentSna { var generatorResult = await GetRazorGeneratorResultAsync(cancellationToken).ConfigureAwait(false); if (generatorResult is null) + { return null; + } var hintName = generatorResult.GetHintName(documentSnapshot.FilePath); - // TODO: use this when the location is case-insensitive on windows (https://github.com/dotnet/roslyn/issues/76869) - //var generator = typeof(RazorSourceGenerator); - //var generatorAssembly = generator.Assembly; - //var generatorName = generatorAssembly.GetName(); - //var generatedDocuments = await _project.GetSourceGeneratedDocumentsForGeneratorAsync(generatorName.Name!, generatorAssembly.Location, generatorName.Version!, generator.Name, cancellationToken).ConfigureAwait(false); + var generatedDocument = await _project.TryGetSourceGeneratedDocumentFromHintNameAsync(hintName, cancellationToken).ConfigureAwait(false); - var generatedDocuments = await _project.GetSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false); - return generatedDocuments.Single(d => d.HintName == hintName); + return generatedDocument ?? throw new InvalidOperationException("Couldn't get the source generated document for a hint name that we got from the generator?"); } private async Task GetRazorGeneratorResultAsync(CancellationToken cancellationToken) { var result = await _project.GetSourceGeneratorRunResultAsync(cancellationToken).ConfigureAwait(false); if (result is null) + { return null; + } var runResult = result.Results.SingleOrDefault(r => r.Generator.GetGeneratorType().Assembly.Location == typeof(RazorSourceGenerator).Assembly.Location); if (runResult.Generator is null) + { return null; + } #pragma warning disable RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. if (!runResult.HostOutputs.TryGetValue(nameof(RazorGeneratorResult), out var objectResult) || objectResult is not RazorGeneratorResult generatorResult) + { return null; + } #pragma warning restore RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. return generatorResult; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentPullDiagnosticsEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentPullDiagnosticsEndpoint.cs index 5c76ebc5952..93015124a4d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentPullDiagnosticsEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentPullDiagnosticsEndpoint.cs @@ -121,13 +121,8 @@ public ImmutableArray GetRegistrations(VSInternalClientCapabilitie private async Task GetCSharpDiagnosticsAsync(TextDocument razorDocument, CancellationToken cancellationToken) { - if (!razorDocument.TryComputeHintNameFromRazorDocument(out var hintName)) - { - return []; - } - - var generatedDocuments = await razorDocument.Project.GetSourceGeneratedDocumentsAsync(cancellationToken); - if (generatedDocuments.FirstOrDefault(d => d.HintName == hintName) is not { } generatedDocument) + if (!razorDocument.TryComputeHintNameFromRazorDocument(out var hintName) || + await razorDocument.Project.TryGetSourceGeneratedDocumentFromHintNameAsync(hintName, cancellationToken).ConfigureAwait(false) is not { } generatedDocument) { return []; }