From fcfd3ce07f3fc8a39390e4dc5af664601623001c Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Thu, 12 Dec 2024 10:15:25 -0800 Subject: [PATCH 01/42] ProjectState: Replace LanguageServerFeatureOptions with enum The Razor project/document state model only need two compiler options: ForceRuntimeCodeGeneration and UseRoslynTokenizer. So, using LanguageServerFeatureOptions directly within ProjectState is a bit overkill. This change introduces a new enum, RazorCompilerOptions, to track the two options that the project model needs to control Razor compilation. --- .../ProjectSnapshotManagerBenchmarkBase.cs | 9 +-- .../LspProjectSnapshotManager.cs | 2 +- .../DocumentState.ComputedStateTracker.cs | 3 +- .../ProjectSystem/ProjectSnapshot.cs | 3 +- .../ProjectSystem/ProjectSnapshotManager.cs | 11 ++- .../ProjectSystem/ProjectState.cs | 26 +++---- .../ProjectSystem/RazorCompilerOptions.cs | 14 ++++ .../RazorCompilerOptionsExtensions.cs | 27 ++++++++ .../VisualStudioProjectSnapshotManager.cs | 2 +- .../ProjectEngineFactoryProviderTest.cs | 13 ++-- .../ProjectSystem/TestProjectSnapshot.cs | 3 +- .../TestProjectSnapshotManager.cs | 2 +- .../DocumentExcerptServiceTestBase.cs | 2 +- .../Workspaces/WorkspaceTestBase.cs | 4 ++ .../DefaultDocumentSnapshotTest.cs | 2 +- .../DefaultProjectSnapshotTest.cs | 6 +- .../GeneratedDocumentTextLoaderTest.cs | 2 +- .../ProjectStateGeneratedOutputTest.cs | 18 ++--- .../ProjectSystem/ProjectStateTest.cs | 68 +++++++++---------- .../RazorSpanMappingServiceTest.cs | 8 +-- .../RazorDocumentOptionsServiceTest.cs | 2 +- .../ProjectWorkspaceStateGeneratorTest.cs | 2 +- 22 files changed, 132 insertions(+), 97 deletions(-) create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/RazorCompilerOptions.cs create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/RazorCompilerOptionsExtensions.cs diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/ProjectSystem/ProjectSnapshotManagerBenchmarkBase.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/ProjectSystem/ProjectSnapshotManagerBenchmarkBase.cs index 0e40658d013..2c38971da0c 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/ProjectSystem/ProjectSnapshotManagerBenchmarkBase.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/ProjectSystem/ProjectSnapshotManagerBenchmarkBase.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using System.IO; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.LanguageServer; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.Logging; @@ -50,11 +49,9 @@ protected ProjectSnapshotManagerBenchmarkBase(int documentCount = 100) Documents = documents.ToImmutable(); } - internal ProjectSnapshotManager CreateProjectSnapshotManager() - { - return new ProjectSnapshotManager( + internal static ProjectSnapshotManager CreateProjectSnapshotManager() + => new( projectEngineFactoryProvider: StaticProjectEngineFactoryProvider.Instance, - languageServerFeatureOptions: new DefaultLanguageServerFeatureOptions(), + compilerOptions: RazorCompilerOptions.None, loggerFactory: EmptyLoggerFactory.Instance); - } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/LspProjectSnapshotManager.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/LspProjectSnapshotManager.cs index 7533651bb7e..35b33b1df1b 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/LspProjectSnapshotManager.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/LspProjectSnapshotManager.cs @@ -12,7 +12,7 @@ internal class LspProjectSnapshotManager( IProjectEngineFactoryProvider projectEngineFactoryProvider, LanguageServerFeatureOptions languageServerFeatureOptions, ILoggerFactory loggerFactory) - : ProjectSnapshotManager(projectEngineFactoryProvider, languageServerFeatureOptions, loggerFactory, initializer: AddMiscFilesProject) + : ProjectSnapshotManager(projectEngineFactoryProvider, languageServerFeatureOptions.ToCompilerOptions(), loggerFactory, initializer: AddMiscFilesProject) { private static void AddMiscFilesProject(Updater updater) { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs index 4b74b384683..4d30a77df18 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs @@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -232,7 +233,7 @@ static void PropagateToTaskCompletionSource( } } - var forceRuntimeCodeGeneration = project.LanguageServerFeatureOptions.ForceRuntimeCodeGeneration; + var forceRuntimeCodeGeneration = project.CompilerOptions.IsFlagSet(RazorCompilerOptions.ForceRuntimeCodeGeneration); var codeDocument = await GenerateCodeDocumentAsync(document, project.GetProjectEngine(), importItems, forceRuntimeCodeGeneration, cancellationToken).ConfigureAwait(false); return (codeDocument, inputVersion); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs index 827ef1fb884..25584ea45ef 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs @@ -11,7 +11,6 @@ using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Utilities; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Razor.Workspaces; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -23,7 +22,7 @@ internal sealed class ProjectSnapshot(ProjectState state) : IProjectSnapshot private readonly Dictionary _filePathToDocumentMap = new(FilePathNormalizingComparer.Instance); public HostProject HostProject => _state.HostProject; - public LanguageServerFeatureOptions LanguageServerFeatureOptions => _state.LanguageServerFeatureOptions; + public RazorCompilerOptions CompilerOptions => _state.CompilerOptions; public ProjectKey Key => _state.HostProject.Key; public RazorConfiguration Configuration => _state.HostProject.Configuration; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.cs index 584d2d2e142..9515f8d1911 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.cs @@ -13,7 +13,6 @@ using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Threading; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -28,7 +27,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; internal partial class ProjectSnapshotManager : IProjectSnapshotManager, IDisposable { private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider; - private readonly LanguageServerFeatureOptions _languageServerFeatureOptions; + private readonly RazorCompilerOptions _compilerOptions; private readonly Dispatcher _dispatcher; private readonly ILogger _logger; private readonly bool _initialized; @@ -83,19 +82,19 @@ internal partial class ProjectSnapshotManager : IProjectSnapshotManager, IDispos /// /// The to /// use when creating . - /// The options that were used to start the language server + /// Options used to control Razor compilation. /// The to use. /// An optional callback to set up the initial set of projects and documents. /// Note that this is called during construction, so it does not run on the dispatcher and notifications /// will not be sent. public ProjectSnapshotManager( IProjectEngineFactoryProvider projectEngineFactoryProvider, - LanguageServerFeatureOptions languageServerFeatureOptions, + RazorCompilerOptions compilerOptions, ILoggerFactory loggerFactory, Action? initializer = null) { _projectEngineFactoryProvider = projectEngineFactoryProvider; - _languageServerFeatureOptions = languageServerFeatureOptions; + _compilerOptions = compilerOptions; _dispatcher = new(loggerFactory); _logger = loggerFactory.GetOrCreateLogger(GetType()); @@ -374,7 +373,7 @@ private bool TryAddProject(HostProject hostProject, [NotNullWhen(true)] out IPro var state = ProjectState.Create( _projectEngineFactoryProvider, - _languageServerFeatureOptions, + _compilerOptions, hostProject, ProjectWorkspaceState.Default); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs index 4db14e3ca9c..2b4a44aa427 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs @@ -6,15 +6,14 @@ using System.Collections.Immutable; using System.IO; using System.Linq; -using System.Threading.Tasks; using System.Threading; +using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectEngineHost; using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Utilities; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.NET.Sdk.Razor.SourceGenerators; @@ -38,27 +37,30 @@ internal class ProjectState private static readonly ImmutableDictionary> s_emptyImportsToRelatedDocuments = ImmutableDictionary.Create>(FilePathNormalizingComparer.Instance); private readonly object _lock; + public HostProject HostProject { get; } + public RazorCompilerOptions CompilerOptions { get; } + public ProjectWorkspaceState ProjectWorkspaceState { get; } + private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider; - private readonly LanguageServerFeatureOptions _languageServerFeatureOptions; private RazorProjectEngine? _projectEngine; public static ProjectState Create( IProjectEngineFactoryProvider projectEngineFactoryProvider, - LanguageServerFeatureOptions languageServerFeatureOptions, + RazorCompilerOptions compilerOptions, HostProject hostProject, ProjectWorkspaceState projectWorkspaceState) { - return new ProjectState(projectEngineFactoryProvider, languageServerFeatureOptions, hostProject, projectWorkspaceState); + return new ProjectState(projectEngineFactoryProvider, compilerOptions, hostProject, projectWorkspaceState); } private ProjectState( IProjectEngineFactoryProvider projectEngineFactoryProvider, - LanguageServerFeatureOptions languageServerFeatureOptions, + RazorCompilerOptions compilerOptions, HostProject hostProject, ProjectWorkspaceState projectWorkspaceState) { _projectEngineFactoryProvider = projectEngineFactoryProvider; - _languageServerFeatureOptions = languageServerFeatureOptions; + CompilerOptions = compilerOptions; HostProject = hostProject; ProjectWorkspaceState = projectWorkspaceState; Documents = s_emptyDocuments; @@ -79,7 +81,7 @@ private ProjectState( ImmutableDictionary> importsToRelatedDocuments) { _projectEngineFactoryProvider = older._projectEngineFactoryProvider; - _languageServerFeatureOptions = older._languageServerFeatureOptions; + CompilerOptions = older.CompilerOptions; Version = older.Version.GetNewerVersion(); HostProject = hostProject; @@ -136,12 +138,6 @@ private ProjectState( // Internal set for testing. public ImmutableDictionary> ImportsToRelatedDocuments { get; internal set; } - public HostProject HostProject { get; } - - internal LanguageServerFeatureOptions LanguageServerFeatureOptions => _languageServerFeatureOptions; - - public ProjectWorkspaceState ProjectWorkspaceState { get; } - public ImmutableArray TagHelpers => ProjectWorkspaceState.TagHelpers; public LanguageVersion CSharpLanguageVersion => ProjectWorkspaceState.CSharpLanguageVersion; @@ -174,7 +170,7 @@ RazorProjectEngine CreateProjectEngine() { var configuration = HostProject.Configuration; var rootDirectoryPath = Path.GetDirectoryName(HostProject.FilePath).AssumeNotNull(); - var useRoslynTokenizer = LanguageServerFeatureOptions.UseRoslynTokenizer; + var useRoslynTokenizer = CompilerOptions.IsFlagSet(RazorCompilerOptions.UseRoslynTokenizer); return _projectEngineFactoryProvider.Create(configuration, rootDirectoryPath, builder => { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/RazorCompilerOptions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/RazorCompilerOptions.cs new file mode 100644 index 00000000000..78723007324 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/RazorCompilerOptions.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; + +[Flags] +internal enum RazorCompilerOptions +{ + None = 0, + ForceRuntimeCodeGeneration = 1 << 0, + UseRoslynTokenizer = 1 << 1 +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/RazorCompilerOptionsExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/RazorCompilerOptionsExtensions.cs new file mode 100644 index 00000000000..d7b8e81cc0c --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/RazorCompilerOptionsExtensions.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; + +namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; + +internal static class RazorCompilerOptionsExtensions +{ + public static RazorCompilerOptions ToCompilerOptions(this LanguageServerFeatureOptions languageServerFeatureOptions) + { + var options = RazorCompilerOptions.None; + + if (languageServerFeatureOptions.ForceRuntimeCodeGeneration) + { + options.SetFlag(RazorCompilerOptions.ForceRuntimeCodeGeneration); + } + + if (languageServerFeatureOptions.UseRoslynTokenizer) + { + options.SetFlag(RazorCompilerOptions.UseRoslynTokenizer); + } + + return options; + } +} diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/VisualStudioProjectSnapshotManager.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/VisualStudioProjectSnapshotManager.cs index 3d7a6b947d5..e72f11e54a3 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/VisualStudioProjectSnapshotManager.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/VisualStudioProjectSnapshotManager.cs @@ -15,6 +15,6 @@ internal sealed class VisualStudioProjectSnapshotManager( IProjectEngineFactoryProvider projectEngineFactoryProvider, LanguageServerFeatureOptions languageServerFeatureOptions, ILoggerFactory loggerFactory) - : ProjectSnapshotManager(projectEngineFactoryProvider, languageServerFeatureOptions, loggerFactory) + : ProjectSnapshotManager(projectEngineFactoryProvider, languageServerFeatureOptions.ToCompilerOptions(), loggerFactory) { } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs index c27bec75298..615d31f17da 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs @@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; -using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Xunit; @@ -50,12 +49,12 @@ public ProjectEngineFactoryProviderTest(ITestOutputHelper testOutput) projectFilePath, intermediateOutputPath, new(RazorLanguageVersion.Version_2_1, "Random-0.1", Extensions: []), rootNamespace: null); - _snapshot_For_1_0 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, TestLanguageServerFeatureOptions.Instance, hostProject_For_1_0, ProjectWorkspaceState.Default)); - _snapshot_For_1_1 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, TestLanguageServerFeatureOptions.Instance, hostProject_For_1_1, ProjectWorkspaceState.Default)); - _snapshot_For_2_0 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, TestLanguageServerFeatureOptions.Instance, hostProject_For_2_0, ProjectWorkspaceState.Default)); - _snapshot_For_2_1 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, TestLanguageServerFeatureOptions.Instance, hostProject_For_2_1, ProjectWorkspaceState.Default)); - _snapshot_For_3_0 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, TestLanguageServerFeatureOptions.Instance, hostProject_For_3_0, ProjectWorkspaceState.Default)); - _snapshot_For_UnknownConfiguration = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, TestLanguageServerFeatureOptions.Instance, hostProject_For_UnknownConfiguration, ProjectWorkspaceState.Default)); + _snapshot_For_1_0 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, RazorCompilerOptions.None, hostProject_For_1_0, ProjectWorkspaceState.Default)); + _snapshot_For_1_1 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, RazorCompilerOptions.None, hostProject_For_1_1, ProjectWorkspaceState.Default)); + _snapshot_For_2_0 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, RazorCompilerOptions.None, hostProject_For_2_0, ProjectWorkspaceState.Default)); + _snapshot_For_2_1 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, RazorCompilerOptions.None, hostProject_For_2_1, ProjectWorkspaceState.Default)); + _snapshot_For_3_0 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, RazorCompilerOptions.None, hostProject_For_3_0, ProjectWorkspaceState.Default)); + _snapshot_For_UnknownConfiguration = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, RazorCompilerOptions.None, hostProject_For_UnknownConfiguration, ProjectWorkspaceState.Default)); _customFactories = [ diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs index dc17c2a705f..ed7b5b26d7d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs @@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectEngineHost; using Microsoft.AspNetCore.Razor.ProjectSystem; -using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -31,7 +30,7 @@ public static TestProjectSnapshot Create(string filePath, ProjectWorkspaceState? var hostProject = TestHostProject.Create(filePath); projectWorkspaceState ??= ProjectWorkspaceState.Default; - var state = ProjectState.Create(ProjectEngineFactories.DefaultProvider, TestLanguageServerFeatureOptions.Instance, hostProject, projectWorkspaceState); + var state = ProjectState.Create(ProjectEngineFactories.DefaultProvider, RazorCompilerOptions.None, hostProject, projectWorkspaceState); return new TestProjectSnapshot(state); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshotManager.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshotManager.cs index 7d273a0e7c0..f149d96ae21 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshotManager.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshotManager.cs @@ -17,7 +17,7 @@ internal partial class TestProjectSnapshotManager( ILoggerFactory loggerFactory, CancellationToken disposalToken, Action? initializer = null) - : ProjectSnapshotManager(projectEngineFactoryProvider, languageServerFeatureOptions, loggerFactory, initializer) + : ProjectSnapshotManager(projectEngineFactoryProvider, languageServerFeatureOptions.ToCompilerOptions(), loggerFactory, initializer) { private readonly CancellationToken _disposalToken = disposalToken; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/DocumentExcerptServiceTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/DocumentExcerptServiceTestBase.cs index cb1451e6b81..0359b82d608 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/DocumentExcerptServiceTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/DocumentExcerptServiceTestBase.cs @@ -42,7 +42,7 @@ public static (SourceText sourceText, TextSpan span) CreateText(string text) private (IDocumentSnapshot primary, Document secondary) InitializeDocument(SourceText sourceText) { var state = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions.ToCompilerOptions(), _hostProject, ProjectWorkspaceState.Default) .AddDocument(_hostDocument, sourceText); var project = new ProjectSnapshot(state); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/WorkspaceTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/WorkspaceTestBase.cs index 2fda7392cb3..dc10f9427fd 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/WorkspaceTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/WorkspaceTestBase.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; using Xunit.Abstractions; @@ -67,6 +68,9 @@ private protected LanguageServerFeatureOptions LanguageServerFeatureOptions } } + private protected RazorCompilerOptions CompilerOptions + => LanguageServerFeatureOptions.ToCompilerOptions(); + private protected override TestProjectSnapshotManager CreateProjectSnapshotManager() => CreateProjectSnapshotManager(ProjectEngineFactoryProvider, LanguageServerFeatureOptions); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs index c4c74a04451..82af1613c9c 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs @@ -31,7 +31,7 @@ public DefaultDocumentSnapshotTest(ITestOutputHelper testOutput) { _sourceText = SourceText.From("

Hello World

"); - var projectState = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, TestProjectData.SomeProject, ProjectWorkspaceState.Default); + var projectState = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, TestProjectData.SomeProject, ProjectWorkspaceState.Default); var project = new ProjectSnapshot(projectState); var textLoader = TestMocks.CreateTextLoader(_sourceText); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs index 555d7e56cd2..a6d2df0bd83 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs @@ -44,7 +44,7 @@ protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder public void ProjectSnapshot_CachesDocumentSnapshots() { // Arrange - var state = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + var state = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[0], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader) .AddDocument(_documents[2], DocumentState.EmptyLoader); @@ -65,7 +65,7 @@ public void ProjectSnapshot_CachesDocumentSnapshots() public void GetRelatedDocuments_NonImportDocument_ReturnsEmpty() { // Arrange - var state = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + var state = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[0], DocumentState.EmptyLoader); var snapshot = new ProjectSnapshot(state); @@ -82,7 +82,7 @@ public void GetRelatedDocuments_NonImportDocument_ReturnsEmpty() public void GetRelatedDocuments_ImportDocument_ReturnsRelated() { // Arrange - var state = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + var state = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[0], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectImportFile, DocumentState.EmptyLoader); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs index cb6ac624a57..7b132653487 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs @@ -21,7 +21,7 @@ public async Task LoadAsync_SpecifiesEncoding() { // Arrange var state = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) .AddDocument(_hostDocument, TestMocks.CreateEmptyTextLoader()); var project = new ProjectSnapshot(state); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs index 13373341466..f4c60c7657d 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs @@ -43,7 +43,7 @@ public async Task AddDocument_CachesOutput() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) .AddDocument(_hostDocument, DocumentState.EmptyLoader); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -62,7 +62,7 @@ public async Task AddDocument_Import_DoesNotCacheOutput() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) .AddDocument(_hostDocument, DocumentState.EmptyLoader); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -82,7 +82,7 @@ public async Task WithDocumentText_DoesNotCacheOutput() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) .AddDocument(_hostDocument, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectImportFile, DocumentState.EmptyLoader); @@ -104,7 +104,7 @@ public async Task WithDocumentText_Import_DoesNotCacheOutput() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) .AddDocument(_hostDocument, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectImportFile, DocumentState.EmptyLoader); @@ -126,7 +126,7 @@ public async Task RemoveDocument_Import_DoesNotCacheOutput() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) .AddDocument(_hostDocument, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectImportFile, DocumentState.EmptyLoader); @@ -147,7 +147,7 @@ public async Task WithProjectWorkspaceState_CachesOutput_EvenWhenNewerProjectWor { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) .AddDocument(_hostDocument, DocumentState.EmptyLoader); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -167,7 +167,7 @@ public async Task WithProjectWorkspaceState_TagHelperChange_DoesNotCacheOutput() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) .AddDocument(_hostDocument, DocumentState.EmptyLoader); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -191,7 +191,7 @@ public async Task WithProjectWorkspaceState_CSharpLanguageVersionChange_DoesNotC var hostProject = TestProjectData.SomeProject with { Configuration = csharp8ValidConfiguration }; var originalWorkspaceState = ProjectWorkspaceState.Create(_someTagHelpers, LanguageVersion.CSharp7); var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, hostProject, originalWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, hostProject, originalWorkspaceState) .AddDocument(_hostDocument, TestMocks.CreateTextLoader("@DateTime.Now", VersionStamp.Default)); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -212,7 +212,7 @@ public async Task WithHostProject_DoesNotCacheOutput() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) .AddDocument(_hostDocument, DocumentState.EmptyLoader); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs index 8460f9f08a2..cd1fa4cc04f 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs @@ -56,7 +56,7 @@ protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder public void GetImportDocumentTargetPaths_DoesNotIncludeCurrentImport() { // Arrange - var state = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState); + var state = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); // Act var paths = state.GetImportDocumentTargetPaths(TestProjectData.SomeProjectComponentImportFile1); @@ -71,7 +71,7 @@ public void ProjectState_ConstructedNew() // Arrange // Act - var state = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState); + var state = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); // Assert Assert.Empty(state.Documents); @@ -82,7 +82,7 @@ public void ProjectState_ConstructedNew() public void ProjectState_AddDocument_ToEmpty() { // Arrange - var original = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); // Act var state = original.AddDocument(_documents[0], DocumentState.EmptyLoader); @@ -100,7 +100,7 @@ public void ProjectState_AddDocument_ToEmpty() public async Task ProjectState_AddDocument_DocumentIsEmpty() { // Arrange - var original = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); // Act var state = original.AddDocument(_documents[0], DocumentState.EmptyLoader); @@ -115,7 +115,7 @@ public void ProjectState_AddDocument_ToProjectWithDocuments() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -140,7 +140,7 @@ public void ProjectState_AddDocument_TracksImports() // Act var state = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectFile2, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectNestedFile3, DocumentState.EmptyLoader) @@ -180,7 +180,7 @@ public void ProjectState_AddDocument_TracksImports_AddImportFile() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectFile2, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectNestedFile3, DocumentState.EmptyLoader) @@ -224,7 +224,7 @@ public void ProjectState_AddDocument_RetainsComputedState() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -258,7 +258,7 @@ public void ProjectState_AddDocument_DuplicateIgnored() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -274,7 +274,7 @@ public async Task ProjectState_WithDocumentText_Loader() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -295,7 +295,7 @@ public async Task ProjectState_WithDocumentText_Snapshot() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -316,7 +316,7 @@ public void ProjectState_WithDocumentText_Loader_RetainsComputedState() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -349,7 +349,7 @@ public void ProjectState_WithDocumentText_Snapshot_RetainsComputedState() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -382,7 +382,7 @@ public void ProjectState_WithDocumentText_Loader_NotFoundIgnored() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -398,7 +398,7 @@ public void ProjectState_WithDocumentText_Snapshot_NotFoundIgnored() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -414,7 +414,7 @@ public void ProjectState_RemoveDocument_FromProjectWithDocuments() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -436,7 +436,7 @@ public void ProjectState_RemoveDocument_TracksImports() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectFile2, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectNestedFile3, DocumentState.EmptyLoader) @@ -477,7 +477,7 @@ public void ProjectState_RemoveDocument_TracksImports_RemoveAllDocuments() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectFile2, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectNestedFile3, DocumentState.EmptyLoader) @@ -500,7 +500,7 @@ public void ProjectState_RemoveDocument_RetainsComputedState() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -533,7 +533,7 @@ public void ProjectState_RemoveDocument_NotFoundIgnored() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -549,7 +549,7 @@ public void ProjectState_WithHostProject_ConfigurationChange_UpdatesConfiguratio { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -588,7 +588,7 @@ public void ProjectState_WithHostProject_RootNamespaceChange_UpdatesConfiguratio { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); var hostProjectWithRootNamespaceChange = original.HostProject with { RootNamespace = "ChangedRootNamespace" }; @@ -609,7 +609,7 @@ public void ProjectState_WithHostProject_NoConfigurationChange_Ignored() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -633,7 +633,7 @@ public void ProjectState_WithHostProject_CallsConfigurationChangeOnDocumentState documents[_documents[1].FilePath] = TestDocumentState.Create(_documents[1], onConfigurationChange: () => callCount++); documents[_documents[2].FilePath] = TestDocumentState.Create(_documents[2], onConfigurationChange: () => callCount++); - var original = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); original.Documents = documents.ToImmutable(); // Act @@ -649,7 +649,7 @@ public void ProjectState_WithHostProject_CallsConfigurationChangeOnDocumentState public void ProjectState_WithHostProject_ResetsImportedDocuments() { // Arrange - var original = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); original = original.AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader); // Act @@ -665,7 +665,7 @@ public void ProjectState_WithHostProject_ResetsImportedDocuments() public void ProjectState_WithProjectWorkspaceState_Changed() { // Arrange - var original = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -704,7 +704,7 @@ public void ProjectState_WithProjectWorkspaceState_Changed() public void ProjectState_WithProjectWorkspaceState_Changed_TagHelpersChanged() { // Arrange - var original = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -738,7 +738,7 @@ public void ProjectState_WithProjectWorkspaceState_Changed_TagHelpersChanged() public void ProjectState_WithProjectWorkspaceState_IdenticalState_Caches() { // Arrange - var original = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState) + var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -763,7 +763,7 @@ public void ProjectState_WithProjectWorkspaceState_CallsWorkspaceProjectChangeOn documents[_documents[1].FilePath] = TestDocumentState.Create(_documents[1], onProjectWorkspaceStateChange: () => callCount++); documents[_documents[2].FilePath] = TestDocumentState.Create(_documents[2], onProjectWorkspaceStateChange: () => callCount++); - var original = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); original.Documents = documents.ToImmutable(); // Act @@ -805,7 +805,7 @@ public void ProjectState_AddDocument_Import_CallsImportsChanged() TestProjectData.SomeProjectNestedFile3.FilePath, TestProjectData.AnotherProjectNestedFile4.FilePath)); - var original = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); original.Documents = documents.ToImmutable(); original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); @@ -848,7 +848,7 @@ public void ProjectState_AddDocument_Import_CallsImportsChanged_Nested() TestProjectData.SomeProjectNestedFile3.FilePath, TestProjectData.AnotherProjectNestedFile4.FilePath)); - var original = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); original.Documents = documents.ToImmutable(); original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); @@ -894,7 +894,7 @@ public void ProjectState_WithDocumentText_Loader_Import_CallsImportsChanged() TestProjectData.SomeProjectNestedFile3.FilePath, TestProjectData.AnotherProjectNestedFile4.FilePath)); - var original = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); original.Documents = documents.ToImmutable(); original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); @@ -940,7 +940,7 @@ public void ProjectState_WithDocumentText_Snapshot_Import_CallsImportsChanged() TestProjectData.SomeProjectNestedFile3.FilePath, TestProjectData.AnotherProjectNestedFile4.FilePath)); - var original = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); original.Documents = documents.ToImmutable(); original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); @@ -986,7 +986,7 @@ public void ProjectState_RemoveDocument_Import_CallsImportsChanged() TestProjectData.SomeProjectNestedFile3.FilePath, TestProjectData.AnotherProjectNestedFile4.FilePath)); - var original = ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); original.Documents = documents.ToImmutable(); original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorSpanMappingServiceTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorSpanMappingServiceTest.cs index fc3cc93d6cd..022f719ae04 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorSpanMappingServiceTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorSpanMappingServiceTest.cs @@ -29,7 +29,7 @@ public async Task TryGetMappedSpans_SpanMatchesSourceMapping_ReturnsTrue() "); var state = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) .AddDocument(_hostDocument, TestMocks.CreateTextLoader(sourceText)); var project = new ProjectSnapshot(state); @@ -61,7 +61,7 @@ public async Task TryGetMappedSpans_SpanMatchesSourceMappingAndPosition_ReturnsT "); var state = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) .AddDocument(_hostDocument, TestMocks.CreateTextLoader(sourceText)); var project = new ProjectSnapshot(state); @@ -94,7 +94,7 @@ public async Task TryGetMappedSpans_SpanWithinSourceMapping_ReturnsTrue() "); var state = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) .AddDocument(_hostDocument, TestMocks.CreateTextLoader(sourceText)); var project = new ProjectSnapshot(state); @@ -126,7 +126,7 @@ public async Task TryGetMappedSpans_SpanOutsideSourceMapping_ReturnsFalse() "); var state = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) .AddDocument(_hostDocument, TestMocks.CreateTextLoader(sourceText)); var project = new ProjectSnapshot(state); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorDocumentOptionsServiceTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorDocumentOptionsServiceTest.cs index 8a472fbd050..23136da3d6a 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorDocumentOptionsServiceTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorDocumentOptionsServiceTest.cs @@ -97,7 +97,7 @@ private Document InitializeDocument(SourceText sourceText) Path.Combine(baseDirectory, "SomeProject", "File1.cshtml"), "File1.cshtml", FileKinds.Legacy); var project = new ProjectSnapshot(ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, hostProject, ProjectWorkspaceState.Default) + .Create(ProjectEngineFactoryProvider, CompilerOptions, hostProject, ProjectWorkspaceState.Default) .AddDocument(hostDocument, TestMocks.CreateTextLoader(sourceText))); var document = project.GetRequiredDocument(hostDocument.FilePath); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectWorkspaceStateGeneratorTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectWorkspaceStateGeneratorTest.cs index 937bfb1856f..ce281f59fc6 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectWorkspaceStateGeneratorTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectWorkspaceStateGeneratorTest.cs @@ -42,7 +42,7 @@ public ProjectWorkspaceStateGeneratorTest(ITestOutputHelper testOutput) TestProjectData.SomeProject.FilePath)); _workspaceProject = solution.GetProject(projectId).AssumeNotNull(); _projectSnapshot = new ProjectSnapshot( - ProjectState.Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions, TestProjectData.SomeProject, ProjectWorkspaceState.Default)); + ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, TestProjectData.SomeProject, ProjectWorkspaceState.Default)); _projectWorkspaceStateWithTagHelpers = ProjectWorkspaceState.Create( [TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly").Build()]); From eb5d9163c0ddab232d44001fe212031a9c1fd6ff Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Thu, 12 Dec 2024 11:19:56 -0800 Subject: [PATCH 02/42] Improve ProjectState.Create(...) factory methods and constructors --- .../ProjectSystem/ProjectSnapshotManager.cs | 6 +- .../ProjectSystem/ProjectState.cs | 50 ++++++++------ .../ProjectEngineFactoryProviderTest.cs | 13 ++-- .../ProjectSystem/TestProjectSnapshot.cs | 5 +- .../DocumentExcerptServiceTestBase.cs | 3 +- .../DefaultDocumentSnapshotTest.cs | 3 +- .../DefaultProjectSnapshotTest.cs | 6 +- .../GeneratedDocumentTextLoaderTest.cs | 3 +- .../ProjectStateGeneratedOutputTest.cs | 18 ++--- .../ProjectSystem/ProjectStateTest.cs | 68 +++++++++---------- .../RazorSpanMappingServiceTest.cs | 9 ++- .../RazorDocumentOptionsServiceTest.cs | 3 +- .../ProjectWorkspaceStateGeneratorTest.cs | 2 +- 13 files changed, 91 insertions(+), 98 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.cs index 9515f8d1911..dac24b3690c 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.cs @@ -371,11 +371,7 @@ private bool TryAddProject(HostProject hostProject, [NotNullWhen(true)] out IPro return false; } - var state = ProjectState.Create( - _projectEngineFactoryProvider, - _compilerOptions, - hostProject, - ProjectWorkspaceState.Default); + var state = ProjectState.Create(hostProject, _compilerOptions, _projectEngineFactoryProvider); var newEntry = new Entry(state); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs index 2b4a44aa427..355d0fb58dc 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs @@ -35,7 +35,7 @@ internal class ProjectState private static readonly ImmutableDictionary s_emptyDocuments = ImmutableDictionary.Create(FilePathNormalizingComparer.Instance); private static readonly ImmutableDictionary> s_emptyImportsToRelatedDocuments = ImmutableDictionary.Create>(FilePathNormalizingComparer.Instance); - private readonly object _lock; + private readonly object _lock = new(); public HostProject HostProject { get; } public RazorCompilerOptions CompilerOptions { get; } @@ -44,32 +44,22 @@ internal class ProjectState private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider; private RazorProjectEngine? _projectEngine; - public static ProjectState Create( - IProjectEngineFactoryProvider projectEngineFactoryProvider, - RazorCompilerOptions compilerOptions, - HostProject hostProject, - ProjectWorkspaceState projectWorkspaceState) - { - return new ProjectState(projectEngineFactoryProvider, compilerOptions, hostProject, projectWorkspaceState); - } - private ProjectState( - IProjectEngineFactoryProvider projectEngineFactoryProvider, - RazorCompilerOptions compilerOptions, HostProject hostProject, - ProjectWorkspaceState projectWorkspaceState) + ProjectWorkspaceState projectWorkspaceState, + RazorCompilerOptions compilerOptions, + IProjectEngineFactoryProvider projectEngineFactoryProvider) { - _projectEngineFactoryProvider = projectEngineFactoryProvider; - CompilerOptions = compilerOptions; HostProject = hostProject; ProjectWorkspaceState = projectWorkspaceState; + CompilerOptions = compilerOptions; + _projectEngineFactoryProvider = projectEngineFactoryProvider; + Documents = s_emptyDocuments; ImportsToRelatedDocuments = s_emptyImportsToRelatedDocuments; Version = VersionStamp.Create(); ProjectWorkspaceStateVersion = Version; DocumentCollectionVersion = Version; - - _lock = new object(); } private ProjectState( @@ -80,16 +70,15 @@ private ProjectState( ImmutableDictionary documents, ImmutableDictionary> importsToRelatedDocuments) { - _projectEngineFactoryProvider = older._projectEngineFactoryProvider; - CompilerOptions = older.CompilerOptions; - Version = older.Version.GetNewerVersion(); - HostProject = hostProject; + CompilerOptions = older.CompilerOptions; + _projectEngineFactoryProvider = older._projectEngineFactoryProvider; ProjectWorkspaceState = projectWorkspaceState; + Documents = documents; ImportsToRelatedDocuments = importsToRelatedDocuments; - _lock = new object(); + Version = older.Version.GetNewerVersion(); if ((difference & ClearDocumentCollectionVersionMask) == 0) { @@ -132,6 +121,23 @@ private ProjectState( } } + public static ProjectState Create( + HostProject hostProject, + ProjectWorkspaceState? projectWorkspaceState = null, + RazorCompilerOptions compilerOptions = RazorCompilerOptions.None, + IProjectEngineFactoryProvider? projectEngineFactoryProvider = null) + => new( + hostProject, + projectWorkspaceState ?? ProjectWorkspaceState.Default, + compilerOptions, + projectEngineFactoryProvider ?? ProjectEngineFactories.DefaultProvider); + + public static ProjectState Create( + HostProject hostProject, + RazorCompilerOptions compilerOptions, + IProjectEngineFactoryProvider? projectEngineFactoryProvider = null) + => Create(hostProject, ProjectWorkspaceState.Default, compilerOptions, projectEngineFactoryProvider); + // Internal set for testing. public ImmutableDictionary Documents { get; internal set; } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs index 615d31f17da..008d1f1d059 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs @@ -5,7 +5,6 @@ using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -49,12 +48,12 @@ public ProjectEngineFactoryProviderTest(ITestOutputHelper testOutput) projectFilePath, intermediateOutputPath, new(RazorLanguageVersion.Version_2_1, "Random-0.1", Extensions: []), rootNamespace: null); - _snapshot_For_1_0 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, RazorCompilerOptions.None, hostProject_For_1_0, ProjectWorkspaceState.Default)); - _snapshot_For_1_1 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, RazorCompilerOptions.None, hostProject_For_1_1, ProjectWorkspaceState.Default)); - _snapshot_For_2_0 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, RazorCompilerOptions.None, hostProject_For_2_0, ProjectWorkspaceState.Default)); - _snapshot_For_2_1 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, RazorCompilerOptions.None, hostProject_For_2_1, ProjectWorkspaceState.Default)); - _snapshot_For_3_0 = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, RazorCompilerOptions.None, hostProject_For_3_0, ProjectWorkspaceState.Default)); - _snapshot_For_UnknownConfiguration = new ProjectSnapshot(ProjectState.Create(ProjectEngineFactories.DefaultProvider, RazorCompilerOptions.None, hostProject_For_UnknownConfiguration, ProjectWorkspaceState.Default)); + _snapshot_For_1_0 = new ProjectSnapshot(ProjectState.Create(hostProject_For_1_0)); + _snapshot_For_1_1 = new ProjectSnapshot(ProjectState.Create(hostProject_For_1_1)); + _snapshot_For_2_0 = new ProjectSnapshot(ProjectState.Create(hostProject_For_2_0)); + _snapshot_For_2_1 = new ProjectSnapshot(ProjectState.Create(hostProject_For_2_1)); + _snapshot_For_3_0 = new ProjectSnapshot(ProjectState.Create(hostProject_For_3_0)); + _snapshot_For_UnknownConfiguration = new ProjectSnapshot(ProjectState.Create(hostProject_For_UnknownConfiguration)); _customFactories = [ diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs index ed7b5b26d7d..ab934337856 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs @@ -7,7 +7,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.ProjectEngineHost; using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -28,9 +27,7 @@ private TestProjectSnapshot(ProjectState state) public static TestProjectSnapshot Create(string filePath, ProjectWorkspaceState? projectWorkspaceState = null) { var hostProject = TestHostProject.Create(filePath); - projectWorkspaceState ??= ProjectWorkspaceState.Default; - - var state = ProjectState.Create(ProjectEngineFactories.DefaultProvider, RazorCompilerOptions.None, hostProject, projectWorkspaceState); + var state = ProjectState.Create(hostProject, projectWorkspaceState); return new TestProjectSnapshot(state); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/DocumentExcerptServiceTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/DocumentExcerptServiceTestBase.cs index 0359b82d608..0e83fdaf113 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/DocumentExcerptServiceTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/DocumentExcerptServiceTestBase.cs @@ -7,7 +7,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; @@ -42,7 +41,7 @@ public static (SourceText sourceText, TextSpan span) CreateText(string text) private (IDocumentSnapshot primary, Document secondary) InitializeDocument(SourceText sourceText) { var state = ProjectState - .Create(ProjectEngineFactoryProvider, LanguageServerFeatureOptions.ToCompilerOptions(), _hostProject, ProjectWorkspaceState.Default) + .Create(_hostProject, LanguageServerFeatureOptions.ToCompilerOptions(), ProjectEngineFactoryProvider) .AddDocument(_hostDocument, sourceText); var project = new ProjectSnapshot(state); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs index 82af1613c9c..7cfc734a5e8 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs @@ -4,7 +4,6 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis.Text; @@ -31,7 +30,7 @@ public DefaultDocumentSnapshotTest(ITestOutputHelper testOutput) { _sourceText = SourceText.From("

Hello World

"); - var projectState = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, TestProjectData.SomeProject, ProjectWorkspaceState.Default); + var projectState = ProjectState.Create(TestProjectData.SomeProject, CompilerOptions, ProjectEngineFactoryProvider); var project = new ProjectSnapshot(projectState); var textLoader = TestMocks.CreateTextLoader(_sourceText); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs index a6d2df0bd83..a723341cc10 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs @@ -44,7 +44,7 @@ protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder public void ProjectSnapshot_CachesDocumentSnapshots() { // Arrange - var state = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[0], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader) .AddDocument(_documents[2], DocumentState.EmptyLoader); @@ -65,7 +65,7 @@ public void ProjectSnapshot_CachesDocumentSnapshots() public void GetRelatedDocuments_NonImportDocument_ReturnsEmpty() { // Arrange - var state = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[0], DocumentState.EmptyLoader); var snapshot = new ProjectSnapshot(state); @@ -82,7 +82,7 @@ public void GetRelatedDocuments_NonImportDocument_ReturnsEmpty() public void GetRelatedDocuments_ImportDocument_ReturnsRelated() { // Arrange - var state = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[0], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectImportFile, DocumentState.EmptyLoader); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs index 7b132653487..7c078b4425e 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs @@ -3,7 +3,6 @@ using System.Text; using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Xunit; @@ -21,7 +20,7 @@ public async Task LoadAsync_SpecifiesEncoding() { // Arrange var state = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, TestMocks.CreateEmptyTextLoader()); var project = new ProjectSnapshot(state); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs index f4c60c7657d..f5ef5acf97d 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs @@ -43,7 +43,7 @@ public async Task AddDocument_CachesOutput() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, DocumentState.EmptyLoader); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -62,7 +62,7 @@ public async Task AddDocument_Import_DoesNotCacheOutput() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, DocumentState.EmptyLoader); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -82,7 +82,7 @@ public async Task WithDocumentText_DoesNotCacheOutput() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectImportFile, DocumentState.EmptyLoader); @@ -104,7 +104,7 @@ public async Task WithDocumentText_Import_DoesNotCacheOutput() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectImportFile, DocumentState.EmptyLoader); @@ -126,7 +126,7 @@ public async Task RemoveDocument_Import_DoesNotCacheOutput() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectImportFile, DocumentState.EmptyLoader); @@ -147,7 +147,7 @@ public async Task WithProjectWorkspaceState_CachesOutput_EvenWhenNewerProjectWor { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, DocumentState.EmptyLoader); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -167,7 +167,7 @@ public async Task WithProjectWorkspaceState_TagHelperChange_DoesNotCacheOutput() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, DocumentState.EmptyLoader); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -191,7 +191,7 @@ public async Task WithProjectWorkspaceState_CSharpLanguageVersionChange_DoesNotC var hostProject = TestProjectData.SomeProject with { Configuration = csharp8ValidConfiguration }; var originalWorkspaceState = ProjectWorkspaceState.Create(_someTagHelpers, LanguageVersion.CSharp7); var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, hostProject, originalWorkspaceState) + .Create(hostProject, originalWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, TestMocks.CreateTextLoader("@DateTime.Now", VersionStamp.Default)); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -212,7 +212,7 @@ public async Task WithHostProject_DoesNotCacheOutput() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, DocumentState.EmptyLoader); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs index cd1fa4cc04f..a47bc913b70 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs @@ -56,7 +56,7 @@ protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder public void GetImportDocumentTargetPaths_DoesNotIncludeCurrentImport() { // Arrange - var state = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); + var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); // Act var paths = state.GetImportDocumentTargetPaths(TestProjectData.SomeProjectComponentImportFile1); @@ -71,7 +71,7 @@ public void ProjectState_ConstructedNew() // Arrange // Act - var state = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); + var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); // Assert Assert.Empty(state.Documents); @@ -82,7 +82,7 @@ public void ProjectState_ConstructedNew() public void ProjectState_AddDocument_ToEmpty() { // Arrange - var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); // Act var state = original.AddDocument(_documents[0], DocumentState.EmptyLoader); @@ -100,7 +100,7 @@ public void ProjectState_AddDocument_ToEmpty() public async Task ProjectState_AddDocument_DocumentIsEmpty() { // Arrange - var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); // Act var state = original.AddDocument(_documents[0], DocumentState.EmptyLoader); @@ -115,7 +115,7 @@ public void ProjectState_AddDocument_ToProjectWithDocuments() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -140,7 +140,7 @@ public void ProjectState_AddDocument_TracksImports() // Act var state = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectFile2, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectNestedFile3, DocumentState.EmptyLoader) @@ -180,7 +180,7 @@ public void ProjectState_AddDocument_TracksImports_AddImportFile() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectFile2, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectNestedFile3, DocumentState.EmptyLoader) @@ -224,7 +224,7 @@ public void ProjectState_AddDocument_RetainsComputedState() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -258,7 +258,7 @@ public void ProjectState_AddDocument_DuplicateIgnored() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -274,7 +274,7 @@ public async Task ProjectState_WithDocumentText_Loader() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -295,7 +295,7 @@ public async Task ProjectState_WithDocumentText_Snapshot() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -316,7 +316,7 @@ public void ProjectState_WithDocumentText_Loader_RetainsComputedState() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -349,7 +349,7 @@ public void ProjectState_WithDocumentText_Snapshot_RetainsComputedState() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -382,7 +382,7 @@ public void ProjectState_WithDocumentText_Loader_NotFoundIgnored() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -398,7 +398,7 @@ public void ProjectState_WithDocumentText_Snapshot_NotFoundIgnored() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -414,7 +414,7 @@ public void ProjectState_RemoveDocument_FromProjectWithDocuments() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -436,7 +436,7 @@ public void ProjectState_RemoveDocument_TracksImports() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectFile2, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectNestedFile3, DocumentState.EmptyLoader) @@ -477,7 +477,7 @@ public void ProjectState_RemoveDocument_TracksImports_RemoveAllDocuments() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectFile2, DocumentState.EmptyLoader) .AddDocument(TestProjectData.SomeProjectNestedFile3, DocumentState.EmptyLoader) @@ -500,7 +500,7 @@ public void ProjectState_RemoveDocument_RetainsComputedState() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -533,7 +533,7 @@ public void ProjectState_RemoveDocument_NotFoundIgnored() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -549,7 +549,7 @@ public void ProjectState_WithHostProject_ConfigurationChange_UpdatesConfiguratio { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -588,7 +588,7 @@ public void ProjectState_WithHostProject_RootNamespaceChange_UpdatesConfiguratio { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); var hostProjectWithRootNamespaceChange = original.HostProject with { RootNamespace = "ChangedRootNamespace" }; @@ -609,7 +609,7 @@ public void ProjectState_WithHostProject_NoConfigurationChange_Ignored() { // Arrange var original = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -633,7 +633,7 @@ public void ProjectState_WithHostProject_CallsConfigurationChangeOnDocumentState documents[_documents[1].FilePath] = TestDocumentState.Create(_documents[1], onConfigurationChange: () => callCount++); documents[_documents[2].FilePath] = TestDocumentState.Create(_documents[2], onConfigurationChange: () => callCount++); - var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); original.Documents = documents.ToImmutable(); // Act @@ -649,7 +649,7 @@ public void ProjectState_WithHostProject_CallsConfigurationChangeOnDocumentState public void ProjectState_WithHostProject_ResetsImportedDocuments() { // Arrange - var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); original = original.AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader); // Act @@ -665,7 +665,7 @@ public void ProjectState_WithHostProject_ResetsImportedDocuments() public void ProjectState_WithProjectWorkspaceState_Changed() { // Arrange - var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -704,7 +704,7 @@ public void ProjectState_WithProjectWorkspaceState_Changed() public void ProjectState_WithProjectWorkspaceState_Changed_TagHelpersChanged() { // Arrange - var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -738,7 +738,7 @@ public void ProjectState_WithProjectWorkspaceState_Changed_TagHelpersChanged() public void ProjectState_WithProjectWorkspaceState_IdenticalState_Caches() { // Arrange - var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState) + var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_documents[2], DocumentState.EmptyLoader) .AddDocument(_documents[1], DocumentState.EmptyLoader); @@ -763,7 +763,7 @@ public void ProjectState_WithProjectWorkspaceState_CallsWorkspaceProjectChangeOn documents[_documents[1].FilePath] = TestDocumentState.Create(_documents[1], onProjectWorkspaceStateChange: () => callCount++); documents[_documents[2].FilePath] = TestDocumentState.Create(_documents[2], onProjectWorkspaceStateChange: () => callCount++); - var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); original.Documents = documents.ToImmutable(); // Act @@ -805,7 +805,7 @@ public void ProjectState_AddDocument_Import_CallsImportsChanged() TestProjectData.SomeProjectNestedFile3.FilePath, TestProjectData.AnotherProjectNestedFile4.FilePath)); - var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); original.Documents = documents.ToImmutable(); original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); @@ -848,7 +848,7 @@ public void ProjectState_AddDocument_Import_CallsImportsChanged_Nested() TestProjectData.SomeProjectNestedFile3.FilePath, TestProjectData.AnotherProjectNestedFile4.FilePath)); - var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); original.Documents = documents.ToImmutable(); original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); @@ -894,7 +894,7 @@ public void ProjectState_WithDocumentText_Loader_Import_CallsImportsChanged() TestProjectData.SomeProjectNestedFile3.FilePath, TestProjectData.AnotherProjectNestedFile4.FilePath)); - var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); original.Documents = documents.ToImmutable(); original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); @@ -940,7 +940,7 @@ public void ProjectState_WithDocumentText_Snapshot_Import_CallsImportsChanged() TestProjectData.SomeProjectNestedFile3.FilePath, TestProjectData.AnotherProjectNestedFile4.FilePath)); - var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); original.Documents = documents.ToImmutable(); original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); @@ -986,7 +986,7 @@ public void ProjectState_RemoveDocument_Import_CallsImportsChanged() TestProjectData.SomeProjectNestedFile3.FilePath, TestProjectData.AnotherProjectNestedFile4.FilePath)); - var original = ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, _projectWorkspaceState); + var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); original.Documents = documents.ToImmutable(); original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorSpanMappingServiceTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorSpanMappingServiceTest.cs index 022f719ae04..cefeb3a9d9e 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorSpanMappingServiceTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorSpanMappingServiceTest.cs @@ -4,7 +4,6 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -29,7 +28,7 @@ public async Task TryGetMappedSpans_SpanMatchesSourceMapping_ReturnsTrue() "); var state = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, TestMocks.CreateTextLoader(sourceText)); var project = new ProjectSnapshot(state); @@ -61,7 +60,7 @@ public async Task TryGetMappedSpans_SpanMatchesSourceMappingAndPosition_ReturnsT "); var state = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, TestMocks.CreateTextLoader(sourceText)); var project = new ProjectSnapshot(state); @@ -94,7 +93,7 @@ public async Task TryGetMappedSpans_SpanWithinSourceMapping_ReturnsTrue() "); var state = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, TestMocks.CreateTextLoader(sourceText)); var project = new ProjectSnapshot(state); @@ -126,7 +125,7 @@ public async Task TryGetMappedSpans_SpanOutsideSourceMapping_ReturnsFalse() "); var state = ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, _hostProject, ProjectWorkspaceState.Default) + .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, TestMocks.CreateTextLoader(sourceText)); var project = new ProjectSnapshot(state); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorDocumentOptionsServiceTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorDocumentOptionsServiceTest.cs index 23136da3d6a..df65c78c417 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorDocumentOptionsServiceTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorDocumentOptionsServiceTest.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.AspNetCore.Razor.Utilities; @@ -97,7 +96,7 @@ private Document InitializeDocument(SourceText sourceText) Path.Combine(baseDirectory, "SomeProject", "File1.cshtml"), "File1.cshtml", FileKinds.Legacy); var project = new ProjectSnapshot(ProjectState - .Create(ProjectEngineFactoryProvider, CompilerOptions, hostProject, ProjectWorkspaceState.Default) + .Create(hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(hostDocument, TestMocks.CreateTextLoader(sourceText))); var document = project.GetRequiredDocument(hostDocument.FilePath); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectWorkspaceStateGeneratorTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectWorkspaceStateGeneratorTest.cs index ce281f59fc6..09d601db4d7 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectWorkspaceStateGeneratorTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectWorkspaceStateGeneratorTest.cs @@ -42,7 +42,7 @@ public ProjectWorkspaceStateGeneratorTest(ITestOutputHelper testOutput) TestProjectData.SomeProject.FilePath)); _workspaceProject = solution.GetProject(projectId).AssumeNotNull(); _projectSnapshot = new ProjectSnapshot( - ProjectState.Create(ProjectEngineFactoryProvider, CompilerOptions, TestProjectData.SomeProject, ProjectWorkspaceState.Default)); + ProjectState.Create(TestProjectData.SomeProject, CompilerOptions, ProjectEngineFactoryProvider)); _projectWorkspaceStateWithTagHelpers = ProjectWorkspaceState.Create( [TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly").Build()]); From ea3fd034374a12b9df05780de7f48a09e0d0aa65 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Thu, 12 Dec 2024 12:09:34 -0800 Subject: [PATCH 03/42] Clean up TestProjectEngineFactoryProvider a bit This change cleans up the TestProjectEngineFactoryProvider to be a bit more usable. --- .../TestProjectEngineFactoryProvider.cs | 42 +++++++++++++++---- .../TestImportProjectFeature.cs | 7 ++-- .../Workspaces/WorkspaceTestBase.cs | 12 +++--- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectEngineFactoryProvider.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectEngineFactoryProvider.cs index d1f7342fa82..9f6f2c8a10c 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectEngineFactoryProvider.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectEngineFactoryProvider.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; +using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectEngineHost; @@ -9,26 +10,51 @@ namespace Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; internal class TestProjectEngineFactoryProvider : IProjectEngineFactoryProvider { - public Action? Configure { get; set; } + public static TestProjectEngineFactoryProvider Instance { get; } = new(baseProvider: null, configure: default); - public IProjectEngineFactory GetFactory(RazorConfiguration configuration) + public IProjectEngineFactoryProvider BaseProvider { get; } + private readonly ImmutableArray> _configure; + + private TestProjectEngineFactoryProvider( + IProjectEngineFactoryProvider? baseProvider, + ImmutableArray> configure) { - return new Factory(Configure); + BaseProvider = baseProvider ?? ProjectEngineFactories.DefaultProvider; + _configure = configure.NullToEmpty(); } - private sealed class Factory(Action? outerConfigure) : IProjectEngineFactory + public TestProjectEngineFactoryProvider WithBaseProvider(IProjectEngineFactoryProvider baseProvider) + => new(baseProvider, _configure); + + public TestProjectEngineFactoryProvider AddConfigure(Action configure) + => new(BaseProvider, _configure.Add(configure)); + + public TestProjectEngineFactoryProvider WithTestImportFeature() + => AddConfigure(static b => b.SetImportFeature(TestImportProjectFeature.Instance)); + + public IProjectEngineFactory GetFactory(RazorConfiguration configuration) + => new FactoryWrapper(this, BaseProvider.GetFactory(configuration)); + + private sealed class FactoryWrapper( + TestProjectEngineFactoryProvider parent, + IProjectEngineFactory factory) + : IProjectEngineFactory { - public string ConfigurationName => "Test"; + public string ConfigurationName => factory.ConfigurationName; public RazorProjectEngine Create( RazorConfiguration configuration, RazorProjectFileSystem fileSystem, - Action? innerConfigure) + Action? configure) { return RazorProjectEngine.Create(configuration, fileSystem, b => { - innerConfigure?.Invoke(b); - outerConfigure?.Invoke(b); + configure?.Invoke(b); + + foreach (var c in parent._configure) + { + c.Invoke(b); + } }); } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestImportProjectFeature.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestImportProjectFeature.cs index 92949eb6d03..8b8bf050c59 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestImportProjectFeature.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestImportProjectFeature.cs @@ -10,12 +10,11 @@ namespace Microsoft.AspNetCore.Razor.Test.Common; public class TestImportProjectFeature : RazorProjectEngineFeatureBase, IImportProjectFeature { + public static IImportProjectFeature Instance { get; } = new TestImportProjectFeature(); + public IReadOnlyList GetImports(RazorProjectItem projectItem) { - if (projectItem is null) - { - throw new ArgumentNullException(nameof(projectItem)); - } + ArgHelper.ThrowIfNull(projectItem); var imports = new List(); AddHierarchicalImports(projectItem, imports); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/WorkspaceTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/WorkspaceTestBase.cs index dc10f9427fd..f24a1540abc 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/WorkspaceTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/WorkspaceTestBase.cs @@ -85,7 +85,12 @@ protected virtual void ConfigureProjectEngine(RazorProjectEngineBuilder builder) { } - [MemberNotNull(nameof(_hostServices), nameof(_workspace), nameof(_workspaceProvider), nameof(_projectEngineFactoryProvider), nameof(_languageServerFeatureOptions))] + [MemberNotNull( + nameof(_hostServices), + nameof(_workspace), + nameof(_workspaceProvider), + nameof(_projectEngineFactoryProvider), + nameof(_languageServerFeatureOptions))] private void EnsureInitialized() { if (_initialized) @@ -98,10 +103,7 @@ private void EnsureInitialized() return; } - _projectEngineFactoryProvider = new TestProjectEngineFactoryProvider() - { - Configure = ConfigureProjectEngine, - }; + _projectEngineFactoryProvider = TestProjectEngineFactoryProvider.Instance.AddConfigure(ConfigureProjectEngine); _hostServices = MefHostServices.DefaultHost; _workspace = TestWorkspace.Create(_hostServices, ConfigureWorkspace); From 9042ae47d3d4c00821485e4036710b4a66383f59 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Thu, 12 Dec 2024 13:32:37 -0800 Subject: [PATCH 04/42] Seal DocumentState and ProjectState and make effectively immutable There were a number of test hooks in DocumentState and ProjectState, such as settable properties and virtual methods. This change removes those test hooks by cleaning up and refactoring ProjectStateTest. --- .../ProjectSystem/DocumentState.cs | 32 +- .../ProjectSystem/ProjectState.cs | 41 +- .../ProjectSystem/TestDocumentSnapshot.cs | 4 +- .../ProjectSystem/TestProjectSnapshot.cs | 2 +- .../ProjectSystem/ProjectStateTest.cs | 1116 +++++++---------- 5 files changed, 500 insertions(+), 695 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs index ea809b9cb85..5b291b4c4f2 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -internal partial class DocumentState +internal sealed partial class DocumentState { private static readonly LoadTextOptions s_loadTextOptions = new(SourceHashAlgorithm.Sha256); @@ -42,14 +42,7 @@ private DocumentState( _textLoader = textLoader ?? EmptyLoader; } - // Internal for testing - internal DocumentState(HostDocument hostDocument, int version, SourceText text, VersionStamp textVersion) - : this(hostDocument, version, TextAndVersion.Create(text, textVersion), textLoader: null) - { - } - - // Internal for testing - internal DocumentState(HostDocument hostDocument, int version, TextLoader loader) + private DocumentState(HostDocument hostDocument, int version, TextLoader loader) : this(hostDocument, version, textAndVersion: null, loader) { } @@ -161,16 +154,13 @@ public bool TryGetTextVersion(out VersionStamp result) return false; } - public virtual DocumentState WithConfigurationChange() + public DocumentState WithConfigurationChange() { - var state = new DocumentState(HostDocument, Version + 1, _textAndVersion, _textLoader); - // Do not cache computed state - - return state; + return new(HostDocument, Version + 1, _textAndVersion, _textLoader); } - public virtual DocumentState WithImportsChange() + public DocumentState WithImportsChange() { var state = new DocumentState(HostDocument, Version + 1, _textAndVersion, _textLoader); @@ -180,7 +170,7 @@ public virtual DocumentState WithImportsChange() return state; } - public virtual DocumentState WithProjectWorkspaceStateChange() + public DocumentState WithProjectWorkspaceStateChange() { var state = new DocumentState(HostDocument, Version + 1, _textAndVersion, _textLoader); @@ -190,18 +180,16 @@ public virtual DocumentState WithProjectWorkspaceStateChange() return state; } - public virtual DocumentState WithText(SourceText text, VersionStamp textVersion) + public DocumentState WithText(SourceText text, VersionStamp textVersion) { // Do not cache the computed state - - return new DocumentState(HostDocument, Version + 1, TextAndVersion.Create(text, textVersion), textLoader: null); + return new(HostDocument, Version + 1, TextAndVersion.Create(text, textVersion), textLoader: null); } - public virtual DocumentState WithTextLoader(TextLoader textLoader) + public DocumentState WithTextLoader(TextLoader textLoader) { // Do not cache the computed state - - return new DocumentState(HostDocument, Version + 1, textAndVersion: null, textLoader); + return new(HostDocument, Version + 1, textAndVersion: null, textLoader); } internal static async Task GenerateCodeDocumentAsync( diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs index 355d0fb58dc..a0c4e00b4f7 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs @@ -19,8 +19,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -// Internal tracker for DefaultProjectSnapshot -internal class ProjectState +internal sealed class ProjectState { private const ProjectDifference ClearConfigurationVersionMask = ProjectDifference.ConfigurationChanged; @@ -41,6 +40,9 @@ internal class ProjectState public RazorCompilerOptions CompilerOptions { get; } public ProjectWorkspaceState ProjectWorkspaceState { get; } + public ImmutableDictionary Documents { get; } + public ImmutableDictionary> ImportsToRelatedDocuments { get; } + private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider; private RazorProjectEngine? _projectEngine; @@ -123,26 +125,28 @@ private ProjectState( public static ProjectState Create( HostProject hostProject, - ProjectWorkspaceState? projectWorkspaceState = null, - RazorCompilerOptions compilerOptions = RazorCompilerOptions.None, - IProjectEngineFactoryProvider? projectEngineFactoryProvider = null) - => new( - hostProject, - projectWorkspaceState ?? ProjectWorkspaceState.Default, - compilerOptions, - projectEngineFactoryProvider ?? ProjectEngineFactories.DefaultProvider); + ProjectWorkspaceState projectWorkspaceState, + RazorCompilerOptions compilerOptions, + IProjectEngineFactoryProvider projectEngineFactoryProvider) + => new(hostProject, projectWorkspaceState, compilerOptions, projectEngineFactoryProvider); + + public static ProjectState Create(HostProject hostProject, ProjectWorkspaceState projectWorkspaceState) + => new(hostProject, projectWorkspaceState, RazorCompilerOptions.None, ProjectEngineFactories.DefaultProvider); public static ProjectState Create( HostProject hostProject, - RazorCompilerOptions compilerOptions, - IProjectEngineFactoryProvider? projectEngineFactoryProvider = null) - => Create(hostProject, ProjectWorkspaceState.Default, compilerOptions, projectEngineFactoryProvider); + ProjectWorkspaceState projectWorkspaceState, + IProjectEngineFactoryProvider projectEngineFactoryProvider) + => new(hostProject, projectWorkspaceState, RazorCompilerOptions.None, projectEngineFactoryProvider); - // Internal set for testing. - public ImmutableDictionary Documents { get; internal set; } + public static ProjectState Create( + HostProject hostProject, + RazorCompilerOptions compilerOptions, + IProjectEngineFactoryProvider projectEngineFactoryProvider) + => new(hostProject, ProjectWorkspaceState.Default, compilerOptions, projectEngineFactoryProvider); - // Internal set for testing. - public ImmutableDictionary> ImportsToRelatedDocuments { get; internal set; } + public static ProjectState Create(HostProject hostProject) + => new(hostProject, ProjectWorkspaceState.Default, RazorCompilerOptions.None, ProjectEngineFactories.DefaultProvider); public ImmutableArray TagHelpers => ProjectWorkspaceState.TagHelpers; @@ -198,6 +202,9 @@ RazorProjectEngine CreateProjectEngine() public VersionStamp ConfigurationVersion { get; } + public ProjectState AddDocument(HostDocument hostDocument) + => AddDocument(hostDocument, DocumentState.EmptyLoader); + public ProjectState AddDocument(HostDocument hostDocument, SourceText text) { ArgHelper.ThrowIfNull(hostDocument); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs index a5afd0fc36c..687aebda2e4 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs @@ -38,7 +38,7 @@ public static TestDocumentSnapshot Create(string filePath, string text, ProjectW var sourceText = SourceText.From(text); var textVersion = VersionStamp.Default; - var documentState = new DocumentState(hostDocument, version, sourceText, textVersion); + var documentState = DocumentState.Create(hostDocument, version, sourceText, textVersion); return new TestDocumentSnapshot(project, documentState); } @@ -54,7 +54,7 @@ public static TestDocumentSnapshot Create(string filePath, RazorCodeDocument cod var sourceText = codeDocument.Source.Text; var textVersion = VersionStamp.Default; - var documentState = new DocumentState(hostDocument, version, sourceText, textVersion); + var documentState = DocumentState.Create(hostDocument, version, sourceText, textVersion); return new TestDocumentSnapshot(project, documentState, codeDocument); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs index ab934337856..b5aebfc2b85 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs @@ -27,7 +27,7 @@ private TestProjectSnapshot(ProjectState state) public static TestProjectSnapshot Create(string filePath, ProjectWorkspaceState? projectWorkspaceState = null) { var hostProject = TestHostProject.Create(filePath); - var state = ProjectState.Create(hostProject, projectWorkspaceState); + var state = ProjectState.Create(hostProject, projectWorkspaceState ?? ProjectWorkspaceState.Default); return new TestProjectSnapshot(state); } diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs index a47bc913b70..91d273d96d5 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs @@ -1,77 +1,55 @@ // 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.Collections.Immutable; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectEngineHost; using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; -using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; +using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; +using Microsoft.AspNetCore.Razor.Utilities; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; using Xunit; using Xunit.Abstractions; +using static Microsoft.AspNetCore.Razor.Test.Common.TestProjectData; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -public class ProjectStateTest : WorkspaceTestBase +public class ProjectStateTest(ITestOutputHelper testOutput) : ToolingTestBase(testOutput) { - private readonly HostDocument[] _documents; - private readonly HostProject _hostProject; - private readonly HostProject _hostProjectWithConfigurationChange; - private readonly ProjectWorkspaceState _projectWorkspaceState; - private readonly TextLoader _textLoader; - private readonly SourceText _text; - - public ProjectStateTest(ITestOutputHelper testOutput) - : base(testOutput) - { - _hostProject = TestProjectData.SomeProject with { Configuration = FallbackRazorConfiguration.MVC_2_0 }; - _hostProjectWithConfigurationChange = TestProjectData.SomeProject with { Configuration = FallbackRazorConfiguration.MVC_1_0 }; - _projectWorkspaceState = ProjectWorkspaceState.Create( - ImmutableArray.Create( - TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly").Build())); - - _documents = new HostDocument[] - { - TestProjectData.SomeProjectFile1, - TestProjectData.SomeProjectFile2, + private static readonly IProjectEngineFactoryProvider s_projectEngineFactoryProvider = + TestProjectEngineFactoryProvider.Instance.WithTestImportFeature(); - // linked file - TestProjectData.AnotherProjectNestedFile3, - }; + private static readonly HostProject s_hostProject = + SomeProject with { Configuration = FallbackRazorConfiguration.MVC_2_0 }; - _text = SourceText.From("Hello, world!"); - _textLoader = TestMocks.CreateTextLoader(_text); - } + private static readonly ProjectWorkspaceState s_projectWorkspaceState = + ProjectWorkspaceState.Create([TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly").Build()]); - protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder) - { - builder.SetImportFeature(new TestImportProjectFeature()); - } + private static readonly SourceText s_text = SourceText.From("Hello, world!"); + private static readonly TextLoader s_textLoader = TestMocks.CreateTextLoader(s_text); [Fact] public void GetImportDocumentTargetPaths_DoesNotIncludeCurrentImport() { // Arrange - var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); + var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider); // Act - var paths = state.GetImportDocumentTargetPaths(TestProjectData.SomeProjectComponentImportFile1); + var paths = state.GetImportDocumentTargetPaths(SomeProjectComponentImportFile1); // Assert - Assert.DoesNotContain(TestProjectData.SomeProjectComponentImportFile1.TargetPath, paths); + Assert.DoesNotContain(SomeProjectComponentImportFile1.TargetPath, paths); } [Fact] public void ProjectState_ConstructedNew() { - // Arrange - - // Act - var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); + // Arrange & Act + var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider); // Assert Assert.Empty(state.Documents); @@ -82,31 +60,30 @@ public void ProjectState_ConstructedNew() public void ProjectState_AddDocument_ToEmpty() { // Arrange - var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); + var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider); // Act - var state = original.AddDocument(_documents[0], DocumentState.EmptyLoader); + var newState = state.AddDocument(SomeProjectFile1); // Assert - Assert.NotEqual(original.Version, state.Version); + Assert.NotEqual(state.Version, newState.Version); - Assert.Collection( - state.Documents.OrderBy(kvp => kvp.Key), - d => Assert.Same(_documents[0], d.Value.HostDocument)); - Assert.NotEqual(original.DocumentCollectionVersion, state.DocumentCollectionVersion); + var documentState = Assert.Single(newState.Documents.Values); + Assert.Same(SomeProjectFile1, documentState.HostDocument); + Assert.NotEqual(state.DocumentCollectionVersion, newState.DocumentCollectionVersion); } [Fact] public async Task ProjectState_AddDocument_DocumentIsEmpty() { // Arrange - var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); + var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider); // Act - var state = original.AddDocument(_documents[0], DocumentState.EmptyLoader); + var newState = state.AddDocument(SomeProjectFile1); // Assert - var text = await state.Documents[_documents[0].FilePath].GetTextAsync(DisposalToken); + var text = await newState.Documents[SomeProjectFile1.FilePath].GetTextAsync(DisposalToken); Assert.Equal(0, text.Length); } @@ -114,63 +91,59 @@ public async Task ProjectState_AddDocument_DocumentIsEmpty() public void ProjectState_AddDocument_ToProjectWithDocuments() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.AddDocument(_documents[0], DocumentState.EmptyLoader); + var newState = state.AddDocument(SomeProjectFile1); // Assert - Assert.NotEqual(original.Version, state.Version); + Assert.NotEqual(state.Version, newState.Version); Assert.Collection( - state.Documents.OrderBy(kvp => kvp.Key), - d => Assert.Same(_documents[2], d.Value.HostDocument), - d => Assert.Same(_documents[0], d.Value.HostDocument), - d => Assert.Same(_documents[1], d.Value.HostDocument)); - Assert.NotEqual(original.DocumentCollectionVersion, state.DocumentCollectionVersion); + newState.Documents.OrderBy(static kvp => kvp.Key), + d => Assert.Same(AnotherProjectNestedFile3, d.Value.HostDocument), + d => Assert.Same(SomeProjectFile1, d.Value.HostDocument), + d => Assert.Same(SomeProjectFile2, d.Value.HostDocument)); + Assert.NotEqual(state.DocumentCollectionVersion, newState.DocumentCollectionVersion); } [Fact] public void ProjectState_AddDocument_TracksImports() { - // Arrange - - // Act + // Arrange & Act var state = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.SomeProjectFile2, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.SomeProjectNestedFile3, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.AnotherProjectNestedFile4, DocumentState.EmptyLoader); + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(SomeProjectFile1) + .AddDocument(SomeProjectFile2) + .AddDocument(SomeProjectNestedFile3) + .AddDocument(AnotherProjectNestedFile4); // Assert Assert.Collection( state.ImportsToRelatedDocuments.OrderBy(kvp => kvp.Key), kvp => { - Assert.Equal(TestProjectData.SomeProjectImportFile.TargetPath, kvp.Key); + Assert.Equal(SomeProjectImportFile.TargetPath, kvp.Key); Assert.Equal( - new string[] - { - TestProjectData.AnotherProjectNestedFile4.FilePath, - TestProjectData.SomeProjectFile1.FilePath, - TestProjectData.SomeProjectFile2.FilePath, - TestProjectData.SomeProjectNestedFile3.FilePath, - }, + [ + AnotherProjectNestedFile4.FilePath, + SomeProjectFile1.FilePath, + SomeProjectFile2.FilePath, + SomeProjectNestedFile3.FilePath, + ], kvp.Value.OrderBy(f => f)); }, kvp => { - Assert.Equal(TestProjectData.SomeProjectNestedImportFile.TargetPath, kvp.Key); + Assert.Equal(SomeProjectNestedImportFile.TargetPath, kvp.Key); Assert.Equal( - new string[] - { - TestProjectData.AnotherProjectNestedFile4.FilePath, - TestProjectData.SomeProjectNestedFile3.FilePath, - }, + [ + AnotherProjectNestedFile4.FilePath, + SomeProjectNestedFile3.FilePath, + ], kvp.Value.OrderBy(f => f)); }); } @@ -179,42 +152,39 @@ public void ProjectState_AddDocument_TracksImports() public void ProjectState_AddDocument_TracksImports_AddImportFile() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.SomeProjectFile2, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.SomeProjectNestedFile3, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.AnotherProjectNestedFile4, DocumentState.EmptyLoader); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(SomeProjectFile1) + .AddDocument(SomeProjectFile2) + .AddDocument(SomeProjectNestedFile3) + .AddDocument(AnotherProjectNestedFile4); // Act - var state = original - .AddDocument(TestProjectData.AnotherProjectImportFile, DocumentState.EmptyLoader); + var newState = state.AddDocument(AnotherProjectImportFile); // Assert Assert.Collection( - state.ImportsToRelatedDocuments.OrderBy(kvp => kvp.Key), + newState.ImportsToRelatedDocuments.OrderBy(kvp => kvp.Key), kvp => { - Assert.Equal(TestProjectData.SomeProjectImportFile.TargetPath, kvp.Key); + Assert.Equal(SomeProjectImportFile.TargetPath, kvp.Key); Assert.Equal( - new string[] - { - TestProjectData.AnotherProjectNestedFile4.FilePath, - TestProjectData.SomeProjectFile1.FilePath, - TestProjectData.SomeProjectFile2.FilePath, - TestProjectData.SomeProjectNestedFile3.FilePath, - }, + [ + AnotherProjectNestedFile4.FilePath, + SomeProjectFile1.FilePath, + SomeProjectFile2.FilePath, + SomeProjectNestedFile3.FilePath, + ], kvp.Value.OrderBy(f => f)); }, kvp => { - Assert.Equal(TestProjectData.SomeProjectNestedImportFile.TargetPath, kvp.Key); + Assert.Equal(SomeProjectNestedImportFile.TargetPath, kvp.Key); Assert.Equal( - new string[] - { - TestProjectData.AnotherProjectNestedFile4.FilePath, - TestProjectData.SomeProjectNestedFile3.FilePath, - }, + [ + AnotherProjectNestedFile4.FilePath, + SomeProjectNestedFile3.FilePath, + ], kvp.Value.OrderBy(f => f)); }); } @@ -223,125 +193,97 @@ public void ProjectState_AddDocument_TracksImports_AddImportFile() public void ProjectState_AddDocument_RetainsComputedState() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); - - // Force init - var originalTagHelpers = original.TagHelpers; - var originalProjectWorkspaceStateVersion = original.ProjectWorkspaceStateVersion; + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.AddDocument(_documents[0], DocumentState.EmptyLoader); + var newState = state.AddDocument(SomeProjectFile1); // Assert - var actualTagHelpers = state.TagHelpers; - var actualProjectWorkspaceStateVersion = state.ProjectWorkspaceStateVersion; - - Assert.Same(original.ProjectEngine, state.ProjectEngine); - - Assert.Equal(originalTagHelpers.Length, actualTagHelpers.Length); - for (var i = 0; i < originalTagHelpers.Length; i++) - { - Assert.Same(originalTagHelpers[i], actualTagHelpers[i]); - } - - Assert.Equal(originalProjectWorkspaceStateVersion, actualProjectWorkspaceStateVersion); - - Assert.Same(original.Documents[_documents[1].FilePath], state.Documents[_documents[1].FilePath]); - Assert.Same(original.Documents[_documents[2].FilePath], state.Documents[_documents[2].FilePath]); + Assert.Same(state.ProjectEngine, newState.ProjectEngine); + AssertSameTagHelpers(state.TagHelpers, newState.TagHelpers); + Assert.Equal(state.ProjectWorkspaceStateVersion, newState.ProjectWorkspaceStateVersion); + Assert.Same(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); + Assert.Same(state.Documents[AnotherProjectNestedFile3.FilePath], newState.Documents[AnotherProjectNestedFile3.FilePath]); } [Fact] public void ProjectState_AddDocument_DuplicateIgnored() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.AddDocument(new HostDocument(_documents[1].FilePath, "SomePath.cshtml"), DocumentState.EmptyLoader); + var newState = state.AddDocument(new HostDocument(SomeProjectFile2.FilePath, "SomePath.cshtml")); // Assert - Assert.Same(original, state); + Assert.Same(state, newState); } [Fact] public async Task ProjectState_WithDocumentText_Loader() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.WithDocumentText(_documents[1].FilePath, _textLoader); + var newState = state.WithDocumentText(SomeProjectFile2.FilePath, s_textLoader); // Assert - Assert.NotEqual(original.Version, state.Version); + Assert.NotEqual(state.Version, newState.Version); - var text = await state.Documents[_documents[1].FilePath].GetTextAsync(DisposalToken); - Assert.Same(_text, text); + var text = await newState.Documents[SomeProjectFile2.FilePath].GetTextAsync(DisposalToken); + Assert.Same(s_text, text); - Assert.Equal(original.DocumentCollectionVersion, state.DocumentCollectionVersion); + Assert.Equal(state.DocumentCollectionVersion, newState.DocumentCollectionVersion); } [Fact] public async Task ProjectState_WithDocumentText_Snapshot() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.WithDocumentText(_documents[1].FilePath, _text); + var newState = state.WithDocumentText(SomeProjectFile2.FilePath, s_text); // Assert - Assert.NotEqual(original.Version, state.Version); + Assert.NotEqual(state.Version, newState.Version); - var text = await state.Documents[_documents[1].FilePath].GetTextAsync(DisposalToken); - Assert.Same(_text, text); + var text = await newState.Documents[SomeProjectFile2.FilePath].GetTextAsync(DisposalToken); + Assert.Same(s_text, text); - Assert.Equal(original.DocumentCollectionVersion, state.DocumentCollectionVersion); + Assert.Equal(state.DocumentCollectionVersion, newState.DocumentCollectionVersion); } [Fact] public void ProjectState_WithDocumentText_Loader_RetainsComputedState() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); - - // Force init - var originalTagHelpers = original.TagHelpers; - var originalProjectWorkspaceStateVersion = original.ProjectWorkspaceStateVersion; + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.WithDocumentText(_documents[1].FilePath, _textLoader); + var newState = state.WithDocumentText(SomeProjectFile2.FilePath, s_textLoader); // Assert - var actualTagHelpers = state.TagHelpers; - var actualProjectWorkspaceStateVersion = state.ProjectWorkspaceStateVersion; - - Assert.Same(original.ProjectEngine, state.ProjectEngine); - - Assert.Equal(originalTagHelpers.Length, actualTagHelpers.Length); - for (var i = 0; i < originalTagHelpers.Length; i++) - { - Assert.Same(originalTagHelpers[i], actualTagHelpers[i]); - } - - Assert.Equal(originalProjectWorkspaceStateVersion, actualProjectWorkspaceStateVersion); - - Assert.NotSame(original.Documents[_documents[1].FilePath], state.Documents[_documents[1].FilePath]); + Assert.Same(state.ProjectEngine, newState.ProjectEngine); + AssertSameTagHelpers(state.TagHelpers, newState.TagHelpers); + Assert.Equal(state.ProjectWorkspaceStateVersion, newState.ProjectWorkspaceStateVersion); + Assert.NotSame(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); } [Fact] @@ -349,125 +291,108 @@ public void ProjectState_WithDocumentText_Snapshot_RetainsComputedState() { // Arrange var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); - - // Force init - var originalTagHelpers = original.TagHelpers; - var originalProjectWorkspaceStateVersion = original.ProjectWorkspaceStateVersion; + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.WithDocumentText(_documents[1].FilePath, _text); + var state = original.WithDocumentText(SomeProjectFile2.FilePath, s_text); // Assert - var actualTagHelpers = state.TagHelpers; - var actualProjectWorkspaceStateVersion = state.ProjectWorkspaceStateVersion; - Assert.Same(original.ProjectEngine, state.ProjectEngine); - - Assert.Equal(originalTagHelpers.Length, actualTagHelpers.Length); - for (var i = 0; i < originalTagHelpers.Length; i++) - { - Assert.Same(originalTagHelpers[i], actualTagHelpers[i]); - } - - Assert.Equal(originalProjectWorkspaceStateVersion, actualProjectWorkspaceStateVersion); - - Assert.NotSame(original.Documents[_documents[1].FilePath], state.Documents[_documents[1].FilePath]); + AssertSameTagHelpers(original.TagHelpers, state.TagHelpers); + Assert.Equal(original.ProjectWorkspaceStateVersion, state.ProjectWorkspaceStateVersion); + Assert.NotSame(original.Documents[SomeProjectFile2.FilePath], state.Documents[SomeProjectFile2.FilePath]); } [Fact] public void ProjectState_WithDocumentText_Loader_NotFoundIgnored() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.WithDocumentText(_documents[0].FilePath, _textLoader); + var newState = state.WithDocumentText(SomeProjectFile1.FilePath, s_textLoader); // Assert - Assert.Same(original, state); + Assert.Same(state, newState); } [Fact] public void ProjectState_WithDocumentText_Snapshot_NotFoundIgnored() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.WithDocumentText(_documents[0].FilePath, _text); + var newState = state.WithDocumentText(SomeProjectFile1.FilePath, s_text); // Assert - Assert.Same(original, state); + Assert.Same(state, newState); } [Fact] public void ProjectState_RemoveDocument_FromProjectWithDocuments() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.RemoveDocument(_documents[1].FilePath); + var newState = state.RemoveDocument(SomeProjectFile2.FilePath); // Assert - Assert.NotEqual(original.Version, state.Version); + Assert.NotEqual(state.Version, newState.Version); - Assert.Collection( - state.Documents.OrderBy(kvp => kvp.Key), - d => Assert.Same(_documents[2], d.Value.HostDocument)); + var documentState = Assert.Single(newState.Documents.Values); + Assert.Same(AnotherProjectNestedFile3, documentState.HostDocument); - Assert.NotEqual(original.DocumentCollectionVersion, state.DocumentCollectionVersion); + Assert.NotEqual(state.DocumentCollectionVersion, newState.DocumentCollectionVersion); } [Fact] public void ProjectState_RemoveDocument_TracksImports() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.SomeProjectFile2, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.SomeProjectNestedFile3, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.AnotherProjectNestedFile4, DocumentState.EmptyLoader); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(SomeProjectFile1) + .AddDocument(SomeProjectFile2) + .AddDocument(SomeProjectNestedFile3) + .AddDocument(AnotherProjectNestedFile4); // Act - var state = original.RemoveDocument(TestProjectData.SomeProjectNestedFile3.FilePath); + var newState = state.RemoveDocument(SomeProjectNestedFile3.FilePath); // Assert Assert.Collection( - state.ImportsToRelatedDocuments.OrderBy(kvp => kvp.Key), + newState.ImportsToRelatedDocuments.OrderBy(kvp => kvp.Key), kvp => { - Assert.Equal(TestProjectData.SomeProjectImportFile.TargetPath, kvp.Key); + Assert.Equal(SomeProjectImportFile.TargetPath, kvp.Key); Assert.Equal( - new string[] - { - TestProjectData.AnotherProjectNestedFile4.FilePath, - TestProjectData.SomeProjectFile1.FilePath, - TestProjectData.SomeProjectFile2.FilePath, - }, + [ + AnotherProjectNestedFile4.FilePath, + SomeProjectFile1.FilePath, + SomeProjectFile2.FilePath, + ], kvp.Value.OrderBy(f => f)); }, kvp => { - Assert.Equal(TestProjectData.SomeProjectNestedImportFile.TargetPath, kvp.Key); + Assert.Equal(SomeProjectNestedImportFile.TargetPath, kvp.Key); Assert.Equal( - new string[] - { - TestProjectData.AnotherProjectNestedFile4.FilePath, - }, + [ + AnotherProjectNestedFile4.FilePath, + ], kvp.Value.OrderBy(f => f)); }); } @@ -476,600 +401,485 @@ public void ProjectState_RemoveDocument_TracksImports() public void ProjectState_RemoveDocument_TracksImports_RemoveAllDocuments() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.SomeProjectFile2, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.SomeProjectNestedFile3, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.AnotherProjectNestedFile4, DocumentState.EmptyLoader); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(SomeProjectFile1) + .AddDocument(SomeProjectFile2) + .AddDocument(SomeProjectNestedFile3) + .AddDocument(AnotherProjectNestedFile4); // Act - var state = original - .RemoveDocument(TestProjectData.SomeProjectFile1.FilePath) - .RemoveDocument(TestProjectData.SomeProjectFile2.FilePath) - .RemoveDocument(TestProjectData.SomeProjectNestedFile3.FilePath) - .RemoveDocument(TestProjectData.AnotherProjectNestedFile4.FilePath); + var newState = state + .RemoveDocument(SomeProjectFile1.FilePath) + .RemoveDocument(SomeProjectFile2.FilePath) + .RemoveDocument(SomeProjectNestedFile3.FilePath) + .RemoveDocument(AnotherProjectNestedFile4.FilePath); // Assert - Assert.Empty(state.Documents); - Assert.Empty(state.ImportsToRelatedDocuments); + Assert.Empty(newState.Documents); + Assert.Empty(newState.ImportsToRelatedDocuments); } [Fact] public void ProjectState_RemoveDocument_RetainsComputedState() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); - - // Force init - var originalTagHelpers = original.TagHelpers; - var originalProjectWorkspaceStateVersion = original.ProjectWorkspaceStateVersion; + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.RemoveDocument(_documents[2].FilePath); + var newState = state.RemoveDocument(AnotherProjectNestedFile3.FilePath); // Assert - var actualTagHelpers = state.TagHelpers; - var actualProjectWorkspaceStateVersion = state.ProjectWorkspaceStateVersion; - - Assert.Same(original.ProjectEngine, state.ProjectEngine); - - Assert.Equal(originalTagHelpers.Length, actualTagHelpers.Length); - for (var i = 0; i < originalTagHelpers.Length; i++) - { - Assert.Same(originalTagHelpers[i], actualTagHelpers[i]); - } - - Assert.Equal(originalProjectWorkspaceStateVersion, actualProjectWorkspaceStateVersion); - - Assert.Same(original.Documents[_documents[1].FilePath], state.Documents[_documents[1].FilePath]); + Assert.Same(state.ProjectEngine, newState.ProjectEngine); + AssertSameTagHelpers(state.TagHelpers, newState.TagHelpers); + Assert.Equal(state.ProjectWorkspaceStateVersion, newState.ProjectWorkspaceStateVersion); + Assert.Same(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); } [Fact] public void ProjectState_RemoveDocument_NotFoundIgnored() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.RemoveDocument(_documents[0].FilePath); + var newState = state.RemoveDocument(SomeProjectFile1.FilePath); // Assert - Assert.Same(original, state); + Assert.Same(state, newState); } [Fact] public void ProjectState_WithHostProject_ConfigurationChange_UpdatesConfigurationState() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); - - // Force init - var originalTagHelpers = original.TagHelpers; - var originalProjectWorkspaceStateVersion = original.ConfigurationVersion; + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.WithHostProject(_hostProjectWithConfigurationChange); + var newState = state.WithHostProject(s_hostProject with { Configuration = FallbackRazorConfiguration.MVC_1_0 }); // Assert - Assert.NotEqual(original.Version, state.Version); - Assert.Same(_hostProjectWithConfigurationChange, state.HostProject); - - var actualTagHelpers = state.TagHelpers; - var actualProjectWorkspaceStateVersion = state.ConfigurationVersion; - - Assert.NotSame(original.ProjectEngine, state.ProjectEngine); - - Assert.Equal(originalTagHelpers.Length, actualTagHelpers.Length); - for (var i = 0; i < originalTagHelpers.Length; i++) - { - Assert.Same(originalTagHelpers[i], actualTagHelpers[i]); - } + Assert.NotEqual(state.Version, newState.Version); + Assert.Same(FallbackRazorConfiguration.MVC_1_0, newState.HostProject.Configuration); - Assert.NotEqual(originalProjectWorkspaceStateVersion, actualProjectWorkspaceStateVersion); + Assert.NotSame(state.ProjectEngine, newState.ProjectEngine); + AssertSameTagHelpers(state.TagHelpers, newState.TagHelpers); + Assert.NotEqual(state.ConfigurationVersion, newState.ConfigurationVersion); - Assert.NotSame(original.Documents[_documents[1].FilePath], state.Documents[_documents[1].FilePath]); - Assert.NotSame(original.Documents[_documents[2].FilePath], state.Documents[_documents[2].FilePath]); + Assert.NotSame(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); + Assert.NotSame(state.Documents[AnotherProjectNestedFile3.FilePath], newState.Documents[AnotherProjectNestedFile3.FilePath]); - Assert.NotEqual(original.DocumentCollectionVersion, state.DocumentCollectionVersion); + Assert.NotEqual(state.DocumentCollectionVersion, newState.DocumentCollectionVersion); } [Fact] public void ProjectState_WithHostProject_RootNamespaceChange_UpdatesConfigurationState() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); - var hostProjectWithRootNamespaceChange = original.HostProject with { RootNamespace = "ChangedRootNamespace" }; - - // Force init - _ = original.TagHelpers; - _ = original.ConfigurationVersion; + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.WithHostProject(hostProjectWithRootNamespaceChange); + var newState = state.WithHostProject(s_hostProject with { RootNamespace = "ChangedRootNamespace" }); // Assert - Assert.NotSame(original, state); + Assert.NotSame(state, newState); + Assert.Equal("ChangedRootNamespace", newState.HostProject.RootNamespace); } [Fact] public void ProjectState_WithHostProject_NoConfigurationChange_Ignored() { // Arrange - var original = ProjectState - .Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); - - // Force init - _ = original.ProjectWorkspaceStateVersion; + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.WithHostProject(_hostProject); + var newState = state.WithHostProject(s_hostProject); // Assert - Assert.Same(original, state); + Assert.Same(state, newState); } [Fact] - public void ProjectState_WithHostProject_CallsConfigurationChangeOnDocumentState() + public void ProjectState_WithConfiguration_Change_UpdatesAllDocuments() { // Arrange - var callCount = 0; - - var documents = ImmutableDictionary.CreateBuilder(FilePathComparer.Instance); - documents[_documents[1].FilePath] = TestDocumentState.Create(_documents[1], onConfigurationChange: () => callCount++); - documents[_documents[2].FilePath] = TestDocumentState.Create(_documents[2], onConfigurationChange: () => callCount++); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(SomeProjectFile2) + .AddDocument(AnotherProjectNestedFile3); - var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); - original.Documents = documents.ToImmutable(); + var documentPathSet = state.Documents.Keys.ToHashSet(FilePathNormalizingComparer.Instance); // Act - var state = original.WithHostProject(_hostProjectWithConfigurationChange); + var newState = state.WithHostProject(s_hostProject with { Configuration = FallbackRazorConfiguration.MVC_1_0 }); // Assert - Assert.NotEqual(original.Version, state.Version); - Assert.Same(_hostProjectWithConfigurationChange, state.HostProject); - Assert.Equal(2, callCount); + Assert.NotEqual(state.Version, newState.Version); + Assert.Equal(FallbackRazorConfiguration.MVC_1_0, newState.HostProject.Configuration); + + // all documents were updated + foreach (var filePath in documentPathSet.ToArray()) + { + AssertDocumentUpdated(filePath, state, newState); + documentPathSet.Remove(filePath); + } + + // no other documents - everything was a related document + Assert.Empty(documentPathSet); } [Fact] - public void ProjectState_WithHostProject_ResetsImportedDocuments() + public void ProjectState_WithConfiguration_Change_ResetsImportMap() { // Arrange - var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); - original = original.AddDocument(TestProjectData.SomeProjectFile1, DocumentState.EmptyLoader); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(SomeProjectFile1); // Act - var state = original.WithHostProject(_hostProjectWithConfigurationChange); + var newState = state.WithHostProject(s_hostProject with { Configuration = FallbackRazorConfiguration.MVC_1_0 }); // Assert - var importMap = Assert.Single(state.ImportsToRelatedDocuments); + var importMap = Assert.Single(newState.ImportsToRelatedDocuments); var documentFilePath = Assert.Single(importMap.Value); - Assert.Equal(TestProjectData.SomeProjectFile1.FilePath, documentFilePath); + Assert.Equal(SomeProjectFile1.FilePath, documentFilePath); } [Fact] public void ProjectState_WithProjectWorkspaceState_Changed() { // Arrange - var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); - - // Force init - var originalTagHelpers = original.TagHelpers; - var originalProjectWorkspaceStateVersion = original.ProjectWorkspaceStateVersion; + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); - var changed = ProjectWorkspaceState.Create(_projectWorkspaceState.TagHelpers, LanguageVersion.CSharp6); + var newWorkspaceState = ProjectWorkspaceState.Create(s_projectWorkspaceState.TagHelpers, LanguageVersion.CSharp6); // Act - var state = original.WithProjectWorkspaceState(changed); + var newState = state.WithProjectWorkspaceState(newWorkspaceState); // Assert - Assert.NotEqual(original.Version, state.Version); - Assert.Same(changed, state.ProjectWorkspaceState); - - var actualTagHelpers = state.TagHelpers; - var actualProjectWorkspaceStateVersion = state.ProjectWorkspaceStateVersion; + Assert.NotEqual(state.Version, newState.Version); + Assert.Same(newWorkspaceState, newState.ProjectWorkspaceState); // The C# language version changed, and the tag helpers didn't change - Assert.NotSame(original.ProjectEngine, state.ProjectEngine); - - Assert.Equal(originalTagHelpers.Length, actualTagHelpers.Length); - for (var i = 0; i < originalTagHelpers.Length; i++) - { - Assert.Same(originalTagHelpers[i], actualTagHelpers[i]); - } - - Assert.NotEqual(originalProjectWorkspaceStateVersion, actualProjectWorkspaceStateVersion); + Assert.NotSame(state.ProjectEngine, newState.ProjectEngine); + AssertSameTagHelpers(state.TagHelpers, newState.TagHelpers); + Assert.NotEqual(state.ProjectWorkspaceStateVersion, newState.ProjectWorkspaceStateVersion); - Assert.NotSame(original.Documents[_documents[1].FilePath], state.Documents[_documents[1].FilePath]); - Assert.NotSame(original.Documents[_documents[2].FilePath], state.Documents[_documents[2].FilePath]); + Assert.NotSame(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); + Assert.NotSame(state.Documents[AnotherProjectNestedFile3.FilePath], newState.Documents[AnotherProjectNestedFile3.FilePath]); } [Fact] public void ProjectState_WithProjectWorkspaceState_Changed_TagHelpersChanged() { // Arrange - var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); - - // Force init - var originalTagHelpers = original.TagHelpers; - var originalProjectWorkspaceStateVersion = original.ProjectWorkspaceStateVersion; - - var changed = ProjectWorkspaceState.Default; + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.WithProjectWorkspaceState(changed); + var newState = state.WithProjectWorkspaceState(ProjectWorkspaceState.Default); // Assert - Assert.NotEqual(original.Version, state.Version); - Assert.Same(changed, state.ProjectWorkspaceState); - - var actualTagHelpers = state.TagHelpers; - var actualProjectWorkspaceStateVersion = state.ProjectWorkspaceStateVersion; + Assert.NotEqual(state.Version, newState.Version); + Assert.Same(ProjectWorkspaceState.Default, newState.ProjectWorkspaceState); // The configuration didn't change, but the tag helpers did - Assert.Same(original.ProjectEngine, state.ProjectEngine); - Assert.NotEqual(originalTagHelpers, actualTagHelpers); - Assert.NotEqual(originalProjectWorkspaceStateVersion, actualProjectWorkspaceStateVersion); - Assert.Equal(state.Version, actualProjectWorkspaceStateVersion); + Assert.Same(state.ProjectEngine, newState.ProjectEngine); + Assert.NotEqual(state.TagHelpers, newState.TagHelpers); + Assert.NotEqual(state.ProjectWorkspaceStateVersion, newState.ProjectWorkspaceStateVersion); + Assert.Equal(newState.Version, newState.ProjectWorkspaceStateVersion); - Assert.NotSame(original.Documents[_documents[1].FilePath], state.Documents[_documents[1].FilePath]); - Assert.NotSame(original.Documents[_documents[2].FilePath], state.Documents[_documents[2].FilePath]); + Assert.NotSame(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); + Assert.NotSame(state.Documents[AnotherProjectNestedFile3.FilePath], newState.Documents[AnotherProjectNestedFile3.FilePath]); } [Fact] public void ProjectState_WithProjectWorkspaceState_IdenticalState_Caches() { // Arrange - var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[2], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader); - - // Force init - _ = original.TagHelpers; - _ = original.ProjectWorkspaceStateVersion; + var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(AnotherProjectNestedFile3) + .AddDocument(SomeProjectFile2); // Act - var state = original.WithProjectWorkspaceState(ProjectWorkspaceState.Create(original.TagHelpers, original.CSharpLanguageVersion)); + var newState = state.WithProjectWorkspaceState(ProjectWorkspaceState.Create(state.TagHelpers, state.CSharpLanguageVersion)); // Assert - Assert.Same(original, state); + Assert.Same(state, newState); } [Fact] - public void ProjectState_WithProjectWorkspaceState_CallsWorkspaceProjectChangeOnDocumentState() + public void ProjectState_WithProjectWorkspaceState_UpdatesAllDocuments() { // Arrange - var callCount = 0; - - var documents = ImmutableDictionary.CreateBuilder(FilePathComparer.Instance); - documents[_documents[1].FilePath] = TestDocumentState.Create(_documents[1], onProjectWorkspaceStateChange: () => callCount++); - documents[_documents[2].FilePath] = TestDocumentState.Create(_documents[2], onProjectWorkspaceStateChange: () => callCount++); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(SomeProjectFile2) + .AddDocument(AnotherProjectNestedFile3); - var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); - original.Documents = documents.ToImmutable(); + var documentPathSet = state.Documents.Keys.ToHashSet(FilePathNormalizingComparer.Instance); // Act - var state = original.WithProjectWorkspaceState(ProjectWorkspaceState.Default); + var newState = state.WithProjectWorkspaceState(ProjectWorkspaceState.Default); // Assert - Assert.NotEqual(original.Version, state.Version); - Assert.Equal(2, callCount); + Assert.NotEqual(state.Version, newState.Version); + Assert.NotEqual(state.ProjectWorkspaceState, newState.ProjectWorkspaceState); + Assert.Same(ProjectWorkspaceState.Default, newState.ProjectWorkspaceState); + + // all documents were updated + foreach (var filePath in documentPathSet.ToArray()) + { + AssertDocumentUpdated(filePath, state, newState); + documentPathSet.Remove(filePath); + } + + // no other documents - everything was a related document + Assert.Empty(documentPathSet); } [Fact] - public void ProjectState_AddDocument_Import_CallsImportsChanged() + public void ProjectState_AddImportDocument_UpdatesRelatedDocuments() { // Arrange - var callCount = 0; - - var document1 = TestProjectData.SomeProjectFile1; - var document2 = TestProjectData.SomeProjectFile2; - var document3 = TestProjectData.SomeProjectNestedFile3; - var document4 = TestProjectData.AnotherProjectNestedFile4; - - var documents = ImmutableDictionary.CreateBuilder(FilePathComparer.Instance); - documents[document1.FilePath] = TestDocumentState.Create(document1, onImportsChange: () => callCount++); - documents[document2.FilePath] = TestDocumentState.Create(document2, onImportsChange: () => callCount++); - documents[document3.FilePath] = TestDocumentState.Create(document3, onImportsChange: () => callCount++); - documents[document4.FilePath] = TestDocumentState.Create(document4, onImportsChange: () => callCount++); - - var importsToRelatedDocuments = ImmutableDictionary.CreateBuilder>(FilePathComparer.Instance); - importsToRelatedDocuments.Add( - TestProjectData.SomeProjectImportFile.TargetPath, - ImmutableArray.Create( - TestProjectData.SomeProjectFile1.FilePath, - TestProjectData.SomeProjectFile2.FilePath, - TestProjectData.SomeProjectNestedFile3.FilePath, - TestProjectData.AnotherProjectNestedFile4.FilePath)); - importsToRelatedDocuments.Add( - TestProjectData.SomeProjectNestedImportFile.TargetPath, - ImmutableArray.Create( - TestProjectData.SomeProjectNestedFile3.FilePath, - TestProjectData.AnotherProjectNestedFile4.FilePath)); - - var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); - original.Documents = documents.ToImmutable(); - original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); + var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(SomeProjectFile1) + .AddDocument(SomeProjectFile2) + .AddDocument(SomeProjectNestedFile3) + .AddDocument(AnotherProjectNestedFile4); + + var documentPathSet = state.Documents.Keys.ToHashSet(FilePathNormalizingComparer.Instance); // Act - var state = original.AddDocument(TestProjectData.AnotherProjectImportFile, DocumentState.EmptyLoader); + var newState = state.AddDocument(AnotherProjectImportFile); // Assert - Assert.NotEqual(original.Version, state.Version); - Assert.Equal(4, callCount); + Assert.NotEqual(state.Version, newState.Version); + + // related documents were updated + var relatedDocumentPaths = newState.ImportsToRelatedDocuments[AnotherProjectImportFile.TargetPath]; + + foreach (var filePath in relatedDocumentPaths) + { + AssertDocumentUpdated(filePath, state, newState); + documentPathSet.Remove(filePath); + } + + // no other documents - everything was a related document + + Assert.Empty(documentPathSet); } [Fact] - public void ProjectState_AddDocument_Import_CallsImportsChanged_Nested() + public void ProjectState_AddImportDocument_UpdatesRelatedDocuments_Nested() { // Arrange - var callCount = 0; - - var document1 = TestProjectData.SomeProjectFile1; - var document2 = TestProjectData.SomeProjectFile2; - var document3 = TestProjectData.SomeProjectNestedFile3; - var document4 = TestProjectData.AnotherProjectNestedFile4; - - var documents = ImmutableDictionary.CreateBuilder(FilePathComparer.Instance); - documents[document1.FilePath] = TestDocumentState.Create(document1, onImportsChange: () => callCount++); - documents[document2.FilePath] = TestDocumentState.Create(document2, onImportsChange: () => callCount++); - documents[document3.FilePath] = TestDocumentState.Create(document3, onImportsChange: () => callCount++); - documents[document4.FilePath] = TestDocumentState.Create(document4, onImportsChange: () => callCount++); - - var importsToRelatedDocuments = ImmutableDictionary.CreateBuilder>(FilePathComparer.Instance); - importsToRelatedDocuments.Add( - TestProjectData.SomeProjectImportFile.TargetPath, - ImmutableArray.Create( - TestProjectData.SomeProjectFile1.FilePath, - TestProjectData.SomeProjectFile2.FilePath, - TestProjectData.SomeProjectNestedFile3.FilePath, - TestProjectData.AnotherProjectNestedFile4.FilePath)); - importsToRelatedDocuments.Add( - TestProjectData.SomeProjectNestedImportFile.TargetPath, - ImmutableArray.Create( - TestProjectData.SomeProjectNestedFile3.FilePath, - TestProjectData.AnotherProjectNestedFile4.FilePath)); - - var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); - original.Documents = documents.ToImmutable(); - original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); + var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(SomeProjectFile1) + .AddDocument(SomeProjectFile2) + .AddDocument(SomeProjectNestedFile3) + .AddDocument(AnotherProjectNestedFile4); + + var documentPathSet = state.Documents.Keys.ToHashSet(FilePathNormalizingComparer.Instance); // Act - var state = original.AddDocument(TestProjectData.AnotherProjectNestedImportFile, DocumentState.EmptyLoader); + var newState = state.AddDocument(AnotherProjectNestedImportFile); // Assert - Assert.NotEqual(original.Version, state.Version); - Assert.Equal(2, callCount); + Assert.NotEqual(state.Version, newState.Version); + + // related documents were updated + var relatedDocumentPaths = newState.ImportsToRelatedDocuments[AnotherProjectNestedImportFile.TargetPath]; + + foreach (var filePath in relatedDocumentPaths) + { + AssertDocumentUpdated(filePath, state, newState); + documentPathSet.Remove(filePath); + } + + // other documents were not updated + foreach (var filePath in documentPathSet.ToArray()) + { + AssertDocumentNotUpdated(filePath, state, newState); + documentPathSet.Remove(filePath); + } + + Assert.Empty(documentPathSet); } [Fact] - public void ProjectState_WithDocumentText_Loader_Import_CallsImportsChanged() + public void ProjectState_WithImportDocumentText_UpdatesRelatedDocuments_TextLoader() { // Arrange - var callCount = 0; - - var document1 = TestProjectData.SomeProjectFile1; - var document2 = TestProjectData.SomeProjectFile2; - var document3 = TestProjectData.SomeProjectNestedFile3; - var document4 = TestProjectData.AnotherProjectNestedFile4; - var document5 = TestProjectData.AnotherProjectNestedImportFile; - - var documents = ImmutableDictionary.CreateBuilder(FilePathComparer.Instance); - documents[document1.FilePath] = TestDocumentState.Create(document1, onImportsChange: () => callCount++); - documents[document2.FilePath] = TestDocumentState.Create(document2, onImportsChange: () => callCount++); - documents[document3.FilePath] = TestDocumentState.Create(document3, onImportsChange: () => callCount++); - documents[document4.FilePath] = TestDocumentState.Create(document4, onImportsChange: () => callCount++); - documents[document5.FilePath] = TestDocumentState.Create(document5, onImportsChange: () => callCount++); - - var importsToRelatedDocuments = ImmutableDictionary.CreateBuilder>(FilePathComparer.Instance); - importsToRelatedDocuments.Add( - TestProjectData.SomeProjectImportFile.TargetPath, - ImmutableArray.Create( - TestProjectData.SomeProjectFile1.FilePath, - TestProjectData.SomeProjectFile2.FilePath, - TestProjectData.SomeProjectNestedFile3.FilePath, - TestProjectData.AnotherProjectNestedFile4.FilePath, - TestProjectData.AnotherProjectNestedImportFile.FilePath)); - importsToRelatedDocuments.Add( - TestProjectData.SomeProjectNestedImportFile.TargetPath, - ImmutableArray.Create( - TestProjectData.SomeProjectNestedFile3.FilePath, - TestProjectData.AnotherProjectNestedFile4.FilePath)); - - var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); - original.Documents = documents.ToImmutable(); - original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); + var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(SomeProjectFile1) + .AddDocument(SomeProjectFile2) + .AddDocument(SomeProjectNestedFile3) + .AddDocument(AnotherProjectNestedFile4) + .AddDocument(AnotherProjectNestedImportFile); + + var documentPathSet = state.Documents.Keys.ToHashSet(FilePathNormalizingComparer.Instance); // Act - var state = original.WithDocumentText(document5.FilePath, DocumentState.EmptyLoader); + var newState = state.WithDocumentText(AnotherProjectNestedImportFile.FilePath, s_textLoader); // Assert - Assert.NotEqual(original.Version, state.Version); - Assert.Equal(2, callCount); + Assert.NotEqual(state.Version, newState.Version); + + // document was updated + AssertDocumentUpdated(AnotherProjectNestedImportFile.FilePath, state, newState); + documentPathSet.Remove(AnotherProjectNestedImportFile.FilePath); + + // related documents were updated + var relatedDocumentPaths = newState.ImportsToRelatedDocuments[AnotherProjectNestedImportFile.TargetPath]; + + foreach (var filePath in relatedDocumentPaths) + { + AssertDocumentUpdated(filePath, state, newState); + documentPathSet.Remove(filePath); + } + + // other documents were not updated + foreach (var filePath in documentPathSet.ToArray()) + { + AssertDocumentNotUpdated(filePath, state, newState); + documentPathSet.Remove(filePath); + } + + Assert.Empty(documentPathSet); } [Fact] - public void ProjectState_WithDocumentText_Snapshot_Import_CallsImportsChanged() + public void ProjectState_WithImportDocumentText_UpdatesRelatedDocuments_Snapshot() { // Arrange - var callCount = 0; - - var document1 = TestProjectData.SomeProjectFile1; - var document2 = TestProjectData.SomeProjectFile2; - var document3 = TestProjectData.SomeProjectNestedFile3; - var document4 = TestProjectData.AnotherProjectNestedFile4; - var document5 = TestProjectData.AnotherProjectNestedImportFile; - - var documents = ImmutableDictionary.CreateBuilder(FilePathComparer.Instance); - documents[document1.FilePath] = TestDocumentState.Create(document1, onImportsChange: () => callCount++); - documents[document2.FilePath] = TestDocumentState.Create(document2, onImportsChange: () => callCount++); - documents[document3.FilePath] = TestDocumentState.Create(document3, onImportsChange: () => callCount++); - documents[document4.FilePath] = TestDocumentState.Create(document4, onImportsChange: () => callCount++); - documents[document5.FilePath] = TestDocumentState.Create(document5, onImportsChange: () => callCount++); - - var importsToRelatedDocuments = ImmutableDictionary.CreateBuilder>(FilePathComparer.Instance); - importsToRelatedDocuments.Add( - TestProjectData.SomeProjectImportFile.TargetPath, - ImmutableArray.Create( - TestProjectData.SomeProjectFile1.FilePath, - TestProjectData.SomeProjectFile2.FilePath, - TestProjectData.SomeProjectNestedFile3.FilePath, - TestProjectData.AnotherProjectNestedFile4.FilePath, - TestProjectData.AnotherProjectNestedImportFile.FilePath)); - importsToRelatedDocuments.Add( - TestProjectData.SomeProjectNestedImportFile.TargetPath, - ImmutableArray.Create( - TestProjectData.SomeProjectNestedFile3.FilePath, - TestProjectData.AnotherProjectNestedFile4.FilePath)); - - var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); - original.Documents = documents.ToImmutable(); - original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); + var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(SomeProjectFile1) + .AddDocument(SomeProjectFile2) + .AddDocument(SomeProjectNestedFile3) + .AddDocument(AnotherProjectNestedFile4) + .AddDocument(AnotherProjectNestedImportFile); + + var documentPathSet = state.Documents.Keys.ToHashSet(FilePathNormalizingComparer.Instance); // Act - var state = original.WithDocumentText(document5.FilePath, _text); + var newState = state.WithDocumentText(AnotherProjectNestedImportFile.FilePath, s_text); // Assert - Assert.NotEqual(original.Version, state.Version); - Assert.Equal(2, callCount); + Assert.NotEqual(state.Version, newState.Version); + + // document was updated + AssertDocumentUpdated(AnotherProjectNestedImportFile.FilePath, state, newState); + documentPathSet.Remove(AnotherProjectNestedImportFile.FilePath); + + // related documents were updated + var relatedDocumentPaths = newState.ImportsToRelatedDocuments[AnotherProjectNestedImportFile.TargetPath]; + + foreach (var filePath in relatedDocumentPaths) + { + AssertDocumentUpdated(filePath, state, newState); + documentPathSet.Remove(filePath); + } + + // other documents were not updated + foreach (var filePath in documentPathSet.ToArray()) + { + AssertDocumentNotUpdated(filePath, state, newState); + documentPathSet.Remove(filePath); + } + + Assert.Empty(documentPathSet); } [Fact] - public void ProjectState_RemoveDocument_Import_CallsImportsChanged() + public void ProjectState_RemoveImportDocument_UpdatesRelatedDocuments() { // Arrange - var callCount = 0; - - var document1 = TestProjectData.SomeProjectFile1; - var document2 = TestProjectData.SomeProjectFile2; - var document3 = TestProjectData.SomeProjectNestedFile3; - var document4 = TestProjectData.AnotherProjectNestedFile4; - var document5 = TestProjectData.AnotherProjectNestedImportFile; - - var documents = ImmutableDictionary.CreateBuilder(FilePathComparer.Instance); - documents[document1.FilePath] = TestDocumentState.Create(document1, onImportsChange: () => callCount++); - documents[document2.FilePath] = TestDocumentState.Create(document2, onImportsChange: () => callCount++); - documents[document3.FilePath] = TestDocumentState.Create(document3, onImportsChange: () => callCount++); - documents[document4.FilePath] = TestDocumentState.Create(document4, onImportsChange: () => callCount++); - documents[document5.FilePath] = TestDocumentState.Create(document5, onImportsChange: () => callCount++); - - var importsToRelatedDocuments = ImmutableDictionary.CreateBuilder>(FilePathComparer.Instance); - importsToRelatedDocuments.Add( - TestProjectData.SomeProjectImportFile.TargetPath, - ImmutableArray.Create( - TestProjectData.SomeProjectFile1.FilePath, - TestProjectData.SomeProjectFile2.FilePath, - TestProjectData.SomeProjectNestedFile3.FilePath, - TestProjectData.AnotherProjectNestedFile4.FilePath, - TestProjectData.AnotherProjectNestedImportFile.FilePath)); - importsToRelatedDocuments.Add( - TestProjectData.SomeProjectNestedImportFile.TargetPath, - ImmutableArray.Create( - TestProjectData.SomeProjectNestedFile3.FilePath, - TestProjectData.AnotherProjectNestedFile4.FilePath)); - - var original = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider); - original.Documents = documents.ToImmutable(); - original.ImportsToRelatedDocuments = importsToRelatedDocuments.ToImmutable(); + var state = ProjectState + .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .AddDocument(SomeProjectFile1) + .AddDocument(SomeProjectFile2) + .AddDocument(SomeProjectNestedFile3) + .AddDocument(AnotherProjectNestedFile4) + .AddDocument(AnotherProjectNestedImportFile); + + var documentPathSet = state.Documents.Keys.ToHashSet(FilePathNormalizingComparer.Instance); + var relatedDocumentPaths = state.ImportsToRelatedDocuments[AnotherProjectNestedImportFile.TargetPath]; // Act - var state = original.RemoveDocument(document5.FilePath); + var newState = state.RemoveDocument(AnotherProjectNestedImportFile.FilePath); // Assert - Assert.NotEqual(original.Version, state.Version); - Assert.Equal(2, callCount); - } + Assert.NotEqual(state.Version, newState.Version); - private class TestDocumentState : DocumentState - { - public static TestDocumentState Create( - HostDocument hostDocument, - TextLoader? loader = null, - Action? onTextChange = null, - Action? onTextLoaderChange = null, - Action? onConfigurationChange = null, - Action? onImportsChange = null, - Action? onProjectWorkspaceStateChange = null) - { - return new TestDocumentState( - hostDocument, - loader, - onTextChange, - onTextLoaderChange, - onConfigurationChange, - onImportsChange, - onProjectWorkspaceStateChange); - } + // document was removed + Assert.False(newState.Documents.ContainsKey(AnotherProjectNestedImportFile.FilePath)); + // TODO: Fix this bug. newState.ImportsToRelatedDocuments should contain an import document after it's been removed. + Assert.True(newState.ImportsToRelatedDocuments.ContainsKey(AnotherProjectNestedImportFile.TargetPath)); + documentPathSet.Remove(AnotherProjectNestedImportFile.FilePath); - private readonly Action? _onTextChange; - private readonly Action? _onTextLoaderChange; - private readonly Action? _onConfigurationChange; - private readonly Action? _onImportsChange; - private readonly Action? _onProjectWorkspaceStateChange; - - private TestDocumentState( - HostDocument hostDocument, - TextLoader? loader, - Action? onTextChange, - Action? onTextLoaderChange, - Action? onConfigurationChange, - Action? onImportsChange, - Action? onProjectWorkspaceStateChange) - : base(hostDocument, version: 1, loader ?? EmptyLoader) + // related documents were updated + foreach (var filePath in relatedDocumentPaths) { - _onTextChange = onTextChange; - _onTextLoaderChange = onTextLoaderChange; - _onConfigurationChange = onConfigurationChange; - _onImportsChange = onImportsChange; - _onProjectWorkspaceStateChange = onProjectWorkspaceStateChange; + AssertDocumentUpdated(filePath, state, newState); + documentPathSet.Remove(filePath); } - public override DocumentState WithText(SourceText sourceText, VersionStamp textVersion) + // other documents were not updated + foreach (var filePath in documentPathSet.ToArray()) { - _onTextChange?.Invoke(); - return base.WithText(sourceText, textVersion); + AssertDocumentNotUpdated(filePath, state, newState); + documentPathSet.Remove(filePath); } - public override DocumentState WithTextLoader(TextLoader loader) - { - _onTextLoaderChange?.Invoke(); - return base.WithTextLoader(loader); - } + Assert.Empty(documentPathSet); + } - public override DocumentState WithConfigurationChange() - { - _onConfigurationChange?.Invoke(); - return base.WithConfigurationChange(); - } + private static void AssertSameTagHelpers(ImmutableArray expected, ImmutableArray actual) + { + Assert.Equal(expected.Length, actual.Length); - public override DocumentState WithImportsChange() + for (var i = 0; i < expected.Length; i++) { - _onImportsChange?.Invoke(); - return base.WithImportsChange(); + Assert.Same(expected[i], actual[i]); } + } - public override DocumentState WithProjectWorkspaceStateChange() - { - _onProjectWorkspaceStateChange?.Invoke(); - return base.WithProjectWorkspaceStateChange(); - } + private static void AssertDocumentUpdated(string filePath, ProjectState oldState, ProjectState newState) + { + Assert.True(oldState.Documents.TryGetValue(filePath, out var document)); + Assert.True(newState.Documents.TryGetValue(filePath, out var newDocument)); + + Assert.NotSame(document, newDocument); + Assert.Same(document.HostDocument, newDocument.HostDocument); + Assert.Equal(document.Version + 1, newDocument.Version); + } + + private static void AssertDocumentNotUpdated(string filePath, ProjectState oldState, ProjectState newState) + { + Assert.True(oldState.Documents.TryGetValue(filePath, out var document)); + Assert.True(newState.Documents.TryGetValue(filePath, out var newDocument)); + + Assert.Same(document, newDocument); } } From ee0e2395966d4c69dc97c7ad59e49dd3a50d7691 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Thu, 12 Dec 2024 16:12:29 -0800 Subject: [PATCH 05/42] Rework ProjectState.ImportsToRelatedDocuments map This change attempts to be a bit more efficient what updating the ImportsToRelatedDocuments map. In addition, related documents are now stored in ImmutableHashSets. --- .../ProjectSystem/ProjectSnapshot.cs | 2 +- .../ProjectSystem/ProjectState.cs | 256 ++++++++++++------ 2 files changed, 172 insertions(+), 86 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs index 25584ea45ef..7d55adfc1a6 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs @@ -106,7 +106,7 @@ public ImmutableArray GetRelatedDocuments(IDocumentSnapshot d lock (_gate) { - using var builder = new PooledArrayBuilder(capacity: relatedDocuments.Length); + using var builder = new PooledArrayBuilder(capacity: relatedDocuments.Count); foreach (var relatedDocumentFilePath in relatedDocuments) { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs index a0c4e00b4f7..156c0904839 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs @@ -10,17 +10,22 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.AspNetCore.Razor.ProjectEngineHost; using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Utilities; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; +using Microsoft.Extensions.ObjectPool; using Microsoft.NET.Sdk.Razor.SourceGenerators; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; internal sealed class ProjectState { + private static readonly ObjectPool.Builder>> s_importMapBuilderPool = + DictionaryPool.Builder>.Create(FilePathNormalizingComparer.Instance); + private const ProjectDifference ClearConfigurationVersionMask = ProjectDifference.ConfigurationChanged; private const ProjectDifference ClearProjectWorkspaceStateVersionMask = @@ -32,8 +37,13 @@ internal sealed class ProjectState ProjectDifference.DocumentAdded | ProjectDifference.DocumentRemoved; - private static readonly ImmutableDictionary s_emptyDocuments = ImmutableDictionary.Create(FilePathNormalizingComparer.Instance); - private static readonly ImmutableDictionary> s_emptyImportsToRelatedDocuments = ImmutableDictionary.Create>(FilePathNormalizingComparer.Instance); + private static readonly ImmutableDictionary s_emptyDocuments + = ImmutableDictionary.Create(FilePathNormalizingComparer.Instance); + private static readonly ImmutableDictionary> s_emptyImportsToRelatedDocuments + = ImmutableDictionary.Create>(FilePathNormalizingComparer.Instance); + private static readonly ImmutableHashSet s_emptyRelatedDocuments + = ImmutableHashSet.Create(FilePathNormalizingComparer.Instance); + private readonly object _lock = new(); public HostProject HostProject { get; } @@ -41,7 +51,7 @@ internal sealed class ProjectState public ProjectWorkspaceState ProjectWorkspaceState { get; } public ImmutableDictionary Documents { get; } - public ImmutableDictionary> ImportsToRelatedDocuments { get; } + public ImmutableDictionary> ImportsToRelatedDocuments { get; } private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider; private RazorProjectEngine? _projectEngine; @@ -70,7 +80,7 @@ private ProjectState( HostProject hostProject, ProjectWorkspaceState projectWorkspaceState, ImmutableDictionary documents, - ImmutableDictionary> importsToRelatedDocuments) + ImmutableDictionary> importsToRelatedDocuments) { HostProject = hostProject; CompilerOptions = older.CompilerOptions; @@ -245,18 +255,10 @@ private ProjectState AddDocument(DocumentState state) var documents = Documents.Add(hostDocument.FilePath, state); // Compute the effect on the import map - var importTargetPaths = GetImportDocumentTargetPaths(hostDocument); - var importsToRelatedDocuments = AddToImportsToRelatedDocuments(ImportsToRelatedDocuments, hostDocument.FilePath, importTargetPaths); + var importsToRelatedDocuments = AddToImportsToRelatedDocuments(hostDocument); - // Now check if the updated document is an import - it's important this this happens after - // updating the imports map. - if (importsToRelatedDocuments.TryGetValue(hostDocument.TargetPath, out var relatedDocuments)) - { - foreach (var relatedDocument in relatedDocuments) - { - documents = documents.SetItem(relatedDocument, documents[relatedDocument].WithImportsChange()); - } - } + // Then, if this is an import, update any related documents. + documents = UpdateRelatedDocuments(hostDocument, documents); return new(this, ProjectDifference.DocumentAdded, HostProject, ProjectWorkspaceState, documents, importsToRelatedDocuments); } @@ -274,19 +276,11 @@ public ProjectState RemoveDocument(string documentFilePath) var documents = Documents.Remove(documentFilePath); - // First check if the updated document is an import - it's important that this happens - // before updating the imports map. - if (ImportsToRelatedDocuments.TryGetValue(hostDocument.TargetPath, out var relatedDocuments)) - { - foreach (var relatedDocument in relatedDocuments) - { - documents = documents.SetItem(relatedDocument, documents[relatedDocument].WithImportsChange()); - } - } + // If this is an import, update any related documents. + documents = UpdateRelatedDocuments(hostDocument, documents); - // Compute the effect on the import map - var importTargetPaths = GetImportDocumentTargetPaths(hostDocument); - var importsToRelatedDocuments = RemoveFromImportsToRelatedDocuments(ImportsToRelatedDocuments, hostDocument, importTargetPaths); + // Then, compute the effect on the import map + var importsToRelatedDocuments = RemoveFromImportsToRelatedDocuments(hostDocument); return new(this, ProjectDifference.DocumentRemoved, HostProject, ProjectWorkspaceState, documents, importsToRelatedDocuments); } @@ -331,123 +325,203 @@ private ProjectState WithDocumentText(DocumentState state, Func kvp.Key, kvp => kvp.Value.WithConfigurationChange(), FilePathNormalizingComparer.Instance); + var documents = UpdateDocuments(static x => x.WithConfigurationChange()); // If the host project has changed then we need to recompute the imports map - var importsToRelatedDocuments = s_emptyImportsToRelatedDocuments; + var importsToRelatedDocuments = BuildImportsMap(documents.Values, ProjectEngine); - foreach (var document in documents) - { - var importTargetPaths = GetImportDocumentTargetPaths(document.Value.HostDocument); - importsToRelatedDocuments = AddToImportsToRelatedDocuments(importsToRelatedDocuments, document.Value.HostDocument.FilePath, importTargetPaths); - } - - var state = new ProjectState(this, ProjectDifference.ConfigurationChanged, hostProject, ProjectWorkspaceState, documents, importsToRelatedDocuments); - return state; + return new(this, ProjectDifference.ConfigurationChanged, hostProject, ProjectWorkspaceState, documents, importsToRelatedDocuments); } public ProjectState WithProjectWorkspaceState(ProjectWorkspaceState projectWorkspaceState) { ArgHelper.ThrowIfNull(projectWorkspaceState); - if (ProjectWorkspaceState == projectWorkspaceState) - { - return this; - } - - if (ProjectWorkspaceState.Equals(projectWorkspaceState)) + if (ProjectWorkspaceState == projectWorkspaceState || + ProjectWorkspaceState.Equals(projectWorkspaceState)) { return this; } - var documents = Documents.ToImmutableDictionary( - kvp => kvp.Key, - kvp => kvp.Value.WithProjectWorkspaceStateChange(), - FilePathNormalizingComparer.Instance); + var documents = UpdateDocuments(static x => x.WithProjectWorkspaceStateChange()); return new(this, ProjectDifference.ProjectWorkspaceStateChanged, HostProject, projectWorkspaceState, documents, ImportsToRelatedDocuments); } - internal static ImmutableDictionary> AddToImportsToRelatedDocuments( - ImmutableDictionary> importsToRelatedDocuments, - string documentFilePath, - List importTargetPaths) + private ImmutableDictionary> AddToImportsToRelatedDocuments(HostDocument hostDocument) { + using var importTargetPaths = new PooledArrayBuilder(); + CollectImportDocumentTargetPaths(hostDocument, ProjectEngine, ref importTargetPaths.AsRef()); + + if (importTargetPaths.Count == 0) + { + return ImportsToRelatedDocuments; + } + + using var _ = ListPool>>.GetPooledObject(out var updates); + + var importsToRelatedDocuments = ImportsToRelatedDocuments; + foreach (var importTargetPath in importTargetPaths) { if (!importsToRelatedDocuments.TryGetValue(importTargetPath, out var relatedDocuments)) { - relatedDocuments = ImmutableArray.Create(); + relatedDocuments = []; } - relatedDocuments = relatedDocuments.Add(documentFilePath); - importsToRelatedDocuments = importsToRelatedDocuments.SetItem(importTargetPath, relatedDocuments); + updates.Add(KeyValuePair.Create(importTargetPath, relatedDocuments.Add(hostDocument.FilePath))); + } + + if (updates.Count > 0) + { + importsToRelatedDocuments = importsToRelatedDocuments.SetItems(updates); } return importsToRelatedDocuments; } - private static ImmutableDictionary> RemoveFromImportsToRelatedDocuments( - ImmutableDictionary> importsToRelatedDocuments, - HostDocument hostDocument, - List importTargetPaths) + private ImmutableDictionary> RemoveFromImportsToRelatedDocuments(HostDocument hostDocument) { + using var importTargetPaths = new PooledArrayBuilder(); + CollectImportDocumentTargetPaths(hostDocument, ProjectEngine, ref importTargetPaths.AsRef()); + + if (importTargetPaths.Count == 0) + { + return ImportsToRelatedDocuments; + } + + using var _1 = ListPool.GetPooledObject(out var removes); + using var _2 = ListPool>>.GetPooledObject(out var updates); + + var importsToRelatedDocuments = ImportsToRelatedDocuments; + foreach (var importTargetPath in importTargetPaths) { if (importsToRelatedDocuments.TryGetValue(importTargetPath, out var relatedDocuments)) { - relatedDocuments = relatedDocuments.Remove(hostDocument.FilePath); - importsToRelatedDocuments = relatedDocuments.Length > 0 - ? importsToRelatedDocuments.SetItem(importTargetPath, relatedDocuments) - : importsToRelatedDocuments.Remove(importTargetPath); + if (relatedDocuments.Count == 1) + { + removes.Add(importTargetPath); + } + else + { + updates.Add(KeyValuePair.Create(importTargetPath, relatedDocuments.Remove(hostDocument.FilePath))); + } } } + if (updates.Count > 0) + { + importsToRelatedDocuments = importsToRelatedDocuments.SetItems(updates); + } + + if (removes.Count > 0) + { + importsToRelatedDocuments = importsToRelatedDocuments.RemoveRange(removes); + } + return importsToRelatedDocuments; } - public List GetImportDocumentTargetPaths(HostDocument hostDocument) + public ImmutableArray GetImportDocumentTargetPaths(HostDocument hostDocument) + { + using var importTargetPaths = new PooledArrayBuilder(); + CollectImportDocumentTargetPaths(hostDocument, ProjectEngine, ref importTargetPaths.AsRef()); + + return importTargetPaths.DrainToImmutable(); + } + + private ImmutableDictionary UpdateDocuments(Func transformer) { - return GetImportDocumentTargetPaths(hostDocument.TargetPath, hostDocument.FileKind, ProjectEngine); + var updates = Documents.Select(x => KeyValuePair.Create(x.Key, transformer(x.Value))); + return Documents.SetItems(updates); + } + + private ImmutableDictionary UpdateRelatedDocuments(HostDocument hostDocument, ImmutableDictionary documents) + { + if (!ImportsToRelatedDocuments.TryGetValue(hostDocument.TargetPath, out var relatedDocuments)) + { + return documents; + } + + var updates = relatedDocuments.Select(x => KeyValuePair.Create(x, documents[x].WithImportsChange())); + return documents.SetItems(updates); } - internal static List GetImportDocumentTargetPaths(string targetPath, string fileKind, RazorProjectEngine projectEngine) + private static ImmutableDictionary> BuildImportsMap(IEnumerable documents, RazorProjectEngine projectEngine) { - var importFeatures = projectEngine.ProjectFeatures.OfType(); - var projectItem = projectEngine.FileSystem.GetItem(targetPath, fileKind); - var importItems = importFeatures.SelectMany(f => f.GetImports(projectItem)).Where(i => i.FilePath != null); + using var _ = s_importMapBuilderPool.GetPooledObject(out var map); + + using var importTargetPaths = new PooledArrayBuilder(); + + foreach (var document in documents) + { + if (importTargetPaths.Count > 0) + { + importTargetPaths.Clear(); + } + + var hostDocument = document.HostDocument; + + CollectImportDocumentTargetPaths(hostDocument, projectEngine, ref importTargetPaths.AsRef()); + + foreach (var importTargetPath in importTargetPaths) + { + if (!map.TryGetValue(importTargetPath, out var relatedDocuments)) + { + relatedDocuments = s_emptyRelatedDocuments.ToBuilder(); + map.Add(importTargetPath, relatedDocuments); + } + + relatedDocuments.Add(hostDocument.FilePath); + } + } + + return map + .Select(static x => KeyValuePair.Create(x.Key, x.Value.ToImmutable())) + .ToImmutableDictionary(FilePathNormalizingComparer.Instance); + } + + private static void CollectImportDocumentTargetPaths(HostDocument hostDocument, RazorProjectEngine projectEngine, ref PooledArrayBuilder targetPaths) + { + var targetPath = hostDocument.TargetPath; + var projectItem = projectEngine.FileSystem.GetItem(targetPath, hostDocument.FileKind); + + using var importProjectItems = new PooledArrayBuilder(); + CollectImportProjectItems(projectItem, projectEngine, ref importProjectItems.AsRef()); + + if (importProjectItems.Count == 0) + { + return; + } // Target path looks like `Foo\\Bar.cshtml` - var targetPaths = new List(); - foreach (var importItem in importItems) + + foreach (var importProjectItem in importProjectItems) { - var itemTargetPath = importItem.FilePath.Replace('/', '\\').TrimStart('\\'); + if (importProjectItem.FilePath is not string filePath) + { + continue; + } + + var itemTargetPath = filePath.Replace('/', '\\').TrimStart('\\'); - if (FilePathNormalizingComparer.Instance.Equals(itemTargetPath, targetPath)) + if (FilePathNormalizer.AreFilePathsEquivalent(filePath, targetPath)) { // We've normalized the original importItem.FilePath into the HostDocument.TargetPath. For instance, if the HostDocument.TargetPath // was '/_Imports.razor' it'd be normalized down into '_Imports.razor'. The purpose of this method is to get the associated document @@ -457,8 +531,20 @@ internal static List GetImportDocumentTargetPaths(string targetPath, str targetPaths.Add(itemTargetPath); } + } - return targetPaths; + private static void CollectImportProjectItems( + RazorProjectItem projectItem, + RazorProjectEngine projectEngine, + ref PooledArrayBuilder importProjectItems) + { + foreach (var projectFeature in projectEngine.ProjectFeatures) + { + if (projectFeature is IImportProjectFeature importProjectFeature) + { + importProjectItems.AddRange(importProjectFeature.GetImports(projectItem)); + } + } } private sealed class UpdatedTextLoader(DocumentState oldState, SourceText text) : TextLoader From 3ba0edaa98f6ed636ba143fbbd1d64fcddd9ee24 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 16 Dec 2024 09:42:45 -0800 Subject: [PATCH 06/42] Simplify DocumentState.Version tracking --- .../ProjectSystem/DocumentState.cs | 38 +++++++++---------- .../ProjectSystem/ProjectState.cs | 4 +- .../DelegatedCompletionListProviderTest.cs | 28 +++++++------- .../RazorBreakpointSpanEndpointTest.cs | 10 ++--- .../RazorProximityExpressionsEndpointTest.cs | 4 +- .../LanguageServer/TestDocumentContext.cs | 16 -------- .../ProjectSystem/TestDocumentSnapshot.cs | 20 +++++----- 7 files changed, 50 insertions(+), 70 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs index 5b291b4c4f2..d90780e2309 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs @@ -32,35 +32,33 @@ internal sealed partial class DocumentState private DocumentState( HostDocument hostDocument, - int version, TextAndVersion? textAndVersion, TextLoader? textLoader) { HostDocument = hostDocument; - Version = version; + Version = 1; + _textAndVersion = textAndVersion; _textLoader = textLoader ?? EmptyLoader; } - private DocumentState(HostDocument hostDocument, int version, TextLoader loader) - : this(hostDocument, version, textAndVersion: null, loader) + private DocumentState( + DocumentState oldState, + TextAndVersion? textAndVersion, + TextLoader? textLoader) { - } + HostDocument = oldState.HostDocument; + Version = oldState.Version + 1; - public static DocumentState Create(HostDocument hostDocument, int version, SourceText text, VersionStamp textVersion) - { - return new DocumentState(hostDocument, version, TextAndVersion.Create(text, textVersion), textLoader: null); + _textAndVersion = textAndVersion; + _textLoader = textLoader ?? EmptyLoader; } - public static DocumentState Create(HostDocument hostDocument, int version, TextLoader loader) - { - return new DocumentState(hostDocument, version, loader); - } + public static DocumentState Create(HostDocument hostDocument, SourceText text) + => new(hostDocument, TextAndVersion.Create(text, VersionStamp.Create()), textLoader: null); public static DocumentState Create(HostDocument hostDocument, TextLoader loader) - { - return new DocumentState(hostDocument, version: 1, loader); - } + => new(hostDocument, textAndVersion: null, loader); public bool IsGeneratedOutputResultAvailable => ComputedState.IsResultAvailable; @@ -157,12 +155,12 @@ public bool TryGetTextVersion(out VersionStamp result) public DocumentState WithConfigurationChange() { // Do not cache computed state - return new(HostDocument, Version + 1, _textAndVersion, _textLoader); + return new(this, _textAndVersion, _textLoader); } public DocumentState WithImportsChange() { - var state = new DocumentState(HostDocument, Version + 1, _textAndVersion, _textLoader); + var state = new DocumentState(this, _textAndVersion, _textLoader); // Optimistically cache the computed state state._computedState = new ComputedStateTracker(_computedState); @@ -172,7 +170,7 @@ public DocumentState WithImportsChange() public DocumentState WithProjectWorkspaceStateChange() { - var state = new DocumentState(HostDocument, Version + 1, _textAndVersion, _textLoader); + var state = new DocumentState(this, _textAndVersion, _textLoader); // Optimistically cache the computed state state._computedState = new ComputedStateTracker(_computedState); @@ -183,13 +181,13 @@ public DocumentState WithProjectWorkspaceStateChange() public DocumentState WithText(SourceText text, VersionStamp textVersion) { // Do not cache the computed state - return new(HostDocument, Version + 1, TextAndVersion.Create(text, textVersion), textLoader: null); + return new(this, TextAndVersion.Create(text, textVersion), textLoader: null); } public DocumentState WithTextLoader(TextLoader textLoader) { // Do not cache the computed state - return new(HostDocument, Version + 1, textAndVersion: null, textLoader); + return new(this, textAndVersion: null, textLoader); } internal static async Task GenerateCodeDocumentAsync( diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs index 156c0904839..6141bff1345 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs @@ -227,7 +227,7 @@ public ProjectState AddDocument(HostDocument hostDocument, SourceText text) return this; } - var state = DocumentState.Create(hostDocument, version: 1, text, VersionStamp.Create()); + var state = DocumentState.Create(hostDocument, text); return AddDocument(state); } @@ -244,7 +244,7 @@ public ProjectState AddDocument(HostDocument hostDocument, TextLoader textLoader return this; } - var state = DocumentState.Create(hostDocument, version: 1, textLoader); + var state = DocumentState.Create(hostDocument, textLoader); return AddDocument(state); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionListProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionListProviderTest.cs index f97b4f2ca53..434c21aaccb 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionListProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionListProviderTest.cs @@ -45,7 +45,7 @@ public async Task HtmlDelegation_Invoked() // Arrange var completionContext = new VSInternalCompletionContext() { TriggerKind = CompletionTriggerKind.Invoked }; var codeDocument = CreateCodeDocument("<"); - var documentContext = TestDocumentContext.Create("C:/path/to/file.cshtml", codeDocument, hostDocumentVersion: 1337); + var documentContext = TestDocumentContext.Create("C:/path/to/file.cshtml", codeDocument); // Act await _provider.GetCompletionListAsync( @@ -63,7 +63,7 @@ await _provider.GetCompletionListAsync( Assert.Equal(RazorLanguageKind.Html, delegatedParameters.ProjectedKind); Assert.Equal(VsLspFactory.CreatePosition(0, 1), delegatedParameters.ProjectedPosition); Assert.Equal(CompletionTriggerKind.Invoked, delegatedParameters.Context.TriggerKind); - Assert.Equal(1337, delegatedParameters.Identifier.Version); + Assert.Equal(1, delegatedParameters.Identifier.Version); Assert.Null(delegatedParameters.ProvisionalTextEdit); } @@ -78,7 +78,7 @@ public async Task HtmlDelegation_TriggerCharacter() TriggerCharacter = "<", }; var codeDocument = CreateCodeDocument("<"); - var documentContext = TestDocumentContext.Create("C:/path/to/file.cshtml", codeDocument, hostDocumentVersion: 1337); + var documentContext = TestDocumentContext.Create("C:/path/to/file.cshtml", codeDocument); // Act await _provider.GetCompletionListAsync( @@ -97,7 +97,7 @@ await _provider.GetCompletionListAsync( Assert.Equal(VsLspFactory.CreatePosition(0, 1), delegatedParameters.ProjectedPosition); Assert.Equal(CompletionTriggerKind.TriggerCharacter, delegatedParameters.Context.TriggerKind); Assert.Equal(VSInternalCompletionInvokeKind.Typing, delegatedParameters.Context.InvokeKind); - Assert.Equal(1337, delegatedParameters.Identifier.Version); + Assert.Equal(1, delegatedParameters.Identifier.Version); Assert.Null(delegatedParameters.ProvisionalTextEdit); } @@ -112,7 +112,7 @@ public async Task HtmlDelegation_UnsupportedTriggerCharacter_TranslatesToInvoked TriggerCharacter = "|", }; var codeDocument = CreateCodeDocument("|"); - var documentContext = TestDocumentContext.Create("C:/path/to/file.cshtml", codeDocument, hostDocumentVersion: 1337); + var documentContext = TestDocumentContext.Create("C:/path/to/file.cshtml", codeDocument); // Act await _provider.GetCompletionListAsync( @@ -131,7 +131,7 @@ await _provider.GetCompletionListAsync( Assert.Equal(VsLspFactory.CreatePosition(0, 1), delegatedParameters.ProjectedPosition); Assert.Equal(CompletionTriggerKind.Invoked, delegatedParameters.Context.TriggerKind); Assert.Equal(VSInternalCompletionInvokeKind.Typing, delegatedParameters.Context.InvokeKind); - Assert.Equal(1337, delegatedParameters.Identifier.Version); + Assert.Equal(1, delegatedParameters.Identifier.Version); Assert.Null(delegatedParameters.ProvisionalTextEdit); } @@ -146,7 +146,7 @@ public async Task Delegation_NullResult_ToIncompleteResult() TriggerCharacter = "<", }; var codeDocument = CreateCodeDocument("<"); - var documentContext = TestDocumentContext.Create("C:/path/to/file.cshtml", codeDocument, hostDocumentVersion: 1337); + var documentContext = TestDocumentContext.Create("C:/path/to/file.cshtml", codeDocument); var provider = TestDelegatedCompletionListProvider.CreateWithNullResponse(LoggerFactory); // Act @@ -200,7 +200,7 @@ public async Task RazorDelegation_Noop() // Arrange var completionContext = new VSInternalCompletionContext() { TriggerKind = CompletionTriggerKind.Invoked }; var codeDocument = CreateCodeDocument("@functions "); - var documentContext = TestDocumentContext.Create("C:/path/to/file.razor", codeDocument, hostDocumentVersion: 1337); + var documentContext = TestDocumentContext.Create("C:/path/to/file.razor", codeDocument); // Act var completionList = await _provider.GetCompletionListAsync( @@ -229,7 +229,7 @@ public async Task ProvisionalCompletion_TranslatesToCSharpWithProvisionalTextEdi TriggerCharacter = ".", }; var codeDocument = CreateCodeDocument("@DateTime."); - var documentContext = TestDocumentContext.Create("C:/path/to/file.cshtml", codeDocument, hostDocumentVersion: 1337); + var documentContext = TestDocumentContext.Create("C:/path/to/file.cshtml", codeDocument); // Act await _provider.GetCompletionListAsync( @@ -250,7 +250,7 @@ await _provider.GetCompletionListAsync( Assert.True(delegatedParameters.ProjectedPosition.Line > 2); Assert.Equal(CompletionTriggerKind.TriggerCharacter, delegatedParameters.Context.TriggerKind); Assert.Equal(VSInternalCompletionInvokeKind.Typing, delegatedParameters.Context.InvokeKind); - Assert.Equal(1337, delegatedParameters.Identifier.Version); + Assert.Equal(1, delegatedParameters.Identifier.Version); Assert.NotNull(delegatedParameters.ProvisionalTextEdit); } @@ -265,7 +265,7 @@ public async Task DotTriggerInMiddleOfCSharpImplicitExpressionNotTreatedAsProvis TriggerCharacter = ".", }; var codeDocument = CreateCodeDocument("@DateTime.Now"); - var documentContext = TestDocumentContext.Create("C:/path/to/file.cshtml", codeDocument, hostDocumentVersion: 1337); + var documentContext = TestDocumentContext.Create("C:/path/to/file.cshtml", codeDocument); // Act await _provider.GetCompletionListAsync( @@ -286,7 +286,7 @@ await _provider.GetCompletionListAsync( Assert.True(delegatedParameters.ProjectedPosition.Line > 2); Assert.Equal(CompletionTriggerKind.TriggerCharacter, delegatedParameters.Context.TriggerKind); Assert.Equal(VSInternalCompletionInvokeKind.Typing, delegatedParameters.Context.InvokeKind); - Assert.Equal(1337, delegatedParameters.Identifier.Version); + Assert.Equal(1, delegatedParameters.Identifier.Version); Assert.Null(delegatedParameters.ProvisionalTextEdit); } @@ -310,7 +310,7 @@ public async Task ShouldIncludeSnippets(string input, bool shouldIncludeSnippets TestFileMarkupParser.GetPosition(input, out var code, out var cursorPosition); var codeDocument = CreateCodeDocument(code); - var documentContext = TestDocumentContext.Create("C:/path/to/file.cshtml", codeDocument, hostDocumentVersion: 1337); + var documentContext = TestDocumentContext.Create("C:/path/to/file.cshtml", codeDocument); var generatedPosition = new LinePosition(0, cursorPosition); @@ -380,7 +380,7 @@ private async Task GetCompletionListAsync(string conte TriggerCharacter = triggerCharacter, InvokeKind = invocationKind, }; - var documentContext = TestDocumentContext.Create("C:/path/to/file.razor", codeDocument, hostDocumentVersion: 1337); + var documentContext = TestDocumentContext.Create("C:/path/to/file.razor", codeDocument); var provider = TestDelegatedCompletionListProvider.Create(csharpServer, LoggerFactory, DisposalToken); var completionList = await provider.GetCompletionListAsync( diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs index bd1d6332378..5fb431e085f 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs @@ -68,7 +68,7 @@ public async Task Handle_StartsInHtml_BreakpointMoved() { Uri = documentPath, Position = VsLspFactory.CreatePosition(1, 0), - HostDocumentSyncVersion = 0, + HostDocumentSyncVersion = 1, }; var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 5, length: 14); var requestContext = CreateRazorRequestContext(documentContext); @@ -94,7 +94,7 @@ public async Task Handle_ImplicitExpression_StartsInHtml_BreakpointMoved() { Uri = documentPath, Position = VsLspFactory.CreatePosition(1, 0), - HostDocumentSyncVersion = 0, + HostDocumentSyncVersion = 1, }; var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 4, length: 12); var requestContext = CreateRazorRequestContext(documentContext); @@ -120,7 +120,7 @@ public async Task Handle_StartsInHtml_BreakpointMoved_Razor() { Uri = documentPath, Position = VsLspFactory.CreatePosition(1, 0), - HostDocumentSyncVersion = 0, + HostDocumentSyncVersion = 1, }; var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 5, length: 14); var requestContext = CreateRazorRequestContext(documentContext); @@ -146,7 +146,7 @@ public async Task Handle_ImplicitExpression_StartsInHtml_BreakpointMoved_Razor() { Uri = documentPath, Position = VsLspFactory.CreatePosition(1, 0), - HostDocumentSyncVersion = 0, + HostDocumentSyncVersion = 1, }; var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 4, length: 12); var requestContext = CreateRazorRequestContext(documentContext); @@ -173,7 +173,7 @@ public async Task Handle_StartsInHtml_InvalidBreakpointSpan_ReturnsNull() { Uri = documentPath, Position = VsLspFactory.CreatePosition(1, 0), - HostDocumentSyncVersion = 0, + HostDocumentSyncVersion = 1, }; var requestContext = CreateRazorRequestContext(documentContext); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs index 2539bf97581..43992e9198f 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs @@ -66,7 +66,7 @@ public async Task Handle_ReturnsValidExpressions() { Uri = documentPath, Position = VsLspFactory.CreatePosition(1, 8), - HostDocumentSyncVersion = 0, + HostDocumentSyncVersion = 1, }; var requestContext = CreateRazorRequestContext(documentContext); @@ -92,7 +92,7 @@ public async Task Handle_StartsInHtml_ReturnsValidExpressions() { Uri = documentPath, Position = VsLspFactory.CreatePosition(1, 0), - HostDocumentSyncVersion = 0, + HostDocumentSyncVersion = 1, }; var requestContext = CreateRazorRequestContext(documentContext); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/TestDocumentContext.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/TestDocumentContext.cs index eeaea0b6411..d5a38993fc8 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/TestDocumentContext.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/TestDocumentContext.cs @@ -19,13 +19,6 @@ public static DocumentContext Create(Uri uri, string text) return new DocumentContext(uri, snapshot, projectContext: null); } - public static DocumentContext Create(string filePath, RazorCodeDocument codeDocument, int hostDocumentVersion) - { - var documentSnapshot = TestDocumentSnapshot.Create(filePath, codeDocument, hostDocumentVersion); - var uri = new Uri(filePath); - return new DocumentContext(uri, documentSnapshot, projectContext: null); - } - public static DocumentContext Create(string filePath, RazorCodeDocument codeDocument) { var documentSnapshot = TestDocumentSnapshot.Create(filePath, codeDocument); @@ -41,13 +34,4 @@ public static DocumentContext Create(string filePath) return Create(filePath, codeDocument); } - - public static DocumentContext From(string filePath, int hostDocumentVersion) - { - var properties = RazorSourceDocumentProperties.Create(filePath, filePath); - var sourceDocument = RazorSourceDocument.Create(content: string.Empty, properties); - var codeDocument = RazorCodeDocument.Create(sourceDocument); - - return Create(filePath, codeDocument, hostDocumentVersion); - } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs index 687aebda2e4..4199fb0581d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs @@ -25,36 +25,34 @@ private TestDocumentSnapshot(TestProjectSnapshot project, DocumentState state, R } public static TestDocumentSnapshot Create(string filePath) - => Create(filePath, text: string.Empty, ProjectWorkspaceState.Default, version: 0); + => Create(filePath, text: string.Empty, ProjectWorkspaceState.Default); - public static TestDocumentSnapshot Create(string filePath, string text, int version = 0) - => Create(filePath, text, ProjectWorkspaceState.Default, version); + public static TestDocumentSnapshot Create(string filePath, string text) + => Create(filePath, text, ProjectWorkspaceState.Default); - public static TestDocumentSnapshot Create(string filePath, string text, ProjectWorkspaceState projectWorkspaceState, int version = 0) + public static TestDocumentSnapshot Create(string filePath, string text, ProjectWorkspaceState projectWorkspaceState) { var project = TestProjectSnapshot.Create(filePath + ".csproj", projectWorkspaceState); var hostDocument = TestHostDocument.Create(project.HostProject, filePath); var sourceText = SourceText.From(text); - var textVersion = VersionStamp.Default; - var documentState = DocumentState.Create(hostDocument, version, sourceText, textVersion); + var documentState = DocumentState.Create(hostDocument, sourceText); return new TestDocumentSnapshot(project, documentState); } - public static TestDocumentSnapshot Create(string filePath, RazorCodeDocument codeDocument, int version = 0) - => Create(filePath, codeDocument, ProjectWorkspaceState.Create([.. codeDocument.GetTagHelpers() ?? []]), version); + public static TestDocumentSnapshot Create(string filePath, RazorCodeDocument codeDocument) + => Create(filePath, codeDocument, ProjectWorkspaceState.Create([.. codeDocument.GetTagHelpers() ?? []])); - public static TestDocumentSnapshot Create(string filePath, RazorCodeDocument codeDocument, ProjectWorkspaceState projectWorkspaceState, int version = 0) + public static TestDocumentSnapshot Create(string filePath, RazorCodeDocument codeDocument, ProjectWorkspaceState projectWorkspaceState) { var project = TestProjectSnapshot.Create(filePath + ".csproj", projectWorkspaceState); var hostDocument = TestHostDocument.Create(project.HostProject, filePath); var sourceText = codeDocument.Source.Text; - var textVersion = VersionStamp.Default; - var documentState = DocumentState.Create(hostDocument, version, sourceText, textVersion); + var documentState = DocumentState.Create(hostDocument, sourceText); return new TestDocumentSnapshot(project, documentState, codeDocument); } From fdf9486410f277b7d126c3947af5f3472c4e6eac Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 16 Dec 2024 10:01:25 -0800 Subject: [PATCH 07/42] Remove unused DocumentState property --- .../DocumentState.ComputedStateTracker.cs | 23 ------------------- .../ProjectSystem/DocumentState.cs | 2 -- 2 files changed, 25 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs index 4d30a77df18..bf2e93a89fa 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs @@ -24,29 +24,6 @@ private class ComputedStateTracker(ComputedStateTracker? older = null) private ComputedOutput? _computedOutput; - public bool IsResultAvailable - { - get - { - if (_computedOutput?.TryGetCachedOutput(out _, out _) == true) - { - return true; - } - - if (_taskUnsafeReference is null) - { - return false; - } - - if (_taskUnsafeReference.TryGetTarget(out var taskUnsafe)) - { - return taskUnsafe.IsCompleted; - } - - return false; - } - } - public bool TryGetGeneratedOutputAndVersion(out (RazorCodeDocument Output, VersionStamp InputVersion) result) { if (_computedOutput?.TryGetCachedOutput(out var output, out var version) == true) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs index d90780e2309..05a6a8da677 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs @@ -60,8 +60,6 @@ public static DocumentState Create(HostDocument hostDocument, SourceText text) public static DocumentState Create(HostDocument hostDocument, TextLoader loader) => new(hostDocument, textAndVersion: null, loader); - public bool IsGeneratedOutputResultAvailable => ComputedState.IsResultAvailable; - private ComputedStateTracker ComputedState => _computedState ??= InterlockedOperations.Initialize(ref _computedState, new ComputedStateTracker()); From 5b0bfb6b7e2d450b6645083c521ec22960c411a3 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 16 Dec 2024 10:04:57 -0800 Subject: [PATCH 08/42] Clean up DocumentState With* methods --- .../ProjectSystem/DocumentState.cs | 37 ++++--------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs index 05a6a8da677..9e8f4b43900 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs @@ -45,13 +45,15 @@ private DocumentState( private DocumentState( DocumentState oldState, TextAndVersion? textAndVersion, - TextLoader? textLoader) + TextLoader? textLoader, + ComputedStateTracker? computedState = null) { HostDocument = oldState.HostDocument; Version = oldState.Version + 1; _textAndVersion = textAndVersion; _textLoader = textLoader ?? EmptyLoader; + _computedState = computedState; } public static DocumentState Create(HostDocument hostDocument, SourceText text) @@ -151,42 +153,19 @@ public bool TryGetTextVersion(out VersionStamp result) } public DocumentState WithConfigurationChange() - { - // Do not cache computed state - return new(this, _textAndVersion, _textLoader); - } + => new(this, _textAndVersion, _textLoader, computedState: null); public DocumentState WithImportsChange() - { - var state = new DocumentState(this, _textAndVersion, _textLoader); - - // Optimistically cache the computed state - state._computedState = new ComputedStateTracker(_computedState); - - return state; - } + => new(this, _textAndVersion, _textLoader, new ComputedStateTracker(_computedState)); public DocumentState WithProjectWorkspaceStateChange() - { - var state = new DocumentState(this, _textAndVersion, _textLoader); - - // Optimistically cache the computed state - state._computedState = new ComputedStateTracker(_computedState); - - return state; - } + => new(this, _textAndVersion, _textLoader, new ComputedStateTracker(_computedState)); public DocumentState WithText(SourceText text, VersionStamp textVersion) - { - // Do not cache the computed state - return new(this, TextAndVersion.Create(text, textVersion), textLoader: null); - } + => new(this, TextAndVersion.Create(text, textVersion), textLoader: null, computedState: null); public DocumentState WithTextLoader(TextLoader textLoader) - { - // Do not cache the computed state - return new(this, textAndVersion: null, textLoader); - } + => new(this, textAndVersion: null, textLoader, computedState: null); internal static async Task GenerateCodeDocumentAsync( IDocumentSnapshot document, From 8d376ccce38d7fc265bebca81d93ceaed03ae187 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 16 Dec 2024 10:11:48 -0800 Subject: [PATCH 09/42] Move DocumentState helper methods for computing imports --- .../DocumentState.ComputedStateTracker.cs | 2 +- .../ProjectSystem/DocumentState.ImportItem.cs | 20 ---- .../ProjectSystem/DocumentState.cs | 89 +---------------- .../ProjectSystem/ImportHelpers.cs | 96 +++++++++++++++++++ .../ProjectSystem/ImportItem.cs | 17 ++++ 5 files changed, 117 insertions(+), 107 deletions(-) delete mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ImportItem.cs create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ImportHelpers.cs create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ImportItem.cs diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs index bf2e93a89fa..3215dfbc3d9 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs @@ -164,7 +164,7 @@ static void PropagateToTaskCompletionSource( var configurationVersion = project.ConfigurationVersion; var projectWorkspaceStateVersion = project.ProjectWorkspaceStateVersion; var documentCollectionVersion = project.DocumentCollectionVersion; - var importItems = await GetImportItemsAsync(document, project.GetProjectEngine(), cancellationToken).ConfigureAwait(false); + var importItems = await ImportHelpers.GetImportItemsAsync(document, project.GetProjectEngine(), cancellationToken).ConfigureAwait(false); var documentVersion = await document.GetTextVersionAsync(cancellationToken).ConfigureAwait(false); // OK now that have the previous output and all of the versions, we can see if anything diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ImportItem.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ImportItem.cs deleted file mode 100644 index 73cca9ac7d1..00000000000 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ImportItem.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT license. See License.txt in the project root for license information. - -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; - -internal partial class DocumentState -{ - private readonly record struct ImportItem( - string? FilePath, - string? FileKind, - SourceText Text, - VersionStamp Version) - { - // Note: The default import does not have file path, file kind, or version stamp. - public static ImportItem CreateDefault(SourceText text) - => new(FilePath: null, FileKind: null, text, Version: default); - } -} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs index 9e8f4b43900..3bb55d6c3e0 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -173,7 +172,7 @@ internal static async Task GenerateCodeDocumentAsync( bool forceRuntimeCodeGeneration, CancellationToken cancellationToken) { - var importItems = await GetImportItemsAsync(document, projectEngine, cancellationToken).ConfigureAwait(false); + var importItems = await ImportHelpers.GetImportItemsAsync(document, projectEngine, cancellationToken).ConfigureAwait(false); return await GenerateCodeDocumentAsync( document, projectEngine, importItems, forceRuntimeCodeGeneration, cancellationToken).ConfigureAwait(false); @@ -186,94 +185,12 @@ private static async Task GenerateCodeDocumentAsync( bool forceRuntimeCodeGeneration, CancellationToken cancellationToken) { - var importSources = GetImportSources(imports, projectEngine); + var importSources = ImportHelpers.GetImportSources(imports, projectEngine); var tagHelpers = await document.Project.GetTagHelpersAsync(cancellationToken).ConfigureAwait(false); - var source = await GetSourceAsync(document, projectEngine, cancellationToken).ConfigureAwait(false); + var source = await ImportHelpers.GetSourceAsync(document, projectEngine, cancellationToken).ConfigureAwait(false); return forceRuntimeCodeGeneration ? projectEngine.Process(source, document.FileKind, importSources, tagHelpers) : projectEngine.ProcessDesignTime(source, document.FileKind, importSources, tagHelpers); } - - private static async Task> GetImportItemsAsync(IDocumentSnapshot document, RazorProjectEngine projectEngine, CancellationToken cancellationToken) - { - var projectItem = projectEngine.FileSystem.GetItem(document.FilePath, document.FileKind); - - using var importProjectItems = new PooledArrayBuilder(); - - foreach (var feature in projectEngine.ProjectFeatures.OfType()) - { - if (feature.GetImports(projectItem) is { } featureImports) - { - importProjectItems.AddRange(featureImports); - } - } - - if (importProjectItems.Count == 0) - { - return []; - } - - var project = document.Project; - - using var importItems = new PooledArrayBuilder(capacity: importProjectItems.Count); - - foreach (var importProjectItem in importProjectItems) - { - if (importProjectItem is NotFoundProjectItem) - { - continue; - } - - if (importProjectItem.PhysicalPath is null) - { - // This is a default import. - using var stream = importProjectItem.Read(); - var text = SourceText.From(stream); - var defaultImport = ImportItem.CreateDefault(text); - - importItems.Add(defaultImport); - } - else if (project.TryGetDocument(importProjectItem.PhysicalPath, out var importDocument)) - { - var text = await importDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); - var versionStamp = await importDocument.GetTextVersionAsync(cancellationToken).ConfigureAwait(false); - var importItem = new ImportItem(importDocument.FilePath, importDocument.FileKind, text, versionStamp); - - importItems.Add(importItem); - } - } - - return importItems.DrainToImmutable(); - } - - private static ImmutableArray GetImportSources(ImmutableArray importItems, RazorProjectEngine projectEngine) - { - using var importSources = new PooledArrayBuilder(importItems.Length); - - foreach (var importItem in importItems) - { - var importProjectItem = importItem is { FilePath: string filePath, FileKind: var fileKind } - ? projectEngine.FileSystem.GetItem(filePath, fileKind) - : null; - - var properties = RazorSourceDocumentProperties.Create(importItem.FilePath, importProjectItem?.RelativePhysicalPath); - var importSource = RazorSourceDocument.Create(importItem.Text, properties); - - importSources.Add(importSource); - } - - return importSources.DrainToImmutable(); - } - - private static async Task GetSourceAsync(IDocumentSnapshot document, RazorProjectEngine projectEngine, CancellationToken cancellationToken) - { - var projectItem = document is { FilePath: string filePath, FileKind: var fileKind } - ? projectEngine.FileSystem.GetItem(filePath, fileKind) - : null; - - var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - var properties = RazorSourceDocumentProperties.Create(document.FilePath, projectItem?.RelativePhysicalPath); - return RazorSourceDocument.Create(text, properties); - } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ImportHelpers.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ImportHelpers.cs new file mode 100644 index 00000000000..346d5a8a37c --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ImportHelpers.cs @@ -0,0 +1,96 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; + +internal static class ImportHelpers +{ + public static async Task> GetImportItemsAsync(IDocumentSnapshot document, RazorProjectEngine projectEngine, CancellationToken cancellationToken) + { + var projectItem = projectEngine.FileSystem.GetItem(document.FilePath, document.FileKind); + + using var importProjectItems = new PooledArrayBuilder(); + + foreach (var feature in projectEngine.ProjectFeatures.OfType()) + { + if (feature.GetImports(projectItem) is { } featureImports) + { + importProjectItems.AddRange(featureImports); + } + } + + if (importProjectItems.Count == 0) + { + return []; + } + + var project = document.Project; + + using var importItems = new PooledArrayBuilder(capacity: importProjectItems.Count); + + foreach (var importProjectItem in importProjectItems) + { + if (importProjectItem is NotFoundProjectItem) + { + continue; + } + + if (importProjectItem.PhysicalPath is null) + { + // This is a default import. + using var stream = importProjectItem.Read(); + var text = SourceText.From(stream); + var defaultImport = ImportItem.CreateDefault(text); + + importItems.Add(defaultImport); + } + else if (project.TryGetDocument(importProjectItem.PhysicalPath, out var importDocument)) + { + var text = await importDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); + var versionStamp = await importDocument.GetTextVersionAsync(cancellationToken).ConfigureAwait(false); + var importItem = new ImportItem(importDocument.FilePath, importDocument.FileKind, text, versionStamp); + + importItems.Add(importItem); + } + } + + return importItems.DrainToImmutable(); + } + + public static ImmutableArray GetImportSources(ImmutableArray importItems, RazorProjectEngine projectEngine) + { + using var importSources = new PooledArrayBuilder(importItems.Length); + + foreach (var importItem in importItems) + { + var importProjectItem = importItem is { FilePath: string filePath, FileKind: var fileKind } + ? projectEngine.FileSystem.GetItem(filePath, fileKind) + : null; + + var properties = RazorSourceDocumentProperties.Create(importItem.FilePath, importProjectItem?.RelativePhysicalPath); + var importSource = RazorSourceDocument.Create(importItem.Text, properties); + + importSources.Add(importSource); + } + + return importSources.DrainToImmutable(); + } + + public static async Task GetSourceAsync(IDocumentSnapshot document, RazorProjectEngine projectEngine, CancellationToken cancellationToken) + { + var projectItem = document is { FilePath: string filePath, FileKind: var fileKind } + ? projectEngine.FileSystem.GetItem(filePath, fileKind) + : null; + + var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var properties = RazorSourceDocumentProperties.Create(document.FilePath, projectItem?.RelativePhysicalPath); + return RazorSourceDocument.Create(text, properties); + } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ImportItem.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ImportItem.cs new file mode 100644 index 00000000000..62d100f6f82 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ImportItem.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; + +internal readonly record struct ImportItem( + string? FilePath, + string? FileKind, + SourceText Text, + VersionStamp Version) +{ + // Note: The default import does not have file path, file kind, or version stamp. + public static ImportItem CreateDefault(SourceText text) + => new(FilePath: null, FileKind: null, text, Version: default); +} From 4601b2d29e88ad1a4c56522d126b48b22b0d88f0 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 16 Dec 2024 10:19:25 -0800 Subject: [PATCH 10/42] Clean up EmptyTextLoader (currently only used by tests) --- .../ProjectSystem/EmptyTextLoader.cs | 17 ++++++++--------- .../DocumentContextFactoryTest.cs | 2 +- .../GeneratedDocumentPublisherTest.cs | 4 ++-- .../GeneratedDocumentSynchronizerTest.cs | 2 +- ...WorkspaceSemanticTokensRefreshTriggerTest.cs | 6 ++++-- .../ProjectSystem/EmptyTextLoaderTest.cs | 14 ++------------ .../RazorDynamicFileInfoProviderTest.cs | 8 ++++---- 7 files changed, 22 insertions(+), 31 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/EmptyTextLoader.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/EmptyTextLoader.cs index 42e62f4236d..d57c6451e75 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/EmptyTextLoader.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/EmptyTextLoader.cs @@ -10,21 +10,20 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -internal class EmptyTextLoader : TextLoader +internal sealed class EmptyTextLoader : TextLoader { - private readonly string _filePath; - private readonly VersionStamp _version; + private static readonly SourceText s_emptySourceText = SourceText.From(string.Empty, Encoding.UTF8); + private static readonly VersionStamp s_version = VersionStamp.Create(); - public EmptyTextLoader(string filePath) + public static TextLoader Instance { get; } = new EmptyTextLoader(); + + private EmptyTextLoader() { - _filePath = filePath; - _version = VersionStamp.Create(); // Version will never change so this can be reused. } public override Task LoadTextAndVersionAsync(LoadTextOptions options, CancellationToken cancellationToken) { - // Providing an encoding here is important for debuggability. Without this edit-and-continue - // won't work for projects with Razor files. - return Task.FromResult(TextAndVersion.Create(SourceText.From("", Encoding.UTF8), _version, _filePath)); + var textAndVersion = TextAndVersion.Create(s_emptySourceText, s_version); + return Task.FromResult(textAndVersion); } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentContextFactoryTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentContextFactoryTest.cs index ae8a5f09046..c33348ad09a 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentContextFactoryTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentContextFactoryTest.cs @@ -99,7 +99,7 @@ public async Task TryCreateAsync_WithProjectContext_Resolves() await _projectManager.UpdateAsync(updater => { updater.AddProject(hostProject); - updater.AddDocument(hostProject.Key, hostDocument, new EmptyTextLoader(filePath)); + updater.AddDocument(hostProject.Key, hostDocument, EmptyTextLoader.Instance); }); // Act diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentPublisherTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentPublisherTest.cs index 2c1112d6e67..0b3dac2da5a 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentPublisherTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentPublisherTest.cs @@ -36,7 +36,7 @@ protected override async Task InitializeAsync() await _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject); - updater.AddDocument(s_hostProject.Key, s_hostDocument, new EmptyTextLoader(s_hostDocument.FilePath)); + updater.AddDocument(s_hostProject.Key, s_hostDocument, EmptyTextLoader.Instance); }); } @@ -370,7 +370,7 @@ await _projectManager.UpdateAsync(updater => await _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject2); - updater.AddDocument(s_hostProject2.Key, s_hostDocument, new EmptyTextLoader(s_hostDocument.FilePath)); + updater.AddDocument(s_hostProject2.Key, s_hostDocument, EmptyTextLoader.Instance); }); publisher.PublishCSharp(s_hostProject2.Key, s_hostDocument.FilePath, changedSourceText, 124); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentSynchronizerTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentSynchronizerTest.cs index 2b0f76a35b3..c301c82cad1 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentSynchronizerTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentSynchronizerTest.cs @@ -40,7 +40,7 @@ protected override async Task InitializeAsync() await _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject); - updater.AddDocument(s_hostProject.Key, s_hostDocument, new EmptyTextLoader(s_hostDocument.FilePath)); + updater.AddDocument(s_hostProject.Key, s_hostDocument, EmptyTextLoader.Instance); }); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WorkspaceSemanticTokensRefreshTriggerTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WorkspaceSemanticTokensRefreshTriggerTest.cs index f2819e20de4..3244174c6dd 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WorkspaceSemanticTokensRefreshTriggerTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WorkspaceSemanticTokensRefreshTriggerTest.cs @@ -30,7 +30,7 @@ protected override Task InitializeAsync() return _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject); - updater.AddDocument(s_hostProject.Key, s_hostDocument, new EmptyTextLoader(s_hostDocument.FilePath)); + updater.AddDocument(s_hostProject.Key, s_hostDocument, EmptyTextLoader.Instance); }); } @@ -49,7 +49,9 @@ public async Task NotifiesOnWorkspaceUpdate() var newDocument = new HostDocument("/path/to/newFile.razor", "newFile.razor"); await _projectManager.UpdateAsync(updater => - updater.AddDocument(s_hostProject.Key, newDocument, new EmptyTextLoader(newDocument.FilePath))); + { + updater.AddDocument(s_hostProject.Key, newDocument, EmptyTextLoader.Instance); + }); // Assert publisher.VerifyAll(); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/EmptyTextLoaderTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/EmptyTextLoaderTest.cs index 8ab0325ae9a..111474cf92a 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/EmptyTextLoaderTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/EmptyTextLoaderTest.cs @@ -1,8 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -#nullable disable - using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Test.Common; @@ -11,21 +9,13 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -public class EmptyTextLoaderTest : ToolingTestBase +public class EmptyTextLoaderTest(ITestOutputHelper testOutput) : ToolingTestBase(testOutput) { - public EmptyTextLoaderTest(ITestOutputHelper testOutput) - : base(testOutput) - { - } - [Fact, WorkItem("https://github.com/dotnet/aspnetcore/issues/7997")] public async Task LoadAsync_SpecifiesEncoding() { - // Arrange - var loader = new EmptyTextLoader("file.cshtml"); - // Act - var textAndVersion = await loader.LoadTextAndVersionAsync(default, DisposalToken); + var textAndVersion = await EmptyTextLoader.Instance.LoadTextAndVersionAsync(options: default, DisposalToken); // Assert Assert.True(textAndVersion.Text.CanBeEmbedded); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/RazorDynamicFileInfoProviderTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/RazorDynamicFileInfoProviderTest.cs index 074f26b21af..d38991bd43f 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/RazorDynamicFileInfoProviderTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/RazorDynamicFileInfoProviderTest.cs @@ -50,8 +50,8 @@ protected override async Task InitializeAsync() await _projectManager.UpdateAsync(updater => { updater.AddProject(hostProject); - updater.AddDocument(hostProject.Key, hostDocument1, new EmptyTextLoader(hostDocument1.FilePath)); - updater.AddDocument(hostProject.Key, hostDocument2, new EmptyTextLoader(hostDocument2.FilePath)); + updater.AddDocument(hostProject.Key, hostDocument1, EmptyTextLoader.Instance); + updater.AddDocument(hostProject.Key, hostDocument2, EmptyTextLoader.Instance); }); _project = _projectManager.GetRequiredProject(hostProject.Key); @@ -84,7 +84,7 @@ await _projectManager.UpdateAsync(updater => .Verifiable(); lspDocumentContainerMock .Setup(container => container.GetTextLoader(It.IsAny())) - .Returns(new EmptyTextLoader(string.Empty)); + .Returns(EmptyTextLoader.Instance); _lspDocumentContainer = lspDocumentContainerMock.Object; var projectInfo = ProjectInfo.Create( @@ -162,7 +162,7 @@ public async Task UpdateLSPFileInfo_SolutionClosing_ClearsAllDocuments() await _projectManager.UpdateAsync(updater => { updater.SolutionClosed(); - updater.CloseDocument(_project.Key, _document1.FilePath, new EmptyTextLoader(string.Empty)); + updater.CloseDocument(_project.Key, _document1.FilePath, EmptyTextLoader.Instance); }); // Act & Assert From e3a9a866a5adae6d16e76f23b79b553d0c398819 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 16 Dec 2024 10:22:51 -0800 Subject: [PATCH 11/42] Replace DocumentState.EmptyLoader with EmptyTextLoader.Instance --- .../ProjectSystem/DocumentState.cs | 10 ++----- .../ProjectSystem/ProjectState.cs | 2 +- .../DefaultProjectSnapshotTest.cs | 14 +++++----- .../ProjectSystem/DocumentStateTest.cs | 18 ++++++------- .../ProjectStateGeneratedOutputTest.cs | 26 +++++++++---------- 5 files changed, 32 insertions(+), 38 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs index 3bb55d6c3e0..3d9da43a1a1 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs @@ -15,12 +15,6 @@ internal sealed partial class DocumentState { private static readonly LoadTextOptions s_loadTextOptions = new(SourceHashAlgorithm.Sha256); - private static readonly TextAndVersion s_emptyTextAndVersion = TextAndVersion.Create( - SourceText.From(string.Empty), - VersionStamp.Default); - - public static readonly TextLoader EmptyLoader = TextLoader.From(s_emptyTextAndVersion); - public HostDocument HostDocument { get; } public int Version { get; } @@ -38,7 +32,7 @@ private DocumentState( Version = 1; _textAndVersion = textAndVersion; - _textLoader = textLoader ?? EmptyLoader; + _textLoader = textLoader ?? EmptyTextLoader.Instance; } private DocumentState( @@ -51,7 +45,7 @@ private DocumentState( Version = oldState.Version + 1; _textAndVersion = textAndVersion; - _textLoader = textLoader ?? EmptyLoader; + _textLoader = textLoader ?? EmptyTextLoader.Instance; _computedState = computedState; } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs index 6141bff1345..a0995b73866 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs @@ -213,7 +213,7 @@ RazorProjectEngine CreateProjectEngine() public VersionStamp ConfigurationVersion { get; } public ProjectState AddDocument(HostDocument hostDocument) - => AddDocument(hostDocument, DocumentState.EmptyLoader); + => AddDocument(hostDocument, EmptyTextLoader.Instance); public ProjectState AddDocument(HostDocument hostDocument, SourceText text) { diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs index a723341cc10..70b615b1dd4 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs @@ -45,9 +45,9 @@ public void ProjectSnapshot_CachesDocumentSnapshots() { // Arrange var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[0], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader) - .AddDocument(_documents[2], DocumentState.EmptyLoader); + .AddDocument(_documents[0], EmptyTextLoader.Instance) + .AddDocument(_documents[1], EmptyTextLoader.Instance) + .AddDocument(_documents[2], EmptyTextLoader.Instance); var snapshot = new ProjectSnapshot(state); // Act @@ -66,7 +66,7 @@ public void GetRelatedDocuments_NonImportDocument_ReturnsEmpty() { // Arrange var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[0], DocumentState.EmptyLoader); + .AddDocument(_documents[0], EmptyTextLoader.Instance); var snapshot = new ProjectSnapshot(state); var document = snapshot.GetRequiredDocument(_documents[0].FilePath); @@ -83,9 +83,9 @@ public void GetRelatedDocuments_ImportDocument_ReturnsRelated() { // Arrange var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[0], DocumentState.EmptyLoader) - .AddDocument(_documents[1], DocumentState.EmptyLoader) - .AddDocument(TestProjectData.SomeProjectImportFile, DocumentState.EmptyLoader); + .AddDocument(_documents[0], EmptyTextLoader.Instance) + .AddDocument(_documents[1], EmptyTextLoader.Instance) + .AddDocument(TestProjectData.SomeProjectImportFile, EmptyTextLoader.Instance); var snapshot = new ProjectSnapshot(state); var document = snapshot.GetRequiredDocument(TestProjectData.SomeProjectImportFile.FilePath); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DocumentStateTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DocumentStateTest.cs index d2c6b7f6233..1162177b1f8 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DocumentStateTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DocumentStateTest.cs @@ -27,7 +27,7 @@ public DocumentStateTest(ITestOutputHelper testOutput) public async Task DocumentState_CreatedNew_HasEmptyText() { // Arrange & Act - var state = DocumentState.Create(_hostDocument, DocumentState.EmptyLoader); + var state = DocumentState.Create(_hostDocument, EmptyTextLoader.Instance); // Assert var text = await state.GetTextAsync(DisposalToken); @@ -38,7 +38,7 @@ public async Task DocumentState_CreatedNew_HasEmptyText() public async Task DocumentState_WithText_CreatesNewState() { // Arrange - var original = DocumentState.Create(_hostDocument, DocumentState.EmptyLoader); + var original = DocumentState.Create(_hostDocument, EmptyTextLoader.Instance); // Act var state = original.WithText(_text, VersionStamp.Create()); @@ -52,7 +52,7 @@ public async Task DocumentState_WithText_CreatesNewState() public async Task DocumentState_WithTextLoader_CreatesNewState() { // Arrange - var original = DocumentState.Create(_hostDocument, DocumentState.EmptyLoader); + var original = DocumentState.Create(_hostDocument, EmptyTextLoader.Instance); // Act var state = original.WithTextLoader(_textLoader); @@ -66,7 +66,7 @@ public async Task DocumentState_WithTextLoader_CreatesNewState() public void DocumentState_WithConfigurationChange_CachesSnapshotText() { // Arrange - var original = DocumentState.Create(_hostDocument, DocumentState.EmptyLoader) + var original = DocumentState.Create(_hostDocument, EmptyTextLoader.Instance) .WithText(_text, VersionStamp.Create()); // Act @@ -81,7 +81,7 @@ public void DocumentState_WithConfigurationChange_CachesSnapshotText() public async Task DocumentState_WithConfigurationChange_CachesLoadedText() { // Arrange - var original = DocumentState.Create(_hostDocument, DocumentState.EmptyLoader) + var original = DocumentState.Create(_hostDocument, EmptyTextLoader.Instance) .WithTextLoader(_textLoader); await original.GetTextAsync(DisposalToken); @@ -98,7 +98,7 @@ public async Task DocumentState_WithConfigurationChange_CachesLoadedText() public void DocumentState_WithImportsChange_CachesSnapshotText() { // Arrange - var original = DocumentState.Create(_hostDocument, DocumentState.EmptyLoader) + var original = DocumentState.Create(_hostDocument, EmptyTextLoader.Instance) .WithText(_text, VersionStamp.Create()); // Act @@ -113,7 +113,7 @@ public void DocumentState_WithImportsChange_CachesSnapshotText() public async Task DocumentState_WithImportsChange_CachesLoadedText() { // Arrange - var original = DocumentState.Create(_hostDocument, DocumentState.EmptyLoader) + var original = DocumentState.Create(_hostDocument, EmptyTextLoader.Instance) .WithTextLoader(_textLoader); await original.GetTextAsync(DisposalToken); @@ -130,7 +130,7 @@ public async Task DocumentState_WithImportsChange_CachesLoadedText() public void DocumentState_WithProjectWorkspaceStateChange_CachesSnapshotText() { // Arrange - var original = DocumentState.Create(_hostDocument, DocumentState.EmptyLoader) + var original = DocumentState.Create(_hostDocument, EmptyTextLoader.Instance) .WithText(_text, VersionStamp.Create()); // Act @@ -145,7 +145,7 @@ public void DocumentState_WithProjectWorkspaceStateChange_CachesSnapshotText() public async Task DocumentState_WithProjectWorkspaceStateChange_CachesLoadedText() { // Arrange - var original = DocumentState.Create(_hostDocument, DocumentState.EmptyLoader) + var original = DocumentState.Create(_hostDocument, EmptyTextLoader.Instance) .WithTextLoader(_textLoader); await original.GetTextAsync(DisposalToken); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs index f5ef5acf97d..0e824cce341 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs @@ -44,12 +44,12 @@ public async Task AddDocument_CachesOutput() // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, DocumentState.EmptyLoader); + .AddDocument(_hostDocument, EmptyTextLoader.Instance); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); // Act - var state = original.AddDocument(TestProjectData.AnotherProjectFile1, DocumentState.EmptyLoader); + var state = original.AddDocument(TestProjectData.AnotherProjectFile1, EmptyTextLoader.Instance); // Assert var (actualOutput, actualInputVersion) = await GetOutputAsync(state, _hostDocument, DisposalToken); @@ -63,12 +63,12 @@ public async Task AddDocument_Import_DoesNotCacheOutput() // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, DocumentState.EmptyLoader); + .AddDocument(_hostDocument, EmptyTextLoader.Instance); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); // Act - var state = original.AddDocument(TestProjectData.SomeProjectImportFile, DocumentState.EmptyLoader); + var state = original.AddDocument(TestProjectData.SomeProjectImportFile, EmptyTextLoader.Instance); // Assert var (actualOutput, actualInputVersion) = await GetOutputAsync(state, _hostDocument, DisposalToken); @@ -83,8 +83,8 @@ public async Task WithDocumentText_DoesNotCacheOutput() // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.SomeProjectImportFile, DocumentState.EmptyLoader); + .AddDocument(_hostDocument, EmptyTextLoader.Instance) + .AddDocument(TestProjectData.SomeProjectImportFile, EmptyTextLoader.Instance); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -105,8 +105,8 @@ public async Task WithDocumentText_Import_DoesNotCacheOutput() // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.SomeProjectImportFile, DocumentState.EmptyLoader); + .AddDocument(_hostDocument, EmptyTextLoader.Instance) + .AddDocument(TestProjectData.SomeProjectImportFile, EmptyTextLoader.Instance); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -127,8 +127,8 @@ public async Task RemoveDocument_Import_DoesNotCacheOutput() // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, DocumentState.EmptyLoader) - .AddDocument(TestProjectData.SomeProjectImportFile, DocumentState.EmptyLoader); + .AddDocument(_hostDocument, EmptyTextLoader.Instance) + .AddDocument(TestProjectData.SomeProjectImportFile, EmptyTextLoader.Instance); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -148,7 +148,7 @@ public async Task WithProjectWorkspaceState_CachesOutput_EvenWhenNewerProjectWor // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, DocumentState.EmptyLoader); + .AddDocument(_hostDocument, EmptyTextLoader.Instance); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -168,7 +168,7 @@ public async Task WithProjectWorkspaceState_TagHelperChange_DoesNotCacheOutput() // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, DocumentState.EmptyLoader); + .AddDocument(_hostDocument, EmptyTextLoader.Instance); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -213,7 +213,7 @@ public async Task WithHostProject_DoesNotCacheOutput() // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, DocumentState.EmptyLoader); + .AddDocument(_hostDocument, EmptyTextLoader.Instance); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); From 4d181379de7a5b6ad15cbb8a4c090a5f31a8ae81 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 16 Dec 2024 10:36:30 -0800 Subject: [PATCH 12/42] Replace CreateEmptyTextLoader with EmptyTextLoader.Instance --- ...extDocumentUriPresentationEndpointTests.cs | 16 +++---- .../OpenDocumentGeneratorTest.cs | 14 +++--- .../IProjectSnapshotManagerExtensionsTest.cs | 10 ++-- .../WorkspaceDiagnosticRefreshTest.cs | 3 +- .../ProjectSystem/TestHostDocument.cs | 4 -- .../BackgroundDocumentGeneratorTest.cs | 15 +++--- .../CSharpVirtualDocumentFactoryTest.cs | 6 +-- .../ProjectSnapshotManagerTest.cs | 48 +++++++++---------- 8 files changed, 56 insertions(+), 60 deletions(-) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs index 06bb06ca62a..b87efbca41d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs @@ -36,8 +36,8 @@ public async Task Handle_SimpleComponent_ReturnsResult() await projectManager.UpdateAsync(updater => { updater.AddProject(hostProject); - updater.AddDocument(hostProject.Key, hostDocument1, hostDocument1.CreateEmptyTextLoader()); - updater.AddDocument(hostProject.Key, hostDocument2, hostDocument2.CreateEmptyTextLoader()); + updater.AddDocument(hostProject.Key, hostDocument1, EmptyTextLoader.Instance); + updater.AddDocument(hostProject.Key, hostDocument2, EmptyTextLoader.Instance); }); var droppedUri = new Uri("file:///c:/path/MyTagHelper.razor"); @@ -96,8 +96,8 @@ public async Task Handle_SimpleComponentWithChildFile_ReturnsResult() await projectManager.UpdateAsync(updater => { updater.AddProject(hostProject); - updater.AddDocument(hostProject.Key, hostDocument1, hostDocument1.CreateEmptyTextLoader()); - updater.AddDocument(hostProject.Key, hostDocument2, hostDocument2.CreateEmptyTextLoader()); + updater.AddDocument(hostProject.Key, hostDocument1, EmptyTextLoader.Instance); + updater.AddDocument(hostProject.Key, hostDocument2, EmptyTextLoader.Instance); }); var droppedUri = new Uri("file:///c:/path/MyTagHelper.razor"); @@ -161,8 +161,8 @@ public async Task Handle_ComponentWithRequiredAttribute_ReturnsResult() await projectManager.UpdateAsync(updater => { updater.AddProject(hostProject); - updater.AddDocument(hostProject.Key, hostDocument1, hostDocument1.CreateEmptyTextLoader()); - updater.AddDocument(hostProject.Key, hostDocument2, hostDocument2.CreateEmptyTextLoader()); + updater.AddDocument(hostProject.Key, hostDocument1, EmptyTextLoader.Instance); + updater.AddDocument(hostProject.Key, hostDocument2, EmptyTextLoader.Instance); }); var droppedUri = new Uri("file:///c:/path/fetchdata.razor"); @@ -321,8 +321,8 @@ public async Task Handle_ComponentWithNestedFiles_ReturnsResult() await projectManager.UpdateAsync(updater => { updater.AddProject(hostProject); - updater.AddDocument(hostProject.Key, hostDocument1, hostDocument1.CreateEmptyTextLoader()); - updater.AddDocument(hostProject.Key, hostDocument2, hostDocument2.CreateEmptyTextLoader()); + updater.AddDocument(hostProject.Key, hostDocument1, EmptyTextLoader.Instance); + updater.AddDocument(hostProject.Key, hostDocument2, EmptyTextLoader.Instance); }); var droppedUri1 = new Uri("file:///c:/path/fetchdata.razor.cs"); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/OpenDocumentGeneratorTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/OpenDocumentGeneratorTest.cs index e5720d2f968..23193fa1bfb 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/OpenDocumentGeneratorTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/OpenDocumentGeneratorTest.cs @@ -40,7 +40,7 @@ await projectManager.UpdateAsync(updater => { updater.AddProject(_hostProject1); updater.AddProject(_hostProject2); - updater.AddDocument(_hostProject1.Key, _documents[0], _documents[0].CreateEmptyTextLoader()); + updater.AddDocument(_hostProject1.Key, _documents[0], EmptyTextLoader.Instance); updater.OpenDocument(_hostProject1.Key, _documents[0].FilePath, SourceText.From(string.Empty)); }); @@ -50,7 +50,7 @@ await projectManager.UpdateAsync(updater => await projectManager.UpdateAsync(updater => { updater.RemoveDocument(_hostProject1.Key, _documents[0].FilePath); - updater.AddDocument(_hostProject2.Key, _documents[0], _documents[0].CreateEmptyTextLoader()); + updater.AddDocument(_hostProject2.Key, _documents[0], EmptyTextLoader.Instance); }); // Assert @@ -73,7 +73,7 @@ await projectManager.UpdateAsync(updater => updater.AddProject(_hostProject2); // Act - updater.AddDocument(_hostProject1.Key, _documents[0], _documents[0].CreateEmptyTextLoader()); + updater.AddDocument(_hostProject1.Key, _documents[0], EmptyTextLoader.Instance); }); // Assert @@ -92,7 +92,7 @@ await projectManager.UpdateAsync(updater => { updater.AddProject(_hostProject1); updater.AddProject(_hostProject2); - updater.AddDocument(_hostProject1.Key, _documents[0], _documents[0].CreateEmptyTextLoader()); + updater.AddDocument(_hostProject1.Key, _documents[0], EmptyTextLoader.Instance); // Act updater.UpdateDocumentText(_hostProject1.Key, _documents[0].FilePath, SourceText.From("new")); @@ -114,7 +114,7 @@ await projectManager.UpdateAsync(updater => { updater.AddProject(_hostProject1); updater.AddProject(_hostProject2); - updater.AddDocument(_hostProject1.Key, _documents[0], _documents[0].CreateEmptyTextLoader()); + updater.AddDocument(_hostProject1.Key, _documents[0], EmptyTextLoader.Instance); updater.OpenDocument(_hostProject1.Key, _documents[0].FilePath, SourceText.From(string.Empty)); // Act @@ -139,7 +139,7 @@ await projectManager.UpdateAsync(updater => { updater.AddProject(_hostProject1); updater.AddProject(_hostProject2); - updater.AddDocument(_hostProject1.Key, _documents[0], _documents[0].CreateEmptyTextLoader()); + updater.AddDocument(_hostProject1.Key, _documents[0], EmptyTextLoader.Instance); // Act updater.UpdateProjectWorkspaceState(_hostProject1.Key, @@ -162,7 +162,7 @@ await projectManager.UpdateAsync(updater => { updater.AddProject(_hostProject1); updater.AddProject(_hostProject2); - updater.AddDocument(_hostProject1.Key, _documents[0], _documents[0].CreateEmptyTextLoader()); + updater.AddDocument(_hostProject1.Key, _documents[0], EmptyTextLoader.Instance); updater.OpenDocument(_hostProject1.Key, _documents[0].FilePath, SourceText.From(string.Empty)); // Act diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectSystem/IProjectSnapshotManagerExtensionsTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectSystem/IProjectSnapshotManagerExtensionsTest.cs index 6ff58079f95..64ac49bbeda 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectSystem/IProjectSnapshotManagerExtensionsTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectSystem/IProjectSnapshotManagerExtensionsTest.cs @@ -42,7 +42,7 @@ await projectManager.UpdateAsync(updater => var hostProject = MiscFilesProject.HostProject with { Configuration = FallbackRazorConfiguration.Latest }; var hostDocument = new HostDocument(normalizedFilePath, targetPath: "document.cshtml"); - updater.AddDocument(hostProject.Key, hostDocument, hostDocument.CreateEmptyTextLoader()); + updater.AddDocument(hostProject.Key, hostDocument, EmptyTextLoader.Instance); }); // Act @@ -135,7 +135,7 @@ public async Task TryResolveAllProjects_OwnerProjectWithOthers_ReturnsTrue() { updater.AddProject(hostProject); updater.AddProject(otherHostProject); - updater.AddDocument(hostProject.Key, hostDocument, hostDocument.CreateEmptyTextLoader()); + updater.AddDocument(hostProject.Key, hostDocument, EmptyTextLoader.Instance); return updater.GetRequiredProject(hostProject.Key); }); @@ -163,7 +163,7 @@ public async Task TryResolveAllProjects_MiscellaneousOwnerProjectWithOthers_Retu var miscProject = await projectManager.UpdateAsync(updater => { - updater.AddDocument(miscFilesHostProject.Key, hostDocument, hostDocument.CreateEmptyTextLoader()); + updater.AddDocument(miscFilesHostProject.Key, hostDocument, EmptyTextLoader.Instance); updater.AddProject(hostProject); return updater.GetRequiredProject(miscFilesHostProject.Key); @@ -189,7 +189,7 @@ public async Task TryResolveAllProjects_OwnerProjectDifferentCasing_ReturnsTrue( var ownerProject = await projectManager.UpdateAsync(updater => { updater.AddProject(hostProject); - updater.AddDocument(hostProject.Key, hostDocument, hostDocument.CreateEmptyTextLoader()); + updater.AddDocument(hostProject.Key, hostDocument, EmptyTextLoader.Instance); return updater.GetRequiredProject(hostProject.Key); }); @@ -257,7 +257,7 @@ await projectManager.UpdateAsync(updater => await projectManager.UpdateAsync(updater => { - updater.AddDocument(hostProject.Key, hostDocument, hostDocument.CreateEmptyTextLoader()); + updater.AddDocument(hostProject.Key, hostDocument, EmptyTextLoader.Instance); }); return projectManager; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WorkspaceDiagnosticRefreshTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WorkspaceDiagnosticRefreshTest.cs index 1f203694b9b..33253217f7a 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WorkspaceDiagnosticRefreshTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WorkspaceDiagnosticRefreshTest.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.VisualStudio.LanguageServer.Protocol; using Moq; using Xunit; @@ -103,7 +104,7 @@ await projectSnapshotManager.UpdateAsync( await projectSnapshotManager.UpdateAsync( updater => { - updater.AddDocument(hostProject.Key, hostDocument, hostDocument.CreateEmptyTextLoader()); + updater.AddDocument(hostProject.Key, hostDocument, EmptyTextLoader.Instance); }); await testAccessor.WaitForRefreshAsync(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestHostDocument.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestHostDocument.cs index 326d4c0d7e0..5cbc8c2793a 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestHostDocument.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestHostDocument.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using Microsoft.AspNetCore.Razor.Utilities; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.ProjectSystem; namespace Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; @@ -20,7 +19,4 @@ public static HostDocument Create(HostProject hostProject, string documentFilePa return new(documentFilePath, targetPath); } - - public static TextLoader CreateEmptyTextLoader(this HostDocument hostDocument) - => TestMocks.CreateTextLoader(hostDocument.FilePath, string.Empty); } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DocumentGenerator/BackgroundDocumentGeneratorTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DocumentGenerator/BackgroundDocumentGeneratorTest.cs index dcf76dad550..d4a867ed175 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DocumentGenerator/BackgroundDocumentGeneratorTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DocumentGenerator/BackgroundDocumentGeneratorTest.cs @@ -12,7 +12,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; -using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common.VisualStudio; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor; @@ -189,8 +188,8 @@ await projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject1); updater.AddProject(s_hostProject2); - updater.AddDocument(s_hostProject1.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); - updater.AddDocument(s_hostProject1.Key, s_documents[1], s_documents[1].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject1.Key, s_documents[0], EmptyTextLoader.Instance); + updater.AddDocument(s_hostProject1.Key, s_documents[1], EmptyTextLoader.Instance); }); var project = projectManager.GetRequiredProject(s_hostProject1.Key); @@ -228,8 +227,8 @@ await projectManager.UpdateAsync(updater => { updater.AddProject(hostProject1); updater.AddProject(hostProject2); - updater.AddDocument(hostProject1.Key, hostDocument1, hostDocument1.CreateEmptyTextLoader()); - updater.AddDocument(hostProject1.Key, hostDocument2, hostDocument2.CreateEmptyTextLoader()); + updater.AddDocument(hostProject1.Key, hostDocument1, EmptyTextLoader.Instance); + updater.AddDocument(hostProject1.Key, hostDocument2, EmptyTextLoader.Instance); }); var project = projectManager.GetRequiredProject(hostProject1.Key); @@ -277,7 +276,7 @@ await projectManager.UpdateAsync(updater => updater.AddProject(s_hostProject1); for (var i = 0; i < documents.Length; i++) { - updater.AddDocument(s_hostProject1.Key, documents[i], documents[i].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject1.Key, documents[i], EmptyTextLoader.Instance); } }); @@ -321,8 +320,8 @@ public async Task RemoveDocument_ReparsesRelatedFiles() await projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject1); - updater.AddDocument(s_hostProject1.Key, TestProjectData.SomeProjectComponentFile1, TestProjectData.SomeProjectComponentFile1.CreateEmptyTextLoader()); - updater.AddDocument(s_hostProject1.Key, TestProjectData.SomeProjectImportFile, TestProjectData.SomeProjectImportFile.CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject1.Key, TestProjectData.SomeProjectComponentFile1, EmptyTextLoader.Instance); + updater.AddDocument(s_hostProject1.Key, TestProjectData.SomeProjectImportFile, EmptyTextLoader.Instance); }); using var generator = new TestBackgroundDocumentGenerator(projectManager, s_fallbackProjectManager, _dynamicFileInfoProvider, LoggerFactory) diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/CSharpVirtualDocumentFactoryTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/CSharpVirtualDocumentFactoryTest.cs index 83a159d8266..e57ca4de7b2 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/CSharpVirtualDocumentFactoryTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/CSharpVirtualDocumentFactoryTest.cs @@ -137,7 +137,7 @@ public async Task TryCreateMultipleFor_RazorLSPBuffer_ReturnsCSharpVirtualDocume await projectManager.UpdateAsync(updater => { updater.AddProject(hostProject); - updater.AddDocument(hostProject.Key, hostDocument, hostDocument.CreateEmptyTextLoader()); + updater.AddDocument(hostProject.Key, hostDocument, EmptyTextLoader.Instance); }); var factory = new CSharpVirtualDocumentFactory( @@ -187,10 +187,10 @@ public async Task TryCreateMultipleFor_RazorLSPBuffer_ReturnsMultipleCSharpVirtu await projectManager.UpdateAsync(updater => { updater.AddProject(hostProject1); - updater.AddDocument(hostProject1.Key, hostDocument1, hostDocument1.CreateEmptyTextLoader()); + updater.AddDocument(hostProject1.Key, hostDocument1, EmptyTextLoader.Instance); updater.AddProject(hostProject2); - updater.AddDocument(hostProject2.Key, hostDocument2, hostDocument2.CreateEmptyTextLoader()); + updater.AddDocument(hostProject2.Key, hostDocument2, EmptyTextLoader.Instance); }); var languageServerFeatureOptions = new TestLanguageServerFeatureOptions(includeProjectKeyInGeneratedFilePath: true); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs index 491c333d348..8fee5b90d06 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs @@ -96,7 +96,7 @@ await _projectManager.UpdateAsync(updater => // Act await _projectManager.UpdateAsync(updater => { - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); }); // Assert @@ -122,7 +122,7 @@ await _projectManager.UpdateAsync(updater => // Act await _projectManager.UpdateAsync(updater => { - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); }); // Assert @@ -150,7 +150,7 @@ await _projectManager.UpdateAsync(updater => // Act await _projectManager.UpdateAsync(updater => { - updater.AddDocument(s_hostProject.Key, s_documents[3], s_documents[3].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[3], EmptyTextLoader.Instance); }); // Assert @@ -171,7 +171,7 @@ public async Task AddDocument_IgnoresDuplicate() await _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject); - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); }); using var listener = _projectManager.ListenToNotifications(); @@ -179,7 +179,7 @@ await _projectManager.UpdateAsync(updater => // Act await _projectManager.UpdateAsync(updater => { - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); }); // Assert @@ -220,7 +220,7 @@ await _projectManager.UpdateAsync(updater => // Act await _projectManager.UpdateAsync(updater => { - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); }); // Assert @@ -275,7 +275,7 @@ await _projectManager.UpdateAsync(updater => // Act await _projectManager.UpdateAsync(updater => { - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); }); // Assert @@ -305,7 +305,7 @@ await _projectManager.UpdateAsync(updater => // Act await _projectManager.UpdateAsync(updater => { - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); }); // Assert @@ -320,9 +320,9 @@ public async Task RemoveDocument_RemovesDocument() await _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject); - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); - updater.AddDocument(s_hostProject.Key, s_documents[1], s_documents[1].CreateEmptyTextLoader()); - updater.AddDocument(s_hostProject.Key, s_documents[2], s_documents[2].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); + updater.AddDocument(s_hostProject.Key, s_documents[1], EmptyTextLoader.Instance); + updater.AddDocument(s_hostProject.Key, s_documents[2], EmptyTextLoader.Instance); }); using var listener = _projectManager.ListenToNotifications(); @@ -392,9 +392,9 @@ await _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject); updater.UpdateProjectWorkspaceState(s_hostProject.Key, _projectWorkspaceStateWithTagHelpers); - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); - updater.AddDocument(s_hostProject.Key, s_documents[1], s_documents[1].CreateEmptyTextLoader()); - updater.AddDocument(s_hostProject.Key, s_documents[2], s_documents[2].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); + updater.AddDocument(s_hostProject.Key, s_documents[1], EmptyTextLoader.Instance); + updater.AddDocument(s_hostProject.Key, s_documents[2], EmptyTextLoader.Instance); }); var originalTagHelpers = await _projectManager @@ -426,9 +426,9 @@ public async Task RemoveDocument_CachesProjectEngine() await _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject); - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); - updater.AddDocument(s_hostProject.Key, s_documents[1], s_documents[1].CreateEmptyTextLoader()); - updater.AddDocument(s_hostProject.Key, s_documents[2], s_documents[2].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); + updater.AddDocument(s_hostProject.Key, s_documents[1], EmptyTextLoader.Instance); + updater.AddDocument(s_hostProject.Key, s_documents[2], EmptyTextLoader.Instance); }); var project = _projectManager.GetRequiredProject(s_hostProject.Key); @@ -452,7 +452,7 @@ public async Task OpenDocument_UpdatesDocument() await _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject); - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); }); using var listener = _projectManager.ListenToNotifications(); @@ -484,7 +484,7 @@ public async Task CloseDocument_UpdatesDocument() await _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject); - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); updater.OpenDocument(s_hostProject.Key, s_documents[0].FilePath, _sourceText); }); @@ -520,7 +520,7 @@ public async Task CloseDocument_AcceptsChange() await _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject); - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); }); using var listener = _projectManager.ListenToNotifications(); @@ -551,7 +551,7 @@ public async Task UpdateDocumentText_Snapshot_UpdatesDocument() await _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject); - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); updater.OpenDocument(s_hostProject.Key, s_documents[0].FilePath, _sourceText); }); @@ -583,7 +583,7 @@ public async Task UpdateDocumentText_Loader_UpdatesDocument() await _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject); - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); updater.OpenDocument(s_hostProject.Key, s_documents[0].FilePath, _sourceText); }); @@ -761,7 +761,7 @@ public async Task UpdateProjectWorkspaceState_UpdateDocuments() await _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject); - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); }); // Act @@ -853,7 +853,7 @@ await _projectManager.UpdateAsync(updater => // Act await _projectManager.UpdateAsync(updater => { - updater.AddDocument(s_hostProject.Key, s_documents[0], s_documents[0].CreateEmptyTextLoader()); + updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance); }); // Assert From 4c9becf997d939be1504a54952dd3d990d3deb5e Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 16 Dec 2024 10:52:50 -0800 Subject: [PATCH 13/42] Clean up TestMocks.CreateTextLoader calls --- .../DocumentContextFactoryTest.cs | 4 +-- .../GeneratedDocumentPublisherTest.cs | 3 +-- .../TestMocks.cs | 26 +------------------ .../GeneratedDocumentTextLoaderTest.cs | 2 +- .../Tooltip/ProjectAvailabilityTests.cs | 14 +++++----- .../RazorProjectInfoDriverTest.cs | 12 ++++----- 6 files changed, 18 insertions(+), 43 deletions(-) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentContextFactoryTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentContextFactoryTest.cs index c33348ad09a..37253a7cd7c 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentContextFactoryTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentContextFactoryTest.cs @@ -65,7 +65,7 @@ public async Task TryCreateAsync_ResolvesContent() await _projectManager.UpdateAsync(updater => { - updater.AddDocument(MiscFilesProject.Key, hostDocument, TestMocks.CreateTextLoader(filePath, "")); + updater.AddDocument(MiscFilesProject.Key, hostDocument, EmptyTextLoader.Instance); }); var documentSnapshot = _projectManager @@ -120,7 +120,7 @@ public async Task TryCreateForOpenDocumentAsync_ResolvesContent() await _projectManager.UpdateAsync(updater => { - updater.AddDocument(MiscFilesProject.Key, hostDocument, TestMocks.CreateTextLoader(filePath, "")); + updater.AddDocument(MiscFilesProject.Key, hostDocument, EmptyTextLoader.Instance); }); var documentSnapshot = _projectManager diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentPublisherTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentPublisherTest.cs index 0b3dac2da5a..ace736b3552 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentPublisherTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentPublisherTest.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; @@ -326,7 +325,7 @@ await _projectManager.UpdateAsync(updater => // Act await _projectManager.UpdateAsync(updater => { - updater.CloseDocument(s_hostProject.Key, s_hostDocument.FilePath, TestMocks.CreateEmptyTextLoader()); + updater.CloseDocument(s_hostProject.Key, s_hostDocument.FilePath, EmptyTextLoader.Instance); }); publisher.PublishCSharp(s_hostProject.Key, s_hostDocument.FilePath, initialSourceText, 123); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestMocks.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestMocks.cs index 7a03653d290..58bcaa318fb 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestMocks.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestMocks.cs @@ -14,32 +14,8 @@ namespace Microsoft.AspNetCore.Razor.Test.Common; internal static class TestMocks { - public static TextLoader CreateEmptyTextLoader() - { - return CreateTextLoader(string.Empty, VersionStamp.Create()); - } - public static TextLoader CreateTextLoader(string text) - { - return CreateTextLoader(text, VersionStamp.Create()); - } - - public static TextLoader CreateTextLoader(string filePath, string text) - { - return CreateTextLoader(filePath, SourceText.From(text)); - } - - public static TextLoader CreateTextLoader(string filePath, SourceText text) - { - var mock = new StrictMock(); - - var textAndVersion = TextAndVersion.Create(text, VersionStamp.Create(), filePath); - - mock.Setup(x => x.LoadTextAndVersionAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(textAndVersion); - - return mock.Object; - } + => CreateTextLoader(text, VersionStamp.Create()); public static TextLoader CreateTextLoader(string text, VersionStamp version) => CreateTextLoader(SourceText.From(text), version); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs index 7c078b4425e..a90a512df2a 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs @@ -21,7 +21,7 @@ public async Task LoadAsync_SpecifiesEncoding() // Arrange var state = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, TestMocks.CreateEmptyTextLoader()); + .AddDocument(_hostDocument, EmptyTextLoader.Instance); var project = new ProjectSnapshot(state); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Tooltip/ProjectAvailabilityTests.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Tooltip/ProjectAvailabilityTests.cs index 18a1bbcbfe2..006885d5319 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Tooltip/ProjectAvailabilityTests.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Tooltip/ProjectAvailabilityTests.cs @@ -57,7 +57,7 @@ await projectManager.UpdateAsync(updater => { updater.AddProject(hostProject); updater.UpdateProjectWorkspaceState(hostProject.Key, projectWorkspaceState); - updater.AddDocument(hostProject.Key, hostDocument, TestMocks.CreateTextLoader(hostDocument.FilePath, text: "")); + updater.AddDocument(hostProject.Key, hostDocument, EmptyTextLoader.Instance); }); var solutionQueryOperations = projectManager.GetQueryOperations(); @@ -102,11 +102,11 @@ await projectManager.UpdateAsync(updater => { updater.AddProject(hostProject1); updater.UpdateProjectWorkspaceState(hostProject1.Key, projectWorkspaceState); - updater.AddDocument(hostProject1.Key, hostDocument, TestMocks.CreateTextLoader(hostDocument.FilePath, text: "")); + updater.AddDocument(hostProject1.Key, hostDocument, EmptyTextLoader.Instance); updater.AddProject(hostProject2); updater.UpdateProjectWorkspaceState(hostProject2.Key, projectWorkspaceState); - updater.AddDocument(hostProject2.Key, hostDocument, TestMocks.CreateTextLoader(hostDocument.FilePath, text: "")); + updater.AddDocument(hostProject2.Key, hostDocument, EmptyTextLoader.Instance); }); var solutionQueryOperations = projectManager.GetQueryOperations(); @@ -151,10 +151,10 @@ await projectManager.UpdateAsync(updater => { updater.AddProject(hostProject1); updater.UpdateProjectWorkspaceState(hostProject1.Key, projectWorkspaceState); - updater.AddDocument(hostProject1.Key, hostDocument, TestMocks.CreateTextLoader(hostDocument.FilePath, text: "")); + updater.AddDocument(hostProject1.Key, hostDocument, EmptyTextLoader.Instance); updater.AddProject(hostProject2); - updater.AddDocument(hostProject2.Key, hostDocument, TestMocks.CreateTextLoader(hostDocument.FilePath, text: "")); + updater.AddDocument(hostProject2.Key, hostDocument, EmptyTextLoader.Instance); }); var solutionQueryOperations = projectManager.GetQueryOperations(); @@ -195,10 +195,10 @@ public async Task GetProjectAvailabilityText_NotAvailableInAnyProject_ReturnsTex await projectManager.UpdateAsync(updater => { updater.AddProject(hostProject1); - updater.AddDocument(hostProject1.Key, hostDocument, TestMocks.CreateTextLoader(hostDocument.FilePath, text: "")); + updater.AddDocument(hostProject1.Key, hostDocument, EmptyTextLoader.Instance); updater.AddProject(hostProject2); - updater.AddDocument(hostProject2.Key, hostDocument, TestMocks.CreateTextLoader(hostDocument.FilePath, text: "")); + updater.AddDocument(hostProject2.Key, hostDocument, EmptyTextLoader.Instance); }); var solutionQueryOperations = projectManager.GetQueryOperations(); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/ProjectSystem/RazorProjectInfoDriverTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/ProjectSystem/RazorProjectInfoDriverTest.cs index 88a5b857945..3d235679229 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/ProjectSystem/RazorProjectInfoDriverTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/ProjectSystem/RazorProjectInfoDriverTest.cs @@ -42,10 +42,10 @@ public async Task ProcessesExistingProjectsDuringInitialization() await projectManager.UpdateAsync(static updater => { updater.AddProject(s_hostProject1); - updater.AddDocument(s_hostProject1.Key, s_hostDocument1, TestMocks.CreateTextLoader(s_hostDocument1.FilePath, "

Hello World

")); + updater.AddDocument(s_hostProject1.Key, s_hostDocument1, TestMocks.CreateTextLoader("

Hello World

")); updater.AddProject(s_hostProject2); - updater.AddDocument(s_hostProject2.Key, s_hostDocument2, TestMocks.CreateTextLoader(s_hostDocument2.FilePath, "

Hello World

")); + updater.AddDocument(s_hostProject2.Key, s_hostDocument2, TestMocks.CreateTextLoader("

Hello World

")); }); var (driver, testAccessor) = await CreateDriverAndInitializeAsync(projectManager); @@ -94,10 +94,10 @@ public async Task ProcessesProjectsAddedAfterInitialization() await projectManager.UpdateAsync(static updater => { updater.AddProject(s_hostProject1); - updater.AddDocument(s_hostProject1.Key, s_hostDocument1, TestMocks.CreateTextLoader(s_hostDocument1.FilePath, "

Hello World

")); + updater.AddDocument(s_hostProject1.Key, s_hostDocument1, TestMocks.CreateTextLoader("

Hello World

")); updater.AddProject(s_hostProject2); - updater.AddDocument(s_hostProject2.Key, s_hostDocument2, TestMocks.CreateTextLoader(s_hostDocument2.FilePath, "

Hello World

")); + updater.AddDocument(s_hostProject2.Key, s_hostDocument2, TestMocks.CreateTextLoader("

Hello World

")); }); await testAccessor.WaitUntilCurrentBatchCompletesAsync(); @@ -135,7 +135,7 @@ await projectManager.UpdateAsync(static updater => await projectManager.UpdateAsync(static updater => { - updater.AddDocument(s_hostProject1.Key, s_hostDocument1, TestMocks.CreateTextLoader(s_hostDocument1.FilePath, "

Hello World

")); + updater.AddDocument(s_hostProject1.Key, s_hostDocument1, TestMocks.CreateTextLoader("

Hello World

")); }); await testAccessor.WaitUntilCurrentBatchCompletesAsync(); @@ -205,7 +205,7 @@ await projectManager.UpdateAsync(static updater => await projectManager.UpdateAsync(static updater => { - updater.AddDocument(s_hostProject1.Key, s_hostDocument1, TestMocks.CreateTextLoader(s_hostDocument1.FilePath, "

Hello World

")); + updater.AddDocument(s_hostProject1.Key, s_hostDocument1, TestMocks.CreateTextLoader("

Hello World

")); }); await testAccessor.WaitUntilCurrentBatchCompletesAsync(); From a3b25f859727d29ff4a743b3770a810a403befe8 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 16 Dec 2024 10:59:55 -0800 Subject: [PATCH 14/42] Clean up calls to ProjectState.AddDocument with empty loaders --- .../ProjectSystem/ProjectState.cs | 2 +- .../DefaultProjectSnapshotTest.cs | 14 +- .../GeneratedDocumentTextLoaderTest.cs | 10 +- .../ProjectStateGeneratedOutputTest.cs | 26 +-- .../ProjectSystem/ProjectStateTest.cs | 176 +++++++++--------- .../RazorSpanMappingServiceTest.cs | 30 +-- 6 files changed, 131 insertions(+), 127 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs index a0995b73866..2c19e0f0bc9 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs @@ -212,7 +212,7 @@ RazorProjectEngine CreateProjectEngine() public VersionStamp ConfigurationVersion { get; } - public ProjectState AddDocument(HostDocument hostDocument) + public ProjectState AddEmptyDocument(HostDocument hostDocument) => AddDocument(hostDocument, EmptyTextLoader.Instance); public ProjectState AddDocument(HostDocument hostDocument, SourceText text) diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs index 70b615b1dd4..0b0e5c0dbc4 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs @@ -45,9 +45,9 @@ public void ProjectSnapshot_CachesDocumentSnapshots() { // Arrange var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[0], EmptyTextLoader.Instance) - .AddDocument(_documents[1], EmptyTextLoader.Instance) - .AddDocument(_documents[2], EmptyTextLoader.Instance); + .AddEmptyDocument(_documents[0]) + .AddEmptyDocument(_documents[1]) + .AddEmptyDocument(_documents[2]); var snapshot = new ProjectSnapshot(state); // Act @@ -66,7 +66,7 @@ public void GetRelatedDocuments_NonImportDocument_ReturnsEmpty() { // Arrange var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[0], EmptyTextLoader.Instance); + .AddEmptyDocument(_documents[0]); var snapshot = new ProjectSnapshot(state); var document = snapshot.GetRequiredDocument(_documents[0].FilePath); @@ -83,9 +83,9 @@ public void GetRelatedDocuments_ImportDocument_ReturnsRelated() { // Arrange var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_documents[0], EmptyTextLoader.Instance) - .AddDocument(_documents[1], EmptyTextLoader.Instance) - .AddDocument(TestProjectData.SomeProjectImportFile, EmptyTextLoader.Instance); + .AddEmptyDocument(_documents[0]) + .AddEmptyDocument(_documents[1]) + .AddEmptyDocument(TestProjectData.SomeProjectImportFile); var snapshot = new ProjectSnapshot(state); var document = snapshot.GetRequiredDocument(TestProjectData.SomeProjectImportFile.FilePath); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs index a90a512df2a..a26e25c66a1 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/GeneratedDocumentTextLoaderTest.cs @@ -12,20 +12,20 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; public class GeneratedDocumentTextLoaderTest(ITestOutputHelper testOutput) : WorkspaceTestBase(testOutput) { - private readonly HostProject _hostProject = TestProjectData.SomeProject; - private readonly HostDocument _hostDocument = TestProjectData.SomeProjectFile1; + private static readonly HostProject s_hostProject = TestProjectData.SomeProject; + private static readonly HostDocument s_hostDocument = TestProjectData.SomeProjectFile1; [Fact, WorkItem("https://github.com/dotnet/aspnetcore/issues/7997")] public async Task LoadAsync_SpecifiesEncoding() { // Arrange var state = ProjectState - .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, EmptyTextLoader.Instance); + .Create(s_hostProject, CompilerOptions, ProjectEngineFactoryProvider) + .AddEmptyDocument(s_hostDocument); var project = new ProjectSnapshot(state); - var document = project.GetRequiredDocument(_hostDocument.FilePath); + var document = project.GetRequiredDocument(s_hostDocument.FilePath); var loader = new GeneratedDocumentTextLoader(document, "file.cshtml"); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs index 0e824cce341..5918aa95d23 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs @@ -44,12 +44,12 @@ public async Task AddDocument_CachesOutput() // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, EmptyTextLoader.Instance); + .AddEmptyDocument(_hostDocument); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); // Act - var state = original.AddDocument(TestProjectData.AnotherProjectFile1, EmptyTextLoader.Instance); + var state = original.AddEmptyDocument(TestProjectData.AnotherProjectFile1); // Assert var (actualOutput, actualInputVersion) = await GetOutputAsync(state, _hostDocument, DisposalToken); @@ -63,12 +63,12 @@ public async Task AddDocument_Import_DoesNotCacheOutput() // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, EmptyTextLoader.Instance); + .AddEmptyDocument(_hostDocument); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); // Act - var state = original.AddDocument(TestProjectData.SomeProjectImportFile, EmptyTextLoader.Instance); + var state = original.AddEmptyDocument(TestProjectData.SomeProjectImportFile); // Assert var (actualOutput, actualInputVersion) = await GetOutputAsync(state, _hostDocument, DisposalToken); @@ -83,8 +83,8 @@ public async Task WithDocumentText_DoesNotCacheOutput() // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, EmptyTextLoader.Instance) - .AddDocument(TestProjectData.SomeProjectImportFile, EmptyTextLoader.Instance); + .AddEmptyDocument(_hostDocument) + .AddEmptyDocument(TestProjectData.SomeProjectImportFile); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -105,8 +105,8 @@ public async Task WithDocumentText_Import_DoesNotCacheOutput() // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, EmptyTextLoader.Instance) - .AddDocument(TestProjectData.SomeProjectImportFile, EmptyTextLoader.Instance); + .AddEmptyDocument(_hostDocument) + .AddEmptyDocument(TestProjectData.SomeProjectImportFile); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -127,8 +127,8 @@ public async Task RemoveDocument_Import_DoesNotCacheOutput() // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, EmptyTextLoader.Instance) - .AddDocument(TestProjectData.SomeProjectImportFile, EmptyTextLoader.Instance); + .AddEmptyDocument(_hostDocument) + .AddEmptyDocument(TestProjectData.SomeProjectImportFile); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -148,7 +148,7 @@ public async Task WithProjectWorkspaceState_CachesOutput_EvenWhenNewerProjectWor // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, EmptyTextLoader.Instance); + .AddEmptyDocument(_hostDocument); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -168,7 +168,7 @@ public async Task WithProjectWorkspaceState_TagHelperChange_DoesNotCacheOutput() // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, EmptyTextLoader.Instance); + .AddEmptyDocument(_hostDocument); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); @@ -213,7 +213,7 @@ public async Task WithHostProject_DoesNotCacheOutput() // Arrange var original = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, EmptyTextLoader.Instance); + .AddEmptyDocument(_hostDocument); var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs index 91d273d96d5..b50cce90066 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs @@ -63,7 +63,7 @@ public void ProjectState_AddDocument_ToEmpty() var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider); // Act - var newState = state.AddDocument(SomeProjectFile1); + var newState = state.AddEmptyDocument(SomeProjectFile1); // Assert Assert.NotEqual(state.Version, newState.Version); @@ -80,7 +80,7 @@ public async Task ProjectState_AddDocument_DocumentIsEmpty() var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider); // Act - var newState = state.AddDocument(SomeProjectFile1); + var newState = state.AddEmptyDocument(SomeProjectFile1); // Assert var text = await newState.Documents[SomeProjectFile1.FilePath].GetTextAsync(DisposalToken); @@ -93,11 +93,11 @@ public void ProjectState_AddDocument_ToProjectWithDocuments() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act - var newState = state.AddDocument(SomeProjectFile1); + var newState = state.AddEmptyDocument(SomeProjectFile1); // Assert Assert.NotEqual(state.Version, newState.Version); @@ -116,10 +116,10 @@ public void ProjectState_AddDocument_TracksImports() // Arrange & Act var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(SomeProjectFile1) - .AddDocument(SomeProjectFile2) - .AddDocument(SomeProjectNestedFile3) - .AddDocument(AnotherProjectNestedFile4); + .AddEmptyDocument(SomeProjectFile1) + .AddEmptyDocument(SomeProjectFile2) + .AddEmptyDocument(SomeProjectNestedFile3) + .AddEmptyDocument(AnotherProjectNestedFile4); // Assert Assert.Collection( @@ -154,13 +154,13 @@ public void ProjectState_AddDocument_TracksImports_AddImportFile() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(SomeProjectFile1) - .AddDocument(SomeProjectFile2) - .AddDocument(SomeProjectNestedFile3) - .AddDocument(AnotherProjectNestedFile4); + .AddEmptyDocument(SomeProjectFile1) + .AddEmptyDocument(SomeProjectFile2) + .AddEmptyDocument(SomeProjectNestedFile3) + .AddEmptyDocument(AnotherProjectNestedFile4); // Act - var newState = state.AddDocument(AnotherProjectImportFile); + var newState = state.AddEmptyDocument(AnotherProjectImportFile); // Assert Assert.Collection( @@ -195,11 +195,11 @@ public void ProjectState_AddDocument_RetainsComputedState() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act - var newState = state.AddDocument(SomeProjectFile1); + var newState = state.AddEmptyDocument(SomeProjectFile1); // Assert Assert.Same(state.ProjectEngine, newState.ProjectEngine); @@ -215,11 +215,11 @@ public void ProjectState_AddDocument_DuplicateIgnored() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act - var newState = state.AddDocument(new HostDocument(SomeProjectFile2.FilePath, "SomePath.cshtml")); + var newState = state.AddEmptyDocument(new HostDocument(SomeProjectFile2.FilePath, "SomePath.cshtml")); // Assert Assert.Same(state, newState); @@ -231,8 +231,8 @@ public async Task ProjectState_WithDocumentText_Loader() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act var newState = state.WithDocumentText(SomeProjectFile2.FilePath, s_textLoader); @@ -252,8 +252,8 @@ public async Task ProjectState_WithDocumentText_Snapshot() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act var newState = state.WithDocumentText(SomeProjectFile2.FilePath, s_text); @@ -273,8 +273,8 @@ public void ProjectState_WithDocumentText_Loader_RetainsComputedState() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act var newState = state.WithDocumentText(SomeProjectFile2.FilePath, s_textLoader); @@ -292,8 +292,8 @@ public void ProjectState_WithDocumentText_Snapshot_RetainsComputedState() // Arrange var original = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act var state = original.WithDocumentText(SomeProjectFile2.FilePath, s_text); @@ -311,8 +311,8 @@ public void ProjectState_WithDocumentText_Loader_NotFoundIgnored() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act var newState = state.WithDocumentText(SomeProjectFile1.FilePath, s_textLoader); @@ -327,8 +327,8 @@ public void ProjectState_WithDocumentText_Snapshot_NotFoundIgnored() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act var newState = state.WithDocumentText(SomeProjectFile1.FilePath, s_text); @@ -343,8 +343,8 @@ public void ProjectState_RemoveDocument_FromProjectWithDocuments() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act var newState = state.RemoveDocument(SomeProjectFile2.FilePath); @@ -364,10 +364,10 @@ public void ProjectState_RemoveDocument_TracksImports() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(SomeProjectFile1) - .AddDocument(SomeProjectFile2) - .AddDocument(SomeProjectNestedFile3) - .AddDocument(AnotherProjectNestedFile4); + .AddEmptyDocument(SomeProjectFile1) + .AddEmptyDocument(SomeProjectFile2) + .AddEmptyDocument(SomeProjectNestedFile3) + .AddEmptyDocument(AnotherProjectNestedFile4); // Act var newState = state.RemoveDocument(SomeProjectNestedFile3.FilePath); @@ -403,10 +403,10 @@ public void ProjectState_RemoveDocument_TracksImports_RemoveAllDocuments() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(SomeProjectFile1) - .AddDocument(SomeProjectFile2) - .AddDocument(SomeProjectNestedFile3) - .AddDocument(AnotherProjectNestedFile4); + .AddEmptyDocument(SomeProjectFile1) + .AddEmptyDocument(SomeProjectFile2) + .AddEmptyDocument(SomeProjectNestedFile3) + .AddEmptyDocument(AnotherProjectNestedFile4); // Act var newState = state @@ -426,8 +426,8 @@ public void ProjectState_RemoveDocument_RetainsComputedState() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act var newState = state.RemoveDocument(AnotherProjectNestedFile3.FilePath); @@ -445,8 +445,8 @@ public void ProjectState_RemoveDocument_NotFoundIgnored() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act var newState = state.RemoveDocument(SomeProjectFile1.FilePath); @@ -461,8 +461,8 @@ public void ProjectState_WithHostProject_ConfigurationChange_UpdatesConfiguratio // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act var newState = state.WithHostProject(s_hostProject with { Configuration = FallbackRazorConfiguration.MVC_1_0 }); @@ -487,8 +487,8 @@ public void ProjectState_WithHostProject_RootNamespaceChange_UpdatesConfiguratio // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act var newState = state.WithHostProject(s_hostProject with { RootNamespace = "ChangedRootNamespace" }); @@ -504,8 +504,8 @@ public void ProjectState_WithHostProject_NoConfigurationChange_Ignored() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act var newState = state.WithHostProject(s_hostProject); @@ -520,8 +520,8 @@ public void ProjectState_WithConfiguration_Change_UpdatesAllDocuments() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(SomeProjectFile2) - .AddDocument(AnotherProjectNestedFile3); + .AddEmptyDocument(SomeProjectFile2) + .AddEmptyDocument(AnotherProjectNestedFile3); var documentPathSet = state.Documents.Keys.ToHashSet(FilePathNormalizingComparer.Instance); @@ -549,7 +549,7 @@ public void ProjectState_WithConfiguration_Change_ResetsImportMap() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(SomeProjectFile1); + .AddEmptyDocument(SomeProjectFile1); // Act var newState = state.WithHostProject(s_hostProject with { Configuration = FallbackRazorConfiguration.MVC_1_0 }); @@ -566,8 +566,8 @@ public void ProjectState_WithProjectWorkspaceState_Changed() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); var newWorkspaceState = ProjectWorkspaceState.Create(s_projectWorkspaceState.TagHelpers, LanguageVersion.CSharp6); @@ -593,8 +593,8 @@ public void ProjectState_WithProjectWorkspaceState_Changed_TagHelpersChanged() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act var newState = state.WithProjectWorkspaceState(ProjectWorkspaceState.Default); @@ -618,8 +618,8 @@ public void ProjectState_WithProjectWorkspaceState_IdenticalState_Caches() { // Arrange var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(AnotherProjectNestedFile3) - .AddDocument(SomeProjectFile2); + .AddEmptyDocument(AnotherProjectNestedFile3) + .AddEmptyDocument(SomeProjectFile2); // Act var newState = state.WithProjectWorkspaceState(ProjectWorkspaceState.Create(state.TagHelpers, state.CSharpLanguageVersion)); @@ -634,8 +634,8 @@ public void ProjectState_WithProjectWorkspaceState_UpdatesAllDocuments() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(SomeProjectFile2) - .AddDocument(AnotherProjectNestedFile3); + .AddEmptyDocument(SomeProjectFile2) + .AddEmptyDocument(AnotherProjectNestedFile3); var documentPathSet = state.Documents.Keys.ToHashSet(FilePathNormalizingComparer.Instance); @@ -663,15 +663,15 @@ public void ProjectState_AddImportDocument_UpdatesRelatedDocuments() { // Arrange var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(SomeProjectFile1) - .AddDocument(SomeProjectFile2) - .AddDocument(SomeProjectNestedFile3) - .AddDocument(AnotherProjectNestedFile4); + .AddEmptyDocument(SomeProjectFile1) + .AddEmptyDocument(SomeProjectFile2) + .AddEmptyDocument(SomeProjectNestedFile3) + .AddEmptyDocument(AnotherProjectNestedFile4); var documentPathSet = state.Documents.Keys.ToHashSet(FilePathNormalizingComparer.Instance); // Act - var newState = state.AddDocument(AnotherProjectImportFile); + var newState = state.AddEmptyDocument(AnotherProjectImportFile); // Assert Assert.NotEqual(state.Version, newState.Version); @@ -695,15 +695,15 @@ public void ProjectState_AddImportDocument_UpdatesRelatedDocuments_Nested() { // Arrange var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(SomeProjectFile1) - .AddDocument(SomeProjectFile2) - .AddDocument(SomeProjectNestedFile3) - .AddDocument(AnotherProjectNestedFile4); + .AddEmptyDocument(SomeProjectFile1) + .AddEmptyDocument(SomeProjectFile2) + .AddEmptyDocument(SomeProjectNestedFile3) + .AddEmptyDocument(AnotherProjectNestedFile4); var documentPathSet = state.Documents.Keys.ToHashSet(FilePathNormalizingComparer.Instance); // Act - var newState = state.AddDocument(AnotherProjectNestedImportFile); + var newState = state.AddEmptyDocument(AnotherProjectNestedImportFile); // Assert Assert.NotEqual(state.Version, newState.Version); @@ -732,11 +732,11 @@ public void ProjectState_WithImportDocumentText_UpdatesRelatedDocuments_TextLoad { // Arrange var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(SomeProjectFile1) - .AddDocument(SomeProjectFile2) - .AddDocument(SomeProjectNestedFile3) - .AddDocument(AnotherProjectNestedFile4) - .AddDocument(AnotherProjectNestedImportFile); + .AddEmptyDocument(SomeProjectFile1) + .AddEmptyDocument(SomeProjectFile2) + .AddEmptyDocument(SomeProjectNestedFile3) + .AddEmptyDocument(AnotherProjectNestedFile4) + .AddEmptyDocument(AnotherProjectNestedImportFile); var documentPathSet = state.Documents.Keys.ToHashSet(FilePathNormalizingComparer.Instance); @@ -774,11 +774,11 @@ public void ProjectState_WithImportDocumentText_UpdatesRelatedDocuments_Snapshot { // Arrange var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(SomeProjectFile1) - .AddDocument(SomeProjectFile2) - .AddDocument(SomeProjectNestedFile3) - .AddDocument(AnotherProjectNestedFile4) - .AddDocument(AnotherProjectNestedImportFile); + .AddEmptyDocument(SomeProjectFile1) + .AddEmptyDocument(SomeProjectFile2) + .AddEmptyDocument(SomeProjectNestedFile3) + .AddEmptyDocument(AnotherProjectNestedFile4) + .AddEmptyDocument(AnotherProjectNestedImportFile); var documentPathSet = state.Documents.Keys.ToHashSet(FilePathNormalizingComparer.Instance); @@ -817,11 +817,11 @@ public void ProjectState_RemoveImportDocument_UpdatesRelatedDocuments() // Arrange var state = ProjectState .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) - .AddDocument(SomeProjectFile1) - .AddDocument(SomeProjectFile2) - .AddDocument(SomeProjectNestedFile3) - .AddDocument(AnotherProjectNestedFile4) - .AddDocument(AnotherProjectNestedImportFile); + .AddEmptyDocument(SomeProjectFile1) + .AddEmptyDocument(SomeProjectFile2) + .AddEmptyDocument(SomeProjectNestedFile3) + .AddEmptyDocument(AnotherProjectNestedFile4) + .AddEmptyDocument(AnotherProjectNestedImportFile); var documentPathSet = state.Documents.Keys.ToHashSet(FilePathNormalizingComparer.Instance); var relatedDocumentPaths = state.ImportsToRelatedDocuments[AnotherProjectNestedImportFile.TargetPath]; diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorSpanMappingServiceTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorSpanMappingServiceTest.cs index cefeb3a9d9e..116a9fb53e0 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorSpanMappingServiceTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorSpanMappingServiceTest.cs @@ -41,7 +41,8 @@ public async Task TryGetMappedSpans_SpanMatchesSourceMapping_ReturnsTrue() var span = new TextSpan(generated.GeneratedCode.IndexOf(symbol, StringComparison.Ordinal), symbol.Length); // Act - var result = RazorSpanMappingService.TryGetMappedSpans(span, await document.GetTextAsync(DisposalToken), generated, out var mappedLinePositionSpan, out var mappedSpan); + var text = await document.GetTextAsync(DisposalToken); + var result = RazorSpanMappingService.TryGetMappedSpans(span, text, generated, out var mappedLinePositionSpan, out var mappedSpan); // Assert Assert.True(result); @@ -53,15 +54,15 @@ public async Task TryGetMappedSpans_SpanMatchesSourceMapping_ReturnsTrue() public async Task TryGetMappedSpans_SpanMatchesSourceMappingAndPosition_ReturnsTrue() { // Arrange - var sourceText = SourceText.From(@" + var code = @" @SomeProperty @SomeProperty @SomeProperty -"); +"; var state = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, TestMocks.CreateTextLoader(sourceText)); + .AddDocument(_hostDocument, TestMocks.CreateTextLoader(code)); var project = new ProjectSnapshot(state); var document = project.GetRequiredDocument(_hostDocument.FilePath); @@ -74,7 +75,8 @@ public async Task TryGetMappedSpans_SpanMatchesSourceMappingAndPosition_ReturnsT var span = new TextSpan(generated.GeneratedCode.IndexOf(symbol, generated.GeneratedCode.IndexOf(symbol, StringComparison.Ordinal) + symbol.Length, StringComparison.Ordinal), symbol.Length); // Act - var result = RazorSpanMappingService.TryGetMappedSpans(span, await document.GetTextAsync(DisposalToken), generated, out var mappedLinePositionSpan, out var mappedSpan); + var text = await document.GetTextAsync(DisposalToken); + var result = RazorSpanMappingService.TryGetMappedSpans(span, text, generated, out var mappedLinePositionSpan, out var mappedSpan); // Assert Assert.True(result); @@ -86,15 +88,15 @@ public async Task TryGetMappedSpans_SpanMatchesSourceMappingAndPosition_ReturnsT public async Task TryGetMappedSpans_SpanWithinSourceMapping_ReturnsTrue() { // Arrange - var sourceText = SourceText.From(@" + var code = @" @{ var x = SomeClass.SomeProperty; } -"); +"; var state = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, TestMocks.CreateTextLoader(sourceText)); + .AddDocument(_hostDocument, TestMocks.CreateTextLoader(code)); var project = new ProjectSnapshot(state); var document = project.GetRequiredDocument(_hostDocument.FilePath); @@ -106,7 +108,8 @@ public async Task TryGetMappedSpans_SpanWithinSourceMapping_ReturnsTrue() var span = new TextSpan(generated.GeneratedCode.IndexOf(symbol, StringComparison.Ordinal), symbol.Length); // Act - var result = RazorSpanMappingService.TryGetMappedSpans(span, await document.GetTextAsync(DisposalToken), generated, out var mappedLinePositionSpan, out var mappedSpan); + var text = await document.GetTextAsync(DisposalToken); + var result = RazorSpanMappingService.TryGetMappedSpans(span, text, generated, out var mappedLinePositionSpan, out var mappedSpan); // Assert Assert.True(result); @@ -118,15 +121,15 @@ public async Task TryGetMappedSpans_SpanWithinSourceMapping_ReturnsTrue() public async Task TryGetMappedSpans_SpanOutsideSourceMapping_ReturnsFalse() { // Arrange - var sourceText = SourceText.From(@" + var code = @" @{ var x = SomeClass.SomeProperty; } -"); +"; var state = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) - .AddDocument(_hostDocument, TestMocks.CreateTextLoader(sourceText)); + .AddDocument(_hostDocument, TestMocks.CreateTextLoader(code)); var project = new ProjectSnapshot(state); var document = project.GetRequiredDocument(_hostDocument.FilePath); @@ -138,7 +141,8 @@ public async Task TryGetMappedSpans_SpanOutsideSourceMapping_ReturnsFalse() var span = new TextSpan(generated.GeneratedCode.IndexOf(symbol, StringComparison.Ordinal), symbol.Length); // Act - var result = RazorSpanMappingService.TryGetMappedSpans(span, await document.GetTextAsync(DisposalToken), generated, out _, out _); + var text = await document.GetTextAsync(DisposalToken); + var result = RazorSpanMappingService.TryGetMappedSpans(span, text, generated, out _, out _); // Assert Assert.False(result); From 18ad48f5491c4f0486b8fb31eec88766d9f491b3 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 16 Dec 2024 11:42:00 -0800 Subject: [PATCH 15/42] Augment Assumed class with new helpers and message parameters --- .../Assumed.cs | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Assumed.cs b/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Assumed.cs index 5b32f5523e9..ef4a65b9cff 100644 --- a/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Assumed.cs +++ b/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Assumed.cs @@ -10,25 +10,61 @@ namespace Microsoft.AspNetCore.Razor; internal static class Assumed { + [DebuggerStepThrough] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void NonNull( + [NotNull] this T value, + [CallerArgumentExpression(nameof(value))] string? valueExpression = null, + [CallerFilePath] string? path = null, + [CallerLineNumber] int line = 0) + where T : class? + { + if (value is null) + { + ThrowInvalidOperation($"Expected '{valueExpression}' to be non-null.", path, line); + } + } + + [DebuggerStepThrough] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void NonNull( + [NotNull] this T? value, + [CallerArgumentExpression(nameof(value))] string? valueExpression = null, + [CallerFilePath] string? path = null, + [CallerLineNumber] int line = 0) + where T : struct + { + if (value is null) + { + ThrowInvalidOperation($"Expected '{valueExpression}' to be non-null.", path, line); + } + } + + [DebuggerStepThrough] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void False( [DoesNotReturnIf(true)] bool condition, + string? message = null, [CallerFilePath] string? path = null, [CallerLineNumber] int line = 0) { if (condition) { - ThrowInvalidOperation(SR.Expected_condition_to_be_false, path, line); + ThrowInvalidOperation(message ?? SR.Expected_condition_to_be_false, path, line); } } + [DebuggerStepThrough] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void True( [DoesNotReturnIf(false)] bool condition, + string? message = null, [CallerFilePath] string? path = null, [CallerLineNumber] int line = 0) { if (!condition) { - ThrowInvalidOperation(SR.Expected_condition_to_be_true, path, line); + ThrowInvalidOperation(message ?? SR.Expected_condition_to_be_true, path, line); } } From ae4e86c0d66786ff3391dc11dbb0bc9ec5757150 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 16 Dec 2024 12:19:25 -0800 Subject: [PATCH 16/42] Introduce AsyncLazy variation from Roslyn This change brings Roslyn's AsyncLazy implementation to Razor, but removes the synchronous computation path, since Razor doesn't need it. --- .../CapabilitiesManager.cs | 2 +- .../Threading/TaskExtensions.cs | 32 -- .../Threading/AsyncLazyTests.cs | 117 +++++ .../Threading/AsyncLazy.cs | 22 + .../Threading/AsyncLazy`1.cs | 468 ++++++++++++++++++ .../Threading/TaskExtensions.cs | 41 ++ 6 files changed, 649 insertions(+), 33 deletions(-) create mode 100644 src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/Threading/AsyncLazyTests.cs create mode 100644 src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/AsyncLazy.cs create mode 100644 src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/AsyncLazy`1.cs create mode 100644 src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/TaskExtensions.cs diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CapabilitiesManager.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CapabilitiesManager.cs index 46635c91ffb..ee8593a3bb1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CapabilitiesManager.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CapabilitiesManager.cs @@ -19,7 +19,7 @@ internal sealed class CapabilitiesManager : IInitializeManager _initializeParamsTaskSource; - private readonly AsyncLazy _lazyRootPath; + private readonly VisualStudio.Threading.AsyncLazy _lazyRootPath; public bool HasInitialized => _initializeParamsTaskSource.Task.IsCompleted; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Threading/TaskExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Threading/TaskExtensions.cs index db3db984e7a..36038bec832 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Threading/TaskExtensions.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Threading/TaskExtensions.cs @@ -7,38 +7,6 @@ namespace Microsoft.AspNetCore.Razor.Threading; internal static class TaskExtensions { - /// - /// Asserts the passed has already been completed. - /// - /// - /// This is useful for a specific case: sometimes you might be calling an API that is "sometimes" async, and you're - /// calling it from a synchronous method where you know it should have completed synchronously. This is an easy - /// way to assert that while silencing any compiler complaints. - /// - public static void VerifyCompleted(this Task task) - { - Assumed.True(task.IsCompleted); - - // Propagate any exceptions that may have been thrown. - task.GetAwaiter().GetResult(); - } - - /// - /// Asserts the passed has already been completed. - /// - /// - /// This is useful for a specific case: sometimes you might be calling an API that is "sometimes" async, and you're - /// calling it from a synchronous method where you know it should have completed synchronously. This is an easy - /// way to assert that while silencing any compiler complaints. - /// - public static TResult VerifyCompleted(this Task task) - { - Assumed.True(task.IsCompleted); - - // Propagate any exceptions that may have been thrown. - return task.GetAwaiter().GetResult(); - } - /// /// Asserts the passed has already been completed. /// diff --git a/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/Threading/AsyncLazyTests.cs b/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/Threading/AsyncLazyTests.cs new file mode 100644 index 00000000000..020be105bb3 --- /dev/null +++ b/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/Threading/AsyncLazyTests.cs @@ -0,0 +1,117 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Threading; +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test.Threading; + +// NOTE: This code is copied and modified from dotnet/roslyn: +// https://github.com/dotnet/roslyn/blob/1715a86114c4f8b6ea2d68db00dc2502da8237d6/src/Workspaces/CoreTest/UtilityTest/AsyncLazyTests.cs#L17 + +#pragma warning disable xUnit1031 // Do not use blocking task operations in test method + +public class AsyncLazyTests +{ + [Fact] + public void GetValueAsyncReturnsCompletedTaskIfAsyncComputationCompletesImmediately() + { + // Note, this test may pass even if GetValueAsync posted a task to the thread pool, since the + // current thread may context switch out and allow the thread pool to complete the task before + // we check the state. However, a failure here definitely indicates a bug in AsyncLazy. + var lazy = AsyncLazy.Create(static c => Task.FromResult(5)); + var t = lazy.GetValueAsync(CancellationToken.None); + Assert.Equal(TaskStatus.RanToCompletion, t.Status); + Assert.Equal(5, t.VerifyCompleted()); + } + + [Fact] + public void GetValueAsyncThrowsCorrectExceptionDuringCancellation() + { + // NOTE: since GetValueAsync will inline the call to the async computation, the GetValueAsync call will throw + // immediately instead of returning a task that transitions to the cancelled state + // A call to GetValueAsync with a token that is cancelled should throw an OperationCancelledException, but it's + // important to make sure the correct token is cancelled. It should be cancelled with the token passed + // to GetValue, not the cancellation that was thrown by the computation function + + using var computeFunctionRunning = new ManualResetEvent(initialState: false); + + var lazy = AsyncLazy.Create( + static (computeFunctionRunning, c) => + { + computeFunctionRunning.Set(); + while (true) + { + c.ThrowIfCancellationRequested(); + } + }, + arg: computeFunctionRunning); + + using var cancellationTokenSource = new CancellationTokenSource(); + + // Create a task that will cancel the request once it's started + Task.Run(() => + { + computeFunctionRunning.WaitOne(); + cancellationTokenSource.Cancel(); + }); + + try + { + lazy.GetValueAsync(cancellationTokenSource.Token); + Assert.Fail($"{nameof(AsyncLazy<>.GetValueAsync)} did not throw an exception."); + } + catch (OperationCanceledException oce) + { + Assert.Equal(cancellationTokenSource.Token, oce.CancellationToken); + } + } + + [Fact] + public void GetValueAsyncThatIsCancelledReturnsTaskCancelledWithCorrectToken() + { + using var cancellationTokenSource = new CancellationTokenSource(); + + var lazy = AsyncLazy.Create(static (cancellationTokenSource, c) => Task.Run((Func)(() => + { + cancellationTokenSource.Cancel(); + while (true) + { + c.ThrowIfCancellationRequested(); + } + }), c), arg: cancellationTokenSource); + + var task = lazy.GetValueAsync(cancellationTokenSource.Token); + + // Now wait until the task completes + try + { + task.Wait(); + Assert.Fail($"{nameof(AsyncLazy<>.GetValueAsync)} did not throw an exception."); + } + catch (AggregateException ex) + { + var operationCancelledException = (OperationCanceledException)ex.Flatten().InnerException!; + Assert.Equal(cancellationTokenSource.Token, operationCancelledException.CancellationToken); + } + } + + [Fact] + public async Task AwaitingProducesCorrectException() + { + var exception = new ArgumentException(); + + var lazy = AsyncLazy.Create(async c => + { + await Task.Yield(); + throw exception; + }); + + var actual = await Assert.ThrowsAsync(async () => await lazy.GetValueAsync(CancellationToken.None)); + + Assert.Same(exception, actual); + } +} diff --git a/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/AsyncLazy.cs b/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/AsyncLazy.cs new file mode 100644 index 00000000000..95376fa95fc --- /dev/null +++ b/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/AsyncLazy.cs @@ -0,0 +1,22 @@ +// 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.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.Razor.Threading; + +internal static class AsyncLazy +{ + public static AsyncLazy Create(Func> asynchronousComputeFunction, TArg arg) + => AsyncLazy.Create(asynchronousComputeFunction, arg); + + public static AsyncLazy Create(Func> asynchronousComputeFunction) + => Create( + asynchronousComputeFunction: static (asynchronousComputeFunction, cancellationToken) => asynchronousComputeFunction(cancellationToken), + arg: asynchronousComputeFunction); + + public static AsyncLazy Create(T value) + => AsyncLazy.Create(value); +} diff --git a/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/AsyncLazy`1.cs b/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/AsyncLazy`1.cs new file mode 100644 index 00000000000..8678c6de8a9 --- /dev/null +++ b/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/AsyncLazy`1.cs @@ -0,0 +1,468 @@ +// 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.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.Razor.Threading; + +// NOTE: This code is copied and modified from dotnet/roslyn: +// https://github.com/dotnet/roslyn/blob/192c9ccc0e43791e8145c7b4cc09e665993551fc/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AsyncLazy%601.cs + +// Of particular note, the synchronous computation feature has been removed. Roslyn needs this to provide +// a GetValue() method to support synchronous requests for syntax trees. Razor does not need this, so the +// implementation can be simplified. + +internal abstract class AsyncLazy +{ + public abstract bool TryGetValue([MaybeNullWhen(false)] out T result); + public abstract Task GetValueAsync(CancellationToken cancellationToken); + + public static AsyncLazy Create( + Func> asynchronousComputeFunction, + TArg data) + => AsyncLazyImpl.CreateImpl(asynchronousComputeFunction, data); + + public static AsyncLazy Create(T value) + => AsyncLazyImpl.CreateImpl(value); + + /// + /// Represents a value that can be retrieved asynchronously by many clients. The value will be + /// computed on-demand the moment the first client asks for it. While being computed, more clients + /// can request the value. As long as there are outstanding clients the underlying computation will + /// proceed. If all outstanding clients cancel their request then the underlying value computation + /// will be cancelled as well. + /// + /// Creators of an can specify whether the result of the computation is + /// cached for future requests or not. Choosing to not cache means the computation function is kept + /// alive, whereas caching means the value (but not function) is kept alive once complete. + /// + private sealed class AsyncLazyImpl : AsyncLazy + { + /// + /// The underlying function that starts an asynchronous computation of the resulting value. + /// Null'ed out once we've computed the result and we've been asked to cache it. Otherwise, + /// it is kept around in case the value needs to be computed again. + /// + private Func>? _asynchronousComputeFunction; + + /// + /// The Task that holds the cached result. + /// + private Task? _cachedResult; + + /// + /// Mutex used to protect reading and writing to all mutable objects and fields. Traces indicate that there's + /// negligible contention on this lock (and on any particular async-lazy in general), hence we can save some + /// memory by using ourselves as the lock, even though this may inhibit cancellation. Work done while holding + /// the lock should be kept to a minimum. + /// + private object SyncObject => this; + + /// + /// The hash set of all currently outstanding asynchronous requests. Null if there are no requests, + /// and will never be empty. + /// + private HashSet? _requests; + + /// + /// If an asynchronous request is active, the CancellationTokenSource that allows for + /// cancelling the underlying computation. + /// + private CancellationTokenSource? _asynchronousComputationCancellationSource; + + /// + /// Whether a computation is active or queued on any thread, whether synchronous or + /// asynchronous. + /// + private bool _computationActive; + + private TData _data; + + /// + /// Creates an AsyncLazy that always returns the value, analogous to . + /// + private AsyncLazyImpl(T value) + { + _cachedResult = Task.FromResult(value); + _data = default!; + } + + /// + /// Creates an AsyncLazy that supports both asynchronous computation and inline synchronous + /// computation. + /// + /// A function called to start the asynchronous + /// computation. This function should be cheap and non-blocking. + /// + private AsyncLazyImpl( + Func> asynchronousComputeFunction, + TData data) + { + ArgHelper.ThrowIfNull(asynchronousComputeFunction); + _asynchronousComputeFunction = asynchronousComputeFunction; + _data = data; + } + + public static AsyncLazy CreateImpl(T value) + => new AsyncLazyImpl(value); + + public static AsyncLazy CreateImpl( + Func> asynchronousComputeFunction, + TData data) + { + return new AsyncLazyImpl(asynchronousComputeFunction, data); + } + + #region Lock Wrapper for Invariant Checking + + /// + /// Takes the lock for this object and if acquired validates the invariants of this class. + /// + private WaitThatValidatesInvariants TakeLock(CancellationToken cancellationToken) + { + Assumed.False(Monitor.IsEntered(SyncObject), "Attempt to take the lock while already holding it!"); + + cancellationToken.ThrowIfCancellationRequested(); + Monitor.Enter(SyncObject); + AssertInvariants_NoLock(); + return new WaitThatValidatesInvariants(this); + } + + private readonly struct WaitThatValidatesInvariants(AsyncLazyImpl asyncLazy) : IDisposable + { + public void Dispose() + { + asyncLazy.AssertInvariants_NoLock(); + Assumed.True(Monitor.IsEntered(asyncLazy.SyncObject)); + Monitor.Exit(asyncLazy.SyncObject); + } + } + + private void AssertInvariants_NoLock() + { + // Invariant #1: thou shalt never have an asynchronous computation running without it + // being considered a computation + Assumed.False(_asynchronousComputationCancellationSource != null && + !_computationActive); + + // Invariant #2: thou shalt never waste memory holding onto empty HashSets + Assumed.False(_requests != null && + _requests.Count == 0); + + // Invariant #3: thou shalt never have an request if there is not + // something trying to compute it + Assumed.False(_requests != null && + !_computationActive); + + // Invariant #4: thou shalt never have a cached value and any computation function + Assumed.False(_cachedResult != null && + (_asynchronousComputeFunction != null)); + } + + #endregion + + public override bool TryGetValue([MaybeNullWhen(false)] out T result) + { + // No need to lock here since this is only a fast check to + // see if the result is already computed. + if (_cachedResult != null) + { + result = _cachedResult.Result; + return true; + } + + result = default; + return false; + } + + private Request CreateNewRequest_NoLock() + { + _requests ??= []; + + var request = new Request(); + _requests.Add(request); + return request; + } + + public override Task GetValueAsync(CancellationToken cancellationToken) + { + // Optimization: if we're already cancelled, do not pass go + if (cancellationToken.IsCancellationRequested) + { + return Task.FromCanceled(cancellationToken); + } + + // Avoid taking the lock if a cached value is available + var cachedResult = _cachedResult; + if (cachedResult != null) + { + return cachedResult; + } + + Request request; + AsynchronousComputationToStart? newAsynchronousComputation = null; + + using (TakeLock(cancellationToken)) + { + // If cached, get immediately + if (_cachedResult != null) + { + return _cachedResult; + } + + request = CreateNewRequest_NoLock(); + + // If we have either synchronous or asynchronous work current in flight, we don't need to do anything. + // Otherwise, we shall start an asynchronous computation for this + if (!_computationActive) + { + newAsynchronousComputation = RegisterAsynchronousComputation_NoLock(); + } + } + + // We now have the request counted for, register for cancellation. It is critical this is + // done outside the lock, as our registration may immediately fire and we want to avoid the + // reentrancy + request.RegisterForCancellation(OnAsynchronousRequestCancelled, cancellationToken); + + if (newAsynchronousComputation != null) + { + StartAsynchronousComputation(newAsynchronousComputation.Value, requestToCompleteSynchronously: request, callerCancellationToken: cancellationToken); + } + + return request.Task; + } + + private AsynchronousComputationToStart RegisterAsynchronousComputation_NoLock() + { + Assumed.False(_computationActive); + Assumed.NonNull(_asynchronousComputeFunction); + + _asynchronousComputationCancellationSource = new CancellationTokenSource(); + _computationActive = true; + + return new(_asynchronousComputeFunction, _asynchronousComputationCancellationSource); + } + + private readonly struct AsynchronousComputationToStart( + Func> asynchronousComputeFunction, + CancellationTokenSource cancellationTokenSource) + { + public readonly Func> AsynchronousComputeFunction = asynchronousComputeFunction; + public readonly CancellationTokenSource CancellationTokenSource = cancellationTokenSource; + } + + private void StartAsynchronousComputation( + AsynchronousComputationToStart computationToStart, + Request? requestToCompleteSynchronously, + CancellationToken callerCancellationToken) + { + var cancellationToken = computationToStart.CancellationTokenSource.Token; + + // DO NOT ACCESS ANY FIELDS OR STATE BEYOND THIS POINT. Since this function + // runs unsynchronized, it's possible that during this function this request + // might be cancelled, and then a whole additional request might start and + // complete inline, and cache the result. By grabbing state before we check + // the cancellation token, we can be assured that we are only operating on + // a state that was complete. + try + { + cancellationToken.ThrowIfCancellationRequested(); + + var task = computationToStart.AsynchronousComputeFunction(_data, cancellationToken); + + // As an optimization, if the task is already completed, mark the + // request as being completed as well. + // + // Note: we want to do this before we do the .ContinueWith below. That way, + // when the async call to CompleteWithTask runs, it sees that we've already + // completed and can bail immediately. + if (requestToCompleteSynchronously != null && task.IsCompleted) + { + using (TakeLock(CancellationToken.None)) + { + task = GetCachedValueAndCacheThisValueIfNoneCached_NoLock(task); + } + + requestToCompleteSynchronously.CompleteFromTask(task); + } + + // We avoid creating a full closure just to pass the token along + // Also, use TaskContinuationOptions.ExecuteSynchronously so that we inline + // the continuation if asynchronousComputeFunction completes synchronously + task.ContinueWith( + (t, s) => CompleteWithTask(t, ((CancellationTokenSource)s!).Token), + computationToStart.CancellationTokenSource, + cancellationToken, + TaskContinuationOptions.ExecuteSynchronously, + TaskScheduler.Default); + } + catch (OperationCanceledException e) when (e.CancellationToken == cancellationToken) + { + // The underlying computation cancelled with the correct token, but we must ourselves ensure that the caller + // on our stack gets an OperationCanceledException thrown with the right token + callerCancellationToken.ThrowIfCancellationRequested(); + + // We can only be here if the computation was cancelled, which means all requests for the value + // must have been cancelled. Therefore, the ThrowIfCancellationRequested above must have thrown + // because that token from the requester was cancelled. + Assumed.Unreachable(); + } + } + + private void CompleteWithTask(Task task, CancellationToken cancellationToken) + { + IEnumerable requestsToComplete; + + using (TakeLock(cancellationToken)) + { + // If the underlying computation was cancelled, then all state was already updated in OnAsynchronousRequestCancelled + // and there is no new work to do here. We *must* use the local one since this completion may be running far after + // the background computation was cancelled and a new one might have already been enqueued. We must do this + // check here under the lock to ensure proper synchronization with OnAsynchronousRequestCancelled. + cancellationToken.ThrowIfCancellationRequested(); + + // The computation is complete, so get all requests to complete and null out the list. We'll create another one + // later if it's needed + requestsToComplete = _requests ?? (IEnumerable)[]; + _requests = null; + + // The computations are done + _asynchronousComputationCancellationSource = null; + _computationActive = false; + task = GetCachedValueAndCacheThisValueIfNoneCached_NoLock(task); + } + + // Complete the requests outside the lock. It's not necessary to do this (none of this is touching any shared state) + // but there's no reason to hold the lock so we could reduce any theoretical lock contention. + foreach (var requestToComplete in requestsToComplete) + { + requestToComplete.CompleteFromTask(task); + } + } + + [SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods", Justification = "This is a Task wrapper, not an asynchronous method.")] + private Task GetCachedValueAndCacheThisValueIfNoneCached_NoLock(Task task) + { + if (_cachedResult != null) + { + return _cachedResult; + } + + if (task.Status == TaskStatus.RanToCompletion) + { + // Hold onto the completed task. We can get rid of the computation functions for good + _cachedResult = task; + + _asynchronousComputeFunction = null; + _data = default!; + } + + return task; + } + + private void OnAsynchronousRequestCancelled(object? state) + { + var request = (Request)state!; + CancellationTokenSource? cancellationTokenSource = null; + + using (TakeLock(CancellationToken.None)) + { + // Now try to remove it. It's possible that requests may already be null. You could + // imagine that cancellation was requested, but before we could acquire the lock + // here the computation completed and the entire CompleteWithTask synchronized + // block ran. In that case, the requests collection may already be null, or it + // (even scarier!) may have been replaced with another collection because another + // computation has started. + if (_requests != null) + { + if (_requests.Remove(request)) + { + if (_requests.Count == 0) + { + _requests = null; + + if (_asynchronousComputationCancellationSource != null) + { + cancellationTokenSource = _asynchronousComputationCancellationSource; + _asynchronousComputationCancellationSource = null; + _computationActive = false; + } + } + } + } + } + + request.Cancel(); + cancellationTokenSource?.Cancel(); + } + + /// + /// This inherits from to avoid allocating two objects when we can just use one. + /// The public surface area of should probably be avoided in favor of the public + /// methods on this class for correct behavior. + /// + private sealed class Request : TaskCompletionSource + { + /// + /// The associated with this request. This field will be initialized before + /// any cancellation is observed from the token. + /// + private CancellationToken _cancellationToken; + private CancellationTokenRegistration _cancellationTokenRegistration; + + // We want to always run continuations asynchronously. Running them synchronously could result in deadlocks: + // if we're looping through a bunch of Requests and completing them one by one, and the continuation for the + // first Request was then blocking waiting for a later Request, we would hang. It also could cause performance + // issues. If the first request then consumes a lot of CPU time, we're not letting other Requests complete that + // could use another CPU core at the same time. + public Request() + : base(TaskCreationOptions.RunContinuationsAsynchronously) + { + } + + public void RegisterForCancellation(Action callback, CancellationToken cancellationToken) + { + _cancellationToken = cancellationToken; + _cancellationTokenRegistration = cancellationToken.Register(callback, this); + } + + public void CompleteFromTask(Task task) + { + // As an optimization, we'll cancel the request even we did get a value for it. + // That way things abort sooner. + if (task.IsCanceled || _cancellationToken.IsCancellationRequested) + { + Cancel(); + } + else if (task.IsFaulted) + { + // TrySetException wraps its argument in an AggregateException, so we pass the inner exceptions from + // the antecedent to avoid wrapping in two layers of AggregateException. + Assumed.NonNull(task.Exception); + if (task.Exception.InnerExceptions.Count > 0) + { + TrySetException(task.Exception.InnerExceptions); + } + else + { + TrySetException(task.Exception); + } + } + else + { + TrySetResult(task.Result); + } + + _cancellationTokenRegistration.Dispose(); + } + + public void Cancel() + => TrySetCanceled(_cancellationToken); + } + } +} diff --git a/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/TaskExtensions.cs b/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/TaskExtensions.cs new file mode 100644 index 00000000000..9adf4ba2a91 --- /dev/null +++ b/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/TaskExtensions.cs @@ -0,0 +1,41 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.Razor.Threading; + +internal static class TaskExtensions +{ + /// + /// Asserts the passed has already been completed. + /// + /// + /// This is useful for a specific case: sometimes you might be calling an API that is "sometimes" async, and you're + /// calling it from a synchronous method where you know it should have completed synchronously. This is an easy + /// way to assert that while silencing any compiler complaints. + /// + public static void VerifyCompleted(this Task task) + { + Assumed.True(task.IsCompleted); + + // Propagate any exceptions that may have been thrown. + task.GetAwaiter().GetResult(); + } + + /// + /// Asserts the passed has already been completed. + /// + /// + /// This is useful for a specific case: sometimes you might be calling an API that is "sometimes" async, and you're + /// calling it from a synchronous method where you know it should have completed synchronously. This is an easy + /// way to assert that while silencing any compiler complaints. + /// + public static TResult VerifyCompleted(this Task task) + { + Assumed.True(task.IsCompleted); + + // Propagate any exceptions that may have been thrown. + return task.GetAwaiter().GetResult(); + } +} From 813e448eec78c19d4ea5dc8f99f1993025ecf0f3 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 16 Dec 2024 14:28:40 -0800 Subject: [PATCH 17/42] Introduce ITextAndVersionSource to manage text loading in DocumentState --- .../ProjectSystem/DocumentState.cs | 107 ++++++++---------- .../Sources/ConstantTextAndVersionSource.cs | 25 ++++ .../Sources/ITextAndVersionSource.cs | 16 +++ .../Sources/LoadableTextAndVersionSource.cs | 25 ++++ 4 files changed, 112 insertions(+), 61 deletions(-) create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/ConstantTextAndVersionSource.cs create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/ITextAndVersionSource.cs create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/LoadableTextAndVersionSource.cs diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs index 3d9da43a1a1..bb53fb183d8 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs @@ -7,53 +7,52 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis.Razor.ProjectSystem.Sources; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; internal sealed partial class DocumentState { - private static readonly LoadTextOptions s_loadTextOptions = new(SourceHashAlgorithm.Sha256); - public HostDocument HostDocument { get; } public int Version { get; } - private TextAndVersion? _textAndVersion; - private readonly TextLoader _textLoader; + private readonly ITextAndVersionSource _textAndVersionSource; private ComputedStateTracker? _computedState; private DocumentState( HostDocument hostDocument, - TextAndVersion? textAndVersion, - TextLoader? textLoader) + ITextAndVersionSource textAndVersionSource) { HostDocument = hostDocument; Version = 1; - - _textAndVersion = textAndVersion; - _textLoader = textLoader ?? EmptyTextLoader.Instance; + _textAndVersionSource = textAndVersionSource; } private DocumentState( DocumentState oldState, - TextAndVersion? textAndVersion, - TextLoader? textLoader, + ITextAndVersionSource textAndVersionSource, ComputedStateTracker? computedState = null) { HostDocument = oldState.HostDocument; Version = oldState.Version + 1; + _textAndVersionSource = textAndVersionSource; - _textAndVersion = textAndVersion; - _textLoader = textLoader ?? EmptyTextLoader.Instance; _computedState = computedState; } public static DocumentState Create(HostDocument hostDocument, SourceText text) - => new(hostDocument, TextAndVersion.Create(text, VersionStamp.Create()), textLoader: null); + => new(hostDocument, CreateTextAndVersionSource(text)); + + public static DocumentState Create(HostDocument hostDocument, TextLoader textLoader) + => new(hostDocument, CreateTextAndVersionSource(textLoader)); + + private static ConstantTextAndVersionSource CreateTextAndVersionSource(SourceText text, VersionStamp? version = null) + => new(text, version ?? VersionStamp.Create()); - public static DocumentState Create(HostDocument hostDocument, TextLoader loader) - => new(hostDocument, textAndVersion: null, loader); + private static LoadableTextAndVersionSource CreateTextAndVersionSource(TextLoader textLoader) + => new(textLoader); private ComputedStateTracker ComputedState => _computedState ??= InterlockedOperations.Initialize(ref _computedState, new ComputedStateTracker()); @@ -71,20 +70,22 @@ public bool TryGetGeneratedOutputAndVersion(out (RazorCodeDocument output, Versi return ComputedState.GetGeneratedOutputAndVersionAsync(project, document, cancellationToken); } + public bool TryGetTextAndVersion([NotNullWhen(true)] out TextAndVersion? result) + => _textAndVersionSource.TryGetValue(out result); + public ValueTask GetTextAndVersionAsync(CancellationToken cancellationToken) - { - return TryGetTextAndVersion(out var result) - ? new(result) - : LoadTextAndVersionAsync(_textLoader, cancellationToken); + => _textAndVersionSource.GetValueAsync(cancellationToken); - async ValueTask LoadTextAndVersionAsync(TextLoader loader, CancellationToken cancellationToken) + public bool TryGetText([NotNullWhen(true)] out SourceText? result) + { + if (TryGetTextAndVersion(out var textAndVersion)) { - var textAndVersion = await loader - .LoadTextAndVersionAsync(s_loadTextOptions, cancellationToken) - .ConfigureAwait(false); - - return InterlockedOperations.Initialize(ref _textAndVersion, textAndVersion); + result = textAndVersion.Text; + return true; } + + result = null; + return false; } public ValueTask GetTextAsync(CancellationToken cancellationToken) @@ -101,64 +102,48 @@ async ValueTask GetTextCoreAsync(CancellationToken cancellationToken } } - public ValueTask GetTextVersionAsync(CancellationToken cancellationToken) - { - return TryGetTextVersion(out var version) - ? new(version) - : GetTextVersionCoreAsync(cancellationToken); - - async ValueTask GetTextVersionCoreAsync(CancellationToken cancellationToken) - { - var textAsVersion = await GetTextAndVersionAsync(cancellationToken).ConfigureAwait(false); - - return textAsVersion.Version; - } - } - - public bool TryGetTextAndVersion([NotNullWhen(true)] out TextAndVersion? result) - { - result = _textAndVersion; - return result is not null; - } - - public bool TryGetText([NotNullWhen(true)] out SourceText? result) + public bool TryGetTextVersion(out VersionStamp result) { if (TryGetTextAndVersion(out var textAndVersion)) { - result = textAndVersion.Text; + result = textAndVersion.Version; return true; } - result = null; + result = default; return false; } - public bool TryGetTextVersion(out VersionStamp result) + public ValueTask GetTextVersionAsync(CancellationToken cancellationToken) { - if (TryGetTextAndVersion(out var textAndVersion)) + return TryGetTextVersion(out var version) + ? new(version) + : GetTextVersionCoreAsync(cancellationToken); + + async ValueTask GetTextVersionCoreAsync(CancellationToken cancellationToken) { - result = textAndVersion.Version; - return true; - } + var textAsVersion = await GetTextAndVersionAsync(cancellationToken).ConfigureAwait(false); - result = default; - return false; + return textAsVersion.Version; + } } public DocumentState WithConfigurationChange() - => new(this, _textAndVersion, _textLoader, computedState: null); + => new(this, _textAndVersionSource, computedState: null); public DocumentState WithImportsChange() - => new(this, _textAndVersion, _textLoader, new ComputedStateTracker(_computedState)); + => new(this, _textAndVersionSource, new(_computedState)); public DocumentState WithProjectWorkspaceStateChange() - => new(this, _textAndVersion, _textLoader, new ComputedStateTracker(_computedState)); + => new(this, _textAndVersionSource, new(_computedState)); public DocumentState WithText(SourceText text, VersionStamp textVersion) - => new(this, TextAndVersion.Create(text, textVersion), textLoader: null, computedState: null); + => new(this, CreateTextAndVersionSource(text, textVersion), computedState: null); public DocumentState WithTextLoader(TextLoader textLoader) - => new(this, textAndVersion: null, textLoader, computedState: null); + => ReferenceEquals(textLoader, _textAndVersionSource.TextLoader) + ? this + : new(this, CreateTextAndVersionSource(textLoader), computedState: null); internal static async Task GenerateCodeDocumentAsync( IDocumentSnapshot document, diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/ConstantTextAndVersionSource.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/ConstantTextAndVersionSource.cs new file mode 100644 index 00000000000..62c79957d78 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/ConstantTextAndVersionSource.cs @@ -0,0 +1,25 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Razor.ProjectSystem.Sources; + +internal sealed class ConstantTextAndVersionSource(SourceText text, VersionStamp version) : ITextAndVersionSource +{ + private readonly TextAndVersion _textAndVersion = TextAndVersion.Create(text, version); + + public TextLoader? TextLoader => null; + + public ValueTask GetValueAsync(CancellationToken cancellationToken) + => new(_textAndVersion); + + public bool TryGetValue([NotNullWhen(true)] out TextAndVersion? result) + { + result = _textAndVersion; + return true; + } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/ITextAndVersionSource.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/ITextAndVersionSource.cs new file mode 100644 index 00000000000..d26d0e9d311 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/ITextAndVersionSource.cs @@ -0,0 +1,16 @@ +// 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.Threading; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.Razor.ProjectSystem.Sources; + +internal interface ITextAndVersionSource +{ + TextLoader? TextLoader { get; } + + bool TryGetValue([NotNullWhen(true)] out TextAndVersion? result); + ValueTask GetValueAsync(CancellationToken cancellationToken); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/LoadableTextAndVersionSource.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/LoadableTextAndVersionSource.cs new file mode 100644 index 00000000000..6c9a081b647 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/LoadableTextAndVersionSource.cs @@ -0,0 +1,25 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Threading; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Razor.ProjectSystem.Sources; + +internal sealed class LoadableTextAndVersionSource(TextLoader textLoader) : ITextAndVersionSource +{ + public TextLoader? TextLoader => textLoader; + + private static readonly LoadTextOptions s_loadTextOptions = new(SourceHashAlgorithm.Sha256); + + private readonly AsyncLazy _lazy = AsyncLazy.Create(ct => textLoader.LoadTextAndVersionAsync(s_loadTextOptions, ct)); + + public ValueTask GetValueAsync(CancellationToken cancellationToken) + => new(_lazy.GetValueAsync(cancellationToken)); + + public bool TryGetValue([NotNullWhen(true)] out TextAndVersion? result) + => _lazy.TryGetValue(out result); +} From b508614abb0da3ea940fe40c1d5ba629c2194421 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 16 Dec 2024 14:33:37 -0800 Subject: [PATCH 18/42] Don't update ProjectState when DocumentState doesn't --- .../ProjectSystem/ProjectState.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs index 2c19e0f0bc9..32f738cfaf3 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs @@ -321,8 +321,15 @@ public ProjectState WithDocumentText(string documentFilePath, TextLoader textLoa private ProjectState WithDocumentText(DocumentState state, Func transformer) { + var newState = transformer(state); + + if (ReferenceEquals(this, newState)) + { + return this; + } + var hostDocument = state.HostDocument; - var documents = Documents.SetItem(hostDocument.FilePath, transformer(state)); + var documents = Documents.SetItem(hostDocument.FilePath, newState); // If this document is an import, update its related documents. documents = UpdateRelatedDocuments(hostDocument, documents); From 1f9144f32337d317d06954205cdb16ef413c17cb Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 16 Dec 2024 16:19:51 -0800 Subject: [PATCH 19/42] Move DocumentState helper methods for compilation --- .../ProjectSystem/CompilationHelpers.cs | 40 +++++++++++++++++++ .../ProjectSystem/DocumentSnapshot.cs | 2 +- .../DocumentState.ComputedStateTracker.cs | 2 +- .../ProjectSystem/DocumentState.cs | 29 -------------- .../ProjectSystem/RemoteDocumentSnapshot.cs | 2 +- 5 files changed, 43 insertions(+), 32 deletions(-) create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs new file mode 100644 index 00000000000..2bcf671cf9b --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs @@ -0,0 +1,40 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Immutable; +using System.Threading.Tasks; +using System.Threading; +using Microsoft.AspNetCore.Razor.Language; + +namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; + +internal static class CompilationHelpers +{ + internal static async Task GenerateCodeDocumentAsync( + IDocumentSnapshot document, + RazorProjectEngine projectEngine, + bool forceRuntimeCodeGeneration, + CancellationToken cancellationToken) + { + var importItems = await ImportHelpers.GetImportItemsAsync(document, projectEngine, cancellationToken).ConfigureAwait(false); + + return await GenerateCodeDocumentAsync( + document, projectEngine, importItems, forceRuntimeCodeGeneration, cancellationToken).ConfigureAwait(false); + } + + internal static async Task GenerateCodeDocumentAsync( + IDocumentSnapshot document, + RazorProjectEngine projectEngine, + ImmutableArray imports, + bool forceRuntimeCodeGeneration, + CancellationToken cancellationToken) + { + var importSources = ImportHelpers.GetImportSources(imports, projectEngine); + var tagHelpers = await document.Project.GetTagHelpersAsync(cancellationToken).ConfigureAwait(false); + var source = await ImportHelpers.GetSourceAsync(document, projectEngine, cancellationToken).ConfigureAwait(false); + + return forceRuntimeCodeGeneration + ? projectEngine.Process(source, document.FileKind, importSources, tagHelpers) + : projectEngine.ProcessDesignTime(source, document.FileKind, importSources, tagHelpers); + } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs index 6943e4badc7..7748ba0eb92 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs @@ -83,7 +83,7 @@ public async ValueTask GetGeneratedOutputAsync(bool forceDesi } private Task GetDesignTimeGeneratedOutputAsync(CancellationToken cancellationToken) - => DocumentState.GenerateCodeDocumentAsync(this, Project.GetProjectEngine(), forceRuntimeCodeGeneration: false, cancellationToken); + => CompilationHelpers.GenerateCodeDocumentAsync(this, Project.GetProjectEngine(), forceRuntimeCodeGeneration: false, cancellationToken); /// /// Retrieves a cached Roslyn from the generated C# document. diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs index 3215dfbc3d9..7c70a69f0a4 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs @@ -211,7 +211,7 @@ static void PropagateToTaskCompletionSource( } var forceRuntimeCodeGeneration = project.CompilerOptions.IsFlagSet(RazorCompilerOptions.ForceRuntimeCodeGeneration); - var codeDocument = await GenerateCodeDocumentAsync(document, project.GetProjectEngine(), importItems, forceRuntimeCodeGeneration, cancellationToken).ConfigureAwait(false); + var codeDocument = await CompilationHelpers.GenerateCodeDocumentAsync(document, project.GetProjectEngine(), importItems, forceRuntimeCodeGeneration, cancellationToken).ConfigureAwait(false); return (codeDocument, inputVersion); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs index bb53fb183d8..7d9766866ca 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; @@ -144,32 +143,4 @@ public DocumentState WithTextLoader(TextLoader textLoader) => ReferenceEquals(textLoader, _textAndVersionSource.TextLoader) ? this : new(this, CreateTextAndVersionSource(textLoader), computedState: null); - - internal static async Task GenerateCodeDocumentAsync( - IDocumentSnapshot document, - RazorProjectEngine projectEngine, - bool forceRuntimeCodeGeneration, - CancellationToken cancellationToken) - { - var importItems = await ImportHelpers.GetImportItemsAsync(document, projectEngine, cancellationToken).ConfigureAwait(false); - - return await GenerateCodeDocumentAsync( - document, projectEngine, importItems, forceRuntimeCodeGeneration, cancellationToken).ConfigureAwait(false); - } - - private static async Task GenerateCodeDocumentAsync( - IDocumentSnapshot document, - RazorProjectEngine projectEngine, - ImmutableArray imports, - bool forceRuntimeCodeGeneration, - CancellationToken cancellationToken) - { - var importSources = ImportHelpers.GetImportSources(imports, projectEngine); - var tagHelpers = await document.Project.GetTagHelpersAsync(cancellationToken).ConfigureAwait(false); - var source = await ImportHelpers.GetSourceAsync(document, projectEngine, cancellationToken).ConfigureAwait(false); - - return forceRuntimeCodeGeneration - ? projectEngine.Process(source, document.FileKind, importSources, tagHelpers) - : projectEngine.ProcessDesignTime(source, document.FileKind, importSources, tagHelpers); - } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs index be35efe147e..57c8c3bfc92 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs @@ -100,7 +100,7 @@ async Task GetRazorCodeDocumentAsync(bool forceRuntimeCodeGen var projectEngine = await ProjectSnapshot.GetProjectEngine_CohostOnlyAsync(cancellationToken).ConfigureAwait(false); - return await DocumentState + return await CompilationHelpers .GenerateCodeDocumentAsync(this, projectEngine, forceRuntimeCodeGeneration, cancellationToken) .ConfigureAwait(false); } From df3e21c1e1d8bb7be6392c98b22d0253e8a2e5ca Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 17 Dec 2024 11:59:21 -0800 Subject: [PATCH 20/42] Remove DocumentState.ComputedStateTracker This change removes the DocumentState.ComputedTracker, and DocumentState no longer weakly caches it's generated RazorCodeDocument. In addition, IDocumentSnapshot.GetGeneratedOutputAsync(...) has been modified to remove the forceDesignTimeGeneratedOutput parameter and the remove project/document snapshot implementations now use Razor's Roslyn-based AsyncLazy. --- .../Threading/SemaphoreSlimExtensions.cs | 56 ++++ .../CodeActions/CodeActionsService.cs | 2 +- .../Extensions/RazorCodeDocumentExtensions.cs | 22 ++ .../Formatting/FormattingContext.cs | 3 +- .../Formatting/RazorFormattingService.cs | 15 +- .../ProjectSystem/CodeDocumentGenerator.cs | 33 +++ .../ProjectSystem/CompilationHelpers.cs | 57 +++- .../ProjectSystem/DocumentSnapshot.cs | 83 ++---- .../DocumentState.ComputedStateTracker.cs | 245 ------------------ .../ProjectSystem/DocumentState.cs | 45 +--- .../ProjectSystem/IDesignTimeCodeGenerator.cs | 13 + .../ProjectSystem/IDocumentSnapshot.cs | 4 +- .../IDocumentSnapshotExtensions.cs | 7 - .../ProjectSystem/ProjectSnapshot.cs | 59 +++++ .../Sources/GeneratedOutputSource.cs | 45 ++++ .../RemoteDocumentMappingService.cs | 1 - .../ProjectSystem/RemoteDocumentSnapshot.cs | 127 ++++----- .../ProjectSystem/RemoteProjectSnapshot.cs | 74 +++--- .../ProjectSystem/RemoteSnapshotManager.cs | 3 +- .../CSharp/CSharpCodeActionProviderTest.cs | 2 +- ...TypeAccessibilityCodeActionProviderTest.cs | 2 +- .../Html/HtmlCodeActionProviderTest.cs | 2 +- ...nentAccessibilityCodeActionProviderTest.cs | 2 +- ...tractToCodeBehindCodeActionProviderTest.cs | 2 +- .../CodeDocumentReferenceHolderTest.cs | 12 +- .../FormattingContentValidationPassTest.cs | 2 +- .../FormattingDiagnosticValidationPassTest.cs | 3 +- .../Formatting_NetFx/FormattingTestBase.cs | 101 +++++--- .../Hover/HoverEndpointTest.cs | 2 +- .../Semantic/SemanticTokensTest.cs | 2 +- .../ProjectSystem/TestDocumentSnapshot.cs | 8 +- .../DefaultDocumentSnapshotTest.cs | 2 +- .../ProjectStateGeneratedOutputTest.cs | 134 ++++------ .../Cohost/CohostEndpointTestBase.cs | 2 +- 34 files changed, 564 insertions(+), 608 deletions(-) create mode 100644 src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Threading/SemaphoreSlimExtensions.cs create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CodeDocumentGenerator.cs delete mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDesignTimeCodeGenerator.cs create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Threading/SemaphoreSlimExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Threading/SemaphoreSlimExtensions.cs new file mode 100644 index 00000000000..89ff9360f54 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Threading/SemaphoreSlimExtensions.cs @@ -0,0 +1,56 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Utilities; + +namespace Microsoft.AspNetCore.Razor.Threading; + +internal static class SemaphoreSlimExtensions +{ + public static SemaphoreDisposer DisposableWait(this SemaphoreSlim semaphore, CancellationToken cancellationToken = default) + { + semaphore.Wait(cancellationToken); + return new SemaphoreDisposer(semaphore); + } + + public static async ValueTask DisposableWaitAsync(this SemaphoreSlim semaphore, CancellationToken cancellationToken = default) + { + await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + return new SemaphoreDisposer(semaphore); + } + + [NonCopyable] + internal struct SemaphoreDisposer : IDisposable + { + private SemaphoreSlim? _semaphore; + + public SemaphoreDisposer(SemaphoreSlim semaphore) + { + _semaphore = semaphore; + } + + public void Dispose() + { + // Officially, Dispose() being called more than once is allowable, but in this case + // if that were to ever happen that means something is very, very wrong. Since it's an internal + // type, better to be strict. + + // Nulling this out also means it's a bit easier to diagnose some async deadlocks; if you have an + // async deadlock where a SemaphoreSlim is held but you're unsure why, as long all the users of the + // SemaphoreSlim used the Disposable helpers, you can search memory and find the instance that + // is pointing to the SemaphoreSlim that hasn't nulled out this field yet; in that case you know + // that's holding the lock and can figure out who is holding that SemaphoreDisposer. + var semaphoreToDispose = Interlocked.Exchange(ref _semaphore, null); + + if (semaphoreToDispose is null) + { + throw new ObjectDisposedException($"Somehow a {nameof(SemaphoreDisposer)} is being disposed twice."); + } + + semaphoreToDispose.Release(); + } + } +} 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 beabb31bd21..e334c974231 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/CodeActionsService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/CodeActionsService.cs @@ -138,7 +138,7 @@ void ConvertCodeActionsToSumType(ImmutableArray codeA public async Task GetCSharpCodeActionsRequestAsync(IDocumentSnapshot documentSnapshot, VSCodeActionParams request, CancellationToken cancellationToken) { // For C# we have to map the ranges to the generated document - var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(forceDesignTimeGeneratedOutput: false, cancellationToken).ConfigureAwait(false); + var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(cancellationToken).ConfigureAwait(false); var csharpDocument = codeDocument.GetCSharpDocument(); if (!_documentMappingService.TryMapToGeneratedDocumentRange(csharpDocument, request.Range, out var projectedRange)) { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs index af23b206d4e..9bca7ed94dd 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs @@ -6,8 +6,11 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Threading; using Microsoft.AspNetCore.Razor.Language.Intermediate; using Microsoft.AspNetCore.Razor.Language.Legacy; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Workspaces; @@ -19,6 +22,7 @@ internal static class RazorCodeDocumentExtensions { private static readonly object s_csharpSourceTextKey = new(); private static readonly object s_htmlSourceTextKey = new(); + private static readonly object s_csharpSyntaxTreeKey = new(); public static SourceText GetCSharpSourceText(this RazorCodeDocument document) { @@ -48,6 +52,24 @@ public static SourceText GetHtmlSourceText(this RazorCodeDocument document) return sourceText.AssumeNotNull(); } + /// + /// Retrieves a cached Roslyn from the generated C# document. + /// If a tree has not yet been cached, a new one will be parsed and added to the cache. + /// + public static SyntaxTree GetOrParseCSharpSyntaxTree(this RazorCodeDocument document, CancellationToken cancellationToken) + { + if (!document.Items.TryGetValue(s_csharpSyntaxTreeKey, out SyntaxTree? syntaxTree)) + { + var csharpText = document.GetCSharpSourceText(); + syntaxTree = CSharpSyntaxTree.ParseText(csharpText, cancellationToken: cancellationToken); + document.Items[s_csharpSyntaxTreeKey] = syntaxTree; + + return syntaxTree; + } + + return syntaxTree.AssumeNotNull(); + } + public static bool TryGetGeneratedDocument( this RazorCodeDocument codeDocument, Uri generatedDocumentUri, diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingContext.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingContext.cs index 1366be999f9..b1c7ae7f9bd 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingContext.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingContext.cs @@ -226,7 +226,8 @@ public async Task WithTextAsync(SourceText changedText, Cance var changedSnapshot = OriginalSnapshot.WithText(changedText); // Formatting always uses design time document - var codeDocument = await changedSnapshot.GetGeneratedOutputAsync(forceDesignTimeGeneratedOutput: true, cancellationToken).ConfigureAwait(false); + var generator = (IDesignTimeCodeGenerator)changedSnapshot; + var codeDocument = await generator.GenerateDesignTimeOutputAsync(cancellationToken).ConfigureAwait(false); DEBUG_ValidateComponents(CodeDocument, codeDocument); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingService.cs index 92af545c4ea..fee7a239782 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingService.cs @@ -62,7 +62,8 @@ public async Task> GetDocumentFormattingChangesAsync( RazorFormattingOptions options, CancellationToken cancellationToken) { - var codeDocument = await documentContext.Snapshot.GetGeneratedOutputAsync(forceDesignTimeGeneratedOutput: true, cancellationToken).ConfigureAwait(false); + var generator = (IDesignTimeCodeGenerator)documentContext.Snapshot; + var codeDocument = await generator.GenerateDesignTimeOutputAsync(cancellationToken).ConfigureAwait(false); // Range formatting happens on every paste, and if there are Razor diagnostics in the file // that can make some very bad results. eg, given: @@ -114,7 +115,8 @@ public async Task> GetDocumentFormattingChangesAsync( public async Task> GetCSharpOnTypeFormattingChangesAsync(DocumentContext documentContext, RazorFormattingOptions options, int hostDocumentIndex, char triggerCharacter, CancellationToken cancellationToken) { var documentSnapshot = documentContext.Snapshot; - var codeDocument = await documentContext.Snapshot.GetGeneratedOutputAsync(forceDesignTimeGeneratedOutput: true, cancellationToken).ConfigureAwait(false); + var generator = (IDesignTimeCodeGenerator)documentSnapshot; + var codeDocument = await generator.GenerateDesignTimeOutputAsync(cancellationToken).ConfigureAwait(false); return await ApplyFormattedChangesAsync( documentSnapshot, @@ -132,7 +134,8 @@ public async Task> GetCSharpOnTypeFormattingChangesAs public async Task> GetHtmlOnTypeFormattingChangesAsync(DocumentContext documentContext, ImmutableArray htmlChanges, RazorFormattingOptions options, int hostDocumentIndex, char triggerCharacter, CancellationToken cancellationToken) { var documentSnapshot = documentContext.Snapshot; - var codeDocument = await documentContext.Snapshot.GetGeneratedOutputAsync(forceDesignTimeGeneratedOutput: true, cancellationToken).ConfigureAwait(false); + var generator = (IDesignTimeCodeGenerator)documentSnapshot; + var codeDocument = await generator.GenerateDesignTimeOutputAsync(cancellationToken).ConfigureAwait(false); return await ApplyFormattedChangesAsync( documentSnapshot, @@ -151,7 +154,7 @@ public async Task> GetHtmlOnTypeFormattingChangesAsyn { var documentSnapshot = documentContext.Snapshot; // Since we've been provided with an edit from the C# generated doc, forcing design time would make things not line up - var codeDocument = await documentContext.Snapshot.GetGeneratedOutputAsync(forceDesignTimeGeneratedOutput: false, cancellationToken).ConfigureAwait(false); + var codeDocument = await documentContext.Snapshot.GetGeneratedOutputAsync(cancellationToken).ConfigureAwait(false); var razorChanges = await ApplyFormattedChangesAsync( documentSnapshot, @@ -171,7 +174,7 @@ public async Task> GetHtmlOnTypeFormattingChangesAsyn { var documentSnapshot = documentContext.Snapshot; // Since we've been provided with edits from the C# generated doc, forcing design time would make things not line up - var codeDocument = await documentContext.Snapshot.GetGeneratedOutputAsync(forceDesignTimeGeneratedOutput: false, cancellationToken).ConfigureAwait(false); + var codeDocument = await documentContext.Snapshot.GetGeneratedOutputAsync(cancellationToken).ConfigureAwait(false); var razorChanges = await ApplyFormattedChangesAsync( documentSnapshot, @@ -193,7 +196,7 @@ public async Task> GetHtmlOnTypeFormattingChangesAsyn var documentSnapshot = documentContext.Snapshot; // Since we've been provided with edits from the C# generated doc, forcing design time would make things not line up - var codeDocument = await documentContext.Snapshot.GetGeneratedOutputAsync(forceDesignTimeGeneratedOutput: false, cancellationToken).ConfigureAwait(false); + var codeDocument = await documentContext.Snapshot.GetGeneratedOutputAsync(cancellationToken).ConfigureAwait(false); var razorChanges = await ApplyFormattedChangesAsync( documentSnapshot, diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CodeDocumentGenerator.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CodeDocumentGenerator.cs new file mode 100644 index 00000000000..976b7650461 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CodeDocumentGenerator.cs @@ -0,0 +1,33 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Razor; +using System.Collections.Immutable; +using Microsoft.AspNetCore.Razor.Language; + +namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; + +internal readonly struct CodeDocumentGenerator(RazorProjectEngine projectEngine, RazorCompilerOptions compilerOptions) +{ + public RazorCodeDocument Generate( + RazorSourceDocument source, + string fileKind, + ImmutableArray importSources, + ImmutableArray tagHelpers) + { + var forceRuntimeCodeGeneration = compilerOptions.IsFlagSet(RazorCompilerOptions.ForceRuntimeCodeGeneration); + + return forceRuntimeCodeGeneration + ? projectEngine.Process(source, fileKind, importSources, tagHelpers) + : projectEngine.ProcessDesignTime(source, fileKind, importSources, tagHelpers); + } + + public RazorCodeDocument GenerateDesignTime( + RazorSourceDocument source, + string fileKind, + ImmutableArray importSources, + ImmutableArray tagHelpers) + { + return projectEngine.ProcessDesignTime(source, fileKind, importSources, tagHelpers); + } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs index 2bcf671cf9b..94cecd9ced4 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs @@ -2,39 +2,82 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System.Collections.Immutable; -using System.Threading.Tasks; using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; internal static class CompilationHelpers { + internal static RazorCodeDocument GenerateCodeDocument( + RazorProjectEngine projectEngine, + RazorCompilerOptions compilerOptions, + RazorSourceDocument source, + string fileKind, + ImmutableArray importSources, + ImmutableArray tagHelpers) + { + var forceRuntimeCodeGeneration = compilerOptions.IsFlagSet(RazorCompilerOptions.ForceRuntimeCodeGeneration); + + return forceRuntimeCodeGeneration + ? projectEngine.Process(source, fileKind, importSources, tagHelpers) + : projectEngine.ProcessDesignTime(source, fileKind, importSources, tagHelpers); + } + internal static async Task GenerateCodeDocumentAsync( IDocumentSnapshot document, RazorProjectEngine projectEngine, - bool forceRuntimeCodeGeneration, + RazorCompilerOptions compilerOptions, CancellationToken cancellationToken) { var importItems = await ImportHelpers.GetImportItemsAsync(document, projectEngine, cancellationToken).ConfigureAwait(false); return await GenerateCodeDocumentAsync( - document, projectEngine, importItems, forceRuntimeCodeGeneration, cancellationToken).ConfigureAwait(false); + document, projectEngine, importItems, compilerOptions, cancellationToken).ConfigureAwait(false); } internal static async Task GenerateCodeDocumentAsync( IDocumentSnapshot document, RazorProjectEngine projectEngine, ImmutableArray imports, - bool forceRuntimeCodeGeneration, + RazorCompilerOptions compilerOptions, CancellationToken cancellationToken) { var importSources = ImportHelpers.GetImportSources(imports, projectEngine); var tagHelpers = await document.Project.GetTagHelpersAsync(cancellationToken).ConfigureAwait(false); var source = await ImportHelpers.GetSourceAsync(document, projectEngine, cancellationToken).ConfigureAwait(false); - return forceRuntimeCodeGeneration - ? projectEngine.Process(source, document.FileKind, importSources, tagHelpers) - : projectEngine.ProcessDesignTime(source, document.FileKind, importSources, tagHelpers); + var generator = new CodeDocumentGenerator(projectEngine, compilerOptions); + return generator.Generate(source, document.FileKind, importSources, tagHelpers); + } + + internal static async Task GenerateDesignTimeCodeDocumentAsync( + IDocumentSnapshot document, + RazorProjectEngine projectEngine, + ImmutableArray imports, + CancellationToken cancellationToken) + { + var importSources = ImportHelpers.GetImportSources(imports, projectEngine); + var tagHelpers = await document.Project.GetTagHelpersAsync(cancellationToken).ConfigureAwait(false); + var source = await ImportHelpers.GetSourceAsync(document, projectEngine, cancellationToken).ConfigureAwait(false); + + var generator = new CodeDocumentGenerator(projectEngine, RazorCompilerOptions.None); + return generator.GenerateDesignTime(source, document.FileKind, importSources, tagHelpers); + } + + internal static async Task GenerateDesignTimeCodeDocumentAsync( + IDocumentSnapshot document, + RazorProjectEngine projectEngine, + CancellationToken cancellationToken) + { + var importItems = await ImportHelpers.GetImportItemsAsync(document, projectEngine, cancellationToken).ConfigureAwait(false); + var importSources = ImportHelpers.GetImportSources(importItems, projectEngine); + var tagHelpers = await document.Project.GetTagHelpersAsync(cancellationToken).ConfigureAwait(false); + var source = await ImportHelpers.GetSourceAsync(document, projectEngine, cancellationToken).ConfigureAwait(false); + + var generator = new CodeDocumentGenerator(projectEngine, RazorCompilerOptions.None); + return generator.GenerateDesignTime(source, document.FileKind, importSources, tagHelpers); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs index 7748ba0eb92..85616505e19 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs @@ -4,102 +4,73 @@ using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -internal sealed class DocumentSnapshot(ProjectSnapshot project, DocumentState state) : IDocumentSnapshot +internal sealed class DocumentSnapshot : IDocumentSnapshot, IDesignTimeCodeGenerator { - private static readonly object s_csharpSyntaxTreeKey = new(); + public ProjectSnapshot Project { get; } - private readonly DocumentState _state = state; - private readonly ProjectSnapshot _project = project; + private readonly DocumentState _state; + + public DocumentSnapshot(ProjectSnapshot project, DocumentState state) + { + Project = project; + _state = state; + } public HostDocument HostDocument => _state.HostDocument; public string FileKind => _state.HostDocument.FileKind; public string FilePath => _state.HostDocument.FilePath; public string TargetPath => _state.HostDocument.TargetPath; - public IProjectSnapshot Project => _project; + IProjectSnapshot IDocumentSnapshot.Project => Project; public int Version => _state.Version; - public ValueTask GetTextAsync(CancellationToken cancellationToken) - => _state.GetTextAsync(cancellationToken); - - public ValueTask GetTextVersionAsync(CancellationToken cancellationToken) - => _state.GetTextVersionAsync(cancellationToken); - public bool TryGetText([NotNullWhen(true)] out SourceText? result) => _state.TryGetText(out result); + public ValueTask GetTextAsync(CancellationToken cancellationToken) + => _state.GetTextAsync(cancellationToken); + public bool TryGetTextVersion(out VersionStamp result) => _state.TryGetTextVersion(out result); + public ValueTask GetTextVersionAsync(CancellationToken cancellationToken) + => _state.GetTextVersionAsync(cancellationToken); + public bool TryGetGeneratedOutput([NotNullWhen(true)] out RazorCodeDocument? result) - { - if (_state.TryGetGeneratedOutputAndVersion(out var outputAndVersion)) - { - result = outputAndVersion.output; - return true; - } + => _state.TryGetGeneratedOutput(out result); - result = null; - return false; - } + public ValueTask GetGeneratedOutputAsync(CancellationToken cancellationToken) + => _state.GetGeneratedOutputAsync(this, cancellationToken); public IDocumentSnapshot WithText(SourceText text) { - return new DocumentSnapshot(_project, _state.WithText(text, VersionStamp.Create())); + return new DocumentSnapshot(Project, _state.WithText(text, VersionStamp.Create())); } public ValueTask GetCSharpSyntaxTreeAsync(CancellationToken cancellationToken) { return TryGetGeneratedOutput(out var codeDocument) - ? new(GetOrParseCSharpSyntaxTree(codeDocument, cancellationToken)) + ? new(codeDocument.GetOrParseCSharpSyntaxTree(cancellationToken)) : new(GetCSharpSyntaxTreeCoreAsync(cancellationToken)); async Task GetCSharpSyntaxTreeCoreAsync(CancellationToken cancellationToken) { - var codeDocument = await GetGeneratedOutputAsync(forceDesignTimeGeneratedOutput: false, cancellationToken).ConfigureAwait(false); - return GetOrParseCSharpSyntaxTree(codeDocument, cancellationToken); + var codeDocument = await GetGeneratedOutputAsync(cancellationToken).ConfigureAwait(false); + return codeDocument.GetOrParseCSharpSyntaxTree(cancellationToken); } } - public async ValueTask GetGeneratedOutputAsync(bool forceDesignTimeGeneratedOutput, CancellationToken cancellationToken) + public async Task GenerateDesignTimeOutputAsync(CancellationToken cancellationToken) { - if (forceDesignTimeGeneratedOutput) - { - return await GetDesignTimeGeneratedOutputAsync(cancellationToken).ConfigureAwait(false); - } + var importItems = await Project.GetImportItemsAsync(FilePath, cancellationToken).ConfigureAwait(false); - var (output, _) = await _state - .GetGeneratedOutputAndVersionAsync(_project, this, cancellationToken) + return await CompilationHelpers + .GenerateDesignTimeCodeDocumentAsync(this, Project.GetProjectEngine(), importItems, cancellationToken) .ConfigureAwait(false); - - return output; - } - - private Task GetDesignTimeGeneratedOutputAsync(CancellationToken cancellationToken) - => CompilationHelpers.GenerateCodeDocumentAsync(this, Project.GetProjectEngine(), forceRuntimeCodeGeneration: false, cancellationToken); - - /// - /// Retrieves a cached Roslyn from the generated C# document. - /// If a tree has not yet been cached, a new one will be parsed and added to the cache. - /// - public static SyntaxTree GetOrParseCSharpSyntaxTree(RazorCodeDocument document, CancellationToken cancellationToken) - { - if (!document.Items.TryGetValue(s_csharpSyntaxTreeKey, out SyntaxTree? syntaxTree)) - { - var csharpText = document.GetCSharpSourceText(); - syntaxTree = CSharpSyntaxTree.ParseText(csharpText, cancellationToken: cancellationToken); - document.Items[s_csharpSyntaxTreeKey] = syntaxTree; - - return syntaxTree; - } - - return syntaxTree.AssumeNotNull(); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs deleted file mode 100644 index 7c70a69f0a4..00000000000 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.ComputedStateTracker.cs +++ /dev/null @@ -1,245 +0,0 @@ -// 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.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor; -using Microsoft.AspNetCore.Razor.Language; - -namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; - -internal partial class DocumentState -{ - private class ComputedStateTracker(ComputedStateTracker? older = null) - { - private readonly object _lock = new(); - - private ComputedStateTracker? _older = older; - - // We utilize a WeakReference here to avoid bloating committed memory. If pieces request document output inbetween GC collections - // then we will provide the weak referenced task; otherwise we require any state requests to be re-computed. - private WeakReference>? _taskUnsafeReference; - - private ComputedOutput? _computedOutput; - - public bool TryGetGeneratedOutputAndVersion(out (RazorCodeDocument Output, VersionStamp InputVersion) result) - { - if (_computedOutput?.TryGetCachedOutput(out var output, out var version) == true) - { - result = (output, version); - return true; - } - - result = default; - return false; - } - - public async Task<(RazorCodeDocument, VersionStamp)> GetGeneratedOutputAndVersionAsync( - ProjectSnapshot project, - IDocumentSnapshot document, - CancellationToken cancellationToken) - { - if (_computedOutput?.TryGetCachedOutput(out var cachedCodeDocument, out var cachedInputVersion) == true) - { - return (cachedCodeDocument, cachedInputVersion); - } - - var (codeDocument, inputVersion) = await GetMemoizedGeneratedOutputAndVersionAsync(project, document, cancellationToken) - .ConfigureAwait(false); - - _computedOutput = new ComputedOutput(codeDocument, inputVersion); - return (codeDocument, inputVersion); - } - - private Task<(RazorCodeDocument, VersionStamp)> GetMemoizedGeneratedOutputAndVersionAsync( - ProjectSnapshot project, - IDocumentSnapshot document, - CancellationToken cancellationToken) - { - if (project is null) - { - throw new ArgumentNullException(nameof(project)); - } - - if (document is null) - { - throw new ArgumentNullException(nameof(document)); - } - - if (_taskUnsafeReference is null || - !_taskUnsafeReference.TryGetTarget(out var taskUnsafe)) - { - TaskCompletionSource<(RazorCodeDocument, VersionStamp)>? tcs = null; - - lock (_lock) - { - if (_taskUnsafeReference is null || - !_taskUnsafeReference.TryGetTarget(out taskUnsafe)) - { - // So this is a bit confusing. Instead of directly calling the Razor parser inside of this lock we create an indirect TaskCompletionSource - // to represent when it completes. The reason behind this is that there are several scenarios in which the Razor parser will run synchronously - // (mostly all in VS) resulting in this lock being held for significantly longer than expected. To avoid threads queuing up repeatedly on the - // above lock and blocking we can allow those threads to await asynchronously for the completion of the original parse. - - tcs = new(TaskCreationOptions.RunContinuationsAsynchronously); - taskUnsafe = tcs.Task; - _taskUnsafeReference = new WeakReference>(taskUnsafe); - } - } - - if (tcs is null) - { - // There's no task completion source created meaning a value was retrieved from cache, just return it. - return taskUnsafe; - } - - // Typically in VS scenarios this will run synchronously because all resources are readily available. - var outputTask = ComputeGeneratedOutputAndVersionAsync(project, document, cancellationToken); - if (outputTask.IsCompleted) - { - // Compiling ran synchronously, lets just immediately propagate to the TCS - PropagateToTaskCompletionSource(outputTask, tcs); - } - else - { - // Task didn't run synchronously (most likely outside of VS), lets allocate a bit more but utilize ContinueWith - // to properly connect the output task and TCS - _ = outputTask.ContinueWith( - static (task, state) => - { - Assumes.NotNull(state); - var tcs = (TaskCompletionSource<(RazorCodeDocument, VersionStamp)>)state; - - PropagateToTaskCompletionSource(task, tcs); - }, - tcs, - CancellationToken.None, - TaskContinuationOptions.ExecuteSynchronously, - TaskScheduler.Default); - } - } - - return taskUnsafe; - - static void PropagateToTaskCompletionSource( - Task<(RazorCodeDocument, VersionStamp)> targetTask, - TaskCompletionSource<(RazorCodeDocument, VersionStamp)> tcs) - { - if (targetTask.Status == TaskStatus.RanToCompletion) - { -#pragma warning disable VSTHRD103 // Call async methods when in an async method - tcs.SetResult(targetTask.Result); -#pragma warning restore VSTHRD103 // Call async methods when in an async method - } - else if (targetTask.Status == TaskStatus.Canceled) - { - tcs.SetCanceled(); - } - else if (targetTask.Status == TaskStatus.Faulted) - { - // Faulted tasks area always aggregate exceptions so we need to extract the "true" exception if it's available: - Assumes.NotNull(targetTask.Exception); - var exception = targetTask.Exception.InnerException ?? targetTask.Exception; - tcs.SetException(exception); - } - } - } - - private async Task<(RazorCodeDocument, VersionStamp)> ComputeGeneratedOutputAndVersionAsync( - ProjectSnapshot project, - IDocumentSnapshot document, - CancellationToken cancellationToken) - { - // We only need to produce the generated code if any of our inputs is newer than the - // previously cached output. - // - // First find the versions that are the inputs: - // - The project + computed state - // - The imports - // - This document - // - // All of these things are cached, so no work is wasted if we do need to generate the code. - var configurationVersion = project.ConfigurationVersion; - var projectWorkspaceStateVersion = project.ProjectWorkspaceStateVersion; - var documentCollectionVersion = project.DocumentCollectionVersion; - var importItems = await ImportHelpers.GetImportItemsAsync(document, project.GetProjectEngine(), cancellationToken).ConfigureAwait(false); - var documentVersion = await document.GetTextVersionAsync(cancellationToken).ConfigureAwait(false); - - // OK now that have the previous output and all of the versions, we can see if anything - // has changed that would require regenerating the code. - var inputVersion = documentVersion; - if (inputVersion.GetNewerVersion(configurationVersion) == configurationVersion) - { - inputVersion = configurationVersion; - } - - if (inputVersion.GetNewerVersion(projectWorkspaceStateVersion) == projectWorkspaceStateVersion) - { - inputVersion = projectWorkspaceStateVersion; - } - - if (inputVersion.GetNewerVersion(documentCollectionVersion) == documentCollectionVersion) - { - inputVersion = documentCollectionVersion; - } - - foreach (var import in importItems) - { - var importVersion = import.Version; - if (inputVersion.GetNewerVersion(importVersion) == importVersion) - { - inputVersion = importVersion; - } - } - - if (_older?._taskUnsafeReference != null && - _older._taskUnsafeReference.TryGetTarget(out var taskUnsafe)) - { - var (olderOutput, olderInputVersion) = await taskUnsafe.ConfigureAwait(false); - if (inputVersion.GetNewerVersion(olderInputVersion) == olderInputVersion) - { - // Nothing has changed, we can use the cached result. - lock (_lock) - { - _taskUnsafeReference = _older._taskUnsafeReference; - _older = null; - return (olderOutput, olderInputVersion); - } - } - } - - var forceRuntimeCodeGeneration = project.CompilerOptions.IsFlagSet(RazorCompilerOptions.ForceRuntimeCodeGeneration); - var codeDocument = await CompilationHelpers.GenerateCodeDocumentAsync(document, project.GetProjectEngine(), importItems, forceRuntimeCodeGeneration, cancellationToken).ConfigureAwait(false); - return (codeDocument, inputVersion); - } - - private class ComputedOutput - { - private readonly VersionStamp _inputVersion; - private readonly WeakReference _codeDocumentReference; - - public ComputedOutput(RazorCodeDocument codeDocument, VersionStamp inputVersion) - { - _codeDocumentReference = new WeakReference(codeDocument); - _inputVersion = inputVersion; - } - - public bool TryGetCachedOutput([NotNullWhen(true)] out RazorCodeDocument? codeDocument, out VersionStamp inputVersion) - { - // The goal here is to capture a weak reference to the code document so if there's ever a sub-system that's still utilizing it - // our computed output maintains its cache. - - if (_codeDocumentReference.TryGetTarget(out codeDocument)) - { - inputVersion = _inputVersion; - return true; - } - - inputVersion = default; - return false; - } - } - } -} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs index 7d9766866ca..91ff97c3e46 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs @@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.ProjectSystem.Sources; using Microsoft.CodeAnalysis.Text; @@ -17,28 +16,22 @@ internal sealed partial class DocumentState public int Version { get; } private readonly ITextAndVersionSource _textAndVersionSource; + private readonly GeneratedOutputSource _generatedOutputSource; - private ComputedStateTracker? _computedState; - - private DocumentState( - HostDocument hostDocument, - ITextAndVersionSource textAndVersionSource) + private DocumentState(HostDocument hostDocument, ITextAndVersionSource textAndVersionSource) { HostDocument = hostDocument; Version = 1; _textAndVersionSource = textAndVersionSource; + _generatedOutputSource = new(); } - private DocumentState( - DocumentState oldState, - ITextAndVersionSource textAndVersionSource, - ComputedStateTracker? computedState = null) + private DocumentState(DocumentState oldState, ITextAndVersionSource textAndVersionSource) { HostDocument = oldState.HostDocument; Version = oldState.Version + 1; _textAndVersionSource = textAndVersionSource; - - _computedState = computedState; + _generatedOutputSource = new(); } public static DocumentState Create(HostDocument hostDocument, SourceText text) @@ -53,21 +46,11 @@ private static ConstantTextAndVersionSource CreateTextAndVersionSource(SourceTex private static LoadableTextAndVersionSource CreateTextAndVersionSource(TextLoader textLoader) => new(textLoader); - private ComputedStateTracker ComputedState - => _computedState ??= InterlockedOperations.Initialize(ref _computedState, new ComputedStateTracker()); + public bool TryGetGeneratedOutput([NotNullWhen(true)] out RazorCodeDocument? result) + => _generatedOutputSource.TryGetValue(out result); - public bool TryGetGeneratedOutputAndVersion(out (RazorCodeDocument output, VersionStamp inputVersion) result) - { - return ComputedState.TryGetGeneratedOutputAndVersion(out result); - } - - public Task<(RazorCodeDocument output, VersionStamp inputVersion)> GetGeneratedOutputAndVersionAsync( - ProjectSnapshot project, - DocumentSnapshot document, - CancellationToken cancellationToken) - { - return ComputedState.GetGeneratedOutputAndVersionAsync(project, document, cancellationToken); - } + public ValueTask GetGeneratedOutputAsync(DocumentSnapshot document, CancellationToken cancellationToken) + => _generatedOutputSource.GetValueAsync(document, cancellationToken); public bool TryGetTextAndVersion([NotNullWhen(true)] out TextAndVersion? result) => _textAndVersionSource.TryGetValue(out result); @@ -128,19 +111,19 @@ async ValueTask GetTextVersionCoreAsync(CancellationToken cancella } public DocumentState WithConfigurationChange() - => new(this, _textAndVersionSource, computedState: null); + => new(this, _textAndVersionSource); public DocumentState WithImportsChange() - => new(this, _textAndVersionSource, new(_computedState)); + => new(this, _textAndVersionSource); public DocumentState WithProjectWorkspaceStateChange() - => new(this, _textAndVersionSource, new(_computedState)); + => new(this, _textAndVersionSource); public DocumentState WithText(SourceText text, VersionStamp textVersion) - => new(this, CreateTextAndVersionSource(text, textVersion), computedState: null); + => new(this, CreateTextAndVersionSource(text, textVersion)); public DocumentState WithTextLoader(TextLoader textLoader) => ReferenceEquals(textLoader, _textAndVersionSource.TextLoader) ? this - : new(this, CreateTextAndVersionSource(textLoader), computedState: null); + : new(this, CreateTextAndVersionSource(textLoader)); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDesignTimeCodeGenerator.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDesignTimeCodeGenerator.cs new file mode 100644 index 00000000000..55937d186db --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDesignTimeCodeGenerator.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; + +namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; + +internal interface IDesignTimeCodeGenerator +{ + Task GenerateDesignTimeOutputAsync(CancellationToken cancellationToken); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshot.cs index b99ccab0f3a..0ce7372c92c 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshot.cs @@ -20,9 +20,7 @@ internal interface IDocumentSnapshot ValueTask GetTextAsync(CancellationToken cancellationToken); ValueTask GetTextVersionAsync(CancellationToken cancellationToken); - ValueTask GetGeneratedOutputAsync( - bool forceDesignTimeGeneratedOutput, - CancellationToken cancellationToken); + ValueTask GetGeneratedOutputAsync(CancellationToken cancellationToken); /// /// Gets the Roslyn syntax tree for the generated C# for this Razor document diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs index 5f44d2b1d47..ca1d6a31b32 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs @@ -54,11 +54,4 @@ public static bool IsPathCandidateForComponent(this IDocumentSnapshot documentSn var fileName = Path.GetFileNameWithoutExtension(documentSnapshot.FilePath); return fileName.AsSpan().Equals(path.Span, FilePathComparison.Instance); } - - public static ValueTask GetGeneratedOutputAsync( - this IDocumentSnapshot documentSnapshot, - CancellationToken cancellationToken) - { - return documentSnapshot.GetGeneratedOutputAsync(forceDesignTimeGeneratedOutput: false, cancellationToken); - } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs index 7d55adfc1a6..ddfc43e229c 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Utilities; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -119,4 +120,62 @@ public ImmutableArray GetRelatedDocuments(IDocumentSnapshot d return builder.DrainToImmutable(); } } + + public ValueTask> GetImportItemsAsync(string filePath, CancellationToken cancellationToken) + { + return _state.Documents.TryGetValue(filePath, out var state) + ? new(GetImportItemsAsync(state.HostDocument, cancellationToken)) + : new([]); + } + + public async Task> GetImportItemsAsync(HostDocument hostDocument, CancellationToken cancellationToken) + { + var projectEngine = GetProjectEngine(); + + var projectItem = projectEngine.FileSystem.GetItem(hostDocument.FilePath, hostDocument.FileKind); + + using var importProjectItems = new PooledArrayBuilder(); + + foreach (var feature in projectEngine.ProjectFeatures.OfType()) + { + if (feature.GetImports(projectItem) is { } featureImports) + { + importProjectItems.AddRange(featureImports); + } + } + + if (importProjectItems.Count == 0) + { + return []; + } + + using var importItems = new PooledArrayBuilder(capacity: importProjectItems.Count); + + foreach (var importProjectItem in importProjectItems) + { + if (importProjectItem is NotFoundProjectItem) + { + continue; + } + + if (importProjectItem.PhysicalPath is null) + { + // This is a default import. + using var stream = importProjectItem.Read(); + var text = SourceText.From(stream); + var defaultImport = ImportItem.CreateDefault(text); + + importItems.Add(defaultImport); + } + else if (_state.Documents.TryGetValue(importProjectItem.PhysicalPath, out var importDocumentState)) + { + var textAndVersion = await importDocumentState.GetTextAndVersionAsync(cancellationToken).ConfigureAwait(false); + var importItem = new ImportItem(importDocumentState.HostDocument.FilePath, importDocumentState.HostDocument.FileKind, textAndVersion.Text, textAndVersion.Version); + + importItems.Add(importItem); + } + } + + return importItems.DrainToImmutable(); + } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs new file mode 100644 index 00000000000..a3a63313a39 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs @@ -0,0 +1,45 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Threading; + +namespace Microsoft.CodeAnalysis.Razor.ProjectSystem.Sources; + +internal sealed class GeneratedOutputSource +{ + private readonly SemaphoreSlim _gate = new(initialCount: 1); + private RazorCodeDocument? _output; + + public bool TryGetValue([NotNullWhen(true)] out RazorCodeDocument? result) + { + result = _output; + return result is not null; + } + + public async ValueTask GetValueAsync(DocumentSnapshot document, CancellationToken cancellationToken) + { + if (TryGetValue(out var result)) + { + return result; + } + + using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) + { + var project = document.Project; + var projectEngine = project.GetProjectEngine(); + var compilerOptions = project.CompilerOptions; + + var importItems = await project.GetImportItemsAsync(document.HostDocument, cancellationToken).ConfigureAwait(false); + + _output = await CompilationHelpers + .GenerateCodeDocumentAsync(document, projectEngine, importItems, compilerOptions, cancellationToken) + .ConfigureAwait(false); + + return _output; + } + } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs index fbf23f55f78..e4f6acf3615 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteDocumentMappingService.cs @@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs index 57c8c3bfc92..56ce328a0c4 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs @@ -8,20 +8,20 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Threading; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; -internal sealed class RemoteDocumentSnapshot : IDocumentSnapshot +internal sealed class RemoteDocumentSnapshot : IDocumentSnapshot, IDesignTimeCodeGenerator { public TextDocument TextDocument { get; } public RemoteProjectSnapshot ProjectSnapshot { get; } // TODO: Delete this field when the source generator is hooked up - private Document? _generatedDocument; - - private RazorCodeDocument? _codeDocument; + private readonly AsyncLazy _lazyDocument; + private readonly AsyncLazy _lazyCodeDocument; public RemoteDocumentSnapshot(TextDocument textDocument, RemoteProjectSnapshot projectSnapshot) { @@ -32,6 +32,9 @@ public RemoteDocumentSnapshot(TextDocument textDocument, RemoteProjectSnapshot p TextDocument = textDocument; ProjectSnapshot = projectSnapshot; + + _lazyDocument = AsyncLazy.Create(HACK_ComputeDocumentAsync); + _lazyCodeDocument = AsyncLazy.Create(ComputeGeneratedOutputAsync); } public string FileKind => FileKinds.GetFileKindFromFilePath(FilePath); @@ -62,48 +65,56 @@ public bool TryGetText([NotNullWhen(true)] out SourceText? result) public bool TryGetTextVersion(out VersionStamp result) => TextDocument.TryGetTextVersion(out result); - public ValueTask GetGeneratedOutputAsync( - bool forceDesignTimeGeneratedOutput, - CancellationToken cancellationToken) + public bool TryGetGeneratedOutput([NotNullWhen(true)] out RazorCodeDocument? result) + => _lazyCodeDocument.TryGetValue(out result); + + public ValueTask GetGeneratedOutputAsync(CancellationToken cancellationToken) { - // We don't cache if we're forcing, as that would break everything else - if (forceDesignTimeGeneratedOutput) + if (TryGetGeneratedOutput(out var result)) { - return new ValueTask(GetRazorCodeDocumentAsync(forceRuntimeCodeGeneration: false, cancellationToken)); + return new(result); } - var forceRuntimeCodeGeneration = ProjectSnapshot.SolutionSnapshot.SnapshotManager.LanguageServerFeatureOptions.ForceRuntimeCodeGeneration; + return new(_lazyCodeDocument.GetValueAsync(cancellationToken)); + } - // TODO: We don't need to worry about locking if we get called from the didOpen/didChange LSP requests, as CLaSP - // takes care of that for us, and blocks requests until those are complete. If that doesn't end up happening, - // then a locking mechanism here would prevent concurrent compilations. - return TryGetGeneratedOutput(out var codeDocument) - ? new(codeDocument) - : new(GetGeneratedOutputCoreAsync(forceRuntimeCodeGeneration, cancellationToken)); + private async Task ComputeGeneratedOutputAsync(CancellationToken cancellationToken) + { + var projectEngine = await ProjectSnapshot.GetProjectEngine_CohostOnlyAsync(cancellationToken).ConfigureAwait(false); + var compilerOptions = ProjectSnapshot.SolutionSnapshot.SnapshotManager.CompilerOptions; - async Task GetGeneratedOutputCoreAsync(bool forceRuntimeCodeGeneration, CancellationToken cancellationToken) - { - codeDocument = await GetRazorCodeDocumentAsync(forceRuntimeCodeGeneration, cancellationToken).ConfigureAwait(false); + return await CompilationHelpers + .GenerateCodeDocumentAsync(this, projectEngine, compilerOptions, cancellationToken) + .ConfigureAwait(false); + } - return _codeDocument ??= InterlockedOperations.Initialize(ref _codeDocument, codeDocument); - } + public async Task GenerateDesignTimeOutputAsync(CancellationToken cancellationToken) + { + var projectEngine = await ProjectSnapshot.GetProjectEngine_CohostOnlyAsync(cancellationToken).ConfigureAwait(false); - async Task GetRazorCodeDocumentAsync(bool forceRuntimeCodeGeneration, CancellationToken cancellationToken) - { - // The non-cohosted DocumentSnapshot implementation uses DocumentState to get the generated output, and we could do that too - // but most of that code is optimized around caching pre-computed results when things change that don't affect the compilation. - // We can't do that here because we are using Roslyn's project snapshots, which don't contain the info that Razor needs. We could - // in future provide a side-car mechanism so we can cache things, but still take advantage of snapshots etc. but the working - // assumption for this code is that the source generator will be used, and it will do all of that, so this implementation is naive - // and simply compiles when asked, and if a new document snapshot comes in, we compile again. This is presumably worse for perf - // but since we don't expect users to ever use cohosting without source generators, it's fine for now. - - var projectEngine = await ProjectSnapshot.GetProjectEngine_CohostOnlyAsync(cancellationToken).ConfigureAwait(false); - - return await CompilationHelpers - .GenerateCodeDocumentAsync(this, projectEngine, forceRuntimeCodeGeneration, cancellationToken) - .ConfigureAwait(false); - } + return await CompilationHelpers + .GenerateDesignTimeCodeDocumentAsync(this, projectEngine, cancellationToken) + .ConfigureAwait(false); + } + + private async Task HACK_ComputeDocumentAsync(CancellationToken cancellationToken) + { + // TODO: A real implementation needs to get the SourceGeneratedDocument from the solution + + var solution = TextDocument.Project.Solution; + var filePathService = ProjectSnapshot.SolutionSnapshot.SnapshotManager.FilePathService; + var generatedFilePath = filePathService.GetRazorCSharpFilePath(Project.Key, FilePath); + var generatedDocumentId = solution + .GetDocumentIdsWithFilePath(generatedFilePath) + .First(TextDocument.Project.Id, static (d, projectId) => d.ProjectId == projectId); + + var generatedDocument = solution.GetRequiredDocument(generatedDocumentId); + + var codeDocument = await GetGeneratedOutputAsync(cancellationToken).ConfigureAwait(false); + var csharpSourceText = codeDocument.GetCSharpSourceText(); + + // HACK: We're not in the same solution fork as the LSP server that provides content for this document + return generatedDocument.WithText(csharpSourceText); } public IDocumentSnapshot WithText(SourceText text) @@ -118,47 +129,17 @@ public IDocumentSnapshot WithText(SourceText text) return snapshotManager.GetSnapshot(newDocument); } - public bool TryGetGeneratedOutput([NotNullWhen(true)] out RazorCodeDocument? result) - { - result = _codeDocument; - return result is not null; - } + public bool TryGetGeneratedDocument([NotNullWhen(true)] out Document? result) + => _lazyDocument.TryGetValue(out result); public ValueTask GetGeneratedDocumentAsync(CancellationToken cancellationToken) { - return TryGetGeneratedDocument(out var generatedDocument) - ? new(generatedDocument) - : GetGeneratedDocumentCoreAsync(cancellationToken); - - async ValueTask GetGeneratedDocumentCoreAsync(CancellationToken cancellationToken) + if (TryGetGeneratedDocument(out var result)) { - var generatedDocument = await HACK_GenerateDocumentAsync(cancellationToken).ConfigureAwait(false); - return _generatedDocument ??= InterlockedOperations.Initialize(ref _generatedDocument, generatedDocument); + return new(result); } - } - - public bool TryGetGeneratedDocument([NotNullWhen(true)] out Document? generatedDocument) - { - generatedDocument = _generatedDocument; - return generatedDocument is not null; - } - private async Task HACK_GenerateDocumentAsync(CancellationToken cancellationToken) - { - // TODO: A real implementation needs to get the SourceGeneratedDocument from the solution - - var solution = TextDocument.Project.Solution; - var filePathService = ProjectSnapshot.SolutionSnapshot.SnapshotManager.FilePathService; - var generatedFilePath = filePathService.GetRazorCSharpFilePath(Project.Key, FilePath); - var projectId = TextDocument.Project.Id; - var generatedDocumentId = solution.GetDocumentIdsWithFilePath(generatedFilePath).First(d => d.ProjectId == projectId); - var generatedDocument = solution.GetRequiredDocument(generatedDocumentId); - - var codeDocument = await this.GetGeneratedOutputAsync(cancellationToken).ConfigureAwait(false); - var csharpSourceText = codeDocument.GetCSharpSourceText(); - - // HACK: We're not in the same solution fork as the LSP server that provides content for this document - return generatedDocument.WithText(csharpSourceText); + return new(_lazyDocument.GetValueAsync(cancellationToken)); } public ValueTask GetCSharpSyntaxTreeAsync(CancellationToken cancellationToken) 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 78a474b8631..0254a971126 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectEngineHost; using Microsoft.AspNetCore.Razor.ProjectSystem; +using Microsoft.AspNetCore.Razor.Threading; using Microsoft.AspNetCore.Razor.Utilities; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -20,7 +21,6 @@ using Microsoft.CodeAnalysis.Razor.Compiler.CSharp; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.NET.Sdk.Razor.SourceGenerators; -using Microsoft.VisualStudio.Threading; namespace Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; @@ -33,10 +33,9 @@ internal sealed class RemoteProjectSnapshot : IProjectSnapshot private readonly Project _project; private readonly AsyncLazy _lazyConfiguration; private readonly AsyncLazy _lazyProjectEngine; + private readonly AsyncLazy> _lazyTagHelpers; private readonly Dictionary _documentMap = []; - private ImmutableArray _tagHelpers; - public RemoteProjectSnapshot(Project project, RemoteSolutionSnapshot solutionSnapshot) { if (!project.ContainsRazorDocuments()) @@ -48,23 +47,9 @@ public RemoteProjectSnapshot(Project project, RemoteSolutionSnapshot solutionSna SolutionSnapshot = solutionSnapshot; Key = _project.ToProjectKey(); - _lazyConfiguration = new AsyncLazy(CreateRazorConfigurationAsync, joinableTaskFactory: null); - _lazyProjectEngine = new AsyncLazy(async () => - { - var configuration = await _lazyConfiguration.GetValueAsync(); - var useRoslynTokenizer = SolutionSnapshot.SnapshotManager.LanguageServerFeatureOptions.UseRoslynTokenizer; - return ProjectEngineFactories.DefaultProvider.Create( - configuration, - rootDirectoryPath: Path.GetDirectoryName(FilePath).AssumeNotNull(), - configure: builder => - { - builder.SetRootNamespace(RootNamespace); - builder.SetCSharpLanguageVersion(CSharpLanguageVersion); - builder.SetSupportLocalizedComponentNames(); - builder.Features.Add(new ConfigureRazorParserOptions(useRoslynTokenizer, CSharpParseOptions.Default)); - }); - }, - joinableTaskFactory: null); + _lazyConfiguration = AsyncLazy.Create(ComputeConfigurationAsync); + _lazyProjectEngine = AsyncLazy.Create(ComputeProjectEngineAsync); + _lazyTagHelpers = AsyncLazy.Create(ComputeTagHelpersAsync); } public RazorConfiguration Configuration => throw new InvalidOperationException("Should not be called for cohosted projects."); @@ -90,20 +75,12 @@ public IEnumerable DocumentFilePaths public ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken) { - return !_tagHelpers.IsDefault - ? new(_tagHelpers) - : GetTagHelpersCoreAsync(cancellationToken); - - async ValueTask> GetTagHelpersCoreAsync(CancellationToken cancellationToken) + if (_lazyTagHelpers.TryGetValue(out var result)) { - var projectEngine = await _lazyProjectEngine.GetValueAsync(cancellationToken); - var telemetryReporter = SolutionSnapshot.SnapshotManager.TelemetryReporter; - var computedTagHelpers = await _project.GetTagHelpersAsync(projectEngine, telemetryReporter, cancellationToken); - - ImmutableInterlocked.InterlockedInitialize(ref _tagHelpers, computedTagHelpers); - - return _tagHelpers; + return new(result); } + + return new(_lazyTagHelpers.GetValueAsync(cancellationToken)); } public ProjectWorkspaceState ProjectWorkspaceState => throw new InvalidOperationException("Should not be called for cohosted projects."); @@ -193,9 +170,10 @@ public bool TryGetDocument(string filePath, [NotNullWhen(true)] out IDocumentSna /// NOTE: To be called only from CohostDocumentSnapshot.GetGeneratedOutputAsync(). Will be removed when that method uses the source generator directly. /// /// - internal Task GetProjectEngine_CohostOnlyAsync(CancellationToken cancellationToken) => _lazyProjectEngine.GetValueAsync(cancellationToken); + internal Task GetProjectEngine_CohostOnlyAsync(CancellationToken cancellationToken) + => _lazyProjectEngine.GetValueAsync(cancellationToken); - private async Task CreateRazorConfigurationAsync() + private async Task ComputeConfigurationAsync(CancellationToken cancellationToken) { // See RazorSourceGenerator.RazorProviders.cs @@ -211,7 +189,7 @@ private async Task CreateRazorConfigurationAsync() razorLanguageVersion = RazorLanguageVersion.Latest; } - var compilation = await _project.GetCompilationAsync().ConfigureAwait(false); + var compilation = await _project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var suppressAddComponentParameter = compilation is not null && !compilation.HasAddComponentParameter(); @@ -222,4 +200,30 @@ private async Task CreateRazorConfigurationAsync() UseConsolidatedMvcViews: true, suppressAddComponentParameter); } + + private async Task ComputeProjectEngineAsync(CancellationToken cancellationToken) + { + var configuration = await _lazyConfiguration.GetValueAsync(cancellationToken).ConfigureAwait(false); + + var useRoslynTokenizer = SolutionSnapshot.SnapshotManager.CompilerOptions.IsFlagSet(RazorCompilerOptions.UseRoslynTokenizer); + + return ProjectEngineFactories.DefaultProvider.Create( + configuration, + rootDirectoryPath: Path.GetDirectoryName(FilePath).AssumeNotNull(), + configure: builder => + { + builder.SetRootNamespace(RootNamespace); + builder.SetCSharpLanguageVersion(CSharpLanguageVersion); + builder.SetSupportLocalizedComponentNames(); + builder.Features.Add(new ConfigureRazorParserOptions(useRoslynTokenizer, CSharpParseOptions.Default)); + }); + } + + private async Task> ComputeTagHelpersAsync(CancellationToken cancellationToken) + { + var projectEngine = await _lazyProjectEngine.GetValueAsync(cancellationToken).ConfigureAwait(false); + var telemetryReporter = SolutionSnapshot.SnapshotManager.TelemetryReporter; + + return await _project.GetTagHelpersAsync(projectEngine, telemetryReporter, cancellationToken).ConfigureAwait(false); + } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteSnapshotManager.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteSnapshotManager.cs index 41ceec49ab6..09abbf16af7 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteSnapshotManager.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteSnapshotManager.cs @@ -4,6 +4,7 @@ using System.Composition; using System.Runtime.CompilerServices; using Microsoft.AspNetCore.Razor.Telemetry; +using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; namespace Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; @@ -15,7 +16,7 @@ internal sealed class RemoteSnapshotManager(LanguageServerFeatureOptions languag { private static readonly ConditionalWeakTable s_solutionToSnapshotMap = new(); - public LanguageServerFeatureOptions LanguageServerFeatureOptions { get; } = languageServerFeatureOptions; + public RazorCompilerOptions CompilerOptions { get; } = languageServerFeatureOptions.ToCompilerOptions(); public IFilePathService FilePathService { get; } = filePathService; public ITelemetryReporter TelemetryReporter { get; } = telemetryReporter; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/CSharpCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/CSharpCodeActionProviderTest.cs index 46073b4d8ad..7cf55813d02 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/CSharpCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/CSharpCodeActionProviderTest.cs @@ -334,7 +334,7 @@ private static RazorCodeActionContext CreateRazorCodeActionContext( var documentSnapshotMock = new StrictMock(); documentSnapshotMock - .Setup(x => x.GetGeneratedOutputAsync(It.IsAny(), It.IsAny())) + .Setup(x => x.GetGeneratedOutputAsync(It.IsAny())) .ReturnsAsync(codeDocument); documentSnapshotMock .Setup(x => x.GetTextAsync(It.IsAny())) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs index 00d808d5996..e934541a3a7 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs @@ -461,7 +461,7 @@ private static RazorCodeActionContext CreateRazorCodeActionContext( var documentSnapshotMock = new StrictMock(); documentSnapshotMock - .Setup(x => x.GetGeneratedOutputAsync(It.IsAny(), It.IsAny())) + .Setup(x => x.GetGeneratedOutputAsync(It.IsAny())) .ReturnsAsync(codeDocument); documentSnapshotMock .Setup(x => x.GetTextAsync(It.IsAny())) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionProviderTest.cs index 28fdb0d0765..bdd7465125e 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionProviderTest.cs @@ -158,7 +158,7 @@ private static RazorCodeActionContext CreateRazorCodeActionContext( var documentSnapshotMock = new StrictMock(); documentSnapshotMock - .Setup(x => x.GetGeneratedOutputAsync(It.IsAny(), It.IsAny())) + .Setup(x => x.GetGeneratedOutputAsync(It.IsAny())) .ReturnsAsync(codeDocument); documentSnapshotMock .Setup(x => x.GetTextAsync(It.IsAny())) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs index d6eb2f6ab87..a42a138f676 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs @@ -463,7 +463,7 @@ private static RazorCodeActionContext CreateRazorCodeActionContext(VSCodeActionP var documentSnapshotMock = new StrictMock(); documentSnapshotMock - .Setup(x => x.GetGeneratedOutputAsync(It.IsAny(), It.IsAny())) + .Setup(x => x.GetGeneratedOutputAsync(It.IsAny())) .ReturnsAsync(codeDocument); documentSnapshotMock .Setup(x => x.GetTextAsync(It.IsAny())) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionProviderTest.cs index f1431272433..29f1d1e6b1c 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionProviderTest.cs @@ -391,7 +391,7 @@ private static RazorCodeActionContext CreateRazorCodeActionContext(VSCodeActionP var documentSnapshotMock = new StrictMock(); documentSnapshotMock - .Setup(x => x.GetGeneratedOutputAsync(It.IsAny(), It.IsAny())) + .Setup(x => x.GetGeneratedOutputAsync(It.IsAny())) .ReturnsAsync(codeDocument); documentSnapshotMock .Setup(x => x.GetTextAsync(It.IsAny())) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeDocumentReferenceHolderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeDocumentReferenceHolderTest.cs index dab2313f584..4144fcedbb4 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeDocumentReferenceHolderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeDocumentReferenceHolderTest.cs @@ -53,7 +53,7 @@ public async Task DocumentProcessed_ReferencesGeneratedCodeDocument() Assert.True(codeDocumentReference.TryGetTarget(out _)); } - [Fact] + [Fact(Skip = "Weak cache removed")] public async Task UpdateUnrelatedDocumentText_ReferencesGeneratedCodeDocument() { // Arrange @@ -65,7 +65,7 @@ await _projectManager.UpdateAsync(updater => updater.AddDocument(s_hostProject.Key, unrelatedHostDocument, TestMocks.CreateTextLoader("

Unrelated

")); }); - var unrelatedDocumentSnapshot = _projectManager.GetRequiredDocument(s_hostProject.Key, unrelatedHostDocument.FilePath); + var unrelatedDocumentSnapshot = _projectManager.GetRequiredDocument(s_hostProject.Key, unrelatedHostDocument.FilePath); var mainCodeDocumentReference = await ProcessDocumentAndRetrieveOutputAsync(documentSnapshot, DisposalToken); var unrelatedCodeDocumentReference = await ProcessDocumentAndRetrieveOutputAsync(unrelatedDocumentSnapshot, DisposalToken); @@ -83,7 +83,7 @@ await _projectManager.UpdateAsync(updater => Assert.False(unrelatedCodeDocumentReference.TryGetTarget(out _)); } - [Fact] + [Fact(Skip = "Weak cache removed")] public async Task UpdateDocumentText_DereferencesGeneratedCodeDocument() { // Arrange @@ -103,7 +103,7 @@ await _projectManager.UpdateAsync(updater => Assert.False(codeDocumentReference.TryGetTarget(out _)); } - [Fact] + [Fact(Skip = "Weak cache removed")] public async Task RemoveDocument_DereferencesGeneratedCodeDocument() { // Arrange @@ -122,7 +122,7 @@ await _projectManager.UpdateAsync(updater => Assert.False(codeDocumentReference.TryGetTarget(out _)); } - [Fact] + [Fact(Skip = "Weak cache removed")] public async Task UpdateProjectConfiguration_DereferencesGeneratedCodeDocument() { // Arrange @@ -141,7 +141,7 @@ await _projectManager.UpdateAsync(updater => Assert.False(codeDocumentReference.TryGetTarget(out _)); } - [Fact] + [Fact(Skip = "Weak cache removed")] public async Task RemoveProject_DereferencesGeneratedCodeDocument() { // Arrange diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs index 934601ed357..778970b06cd 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs @@ -106,7 +106,7 @@ private static (RazorCodeDocument, IDocumentSnapshot) CreateCodeDocumentAndSnaps var documentSnapshot = new StrictMock(); documentSnapshot - .Setup(d => d.GetGeneratedOutputAsync(It.IsAny(), It.IsAny())) + .Setup(d => d.GetGeneratedOutputAsync(It.IsAny())) .ReturnsAsync(codeDocument); documentSnapshot .Setup(d => d.TargetPath) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs index f5a0c708a79..23379b4a72d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs @@ -102,7 +102,8 @@ private static (RazorCodeDocument, IDocumentSnapshot) CreateCodeDocumentAndSnaps }); var codeDocument = projectEngine.ProcessDesignTime(sourceDocument, fileKind, importSources: default, tagHelpers); - var documentSnapshot = FormattingTestBase.CreateDocumentSnapshot(path, tagHelpers, fileKind, importsDocuments: [], imports: [], projectEngine, codeDocument); + var documentSnapshot = FormattingTestBase.CreateDocumentSnapshot( + path, fileKind, codeDocument, projectEngine, imports: [], importDocuments: [], tagHelpers, inGlobalNamespace: false); return (codeDocument, documentSnapshot); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs index a7b6150fd7a..3fd1373b196 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs @@ -267,32 +267,32 @@ private static (RazorCodeDocument, IDocumentSnapshot) CreateCodeDocumentAndSnaps relativePath: inGlobalNamespace ? Path.GetFileName(path) : path)); const string DefaultImports = """ - @using BlazorApp1 - @using BlazorApp1.Pages - @using BlazorApp1.Shared - @using Microsoft.AspNetCore.Components - @using Microsoft.AspNetCore.Components.Authorization - @using Microsoft.AspNetCore.Components.Routing - @using Microsoft.AspNetCore.Components.Web - """; - - var importsPath = new Uri("file:///path/to/_Imports.razor").AbsolutePath; - var importsSourceText = SourceText.From(DefaultImports); - var importsDocument = RazorSourceDocument.Create(importsSourceText, RazorSourceDocumentProperties.Create(importsPath, importsPath)); - var importsSnapshot = new StrictMock(); - importsSnapshot + @using BlazorApp1 + @using BlazorApp1.Pages + @using BlazorApp1.Shared + @using Microsoft.AspNetCore.Components + @using Microsoft.AspNetCore.Components.Authorization + @using Microsoft.AspNetCore.Components.Routing + @using Microsoft.AspNetCore.Components.Web + """; + + var importPath = new Uri("file:///path/to/_Imports.razor").AbsolutePath; + var importText = SourceText.From(DefaultImports); + var importSource = RazorSourceDocument.Create(importText, RazorSourceDocumentProperties.Create(importPath, importPath)); + var importSnapshotMock = new StrictMock(); + importSnapshotMock .Setup(d => d.GetTextAsync(It.IsAny())) - .ReturnsAsync(importsSourceText); - importsSnapshot + .ReturnsAsync(importText); + importSnapshotMock .Setup(d => d.FilePath) - .Returns(importsPath); - importsSnapshot + .Returns(importPath); + importSnapshotMock .Setup(d => d.TargetPath) - .Returns(importsPath); + .Returns(importPath); var projectFileSystem = new TestRazorProjectFileSystem([ new TestRazorProjectItem(path, fileKind: fileKind), - new TestRazorProjectItem(importsPath, fileKind: FileKinds.ComponentImport)]); + new TestRazorProjectItem(importPath, fileKind: FileKinds.ComponentImport)]); var projectEngine = RazorProjectEngine.Create( new RazorConfiguration(RazorLanguageVersion.Latest, "TestConfiguration", Extensions: []), @@ -305,63 +305,80 @@ @using Microsoft.AspNetCore.Components.Web RazorExtensions.Register(builder); }); - var codeDocument = projectEngine.ProcessDesignTime(sourceDocument, fileKind, [importsDocument], tagHelpers); + var codeDocument = projectEngine.ProcessDesignTime(sourceDocument, fileKind, [importSource], tagHelpers); if (!allowDiagnostics) { Assert.False(codeDocument.GetCSharpDocument().Diagnostics.Any(), "Error creating document:" + Environment.NewLine + string.Join(Environment.NewLine, codeDocument.GetCSharpDocument().Diagnostics)); } - var imports = ImmutableArray.Create(importsSnapshot.Object); - var importsDocuments = ImmutableArray.Create(importsDocument); - var documentSnapshot = CreateDocumentSnapshot(path, tagHelpers, fileKind, importsDocuments, imports, projectEngine, codeDocument, inGlobalNamespace: inGlobalNamespace); + var documentSnapshot = CreateDocumentSnapshot( + path, fileKind, codeDocument, projectEngine, [importSnapshotMock.Object], [importSource], tagHelpers, inGlobalNamespace); return (codeDocument, documentSnapshot); } - internal static IDocumentSnapshot CreateDocumentSnapshot(string path, ImmutableArray tagHelpers, string fileKind, ImmutableArray importsDocuments, ImmutableArray imports, RazorProjectEngine projectEngine, RazorCodeDocument codeDocument, bool inGlobalNamespace = false) + internal static IDocumentSnapshot CreateDocumentSnapshot( + string path, + string fileKind, + RazorCodeDocument codeDocument, + RazorProjectEngine projectEngine, + ImmutableArray imports, + ImmutableArray importDocuments, + ImmutableArray tagHelpers, + bool inGlobalNamespace) { - var documentSnapshot = new StrictMock(); - documentSnapshot - .Setup(d => d.GetGeneratedOutputAsync(It.IsAny(), It.IsAny())) + var snapshotMock = new StrictMock(); + + snapshotMock + .Setup(d => d.GetGeneratedOutputAsync(It.IsAny())) .ReturnsAsync(codeDocument); - documentSnapshot + snapshotMock .Setup(d => d.FilePath) .Returns(path); - documentSnapshot + snapshotMock .Setup(d => d.Project.Key) .Returns(TestProjectKey.Create("/obj")); - documentSnapshot + snapshotMock .Setup(d => d.TargetPath) .Returns(path); - documentSnapshot + snapshotMock .Setup(d => d.Project.Configuration) .Returns(projectEngine.Configuration); - documentSnapshot + snapshotMock .Setup(d => d.GetTextAsync(It.IsAny())) .ReturnsAsync(codeDocument.Source.Text); - documentSnapshot + snapshotMock .Setup(d => d.Project.GetTagHelpersAsync(It.IsAny())) .ReturnsAsync(tagHelpers); - documentSnapshot + snapshotMock .Setup(d => d.Project.GetProjectEngine()) .Returns(projectEngine); - documentSnapshot + snapshotMock .Setup(d => d.FileKind) .Returns(fileKind); - documentSnapshot + snapshotMock .Setup(d => d.Version) .Returns(1); - documentSnapshot + snapshotMock .Setup(d => d.WithText(It.IsAny())) .Returns(text => { - var sourceDocument = RazorSourceDocument.Create(text, RazorSourceDocumentProperties.Create( + var source = RazorSourceDocument.Create(text, RazorSourceDocumentProperties.Create( filePath: path, relativePath: inGlobalNamespace ? Path.GetFileName(path) : path)); - var codeDocument = projectEngine.ProcessDesignTime(sourceDocument, fileKind, importsDocuments, tagHelpers); - return CreateDocumentSnapshot(path, tagHelpers, fileKind, importsDocuments, imports, projectEngine, codeDocument, inGlobalNamespace: inGlobalNamespace); + + var codeDocument = projectEngine.ProcessDesignTime(source, fileKind, importDocuments, tagHelpers); + + return CreateDocumentSnapshot( + path, fileKind, codeDocument, projectEngine, imports, importDocuments, tagHelpers, inGlobalNamespace); }); - return documentSnapshot.Object; + + var generatorMock = snapshotMock.As(); + generatorMock + .Setup(x => x.GenerateDesignTimeOutputAsync(It.IsAny())) + .ReturnsAsync(codeDocument); + + return snapshotMock.Object; } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverEndpointTest.cs index 0b382a6687c..0464645ab42 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverEndpointTest.cs @@ -255,7 +255,7 @@ private static (DocumentContext, Position) CreateDefaultDocumentContext() var documentSnapshotMock = new StrictMock(); documentSnapshotMock - .Setup(x => x.GetGeneratedOutputAsync(It.IsAny(), It.IsAny())) + .Setup(x => x.GetGeneratedOutputAsync(It.IsAny())) .ReturnsAsync(codeDocument); documentSnapshotMock .Setup(x => x.GetTextAsync(It.IsAny())) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs index 0e0af6e7b41..2828946d072 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs @@ -955,7 +955,7 @@ private static DocumentContext CreateDocumentContext( .SetupGet(x => x.Project) .Returns(projectSnapshot.Object); documentSnapshotMock - .Setup(x => x.GetGeneratedOutputAsync(It.IsAny(), It.IsAny())) + .Setup(x => x.GetGeneratedOutputAsync(It.IsAny())) .ReturnsAsync(document); documentSnapshotMock .Setup(x => x.GetTextAsync(It.IsAny())) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs index 4199fb0581d..636e31626fb 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestDocumentSnapshot.cs @@ -65,12 +65,10 @@ public static TestDocumentSnapshot Create(string filePath, RazorCodeDocument cod public IProjectSnapshot Project => RealSnapshot.Project; public int Version => RealSnapshot.Version; - public ValueTask GetGeneratedOutputAsync( - bool forceDesignTimeGeneratedOutput, - CancellationToken cancellationToken) + public ValueTask GetGeneratedOutputAsync(CancellationToken cancellationToken) { return _codeDocument is null - ? RealSnapshot.GetGeneratedOutputAsync(forceDesignTimeGeneratedOutput, cancellationToken) + ? RealSnapshot.GetGeneratedOutputAsync(cancellationToken) : new(_codeDocument); } @@ -88,7 +86,7 @@ public ValueTask GetCSharpSyntaxTreeAsync(CancellationToken cancella { return _codeDocument is null ? RealSnapshot.GetCSharpSyntaxTreeAsync(cancellationToken) - : new(DocumentSnapshot.GetOrParseCSharpSyntaxTree(_codeDocument, cancellationToken)); + : new(_codeDocument.GetOrParseCSharpSyntaxTree(cancellationToken)); } public bool TryGetGeneratedOutput([NotNullWhen(true)] out RazorCodeDocument? result) diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs index 7cfc734a5e8..0839e737fa8 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs @@ -48,7 +48,7 @@ public DefaultDocumentSnapshotTest(ITestOutputHelper testOutput) _nestedComponentDocument = new DocumentSnapshot(project, documentState); } - [Fact] + [Fact(Skip = "Weak cache removed")] public async Task GCCollect_OutputIsNoLongerCached() { // Arrange diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs index 5918aa95d23..3b4e91e6932 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System.Collections.Immutable; -using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectSystem; @@ -42,201 +41,182 @@ protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder public async Task AddDocument_CachesOutput() { // Arrange - var original = ProjectState + var state = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddEmptyDocument(_hostDocument); - var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); + var output = await GetGeneratedOutputAsync(state, _hostDocument); // Act - var state = original.AddEmptyDocument(TestProjectData.AnotherProjectFile1); + var newState = state.AddEmptyDocument(TestProjectData.AnotherProjectFile1); + var newOutput = await GetGeneratedOutputAsync(newState, _hostDocument); // Assert - var (actualOutput, actualInputVersion) = await GetOutputAsync(state, _hostDocument, DisposalToken); - Assert.Same(originalOutput, actualOutput); - Assert.Equal(originalInputVersion, actualInputVersion); + Assert.Same(output, newOutput); } [Fact] public async Task AddDocument_Import_DoesNotCacheOutput() { // Arrange - var original = ProjectState + var state = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddEmptyDocument(_hostDocument); - var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); + var output = await GetGeneratedOutputAsync(state, _hostDocument); // Act - var state = original.AddEmptyDocument(TestProjectData.SomeProjectImportFile); + var newState = state.AddEmptyDocument(TestProjectData.SomeProjectImportFile); + var newOutput = await GetGeneratedOutputAsync(newState, _hostDocument); // Assert - var (actualOutput, actualInputVersion) = await GetOutputAsync(state, _hostDocument, DisposalToken); - Assert.NotSame(originalOutput, actualOutput); - Assert.NotEqual(originalInputVersion, actualInputVersion); - Assert.Equal(state.DocumentCollectionVersion, actualInputVersion); + Assert.NotSame(output, newOutput); } [Fact] public async Task WithDocumentText_DoesNotCacheOutput() { // Arrange - var original = ProjectState + var state = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddEmptyDocument(_hostDocument) .AddEmptyDocument(TestProjectData.SomeProjectImportFile); - var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); + var output = await GetGeneratedOutputAsync(state, _hostDocument); // Act - var version = VersionStamp.Create(); - var state = original.WithDocumentText(_hostDocument.FilePath, TestMocks.CreateTextLoader("@using System", version)); + var newState = state.WithDocumentText(_hostDocument.FilePath, TestMocks.CreateTextLoader("@using System")); + var newOutput = await GetGeneratedOutputAsync(newState, _hostDocument); // Assert - var (actualOutput, actualInputVersion) = await GetOutputAsync(state, _hostDocument, DisposalToken); - Assert.NotSame(originalOutput, actualOutput); - Assert.NotEqual(originalInputVersion, actualInputVersion); - Assert.Equal(version, actualInputVersion); + Assert.NotSame(output, newOutput); } [Fact] public async Task WithDocumentText_Import_DoesNotCacheOutput() { // Arrange - var original = ProjectState + var state = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddEmptyDocument(_hostDocument) .AddEmptyDocument(TestProjectData.SomeProjectImportFile); - var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); + var output = await GetGeneratedOutputAsync(state, _hostDocument); // Act - var version = VersionStamp.Create(); - var state = original.WithDocumentText(TestProjectData.SomeProjectImportFile.FilePath, TestMocks.CreateTextLoader("@using System", version)); + var newState = state.WithDocumentText(TestProjectData.SomeProjectImportFile.FilePath, TestMocks.CreateTextLoader("@using System")); + var newOutput = await GetGeneratedOutputAsync(newState, _hostDocument); // Assert - var (actualOutput, actualInputVersion) = await GetOutputAsync(state, _hostDocument, DisposalToken); - Assert.NotSame(originalOutput, actualOutput); - Assert.NotEqual(originalInputVersion, actualInputVersion); - Assert.Equal(version, actualInputVersion); + Assert.NotSame(output, newOutput); } [Fact] public async Task RemoveDocument_Import_DoesNotCacheOutput() { // Arrange - var original = ProjectState + var state = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddEmptyDocument(_hostDocument) .AddEmptyDocument(TestProjectData.SomeProjectImportFile); - var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); + var output = await GetGeneratedOutputAsync(state, _hostDocument); // Act - var state = original.RemoveDocument(TestProjectData.SomeProjectImportFile.FilePath); + var newState = state.RemoveDocument(TestProjectData.SomeProjectImportFile.FilePath); + var newOutput = await GetGeneratedOutputAsync(newState, _hostDocument); // Assert - var (actualOutput, actualInputVersion) = await GetOutputAsync(state, _hostDocument, DisposalToken); - Assert.NotSame(originalOutput, actualOutput); - Assert.NotEqual(originalInputVersion, actualInputVersion); - Assert.Equal(state.DocumentCollectionVersion, actualInputVersion); + Assert.NotSame(output, newOutput); } [Fact] public async Task WithProjectWorkspaceState_CachesOutput_EvenWhenNewerProjectWorkspaceState() { // Arrange - var original = ProjectState + var state = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddEmptyDocument(_hostDocument); - var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); + var output = await GetGeneratedOutputAsync(state, _hostDocument); // Act - var state = original.WithProjectWorkspaceState(ProjectWorkspaceState.Default); + var newState = state.WithProjectWorkspaceState(ProjectWorkspaceState.Default); + var newOutput = await GetGeneratedOutputAsync(newState, _hostDocument); // Assert - var (actualOutput, actualInputVersion) = await GetOutputAsync(state, _hostDocument, DisposalToken); - Assert.Same(originalOutput, actualOutput); - Assert.Equal(originalInputVersion, actualInputVersion); + Assert.Same(output, newOutput); } - // The generated code's text doesn't change as a result, so the output version does not change [Fact] public async Task WithProjectWorkspaceState_TagHelperChange_DoesNotCacheOutput() { // Arrange - var original = ProjectState + var state = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddEmptyDocument(_hostDocument); - var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); + var output = await GetGeneratedOutputAsync(state, _hostDocument); // Act - var state = original.WithProjectWorkspaceState( - ProjectWorkspaceState.Create(_someTagHelpers)); + var newState = state.WithProjectWorkspaceState(ProjectWorkspaceState.Create(_someTagHelpers)); + var newOutput = await GetGeneratedOutputAsync(newState, _hostDocument); // Assert - var (actualOutput, actualInputVersion) = await GetOutputAsync(state, _hostDocument, DisposalToken); - Assert.NotSame(originalOutput, actualOutput); - Assert.NotEqual(originalInputVersion, actualInputVersion); - Assert.Equal(state.ProjectWorkspaceStateVersion, actualInputVersion); + Assert.NotSame(output, newOutput); } [Fact] public async Task WithProjectWorkspaceState_CSharpLanguageVersionChange_DoesNotCacheOutput() { // Arrange - var csharp8ValidConfiguration = new RazorConfiguration(RazorLanguageVersion.Version_3_0, _hostProject.Configuration.ConfigurationName, _hostProject.Configuration.Extensions); - var hostProject = TestProjectData.SomeProject with { Configuration = csharp8ValidConfiguration }; - var originalWorkspaceState = ProjectWorkspaceState.Create(_someTagHelpers, LanguageVersion.CSharp7); - var original = ProjectState - .Create(hostProject, originalWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) + var hostProject = TestProjectData.SomeProject with + { + Configuration = _hostProject.Configuration with { LanguageVersion = RazorLanguageVersion.Version_3_0 } + }; + + var projectWorkspaceState = ProjectWorkspaceState.Create(_someTagHelpers, LanguageVersion.CSharp7); + + var state = ProjectState + .Create(hostProject, projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) .AddDocument(_hostDocument, TestMocks.CreateTextLoader("@DateTime.Now", VersionStamp.Default)); - var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); + var output = await GetGeneratedOutputAsync(state, _hostDocument); // Act - var state = original.WithProjectWorkspaceState( - ProjectWorkspaceState.Create(_someTagHelpers, LanguageVersion.CSharp8)); + var newProjectWorkspaceState = ProjectWorkspaceState.Create(_someTagHelpers, LanguageVersion.CSharp8); + var newState = state.WithProjectWorkspaceState(newProjectWorkspaceState); + var newOutput = await GetGeneratedOutputAsync(newState, _hostDocument); // Assert - var (actualOutput, actualInputVersion) = await GetOutputAsync(state, _hostDocument, DisposalToken); - Assert.NotSame(originalOutput, actualOutput); - Assert.NotEqual(originalInputVersion, actualInputVersion); - Assert.Equal(state.ProjectWorkspaceStateVersion, actualInputVersion); + Assert.NotSame(output, newOutput); } [Fact] public async Task WithHostProject_DoesNotCacheOutput() { // Arrange - var original = ProjectState + var state = ProjectState .Create(_hostProject, CompilerOptions, ProjectEngineFactoryProvider) .AddEmptyDocument(_hostDocument); - var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken); + var output = await GetGeneratedOutputAsync(state, _hostDocument); // Act - var state = original.WithHostProject(_hostProjectWithConfigurationChange); + var newState = state.WithHostProject(_hostProjectWithConfigurationChange); + var newOutput = await GetGeneratedOutputAsync(newState, _hostDocument); // Assert - var (actualOutput, actualInputVersion) = await GetOutputAsync(state, _hostDocument, DisposalToken); - Assert.NotSame(originalOutput, actualOutput); - Assert.NotEqual(originalInputVersion, actualInputVersion); - Assert.NotEqual(state.ProjectWorkspaceStateVersion, actualInputVersion); + Assert.NotSame(output, newOutput); } - private static Task<(RazorCodeDocument, VersionStamp)> GetOutputAsync(ProjectState project, HostDocument hostDocument, CancellationToken cancellationToken) + private ValueTask GetGeneratedOutputAsync(ProjectState project, HostDocument hostDocument) { var document = project.Documents[hostDocument.FilePath]; - return GetOutputAsync(project, document, cancellationToken); - } - private static Task<(RazorCodeDocument, VersionStamp)> GetOutputAsync(ProjectState project, DocumentState document, CancellationToken cancellationToken) - { var projectSnapshot = new ProjectSnapshot(project); var documentSnapshot = new DocumentSnapshot(projectSnapshot, document); - return document.GetGeneratedOutputAndVersionAsync(projectSnapshot, documentSnapshot, cancellationToken); + + return documentSnapshot.GetGeneratedOutputAsync(DisposalToken); } } 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 491362c92ba..3b69d7de3ed 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 @@ -204,7 +204,7 @@ private async Task CreateLocalProjectAndRazorDocumentAsync( var snapshotManager = _exportProvider.AssumeNotNull().GetExportedValue(); var snapshot = snapshotManager.GetSnapshot(razorDocument); // Compile the Razor file - var codeDocument = await snapshot.GetGeneratedOutputAsync(forceDesignTimeGeneratedOutput: false, DisposalToken); + var codeDocument = await snapshot.GetGeneratedOutputAsync(DisposalToken); // Update the generated doc contents var generatedDocumentIds = solution.GetDocumentIdsWithFilePath(documentFilePath + CSharpVirtualDocumentSuffix); solution = solution.WithDocumentText(generatedDocumentIds, codeDocument.GetCSharpSourceText()); From 1e045ea2fcf96e4bed9c86cc35834c16d1a7decd Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 17 Dec 2024 12:34:09 -0800 Subject: [PATCH 21/42] Introduce legacy snapshot interfaces to support legacy editor This change adds ILegacyDocumentSnapshot and ILegacyProjectSnapshot to be used exclusively by the legacy editor. These provide synchronous methods that should *only* be used by the legacy editor. --- .../ProjectSystem/DocumentSnapshot.cs | 22 +++--- .../Legacy/ILegacyDocumentSnapshot.cs | 15 ++++ .../Legacy/ILegacyProjectSnapshot.cs | 29 ++++++++ .../ProjectSystem/ProjectSnapshot.cs | 35 ++++++++- .../EphemeralProjectSnapshot.cs | 71 ++++--------------- .../IVisualStudioDocumentTracker.cs | 4 +- .../ImportDocumentManager.cs | 4 +- .../Parsing/VisualStudioRazorParser.cs | 6 +- .../VisualStudioDocumentTracker.cs | 43 ++++++----- .../ProjectSystem/TestProjectSnapshot.cs | 11 ++- .../ImportDocumentManagerIntegrationTest.cs | 9 +-- .../ImportDocumentManagerTest.cs | 25 +++---- .../VisualStudioRazorParserIntegrationTest.cs | 4 +- .../Parsing/VisualStudioRazorParserTest.cs | 3 +- 14 files changed, 164 insertions(+), 117 deletions(-) create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Legacy/ILegacyDocumentSnapshot.cs create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Legacy/ILegacyProjectSnapshot.cs diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs index 85616505e19..bca7a49b1ce 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs @@ -5,30 +5,26 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis.Razor.ProjectSystem.Legacy; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -internal sealed class DocumentSnapshot : IDocumentSnapshot, IDesignTimeCodeGenerator +internal sealed class DocumentSnapshot(ProjectSnapshot project, DocumentState state) : IDocumentSnapshot, IDesignTimeCodeGenerator, ILegacyDocumentSnapshot { - public ProjectSnapshot Project { get; } + public ProjectSnapshot Project { get; } = project; - private readonly DocumentState _state; - - public DocumentSnapshot(ProjectSnapshot project, DocumentState state) - { - Project = project; - _state = state; - } + private readonly DocumentState _state = state; public HostDocument HostDocument => _state.HostDocument; public string FileKind => _state.HostDocument.FileKind; public string FilePath => _state.HostDocument.FilePath; public string TargetPath => _state.HostDocument.TargetPath; - IProjectSnapshot IDocumentSnapshot.Project => Project; public int Version => _state.Version; + IProjectSnapshot IDocumentSnapshot.Project => Project; + public bool TryGetText([NotNullWhen(true)] out SourceText? result) => _state.TryGetText(out result); @@ -73,4 +69,10 @@ public async Task GenerateDesignTimeOutputAsync(CancellationT .GenerateDesignTimeCodeDocumentAsync(this, Project.GetProjectEngine(), importItems, cancellationToken) .ConfigureAwait(false); } + + #region ILegacyDocumentSnapshot support + + string ILegacyDocumentSnapshot.FileKind => FileKind; + + #endregion } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Legacy/ILegacyDocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Legacy/ILegacyDocumentSnapshot.cs new file mode 100644 index 00000000000..a8df3962469 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Legacy/ILegacyDocumentSnapshot.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +namespace Microsoft.CodeAnalysis.Razor.ProjectSystem.Legacy; + +/// +/// Provides document snapshot members used by the legacy editor. +/// +/// +/// This interface should only be accessed by the legacy editor. +/// +internal interface ILegacyDocumentSnapshot +{ + string FileKind { get; } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Legacy/ILegacyProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Legacy/ILegacyProjectSnapshot.cs new file mode 100644 index 00000000000..35449dc4faf --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Legacy/ILegacyProjectSnapshot.cs @@ -0,0 +1,29 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Immutable; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis.CSharp; + +namespace Microsoft.CodeAnalysis.Razor.ProjectSystem.Legacy; + +/// +/// Provides project snapshot members used by the legacy editor. +/// +/// +/// This interface should only be accessed by the legacy editor. +/// +internal interface ILegacyProjectSnapshot +{ + RazorConfiguration Configuration { get; } + + string FilePath { get; } + + string? RootNamespace { get; } + LanguageVersion CSharpLanguageVersion { get; } + ImmutableArray TagHelpers { get; } + + RazorProjectEngine GetProjectEngine(); + + ILegacyDocumentSnapshot? GetDocument(string filePath); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs index ddfc43e229c..8e6889d8458 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs @@ -11,11 +11,12 @@ using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Utilities; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Razor.ProjectSystem.Legacy; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -internal sealed class ProjectSnapshot(ProjectState state) : IProjectSnapshot +internal sealed class ProjectSnapshot(ProjectState state) : IProjectSnapshot, ILegacyProjectSnapshot { private readonly ProjectState _state = state; @@ -64,7 +65,7 @@ public bool ContainsDocument(string filePath) } } - public bool TryGetDocument(string filePath, [NotNullWhen(true)] out IDocumentSnapshot? document) + public bool TryGetDocument(string filePath, [NotNullWhen(true)] out DocumentSnapshot? document) { lock (_gate) { @@ -91,6 +92,18 @@ public bool TryGetDocument(string filePath, [NotNullWhen(true)] out IDocumentSna } } + bool IProjectSnapshot.TryGetDocument(string filePath, [NotNullWhen(true)] out IDocumentSnapshot? document) + { + if (TryGetDocument(filePath, out var result)) + { + document = result; + return true; + } + + document = null; + return false; + } + /// /// If the provided document is an import document, gets the other documents in the project /// that include directives specified by the provided document. Otherwise returns an empty @@ -178,4 +191,22 @@ public async Task> GetImportItemsAsync(HostDocument h return importItems.DrainToImmutable(); } + + #region ILegacyProjectSnapshot support + + RazorConfiguration ILegacyProjectSnapshot.Configuration => Configuration; + string ILegacyProjectSnapshot.FilePath => FilePath; + string? ILegacyProjectSnapshot.RootNamespace => RootNamespace; + LanguageVersion ILegacyProjectSnapshot.CSharpLanguageVersion => CSharpLanguageVersion; + ImmutableArray ILegacyProjectSnapshot.TagHelpers => ProjectWorkspaceState.TagHelpers; + + RazorProjectEngine ILegacyProjectSnapshot.GetProjectEngine() + => _state.ProjectEngine; + + ILegacyDocumentSnapshot? ILegacyProjectSnapshot.GetDocument(string filePath) + => TryGetDocument(filePath, out var document) + ? document + : null; + + #endregion } diff --git a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/EphemeralProjectSnapshot.cs b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/EphemeralProjectSnapshot.cs index bbd1a585693..2567583f46f 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/EphemeralProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/EphemeralProjectSnapshot.cs @@ -2,76 +2,35 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Threading; -using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectEngineHost; -using Microsoft.AspNetCore.Razor.ProjectSystem; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.ProjectSystem.Legacy; namespace Microsoft.VisualStudio.LegacyEditor.Razor; -internal class EphemeralProjectSnapshot : IProjectSnapshot +internal sealed class EphemeralProjectSnapshot(IProjectEngineFactoryProvider projectEngineFactoryProvider, string filePath) : ILegacyProjectSnapshot { - private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider; - private readonly Lazy _projectEngine; + public string FilePath { get; } = filePath; - public EphemeralProjectSnapshot(IProjectEngineFactoryProvider projectEngineFactoryProvider, string projectPath) - { - _projectEngineFactoryProvider = projectEngineFactoryProvider; - FilePath = projectPath; - IntermediateOutputPath = Path.Combine(Path.GetDirectoryName(FilePath) ?? FilePath, "obj"); - DisplayName = Path.GetFileNameWithoutExtension(projectPath); - - _projectEngine = new Lazy(CreateProjectEngine); - - Key = new ProjectKey(IntermediateOutputPath); - } - - public ProjectKey Key { get; } + private readonly Lazy _projectEngine = new(() => + projectEngineFactoryProvider.Create( + FallbackRazorConfiguration.Latest, + rootDirectoryPath: Path.GetDirectoryName(filePath).AssumeNotNull(), + configure: null)); public RazorConfiguration Configuration => FallbackRazorConfiguration.Latest; - - public IEnumerable DocumentFilePaths => Array.Empty(); - - public string FilePath { get; } - - public string IntermediateOutputPath { get; } - - public string? RootNamespace { get; } - - public string DisplayName { get; } - - public VersionStamp Version => VersionStamp.Default; - - public LanguageVersion CSharpLanguageVersion => ProjectWorkspaceState.CSharpLanguageVersion; - - public ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken) => new(ProjectWorkspaceState.TagHelpers); - - public ProjectWorkspaceState ProjectWorkspaceState => ProjectWorkspaceState.Default; - - public bool ContainsDocument(string filePath) - => false; - - public bool TryGetDocument(string filePath, [NotNullWhen(true)] out IDocumentSnapshot? document) - { - document = null; - return false; - } + public string? RootNamespace => null; + public LanguageVersion CSharpLanguageVersion => LanguageVersion.Default; + public ImmutableArray TagHelpers => []; public RazorProjectEngine GetProjectEngine() - { - return _projectEngine.Value; - } + => _projectEngine.Value; - private RazorProjectEngine CreateProjectEngine() - { - return _projectEngineFactoryProvider.Create(this); - } + public ILegacyDocumentSnapshot? GetDocument(string filePath) + => null; } diff --git a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/IVisualStudioDocumentTracker.cs b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/IVisualStudioDocumentTracker.cs index 0321105f046..bbf6d642f09 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/IVisualStudioDocumentTracker.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/IVisualStudioDocumentTracker.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.ProjectSystem.Legacy; using Microsoft.CodeAnalysis.Razor.Settings; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; @@ -20,7 +20,7 @@ internal interface IVisualStudioDocumentTracker bool IsSupportedProject { get; } string FilePath { get; } string ProjectPath { get; } - IProjectSnapshot? ProjectSnapshot { get; } + ILegacyProjectSnapshot? ProjectSnapshot { get; } ITextBuffer TextBuffer { get; } IReadOnlyList TextViews { get; } diff --git a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/ImportDocumentManager.cs b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/ImportDocumentManager.cs index 28cc774d230..84394217372 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/ImportDocumentManager.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/ImportDocumentManager.cs @@ -8,7 +8,7 @@ using System.Diagnostics; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.ProjectSystem.Legacy; using Microsoft.VisualStudio.Razor.Documents; namespace Microsoft.VisualStudio.LegacyEditor.Razor; @@ -94,7 +94,7 @@ public void OnUnsubscribed(IVisualStudioDocumentTracker documentTracker) } } - private static IEnumerable GetPhysicalImportItems(string filePath, IProjectSnapshot projectSnapshot) + private static IEnumerable GetPhysicalImportItems(string filePath, ILegacyProjectSnapshot projectSnapshot) { var projectEngine = projectSnapshot.GetProjectEngine(); var documentSnapshot = projectSnapshot.GetDocument(filePath); diff --git a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/Parsing/VisualStudioRazorParser.cs b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/Parsing/VisualStudioRazorParser.cs index c7d0d99e534..c98d756b184 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/Parsing/VisualStudioRazorParser.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/Parsing/VisualStudioRazorParser.cs @@ -15,7 +15,6 @@ using Microsoft.AspNetCore.Razor.ProjectEngineHost; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Settings; using Microsoft.Extensions.Internal; using Microsoft.VisualStudio.Language.Intellisense; @@ -223,7 +222,10 @@ internal void StartParser() var projectSnapshot = _documentTracker.ProjectSnapshot.AssumeNotNull(); - _projectEngine = _projectEngineFactoryProvider.Create(projectSnapshot, ConfigureProjectEngine).AssumeNotNull(); + _projectEngine = _projectEngineFactoryProvider.Create( + projectSnapshot.Configuration, + rootDirectoryPath: Path.GetDirectoryName(projectSnapshot.FilePath).AssumeNotNull(), + ConfigureProjectEngine); Debug.Assert(_projectEngine.Engine is not null); Debug.Assert(_projectEngine.FileSystem is not null); diff --git a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTracker.cs b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTracker.cs index 9b40391d28d..737bb1f7e2d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTracker.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTracker.cs @@ -7,9 +7,11 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectEngineHost; using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.ProjectSystem.Legacy; using Microsoft.CodeAnalysis.Razor.Settings; using Microsoft.VisualStudio.LegacyEditor.Razor.Settings; using Microsoft.VisualStudio.Razor.Extensions; @@ -32,7 +34,7 @@ internal sealed class VisualStudioDocumentTracker : IVisualStudioDocumentTracker private readonly List _textViews; private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider; private bool _isSupportedProject; - private IProjectSnapshot? _projectSnapshot; + private ILegacyProjectSnapshot? _projectSnapshot; private int _subscribeCount; @@ -70,13 +72,13 @@ public VisualStudioDocumentTracker( public ClientSpaceSettings EditorSettings => _workspaceEditorSettings.Current.ClientSpaceSettings; public ImmutableArray TagHelpers - => _projectSnapshot is { ProjectWorkspaceState.TagHelpers: var tagHelpers } + => _projectSnapshot is { TagHelpers: var tagHelpers } ? tagHelpers : []; public bool IsSupportedProject => _isSupportedProject; - public IProjectSnapshot? ProjectSnapshot => _projectSnapshot; + public ILegacyProjectSnapshot? ProjectSnapshot => _projectSnapshot; public ITextBuffer TextBuffer => _textBuffer; @@ -147,16 +149,16 @@ public void Subscribe() _importDocumentManager.OnSubscribed(this); - _ = OnContextChangedAsync(ContextChangeKind.ProjectChanged); + OnContextChangedAsync(ContextChangeKind.ProjectChanged).Forget(); } - private IProjectSnapshot GetOrCreateProject(string projectFilePath) + private ILegacyProjectSnapshot GetOrCreateProject(string projectFilePath) { var projectKeys = _projectManager.GetProjectKeysWithFilePath(projectFilePath); if (projectKeys is [var projectKey, ..] && _projectManager.TryGetProject(projectKey, out var project)) { - return project; + return (ILegacyProjectSnapshot)project; } return new EphemeralProjectSnapshot(_projectEngineFactoryProvider, projectFilePath); @@ -179,7 +181,7 @@ public void Unsubscribe() _isSupportedProject = false; _projectSnapshot = null; - _ = OnContextChangedAsync(kind: ContextChangeKind.ProjectChanged); + OnContextChangedAsync(ContextChangeKind.ProjectChanged).Forget(); } private async Task OnContextChangedAsync(ContextChangeKind kind) @@ -200,40 +202,35 @@ internal void ProjectManager_Changed(object sender, ProjectChangeEventArgs e) if (_projectPath is not null && string.Equals(_projectPath, e.ProjectFilePath, StringComparison.OrdinalIgnoreCase)) { - // This will be the new snapshot unless the project was removed. - if (!_projectManager.TryGetProject(e.ProjectKey, out _projectSnapshot)) - { - _projectSnapshot = null; - } - switch (e.Kind) { case ProjectChangeKind.DocumentAdded: case ProjectChangeKind.DocumentRemoved: case ProjectChangeKind.DocumentChanged: - - // Nothing to do. + _projectSnapshot = (e.Newer as ILegacyProjectSnapshot).AssumeNotNull(); break; case ProjectChangeKind.ProjectAdded: case ProjectChangeKind.ProjectChanged: + var newer = (e.Newer as ILegacyProjectSnapshot).AssumeNotNull(); + _projectSnapshot = newer; // Just an update - _ = OnContextChangedAsync(ContextChangeKind.ProjectChanged); + OnContextChangedAsync(ContextChangeKind.ProjectChanged).Forget(); - if (e.Older is null || - !e.Older.ProjectWorkspaceState.TagHelpers.SequenceEqual(e.Newer!.ProjectWorkspaceState.TagHelpers)) + if (e.Older is not ILegacyProjectSnapshot older || + !older.TagHelpers.SequenceEqual(newer.TagHelpers)) { - _ = OnContextChangedAsync(ContextChangeKind.TagHelpersChanged); + OnContextChangedAsync(ContextChangeKind.TagHelpersChanged).Forget(); } break; case ProjectChangeKind.ProjectRemoved: - // Fall back to ephemeral project _projectSnapshot = GetOrCreateProject(ProjectPath); - _ = OnContextChangedAsync(ContextChangeKind.ProjectChanged); + OnContextChangedAsync(ContextChangeKind.ProjectChanged).Forget(); + break; default: @@ -244,7 +241,7 @@ internal void ProjectManager_Changed(object sender, ProjectChangeEventArgs e) // Internal for testing internal void EditorSettingsManager_Changed(object sender, ClientSettingsChangedEventArgs args) - => _ = OnContextChangedAsync(ContextChangeKind.EditorSettingsChanged); + => OnContextChangedAsync(ContextChangeKind.EditorSettingsChanged).Forget(); // Internal for testing internal void Import_Changed(object sender, ImportChangedEventArgs args) @@ -253,7 +250,7 @@ internal void Import_Changed(object sender, ImportChangedEventArgs args) { if (string.Equals(_filePath, path, StringComparison.OrdinalIgnoreCase)) { - _ = OnContextChangedAsync(ContextChangeKind.ImportsChanged); + OnContextChangedAsync(ContextChangeKind.ImportsChanged).Forget(); break; } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs index b5aebfc2b85..b9bfaa3b6b3 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs @@ -58,5 +58,14 @@ public bool ContainsDocument(string filePath) => RealSnapshot.ContainsDocument(filePath); public bool TryGetDocument(string filePath, [NotNullWhen(true)] out IDocumentSnapshot? document) - => RealSnapshot.TryGetDocument(filePath, out document); + { + if (RealSnapshot.TryGetDocument(filePath, out var result)) + { + document = result; + return true; + } + + document = null; + return false; + } } diff --git a/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/ImportDocumentManagerIntegrationTest.cs b/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/ImportDocumentManagerIntegrationTest.cs index 4f6b18fee1a..5261a18467f 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/ImportDocumentManagerIntegrationTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/ImportDocumentManagerIntegrationTest.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.VisualStudio; using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.ProjectSystem.Legacy; using Microsoft.VisualStudio.Razor.Documents; using Moq; using Xunit; @@ -43,16 +44,16 @@ public void Changed_TrackerChanged_ResultsInChangedHavingCorrectArgs() var tracker = StrictMock.Of(t => t.FilePath == Path.Combine(_directoryPath, "Views", "Home", "_ViewImports.cshtml") && t.ProjectPath == _projectPath && - t.ProjectSnapshot == StrictMock.Of(p => + t.ProjectSnapshot == StrictMock.Of(p => p.GetProjectEngine() == _projectEngine && - p.TryGetDocument(It.IsAny(), out It.Ref.IsAny) == false)); + p.GetDocument(It.IsAny()) == null)); var anotherTracker = StrictMock.Of(t => t.FilePath == Path.Combine(_directoryPath, "anotherFile.cshtml") && t.ProjectPath == _projectPath && - t.ProjectSnapshot == StrictMock.Of(p => + t.ProjectSnapshot == StrictMock.Of(p => p.GetProjectEngine() == _projectEngine && - p.TryGetDocument(It.IsAny(), out It.Ref.IsAny) == false)); + p.GetDocument(It.IsAny()) == null)); var fileChangeTrackerFactoryMock = new StrictMock(); var fileChangeTracker1Mock = new StrictMock(); diff --git a/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/ImportDocumentManagerTest.cs b/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/ImportDocumentManagerTest.cs index a2d1c33a5aa..aceeb667d4c 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/ImportDocumentManagerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/ImportDocumentManagerTest.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.VisualStudio; using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.ProjectSystem.Legacy; using Microsoft.VisualStudio.Razor.Documents; using Moq; using Xunit; @@ -42,9 +43,9 @@ public void OnSubscribed_StartsFileChangeTrackers() var tracker = StrictMock.Of(t => t.FilePath == Path.Combine(_directoryPath, "Views", "Home", "file.cshtml") && t.ProjectPath == _projectPath && - t.ProjectSnapshot == StrictMock.Of(p => + t.ProjectSnapshot == StrictMock.Of(p => p.GetProjectEngine() == _projectEngine && - p.TryGetDocument(It.IsAny(), out It.Ref.IsAny) == false)); + p.GetDocument(It.IsAny()) == null)); var fileChangeTrackerFactoryMock = new StrictMock(); var fileChangeTracker1Mock = new StrictMock(); @@ -89,16 +90,16 @@ public void OnSubscribed_AlreadySubscribed_DoesNothing() var tracker = StrictMock.Of(t => t.FilePath == Path.Combine(_directoryPath, "file.cshtml") && t.ProjectPath == _projectPath && - t.ProjectSnapshot == StrictMock.Of(p => + t.ProjectSnapshot == StrictMock.Of(p => p.GetProjectEngine() == _projectEngine && - p.TryGetDocument(It.IsAny(), out It.Ref.IsAny) == false)); + p.GetDocument(It.IsAny()) == null)); var anotherTracker = StrictMock.Of(t => t.FilePath == Path.Combine(_directoryPath, "anotherFile.cshtml") && t.ProjectPath == _projectPath && - t.ProjectSnapshot == StrictMock.Of(p => + t.ProjectSnapshot == StrictMock.Of(p => p.GetProjectEngine() == _projectEngine && - p.TryGetDocument(It.IsAny(), out It.Ref.IsAny) == false)); + p.GetDocument(It.IsAny()) == null)); var callCount = 0; var fileChangeTrackerFactoryMock = new StrictMock(); @@ -127,9 +128,9 @@ public void OnUnsubscribed_StopsFileChangeTracker() var tracker = StrictMock.Of(t => t.FilePath == Path.Combine(_directoryPath, "file.cshtml") && t.ProjectPath == _projectPath && - t.ProjectSnapshot == StrictMock.Of(p => + t.ProjectSnapshot == StrictMock.Of(p => p.GetProjectEngine() == _projectEngine && - p.TryGetDocument(It.IsAny(), out It.Ref.IsAny) == false)); + p.GetDocument(It.IsAny()) == null)); var fileChangeTrackerFactoryMock = new StrictMock(); var fileChangeTrackerMock = new StrictMock(); @@ -161,16 +162,16 @@ public void OnUnsubscribed_AnotherDocumentTrackingImport_DoesNotStopFileChangeTr var tracker = StrictMock.Of(t => t.FilePath == Path.Combine(_directoryPath, "file.cshtml") && t.ProjectPath == _projectPath && - t.ProjectSnapshot == StrictMock.Of(p => + t.ProjectSnapshot == StrictMock.Of(p => p.GetProjectEngine() == _projectEngine && - p.TryGetDocument(It.IsAny(), out It.Ref.IsAny) == false)); + p.GetDocument(It.IsAny()) == null)); var anotherTracker = StrictMock.Of(t => t.FilePath == Path.Combine(_directoryPath, "anotherFile.cshtml") && t.ProjectPath == _projectPath && - t.ProjectSnapshot == StrictMock.Of(p => + t.ProjectSnapshot == StrictMock.Of(p => p.GetProjectEngine() == _projectEngine && - p.TryGetDocument(It.IsAny(), out It.Ref.IsAny) == false)); + p.GetDocument(It.IsAny()) == null)); var fileChangeTrackerFactoryMock = new StrictMock(); var fileChangeTrackerMock = new StrictMock(); diff --git a/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Parsing/VisualStudioRazorParserIntegrationTest.cs b/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Parsing/VisualStudioRazorParserIntegrationTest.cs index 0f5427a7a3b..a89aa70ee89 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Parsing/VisualStudioRazorParserIntegrationTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Parsing/VisualStudioRazorParserIntegrationTest.cs @@ -14,7 +14,7 @@ using Microsoft.AspNetCore.Razor.Test.Common.Editor; using Microsoft.AspNetCore.Razor.Test.Common.VisualStudio; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.ProjectSystem.Legacy; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; @@ -31,7 +31,7 @@ public class VisualStudioRazorParserIntegrationTest : VisualStudioTestBase private const string TestProjectPath = @"C:\This\Path\Is\Just\For\Project.csproj"; private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider; - private readonly IProjectSnapshot _projectSnapshot; + private readonly ILegacyProjectSnapshot _projectSnapshot; private readonly CodeAnalysis.Workspace _workspace; public VisualStudioRazorParserIntegrationTest(ITestOutputHelper testOutput) diff --git a/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Parsing/VisualStudioRazorParserTest.cs b/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Parsing/VisualStudioRazorParserTest.cs index 43f35596bc0..ae9e3b6c643 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Parsing/VisualStudioRazorParserTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Parsing/VisualStudioRazorParserTest.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Razor.Test.Common.VisualStudio; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.ProjectSystem.Legacy; using Microsoft.VisualStudio.Language.Intellisense; using Moq; using Xunit; @@ -20,7 +21,7 @@ namespace Microsoft.VisualStudio.LegacyEditor.Razor.Parsing; public class VisualStudioRazorParserTest : VisualStudioTestBase { - private readonly IProjectSnapshot _projectSnapshot; + private readonly ILegacyProjectSnapshot _projectSnapshot; private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider; private readonly CodeAnalysis.Workspace _workspace; From 0049ac02dab966bbf52e7932eed406aae149c496 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 17 Dec 2024 12:56:11 -0800 Subject: [PATCH 22/42] Remove IProjectSnapshot.Version This property isn't actually used outside of ProjectState. --- .../ProjectSystem/IProjectSnapshot.cs | 1 - .../ProjectSystem/ProjectSnapshot.cs | 5 ----- .../ProjectSystem/RemoteProjectSnapshot.cs | 2 -- .../Semantic/SemanticTokensTest.cs | 7 ++----- .../ProjectSystem/TestProjectSnapshot.cs | 1 - 5 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs index 30da674be39..784633bb9bc 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs @@ -31,7 +31,6 @@ internal interface IProjectSnapshot string? RootNamespace { get; } string DisplayName { get; } - VersionStamp Version { get; } LanguageVersion CSharpLanguageVersion { get; } ProjectWorkspaceState ProjectWorkspaceState { get; } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs index 8e6889d8458..11ac029970e 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs @@ -33,16 +33,11 @@ internal sealed class ProjectSnapshot(ProjectState state) : IProjectSnapshot, IL public string IntermediateOutputPath => _state.HostProject.IntermediateOutputPath; public string? RootNamespace => _state.HostProject.RootNamespace; public string DisplayName => _state.HostProject.DisplayName; - public VersionStamp Version => _state.Version; public LanguageVersion CSharpLanguageVersion => _state.CSharpLanguageVersion; public ProjectWorkspaceState ProjectWorkspaceState => _state.ProjectWorkspaceState; public int DocumentCount => _state.Documents.Count; - public VersionStamp ConfigurationVersion => _state.ConfigurationVersion; - public VersionStamp ProjectWorkspaceStateVersion => _state.ProjectWorkspaceStateVersion; - public VersionStamp DocumentCollectionVersion => _state.DocumentCollectionVersion; - public RazorProjectEngine GetProjectEngine() => _state.ProjectEngine; 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 0254a971126..369bafd1b9f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs @@ -67,8 +67,6 @@ public IEnumerable DocumentFilePaths public string DisplayName => _project.Name; - public VersionStamp Version => _project.Version; - public Project Project => _project; public LanguageVersion CSharpLanguageVersion => ((CSharpParseOptions)_project.ParseOptions.AssumeNotNull()).LanguageVersion; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs index 2828946d072..0389bc7d4e0 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs @@ -945,15 +945,12 @@ private static DocumentContext CreateDocumentContext( { var document = CreateCodeDocument(documentText, isRazorFile, tagHelpers); - var projectSnapshot = new StrictMock(); - projectSnapshot - .SetupGet(p => p.Version) - .Returns(VersionStamp.Default); + var projectSnapshot = StrictMock.Of(); var documentSnapshotMock = new StrictMock(); documentSnapshotMock .SetupGet(x => x.Project) - .Returns(projectSnapshot.Object); + .Returns(projectSnapshot); documentSnapshotMock .Setup(x => x.GetGeneratedOutputAsync(It.IsAny())) .ReturnsAsync(document); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs index b9bfaa3b6b3..d99c8c1e904 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs @@ -43,7 +43,6 @@ public static TestProjectSnapshot Create(string filePath, ProjectWorkspaceState? public string DisplayName => RealSnapshot.DisplayName; public LanguageVersion CSharpLanguageVersion => RealSnapshot.CSharpLanguageVersion; public ProjectWorkspaceState ProjectWorkspaceState => RealSnapshot.ProjectWorkspaceState; - public VersionStamp Version => RealSnapshot.Version; public RazorProjectEngine GetProjectEngine() => RazorProjectEngine.Create( From b5acc30edfadc68ab4de077f4af82339eb78f69d Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 17 Dec 2024 13:01:10 -0800 Subject: [PATCH 23/42] Remove ProjectState.DocumentCollectionVersion --- .../ProjectSystem/ProjectState.cs | 23 ------------------- .../ProjectSystem/ProjectStateTest.cs | 10 -------- 2 files changed, 33 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs index 32f738cfaf3..34b72f9934a 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs @@ -32,11 +32,6 @@ internal sealed class ProjectState ProjectDifference.ConfigurationChanged | ProjectDifference.ProjectWorkspaceStateChanged; - private const ProjectDifference ClearDocumentCollectionVersionMask = - ProjectDifference.ConfigurationChanged | - ProjectDifference.DocumentAdded | - ProjectDifference.DocumentRemoved; - private static readonly ImmutableDictionary s_emptyDocuments = ImmutableDictionary.Create(FilePathNormalizingComparer.Instance); private static readonly ImmutableDictionary> s_emptyImportsToRelatedDocuments @@ -71,7 +66,6 @@ private ProjectState( ImportsToRelatedDocuments = s_emptyImportsToRelatedDocuments; Version = VersionStamp.Create(); ProjectWorkspaceStateVersion = Version; - DocumentCollectionVersion = Version; } private ProjectState( @@ -92,16 +86,6 @@ private ProjectState( Version = older.Version.GetNewerVersion(); - if ((difference & ClearDocumentCollectionVersionMask) == 0) - { - // Document collection hasn't changed - DocumentCollectionVersion = older.DocumentCollectionVersion; - } - else - { - DocumentCollectionVersion = Version; - } - if ((difference & ClearConfigurationVersionMask) == 0 && older._projectEngine != null) { // Optimistically cache the RazorProjectEngine. @@ -168,13 +152,6 @@ public static ProjectState Create(HostProject hostProject) /// public VersionStamp Version { get; } - /// - /// Gets the version of this project, NOT INCLUDING computed or content changes. The - /// is incremented each time the configuration changes or - /// a document is added or removed. - /// - public VersionStamp DocumentCollectionVersion { get; } - public RazorProjectEngine ProjectEngine { get diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs index b50cce90066..415406abec2 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs @@ -70,7 +70,6 @@ public void ProjectState_AddDocument_ToEmpty() var documentState = Assert.Single(newState.Documents.Values); Assert.Same(SomeProjectFile1, documentState.HostDocument); - Assert.NotEqual(state.DocumentCollectionVersion, newState.DocumentCollectionVersion); } [Fact] @@ -107,7 +106,6 @@ public void ProjectState_AddDocument_ToProjectWithDocuments() d => Assert.Same(AnotherProjectNestedFile3, d.Value.HostDocument), d => Assert.Same(SomeProjectFile1, d.Value.HostDocument), d => Assert.Same(SomeProjectFile2, d.Value.HostDocument)); - Assert.NotEqual(state.DocumentCollectionVersion, newState.DocumentCollectionVersion); } [Fact] @@ -242,8 +240,6 @@ public async Task ProjectState_WithDocumentText_Loader() var text = await newState.Documents[SomeProjectFile2.FilePath].GetTextAsync(DisposalToken); Assert.Same(s_text, text); - - Assert.Equal(state.DocumentCollectionVersion, newState.DocumentCollectionVersion); } [Fact] @@ -263,8 +259,6 @@ public async Task ProjectState_WithDocumentText_Snapshot() var text = await newState.Documents[SomeProjectFile2.FilePath].GetTextAsync(DisposalToken); Assert.Same(s_text, text); - - Assert.Equal(state.DocumentCollectionVersion, newState.DocumentCollectionVersion); } [Fact] @@ -354,8 +348,6 @@ public void ProjectState_RemoveDocument_FromProjectWithDocuments() var documentState = Assert.Single(newState.Documents.Values); Assert.Same(AnotherProjectNestedFile3, documentState.HostDocument); - - Assert.NotEqual(state.DocumentCollectionVersion, newState.DocumentCollectionVersion); } [Fact] @@ -477,8 +469,6 @@ public void ProjectState_WithHostProject_ConfigurationChange_UpdatesConfiguratio Assert.NotSame(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); Assert.NotSame(state.Documents[AnotherProjectNestedFile3.FilePath], newState.Documents[AnotherProjectNestedFile3.FilePath]); - - Assert.NotEqual(state.DocumentCollectionVersion, newState.DocumentCollectionVersion); } [Fact] From f26bd8179e49f2f791e9f1e3d53dfeda8b5c51f7 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 17 Dec 2024 13:11:47 -0800 Subject: [PATCH 24/42] Remove remaining version logic from ProjectState --- .../ProjectSystem/ProjectDifference.cs | 17 ----- .../ProjectSystem/ProjectState.cs | 71 ++++--------------- .../ProjectSystem/ProjectStateTest.cs | 30 -------- 3 files changed, 12 insertions(+), 106 deletions(-) delete mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectDifference.cs diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectDifference.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectDifference.cs deleted file mode 100644 index f309380a705..00000000000 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectDifference.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT license. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; - -[Flags] -internal enum ProjectDifference -{ - None = 0, - ConfigurationChanged = 1, - ProjectWorkspaceStateChanged = 2, - DocumentAdded = 4, - DocumentRemoved = 8, - DocumentChanged = 16, -} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs index 34b72f9934a..28ede34a5cb 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs @@ -26,12 +26,6 @@ internal sealed class ProjectState private static readonly ObjectPool.Builder>> s_importMapBuilderPool = DictionaryPool.Builder>.Create(FilePathNormalizingComparer.Instance); - private const ProjectDifference ClearConfigurationVersionMask = ProjectDifference.ConfigurationChanged; - - private const ProjectDifference ClearProjectWorkspaceStateVersionMask = - ProjectDifference.ConfigurationChanged | - ProjectDifference.ProjectWorkspaceStateChanged; - private static readonly ImmutableDictionary s_emptyDocuments = ImmutableDictionary.Create(FilePathNormalizingComparer.Instance); private static readonly ImmutableDictionary> s_emptyImportsToRelatedDocuments @@ -64,17 +58,15 @@ private ProjectState( Documents = s_emptyDocuments; ImportsToRelatedDocuments = s_emptyImportsToRelatedDocuments; - Version = VersionStamp.Create(); - ProjectWorkspaceStateVersion = Version; } private ProjectState( ProjectState older, - ProjectDifference difference, HostProject hostProject, ProjectWorkspaceState projectWorkspaceState, ImmutableDictionary documents, - ImmutableDictionary> importsToRelatedDocuments) + ImmutableDictionary> importsToRelatedDocuments, + bool retainProjectEngine) { HostProject = hostProject; CompilerOptions = older.CompilerOptions; @@ -84,36 +76,9 @@ private ProjectState( Documents = documents; ImportsToRelatedDocuments = importsToRelatedDocuments; - Version = older.Version.GetNewerVersion(); - - if ((difference & ClearConfigurationVersionMask) == 0 && older._projectEngine != null) - { - // Optimistically cache the RazorProjectEngine. - _projectEngine = older.ProjectEngine; - ConfigurationVersion = older.ConfigurationVersion; - } - else + if (retainProjectEngine) { - ConfigurationVersion = Version; - } - - if ((difference & ClearProjectWorkspaceStateVersionMask) == 0 || - ProjectWorkspaceState == older.ProjectWorkspaceState || - ProjectWorkspaceState.Equals(older.ProjectWorkspaceState)) - { - ProjectWorkspaceStateVersion = older.ProjectWorkspaceStateVersion; - } - else - { - ProjectWorkspaceStateVersion = Version; - } - - if ((difference & ClearProjectWorkspaceStateVersionMask) != 0 && - CSharpLanguageVersion != older.CSharpLanguageVersion) - { - // C# language version changed. This impacts the ProjectEngine, reset it. - _projectEngine = null; - ConfigurationVersion = Version; + _projectEngine = older._projectEngine; } } @@ -146,12 +111,6 @@ public static ProjectState Create(HostProject hostProject) public LanguageVersion CSharpLanguageVersion => ProjectWorkspaceState.CSharpLanguageVersion; - /// - /// Gets the version of this project, INCLUDING content changes. The is - /// incremented for each new instance created. - /// - public VersionStamp Version { get; } - public RazorProjectEngine ProjectEngine { get @@ -180,15 +139,6 @@ RazorProjectEngine CreateProjectEngine() } } - /// - /// Gets the version of this project based on the project workspace state, NOT INCLUDING content - /// changes. The computed state is guaranteed to change when the configuration or tag helpers - /// change. - /// - public VersionStamp ProjectWorkspaceStateVersion { get; } - - public VersionStamp ConfigurationVersion { get; } - public ProjectState AddEmptyDocument(HostDocument hostDocument) => AddDocument(hostDocument, EmptyTextLoader.Instance); @@ -237,7 +187,7 @@ private ProjectState AddDocument(DocumentState state) // Then, if this is an import, update any related documents. documents = UpdateRelatedDocuments(hostDocument, documents); - return new(this, ProjectDifference.DocumentAdded, HostProject, ProjectWorkspaceState, documents, importsToRelatedDocuments); + return new(this, HostProject, ProjectWorkspaceState, documents, importsToRelatedDocuments, retainProjectEngine: true); } public ProjectState RemoveDocument(string documentFilePath) @@ -259,7 +209,7 @@ public ProjectState RemoveDocument(string documentFilePath) // Then, compute the effect on the import map var importsToRelatedDocuments = RemoveFromImportsToRelatedDocuments(hostDocument); - return new(this, ProjectDifference.DocumentRemoved, HostProject, ProjectWorkspaceState, documents, importsToRelatedDocuments); + return new(this, HostProject, ProjectWorkspaceState, documents, importsToRelatedDocuments, retainProjectEngine: true); } public ProjectState WithDocumentText(string documentFilePath, SourceText text) @@ -311,7 +261,7 @@ private ProjectState WithDocumentText(DocumentState state, Func x.WithProjectWorkspaceStateChange()); - return new(this, ProjectDifference.ProjectWorkspaceStateChanged, HostProject, projectWorkspaceState, documents, ImportsToRelatedDocuments); + // If the C# language version changed, we need a new project engine. + var retainProjectEngine = ProjectWorkspaceState.CSharpLanguageVersion == projectWorkspaceState.CSharpLanguageVersion; + + return new(this, HostProject, projectWorkspaceState, documents, ImportsToRelatedDocuments, retainProjectEngine); } private ImmutableDictionary> AddToImportsToRelatedDocuments(HostDocument hostDocument) diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs index 415406abec2..a917910c7bc 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs @@ -53,7 +53,6 @@ public void ProjectState_ConstructedNew() // Assert Assert.Empty(state.Documents); - Assert.NotEqual(VersionStamp.Default, state.Version); } [Fact] @@ -66,8 +65,6 @@ public void ProjectState_AddDocument_ToEmpty() var newState = state.AddEmptyDocument(SomeProjectFile1); // Assert - Assert.NotEqual(state.Version, newState.Version); - var documentState = Assert.Single(newState.Documents.Values); Assert.Same(SomeProjectFile1, documentState.HostDocument); } @@ -99,8 +96,6 @@ public void ProjectState_AddDocument_ToProjectWithDocuments() var newState = state.AddEmptyDocument(SomeProjectFile1); // Assert - Assert.NotEqual(state.Version, newState.Version); - Assert.Collection( newState.Documents.OrderBy(static kvp => kvp.Key), d => Assert.Same(AnotherProjectNestedFile3, d.Value.HostDocument), @@ -202,7 +197,6 @@ public void ProjectState_AddDocument_RetainsComputedState() // Assert Assert.Same(state.ProjectEngine, newState.ProjectEngine); AssertSameTagHelpers(state.TagHelpers, newState.TagHelpers); - Assert.Equal(state.ProjectWorkspaceStateVersion, newState.ProjectWorkspaceStateVersion); Assert.Same(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); Assert.Same(state.Documents[AnotherProjectNestedFile3.FilePath], newState.Documents[AnotherProjectNestedFile3.FilePath]); } @@ -236,8 +230,6 @@ public async Task ProjectState_WithDocumentText_Loader() var newState = state.WithDocumentText(SomeProjectFile2.FilePath, s_textLoader); // Assert - Assert.NotEqual(state.Version, newState.Version); - var text = await newState.Documents[SomeProjectFile2.FilePath].GetTextAsync(DisposalToken); Assert.Same(s_text, text); } @@ -255,8 +247,6 @@ public async Task ProjectState_WithDocumentText_Snapshot() var newState = state.WithDocumentText(SomeProjectFile2.FilePath, s_text); // Assert - Assert.NotEqual(state.Version, newState.Version); - var text = await newState.Documents[SomeProjectFile2.FilePath].GetTextAsync(DisposalToken); Assert.Same(s_text, text); } @@ -276,7 +266,6 @@ public void ProjectState_WithDocumentText_Loader_RetainsComputedState() // Assert Assert.Same(state.ProjectEngine, newState.ProjectEngine); AssertSameTagHelpers(state.TagHelpers, newState.TagHelpers); - Assert.Equal(state.ProjectWorkspaceStateVersion, newState.ProjectWorkspaceStateVersion); Assert.NotSame(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); } @@ -295,7 +284,6 @@ public void ProjectState_WithDocumentText_Snapshot_RetainsComputedState() // Assert Assert.Same(original.ProjectEngine, state.ProjectEngine); AssertSameTagHelpers(original.TagHelpers, state.TagHelpers); - Assert.Equal(original.ProjectWorkspaceStateVersion, state.ProjectWorkspaceStateVersion); Assert.NotSame(original.Documents[SomeProjectFile2.FilePath], state.Documents[SomeProjectFile2.FilePath]); } @@ -344,8 +332,6 @@ public void ProjectState_RemoveDocument_FromProjectWithDocuments() var newState = state.RemoveDocument(SomeProjectFile2.FilePath); // Assert - Assert.NotEqual(state.Version, newState.Version); - var documentState = Assert.Single(newState.Documents.Values); Assert.Same(AnotherProjectNestedFile3, documentState.HostDocument); } @@ -427,7 +413,6 @@ public void ProjectState_RemoveDocument_RetainsComputedState() // Assert Assert.Same(state.ProjectEngine, newState.ProjectEngine); AssertSameTagHelpers(state.TagHelpers, newState.TagHelpers); - Assert.Equal(state.ProjectWorkspaceStateVersion, newState.ProjectWorkspaceStateVersion); Assert.Same(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); } @@ -460,12 +445,10 @@ public void ProjectState_WithHostProject_ConfigurationChange_UpdatesConfiguratio var newState = state.WithHostProject(s_hostProject with { Configuration = FallbackRazorConfiguration.MVC_1_0 }); // Assert - Assert.NotEqual(state.Version, newState.Version); Assert.Same(FallbackRazorConfiguration.MVC_1_0, newState.HostProject.Configuration); Assert.NotSame(state.ProjectEngine, newState.ProjectEngine); AssertSameTagHelpers(state.TagHelpers, newState.TagHelpers); - Assert.NotEqual(state.ConfigurationVersion, newState.ConfigurationVersion); Assert.NotSame(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); Assert.NotSame(state.Documents[AnotherProjectNestedFile3.FilePath], newState.Documents[AnotherProjectNestedFile3.FilePath]); @@ -519,7 +502,6 @@ public void ProjectState_WithConfiguration_Change_UpdatesAllDocuments() var newState = state.WithHostProject(s_hostProject with { Configuration = FallbackRazorConfiguration.MVC_1_0 }); // Assert - Assert.NotEqual(state.Version, newState.Version); Assert.Equal(FallbackRazorConfiguration.MVC_1_0, newState.HostProject.Configuration); // all documents were updated @@ -565,13 +547,11 @@ public void ProjectState_WithProjectWorkspaceState_Changed() var newState = state.WithProjectWorkspaceState(newWorkspaceState); // Assert - Assert.NotEqual(state.Version, newState.Version); Assert.Same(newWorkspaceState, newState.ProjectWorkspaceState); // The C# language version changed, and the tag helpers didn't change Assert.NotSame(state.ProjectEngine, newState.ProjectEngine); AssertSameTagHelpers(state.TagHelpers, newState.TagHelpers); - Assert.NotEqual(state.ProjectWorkspaceStateVersion, newState.ProjectWorkspaceStateVersion); Assert.NotSame(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); Assert.NotSame(state.Documents[AnotherProjectNestedFile3.FilePath], newState.Documents[AnotherProjectNestedFile3.FilePath]); @@ -590,15 +570,11 @@ public void ProjectState_WithProjectWorkspaceState_Changed_TagHelpersChanged() var newState = state.WithProjectWorkspaceState(ProjectWorkspaceState.Default); // Assert - Assert.NotEqual(state.Version, newState.Version); Assert.Same(ProjectWorkspaceState.Default, newState.ProjectWorkspaceState); // The configuration didn't change, but the tag helpers did Assert.Same(state.ProjectEngine, newState.ProjectEngine); Assert.NotEqual(state.TagHelpers, newState.TagHelpers); - Assert.NotEqual(state.ProjectWorkspaceStateVersion, newState.ProjectWorkspaceStateVersion); - Assert.Equal(newState.Version, newState.ProjectWorkspaceStateVersion); - Assert.NotSame(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); Assert.NotSame(state.Documents[AnotherProjectNestedFile3.FilePath], newState.Documents[AnotherProjectNestedFile3.FilePath]); } @@ -633,7 +609,6 @@ public void ProjectState_WithProjectWorkspaceState_UpdatesAllDocuments() var newState = state.WithProjectWorkspaceState(ProjectWorkspaceState.Default); // Assert - Assert.NotEqual(state.Version, newState.Version); Assert.NotEqual(state.ProjectWorkspaceState, newState.ProjectWorkspaceState); Assert.Same(ProjectWorkspaceState.Default, newState.ProjectWorkspaceState); @@ -664,7 +639,6 @@ public void ProjectState_AddImportDocument_UpdatesRelatedDocuments() var newState = state.AddEmptyDocument(AnotherProjectImportFile); // Assert - Assert.NotEqual(state.Version, newState.Version); // related documents were updated var relatedDocumentPaths = newState.ImportsToRelatedDocuments[AnotherProjectImportFile.TargetPath]; @@ -696,7 +670,6 @@ public void ProjectState_AddImportDocument_UpdatesRelatedDocuments_Nested() var newState = state.AddEmptyDocument(AnotherProjectNestedImportFile); // Assert - Assert.NotEqual(state.Version, newState.Version); // related documents were updated var relatedDocumentPaths = newState.ImportsToRelatedDocuments[AnotherProjectNestedImportFile.TargetPath]; @@ -734,7 +707,6 @@ public void ProjectState_WithImportDocumentText_UpdatesRelatedDocuments_TextLoad var newState = state.WithDocumentText(AnotherProjectNestedImportFile.FilePath, s_textLoader); // Assert - Assert.NotEqual(state.Version, newState.Version); // document was updated AssertDocumentUpdated(AnotherProjectNestedImportFile.FilePath, state, newState); @@ -776,7 +748,6 @@ public void ProjectState_WithImportDocumentText_UpdatesRelatedDocuments_Snapshot var newState = state.WithDocumentText(AnotherProjectNestedImportFile.FilePath, s_text); // Assert - Assert.NotEqual(state.Version, newState.Version); // document was updated AssertDocumentUpdated(AnotherProjectNestedImportFile.FilePath, state, newState); @@ -820,7 +791,6 @@ public void ProjectState_RemoveImportDocument_UpdatesRelatedDocuments() var newState = state.RemoveDocument(AnotherProjectNestedImportFile.FilePath); // Assert - Assert.NotEqual(state.Version, newState.Version); // document was removed Assert.False(newState.Documents.ContainsKey(AnotherProjectNestedImportFile.FilePath)); From b3416038a92ffb9d50ada6510d241ac54582ddc1 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 17 Dec 2024 14:13:39 -0800 Subject: [PATCH 25/42] Make IProjectSnapshot.GetProjectEngine() async --- .../ProjectSystem/DocumentSnapshot.cs | 3 ++- .../ProjectSystem/IProjectSnapshot.cs | 2 +- .../ProjectSystem/ProjectSnapshot.cs | 6 ++--- .../Sources/GeneratedOutputSource.cs | 2 +- .../ProjectSystem/RemoteDocumentSnapshot.cs | 4 +-- .../ProjectSystem/RemoteProjectSnapshot.cs | 16 ++++++----- .../Remote/OutOfProcTagHelperResolver.cs | 7 +++-- .../Formatting_NetFx/FormattingTestBase.cs | 4 +-- .../ProjectSystem/TestProjectSnapshot.cs | 9 ++----- .../ProjectSnapshotManagerTest.cs | 27 ++++++++++++------- 10 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs index bca7a49b1ce..eb09ea14ea3 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs @@ -64,9 +64,10 @@ async Task GetCSharpSyntaxTreeCoreAsync(CancellationToken cancellati public async Task GenerateDesignTimeOutputAsync(CancellationToken cancellationToken) { var importItems = await Project.GetImportItemsAsync(FilePath, cancellationToken).ConfigureAwait(false); + var projectEngine = await Project.GetProjectEngineAsync(cancellationToken).ConfigureAwait(false); return await CompilationHelpers - .GenerateDesignTimeCodeDocumentAsync(this, Project.GetProjectEngine(), importItems, cancellationToken) + .GenerateDesignTimeCodeDocumentAsync(this, projectEngine, importItems, cancellationToken) .ConfigureAwait(false); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs index 784633bb9bc..c8fe9b45bb5 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs @@ -34,7 +34,7 @@ internal interface IProjectSnapshot LanguageVersion CSharpLanguageVersion { get; } ProjectWorkspaceState ProjectWorkspaceState { get; } - RazorProjectEngine GetProjectEngine(); + ValueTask GetProjectEngineAsync(CancellationToken cancellationToken); ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken); bool ContainsDocument(string filePath); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs index 11ac029970e..b9d89780a05 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs @@ -38,8 +38,8 @@ internal sealed class ProjectSnapshot(ProjectState state) : IProjectSnapshot, IL public int DocumentCount => _state.Documents.Count; - public RazorProjectEngine GetProjectEngine() - => _state.ProjectEngine; + public ValueTask GetProjectEngineAsync(CancellationToken cancellationToken) + => new(_state.ProjectEngine); public ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken) => new(_state.TagHelpers); @@ -138,7 +138,7 @@ public ValueTask> GetImportItemsAsync(string filePath public async Task> GetImportItemsAsync(HostDocument hostDocument, CancellationToken cancellationToken) { - var projectEngine = GetProjectEngine(); + var projectEngine = await GetProjectEngineAsync(cancellationToken).ConfigureAwait(false); var projectItem = projectEngine.FileSystem.GetItem(hostDocument.FilePath, hostDocument.FileKind); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs index a3a63313a39..71c763bfed8 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs @@ -30,7 +30,7 @@ public async ValueTask GetValueAsync(DocumentSnapshot documen using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { var project = document.Project; - var projectEngine = project.GetProjectEngine(); + var projectEngine = await project.GetProjectEngineAsync(cancellationToken).ConfigureAwait(false); var compilerOptions = project.CompilerOptions; var importItems = await project.GetImportItemsAsync(document.HostDocument, cancellationToken).ConfigureAwait(false); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs index 56ce328a0c4..dfc1181e92f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs @@ -80,7 +80,7 @@ public ValueTask GetGeneratedOutputAsync(CancellationToken ca private async Task ComputeGeneratedOutputAsync(CancellationToken cancellationToken) { - var projectEngine = await ProjectSnapshot.GetProjectEngine_CohostOnlyAsync(cancellationToken).ConfigureAwait(false); + var projectEngine = await ProjectSnapshot.GetProjectEngineAsync(cancellationToken).ConfigureAwait(false); var compilerOptions = ProjectSnapshot.SolutionSnapshot.SnapshotManager.CompilerOptions; return await CompilationHelpers @@ -90,7 +90,7 @@ private async Task ComputeGeneratedOutputAsync(CancellationTo public async Task GenerateDesignTimeOutputAsync(CancellationToken cancellationToken) { - var projectEngine = await ProjectSnapshot.GetProjectEngine_CohostOnlyAsync(cancellationToken).ConfigureAwait(false); + var projectEngine = await ProjectSnapshot.GetProjectEngineAsync(cancellationToken).ConfigureAwait(false); return await CompilationHelpers .GenerateDesignTimeCodeDocumentAsync(this, projectEngine, cancellationToken) 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 369bafd1b9f..b37c4e28fe1 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs @@ -162,14 +162,18 @@ public bool TryGetDocument(string filePath, [NotNullWhen(true)] out IDocumentSna return false; } - public RazorProjectEngine GetProjectEngine() => throw new InvalidOperationException("Should not be called for cohosted projects."); - /// - /// NOTE: To be called only from CohostDocumentSnapshot.GetGeneratedOutputAsync(). Will be removed when that method uses the source generator directly. + /// NOTE: This will be removed when that method uses the source generator directly. /// - /// - internal Task GetProjectEngine_CohostOnlyAsync(CancellationToken cancellationToken) - => _lazyProjectEngine.GetValueAsync(cancellationToken); + public ValueTask GetProjectEngineAsync(CancellationToken cancellationToken) + { + if (_lazyProjectEngine.TryGetValue(out var result)) + { + return new(result); + } + + return new(_lazyProjectEngine.GetValueAsync(cancellationToken)); + } private async Task ComputeConfigurationAsync(CancellationToken cancellationToken) { diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/OutOfProcTagHelperResolver.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/OutOfProcTagHelperResolver.cs index 63078a39543..34a1ac4217b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/OutOfProcTagHelperResolver.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/OutOfProcTagHelperResolver.cs @@ -174,9 +174,12 @@ protected ImmutableArray ProduceChecksumsFromDelta(ProjectId projectId return checksums; } - protected virtual ValueTask> ResolveTagHelpersInProcessAsync( + protected virtual async ValueTask> ResolveTagHelpersInProcessAsync( Project project, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken) - => project.GetTagHelpersAsync(projectSnapshot.GetProjectEngine(), _telemetryReporter, cancellationToken); + { + var projectEngine = await projectSnapshot.GetProjectEngineAsync(cancellationToken).ConfigureAwait(false); + return await project.GetTagHelpersAsync(projectEngine, _telemetryReporter, cancellationToken).ConfigureAwait(false); + } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs index 3fd1373b196..7d30979e31f 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs @@ -352,8 +352,8 @@ internal static IDocumentSnapshot CreateDocumentSnapshot( .Setup(d => d.Project.GetTagHelpersAsync(It.IsAny())) .ReturnsAsync(tagHelpers); snapshotMock - .Setup(d => d.Project.GetProjectEngine()) - .Returns(projectEngine); + .Setup(d => d.Project.GetProjectEngineAsync(It.IsAny())) + .ReturnsAsync(projectEngine); snapshotMock .Setup(d => d.FileKind) .Returns(fileKind); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs index d99c8c1e904..fbe8d6d656e 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs @@ -8,10 +8,8 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectSystem; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.NET.Sdk.Razor.SourceGenerators; namespace Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; @@ -44,11 +42,8 @@ public static TestProjectSnapshot Create(string filePath, ProjectWorkspaceState? public LanguageVersion CSharpLanguageVersion => RealSnapshot.CSharpLanguageVersion; public ProjectWorkspaceState ProjectWorkspaceState => RealSnapshot.ProjectWorkspaceState; - public RazorProjectEngine GetProjectEngine() - => RazorProjectEngine.Create( - Configuration, - RazorProjectFileSystem.Create("C:/"), - b => b.Features.Add(new ConfigureRazorParserOptions(useRoslynTokenizer: true, CSharpParseOptions.Default))); + public ValueTask GetProjectEngineAsync(CancellationToken cancellationToken) + => RealSnapshot.GetProjectEngineAsync(cancellationToken); public ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken) => RealSnapshot.GetTagHelpersAsync(cancellationToken); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs index 8fee5b90d06..61fcb44e458 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs @@ -300,7 +300,7 @@ await _projectManager.UpdateAsync(updater => }); var project = _projectManager.GetRequiredProject(s_hostProject.Key); - var projectEngine = project.GetProjectEngine(); + var projectEngine = await project.GetProjectEngineAsync(DisposalToken); // Act await _projectManager.UpdateAsync(updater => @@ -309,8 +309,11 @@ await _projectManager.UpdateAsync(updater => }); // Assert - project = _projectManager.GetRequiredProject(s_hostProject.Key); - Assert.Same(projectEngine, project.GetProjectEngine()); + var newProjectEngine = await _projectManager + .GetRequiredProject(s_hostProject.Key) + .GetProjectEngineAsync(DisposalToken); + + Assert.Same(projectEngine, newProjectEngine); } [UIFact] @@ -432,7 +435,7 @@ await _projectManager.UpdateAsync(updater => }); var project = _projectManager.GetRequiredProject(s_hostProject.Key); - var projectEngine = project.GetProjectEngine(); + var projectEngine = await project.GetProjectEngineAsync(DisposalToken); // Act await _projectManager.UpdateAsync(updater => @@ -441,8 +444,11 @@ await _projectManager.UpdateAsync(updater => }); // Assert - project = _projectManager.GetRequiredProject(s_hostProject.Key); - Assert.Same(projectEngine, project.GetProjectEngine()); + var newProjectEngine = await _projectManager + .GetRequiredProject(s_hostProject.Key) + .GetProjectEngineAsync(DisposalToken); + + Assert.Same(projectEngine, newProjectEngine); } [UIFact] @@ -681,7 +687,7 @@ await _projectManager.UpdateAsync(updater => }); var project = _projectManager.GetRequiredProject(s_hostProject.Key); - var projectEngine = project.GetProjectEngine(); + var projectEngine = await project.GetProjectEngineAsync(DisposalToken); // Act await _projectManager.UpdateAsync(updater => @@ -690,8 +696,11 @@ await _projectManager.UpdateAsync(updater => }); // Assert - project = _projectManager.GetRequiredProject(s_hostProjectWithConfigurationChange.Key); - Assert.NotSame(projectEngine, project.GetProjectEngine()); + var newProjectEngine = await _projectManager + .GetRequiredProject(s_hostProjectWithConfigurationChange.Key) + .GetProjectEngineAsync(DisposalToken); + + Assert.NotSame(projectEngine, newProjectEngine); } [UIFact] From aafea13eec611b136c0c8570a9d1406dd9720bdc Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 17 Dec 2024 16:54:44 -0800 Subject: [PATCH 26/42] Remove IProjectSnapshotManager interface This change fully removes the IProjectSnapshotManager interface. Components in the language server and VS client layers can import a ProjectSnapshotManager. ProjectSnapshotManager provides direct access to DocumentSnapshot and ProjectSnapshot, which implement IDocumentSnapshot and IProjectSnapshot. --- .../CodeDocumentReferenceHolder.cs | 82 -- .../RazorCompletionResolveEndpoint.cs | 4 +- .../Definition/DefinitionEndpoint.cs | 4 +- .../RazorDiagnosticsPublisher.TestAccessor.cs | 2 +- .../Diagnostics/RazorDiagnosticsPublisher.cs | 16 +- .../DocumentContextFactory.cs | 6 +- .../IServiceCollectionExtensions.cs | 3 +- .../FindAllReferencesEndpoint.cs | 4 +- .../GeneratedDocumentPublisher.cs | 4 +- .../GeneratedDocumentSynchronizer.cs | 6 +- .../Hover/HoverEndpoint.cs | 4 +- .../IDocumentProcessedListener.cs | 2 +- .../OpenDocumentGenerator.cs | 12 +- ...nagerExtensions.SolutionQueryOperations.cs | 9 +- .../IProjectSnapshotManagerExtensions.cs | 18 +- .../ProjectSystem/MiscFilesProject.cs | 4 +- .../ProjectSystem/RazorProjectService.cs | 16 +- .../Refactoring/RenameEndpoint.cs | 4 +- .../WorkspaceDiagnosticsRefresher.cs | 4 +- .../WorkspaceSemanticTokensRefreshTrigger.cs | 4 +- .../ITagHelperResolver.cs | 4 +- .../ProjectSystem/IProjectSnapshotManager.cs | 38 - .../ProjectSystem/ProjectChangeEventArgs.cs | 20 +- .../ProjectSystem/ProjectSnapshot.cs | 4 +- ...nsions.cs => ProjectSnapshotExtensions.cs} | 24 +- .../ProjectSnapshotManager.Entry.cs | 4 +- .../ProjectSnapshotManager.Updater.cs | 5 +- .../ProjectSystem/ProjectSnapshotManager.cs | 20 +- ...cs => ProjectSnapshotManagerExtensions.cs} | 26 +- .../EditorDocumentManagerListener.cs | 7 +- ...eDocumentProvidingSnapshotChangeTrigger.cs | 4 +- .../BackgroundDocumentGenerator.Comparer.cs | 6 +- .../BackgroundDocumentGenerator.cs | 20 +- .../RazorDynamicFileInfoProvider.cs | 2 +- .../IProjectWorkspaceStateGenerator.cs | 2 +- .../CSharpVirtualDocumentFactory.cs | 4 +- .../CSharpVirtualDocumentManager.cs | 2 +- .../Endpoints/RazorCustomMessageTarget.cs | 4 +- .../ProjectSystem/RazorProjectInfoDriver.cs | 4 +- .../RazorLanguageServerClient.cs | 4 +- .../ProjectSnapshotSynchronizationService.cs | 4 +- ...ctSnapshotSynchronizationServiceFactory.cs | 2 +- .../Host/ProjectSnapshotManagerProxy.cs | 22 +- .../ProjectSnapshotManagerProxyFactory.cs | 2 +- .../DefaultWindowsRazorProjectHost.cs | 2 +- .../ProjectSystem/FallbackProjectManager.cs | 6 +- .../FallbackWindowsRazorProjectHost.cs | 2 +- .../ProjectSystem/IFallbackProjectManager.cs | 2 +- .../VisualStudioProjectSnapshotManager.cs | 2 +- .../WindowsRazorProjectHostBase.cs | 4 +- .../ProjectWorkspaceStateGenerator.cs | 12 +- .../Remote/OutOfProcTagHelperResolver.cs | 6 +- .../VisualStudioSolutionCloseChangeTrigger.cs | 4 +- ...tionUpdatesProjectSnapshotChangeTrigger.cs | 4 +- ...paceProjectStateChangeDetector.Comparer.cs | 6 +- .../WorkspaceProjectStateChangeDetector.cs | 18 +- .../VisualStudioDocumentTracker.cs | 4 +- .../VisualStudioDocumentTrackerFactory.cs | 4 +- .../CodeDocumentReferenceHolderTest.cs | 190 --- .../RazorDiagnosticsPublisherTest.cs | 309 ++-- .../GeneratedDocumentSynchronizerTest.cs | 40 +- .../Mapping/RazorEditHelperTest.cs | 1246 ++++++++--------- .../OpenDocumentGeneratorTest.cs | 5 +- .../IProjectSnapshotManagerExtensionsTest.cs | 2 +- .../RazorComponentSearchEngineTest.cs | 2 +- .../TestRazorProjectService.cs | 31 +- ...rkspaceSemanticTokensRefreshTriggerTest.cs | 2 +- .../ProjectEngineFactoryProviderTest.cs | 12 +- .../TestTagHelperResolver.cs | 2 +- .../ToolingTestBase.cs | 8 +- .../Workspaces/WorkspaceTestBase.cs | 2 +- .../IProjectSnapshotManagerExtensions.cs | 9 +- .../BackgroundDocumentGeneratorTest.cs | 12 +- .../EditorDocumentManagerListenerTest.cs | 8 +- .../CSharpVirtualDocumentFactoryTest.cs | 4 +- .../RazorProjectInfoDriverTest.cs | 2 +- .../RazorCustomMessageTargetTest.cs | 21 +- .../FallbackWindowsRazorProjectHostTest.cs | 2 +- .../RazorDynamicFileInfoProviderTest.cs | 6 +- .../TestProjectWorkspaceStateGenerator.cs | 4 +- ...WorkspaceProjectStateChangeDetectorTest.cs | 2 +- ...fProcTagHelperResolverTest.TestResolver.cs | 8 +- .../InProcess/RazorProjectSystemInProcess.cs | 8 +- 83 files changed, 1047 insertions(+), 1408 deletions(-) delete mode 100644 src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeDocumentReferenceHolder.cs delete mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshotManager.cs rename src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/{IProjectSnapshotExtensions.cs => ProjectSnapshotExtensions.cs} (72%) rename src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/{IProjectSnapshotManagerExtensions.cs => ProjectSnapshotManagerExtensions.cs} (59%) delete mode 100644 src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeDocumentReferenceHolderTest.cs diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeDocumentReferenceHolder.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeDocumentReferenceHolder.cs deleted file mode 100644 index 00564573173..00000000000 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeDocumentReferenceHolder.cs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT license. See License.txt in the project root for license information. - -using System.Collections.Generic; -using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; - -namespace Microsoft.AspNetCore.Razor.LanguageServer; - -internal class CodeDocumentReferenceHolder : IDocumentProcessedListener -{ - private readonly IProjectSnapshotManager _projectManager; - private readonly Dictionary _codeDocumentCache; - - public CodeDocumentReferenceHolder(IProjectSnapshotManager projectManager) - { - _projectManager = projectManager; - _codeDocumentCache = []; - - _projectManager.Changed += ProjectManager_Changed; - } - - public void DocumentProcessed(RazorCodeDocument codeDocument, IDocumentSnapshot documentSnapshot) - { - // We capture a reference to the code document after a document has been processed in order to ensure that - // latest document state information is readily available without re-computation. The DocumentState type - // (brains of DocumentSnapshot) will garbage collect its generated output aggressively and due to the - // nature of LSP being heavily asynchronous (multiple requests for single keystrokes) we don't want to cause - // multiple parses/regenerations across LSP requests that are all for the same document version. - lock (_codeDocumentCache) - { - var key = new DocumentKey(documentSnapshot.Project.Key, documentSnapshot.FilePath); - _codeDocumentCache[key] = codeDocument; - } - } - - private void ProjectManager_Changed(object? sender, ProjectChangeEventArgs args) - { - // Goal here is to evict cache entries (really just references to code documents) of known documents when - // related information changes for them - - switch (args.Kind) - { - case ProjectChangeKind.ProjectChanged: - foreach (var documentFilePath in args.Newer!.DocumentFilePaths) - { - lock (_codeDocumentCache) - { - var key = new DocumentKey(args.Newer.Key, documentFilePath); - _codeDocumentCache.Remove(key); - } - } - - break; - - case ProjectChangeKind.ProjectRemoved: - foreach (var documentFilePath in args.Older!.DocumentFilePaths) - { - lock (_codeDocumentCache) - { - var key = new DocumentKey(args.Older.Key, documentFilePath); - _codeDocumentCache.Remove(key); - } - } - - break; - - case ProjectChangeKind.DocumentChanged: - case ProjectChangeKind.DocumentRemoved: - { - lock (_codeDocumentCache) - { - var key = new DocumentKey(args.ProjectKey, args.DocumentFilePath.AssumeNotNull()); - _codeDocumentCache.Remove(key); - } - } - - break; - } - } -} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionResolveEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionResolveEndpoint.cs index afbd950bac8..29c523ed396 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionResolveEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionResolveEndpoint.cs @@ -19,13 +19,13 @@ internal class RazorCompletionResolveEndpoint { private readonly AggregateCompletionItemResolver _completionItemResolver; private readonly CompletionListCache _completionListCache; - private readonly IProjectSnapshotManager _projectSnapshotManager; + private readonly ProjectSnapshotManager _projectSnapshotManager; private VSInternalClientCapabilities? _clientCapabilities; public RazorCompletionResolveEndpoint( AggregateCompletionItemResolver completionItemResolver, CompletionListCache completionListCache, - IProjectSnapshotManager projectSnapshotManager) + ProjectSnapshotManager projectSnapshotManager) { _completionItemResolver = completionItemResolver; _completionListCache = completionListCache; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs index 44014b47563..5e1302f78f6 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition; internal sealed class DefinitionEndpoint( IRazorComponentDefinitionService componentDefinitionService, IDocumentMappingService documentMappingService, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, LanguageServerFeatureOptions languageServerFeatureOptions, IClientConnection clientConnection, ILoggerFactory loggerFactory) @@ -37,7 +37,7 @@ internal sealed class DefinitionEndpoint( { private readonly IRazorComponentDefinitionService _componentDefinitionService = componentDefinitionService; private readonly IDocumentMappingService _documentMappingService = documentMappingService; - private readonly IProjectSnapshotManager _projectManager = projectManager; + private readonly ProjectSnapshotManager _projectManager = projectManager; protected override bool PreferCSharpOverHtmlIfPossible => true; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.TestAccessor.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.TestAccessor.cs index ddcc99f5817..cfd11e395eb 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.TestAccessor.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.TestAccessor.cs @@ -49,7 +49,7 @@ public void ClearClosedDocuments() instance.ClearClosedDocuments(); } - public Task PublishDiagnosticsAsync(IDocumentSnapshot document, CancellationToken cancellationToken) + public Task PublishDiagnosticsAsync(DocumentSnapshot document, CancellationToken cancellationToken) { return instance.PublishDiagnosticsAsync(document, cancellationToken); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.cs index 8ba6aee4cfa..cbc8c84aad6 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.cs @@ -33,7 +33,7 @@ private readonly record struct PublishedDiagnostics(IReadOnlyList _documentContextFactory; private readonly CancellationTokenSource _disposeTokenSource; - private readonly AsyncBatchingWorkQueue _workQueue; + private readonly AsyncBatchingWorkQueue _workQueue; private readonly Dictionary _publishedDiagnostics; private Task _clearClosedDocumentsTask = Task.CompletedTask; public RazorDiagnosticsPublisher( - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, IClientConnection clientConnection, LanguageServerFeatureOptions options, Lazy translateDiagnosticsService, @@ -61,7 +61,7 @@ public RazorDiagnosticsPublisher( // Present for test to specify publish delay protected RazorDiagnosticsPublisher( - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, IClientConnection clientConnection, LanguageServerFeatureOptions options, Lazy translateDiagnosticsService, @@ -76,7 +76,7 @@ protected RazorDiagnosticsPublisher( _documentContextFactory = documentContextFactory; _disposeTokenSource = new(); - _workQueue = new AsyncBatchingWorkQueue(publishDelay, ProcessBatchAsync, _disposeTokenSource.Token); + _workQueue = new AsyncBatchingWorkQueue(publishDelay, ProcessBatchAsync, _disposeTokenSource.Token); _publishedDiagnostics = new Dictionary(FilePathComparer.Instance); _logger = loggerFactory.GetOrCreateLogger(); @@ -93,14 +93,14 @@ public void Dispose() _disposeTokenSource.Dispose(); } - public void DocumentProcessed(RazorCodeDocument codeDocument, IDocumentSnapshot document) + public void DocumentProcessed(RazorCodeDocument codeDocument, DocumentSnapshot document) { _workQueue.AddWork(document); StartDelayToClearDocuments(); } - private async ValueTask ProcessBatchAsync(ImmutableArray items, CancellationToken token) + private async ValueTask ProcessBatchAsync(ImmutableArray items, CancellationToken token) { foreach (var document in items.GetMostRecentUniqueItems(Comparer.Instance)) { @@ -113,7 +113,7 @@ private async ValueTask ProcessBatchAsync(ImmutableArray item } } - private async Task PublishDiagnosticsAsync(IDocumentSnapshot document, CancellationToken cancellationToken) + private async Task PublishDiagnosticsAsync(DocumentSnapshot document, CancellationToken cancellationToken) { var result = await document.GetGeneratedOutputAsync(cancellationToken).ConfigureAwait(false); var csharpDiagnostics = await GetCSharpDiagnosticsAsync(document, cancellationToken).ConfigureAwait(false); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentContextFactory.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentContextFactory.cs index 5917981ba30..83575e7e2e8 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentContextFactory.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentContextFactory.cs @@ -13,11 +13,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer; internal sealed class DocumentContextFactory( - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, ILoggerFactory loggerFactory) : IDocumentContextFactory { - private readonly IProjectSnapshotManager _projectManager = projectManager; + private readonly ProjectSnapshotManager _projectManager = projectManager; private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); public bool TryCreate( @@ -41,7 +41,7 @@ public bool TryCreate( private bool TryResolveDocument( string filePath, VSProjectContext? projectContext, - [NotNullWhen(true)] out IDocumentSnapshot? documentSnapshot) + [NotNullWhen(true)] out DocumentSnapshot? documentSnapshot) { if (projectContext is null) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs index 39ab956db0a..492e463bac6 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Extensions/IServiceCollectionExtensions.cs @@ -225,10 +225,9 @@ public static void AddDocumentManagementServices(this IServiceCollection service } services.AddSingleton(); - services.AddSingleton(); // Add project snapshot manager services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs index deef6d83f68..c8864220d42 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/FindAllReferences/FindAllReferencesEndpoint.cs @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.FindAllReferences; internal sealed class FindAllReferencesEndpoint : AbstractRazorDelegatingEndpoint, ICapabilitiesProvider { private readonly IFilePathService _filePathService; - private readonly IProjectSnapshotManager _projectSnapshotManager; + private readonly ProjectSnapshotManager _projectSnapshotManager; private readonly IDocumentMappingService _documentMappingService; public FindAllReferencesEndpoint( @@ -36,7 +36,7 @@ public FindAllReferencesEndpoint( IClientConnection clientConnection, ILoggerFactory loggerFactory, IFilePathService filePathService, - IProjectSnapshotManager projectSnapshotManager) + ProjectSnapshotManager projectSnapshotManager) : base(languageServerFeatureOptions, documentMappingService, clientConnection, loggerFactory.GetOrCreateLogger()) { _filePathService = filePathService ?? throw new ArgumentNullException(nameof(filePathService)); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/GeneratedDocumentPublisher.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/GeneratedDocumentPublisher.cs index 5a4c15e9a1c..3587385d0c0 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/GeneratedDocumentPublisher.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/GeneratedDocumentPublisher.cs @@ -25,13 +25,13 @@ internal sealed class GeneratedDocumentPublisher : IGeneratedDocumentPublisher, { private readonly Dictionary _publishedCSharpData; private readonly Dictionary _publishedHtmlData; - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; private readonly IClientConnection _clientConnection; private readonly LanguageServerFeatureOptions _options; private readonly ILogger _logger; public GeneratedDocumentPublisher( - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, IClientConnection clientConnection, LanguageServerFeatureOptions options, ILoggerFactory loggerFactory) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/GeneratedDocumentSynchronizer.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/GeneratedDocumentSynchronizer.cs index 2f4fc6378f4..d1f96409fdb 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/GeneratedDocumentSynchronizer.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/GeneratedDocumentSynchronizer.cs @@ -10,13 +10,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer; internal class GeneratedDocumentSynchronizer( IGeneratedDocumentPublisher publisher, LanguageServerFeatureOptions languageServerFeatureOptions, - IProjectSnapshotManager projectManager) : IDocumentProcessedListener + ProjectSnapshotManager projectManager) : IDocumentProcessedListener { private readonly IGeneratedDocumentPublisher _publisher = publisher; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions = languageServerFeatureOptions; - private readonly IProjectSnapshotManager _projectManager = projectManager; + private readonly ProjectSnapshotManager _projectManager = projectManager; - public void DocumentProcessed(RazorCodeDocument codeDocument, IDocumentSnapshot document) + public void DocumentProcessed(RazorCodeDocument codeDocument, DocumentSnapshot document) { var hostDocumentVersion = document.Version; var filePath = document.FilePath; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs index 90afa35df3f..7c795f7413a 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverEndpoint.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Hover; [RazorLanguageServerEndpoint(Methods.TextDocumentHoverName)] internal sealed class HoverEndpoint( - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, IClientCapabilitiesService clientCapabilitiesService, LanguageServerFeatureOptions languageServerFeatureOptions, IDocumentMappingService documentMappingService, @@ -34,7 +34,7 @@ internal sealed class HoverEndpoint( clientConnection, loggerFactory.GetOrCreateLogger()), ICapabilitiesProvider { - private readonly IProjectSnapshotManager _projectManager = projectManager; + private readonly ProjectSnapshotManager _projectManager = projectManager; private readonly IClientCapabilitiesService _clientCapabilitiesService = clientCapabilitiesService; public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, VSInternalClientCapabilities clientCapabilities) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentProcessedListener.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentProcessedListener.cs index ec6387a0c7e..6b758bf6aa7 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentProcessedListener.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentProcessedListener.cs @@ -8,5 +8,5 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer; internal interface IDocumentProcessedListener { - void DocumentProcessed(RazorCodeDocument codeDocument, IDocumentSnapshot documentSnapshot); + void DocumentProcessed(RazorCodeDocument codeDocument, DocumentSnapshot documentSnapshot); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/OpenDocumentGenerator.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/OpenDocumentGenerator.cs index d5012950075..be6fd786ca8 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/OpenDocumentGenerator.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/OpenDocumentGenerator.cs @@ -28,16 +28,16 @@ internal partial class OpenDocumentGenerator : IRazorStartupService, IDisposable private static readonly TimeSpan s_delay = TimeSpan.FromMilliseconds(10); private readonly ImmutableArray _listeners; - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; private readonly LanguageServerFeatureOptions _options; private readonly ILogger _logger; - private readonly AsyncBatchingWorkQueue _workQueue; + private readonly AsyncBatchingWorkQueue _workQueue; private readonly CancellationTokenSource _disposeTokenSource; public OpenDocumentGenerator( IEnumerable listeners, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, LanguageServerFeatureOptions options, ILoggerFactory loggerFactory) { @@ -46,7 +46,7 @@ public OpenDocumentGenerator( _options = options; _disposeTokenSource = new(); - _workQueue = new AsyncBatchingWorkQueue( + _workQueue = new AsyncBatchingWorkQueue( s_delay, ProcessBatchAsync, _disposeTokenSource.Token); @@ -66,7 +66,7 @@ public void Dispose() _disposeTokenSource.Dispose(); } - private async ValueTask ProcessBatchAsync(ImmutableArray items, CancellationToken token) + private async ValueTask ProcessBatchAsync(ImmutableArray items, CancellationToken token) { foreach (var document in items.GetMostRecentUniqueItems(Comparer.Instance)) { @@ -167,7 +167,7 @@ private void ProjectManager_Changed(object? sender, ProjectChangeEventArgs args) } } - void EnqueueIfNecessary(IDocumentSnapshot document) + void EnqueueIfNecessary(DocumentSnapshot document) { if (!_projectManager.IsDocumentOpen(document.FilePath) && !_options.UpdateBuffersForClosedDocuments) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/IProjectSnapshotManagerExtensions.SolutionQueryOperations.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/IProjectSnapshotManagerExtensions.SolutionQueryOperations.cs index f89964faa8d..30e2c0072fb 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/IProjectSnapshotManagerExtensions.SolutionQueryOperations.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/IProjectSnapshotManagerExtensions.SolutionQueryOperations.cs @@ -3,20 +3,21 @@ using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor.ProjectSystem; namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; -internal static partial class IProjectSnapshotManagerExtensions +internal static partial class ProjectSnapshotManagerExtensions { - private sealed class SolutionQueryOperations(IProjectSnapshotManager projectManager) : ISolutionQueryOperations + private sealed class SolutionQueryOperations(ProjectSnapshotManager projectManager) : ISolutionQueryOperations { - private readonly IProjectSnapshotManager _projectManager = projectManager; + private readonly ProjectSnapshotManager _projectManager = projectManager; public IEnumerable GetProjects() { - return _projectManager.GetProjects(); + return _projectManager.GetProjects().Cast(); } public ImmutableArray GetProjectsContainingDocument(string documentFilePath) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/IProjectSnapshotManagerExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/IProjectSnapshotManagerExtensions.cs index 738122f9323..a424cfefe64 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/IProjectSnapshotManagerExtensions.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/IProjectSnapshotManagerExtensions.cs @@ -12,16 +12,16 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; -internal static partial class IProjectSnapshotManagerExtensions +internal static partial class ProjectSnapshotManagerExtensions { /// /// Finds all the projects where the document path starts with the path of the folder that contains the project file. /// - public static ImmutableArray FindPotentialProjects(this IProjectSnapshotManager projectManager, string documentFilePath) + public static ImmutableArray FindPotentialProjects(this ProjectSnapshotManager projectManager, string documentFilePath) { var normalizedDocumentPath = FilePathNormalizer.Normalize(documentFilePath); - using var projects = new PooledArrayBuilder(); + using var projects = new PooledArrayBuilder(); foreach (var project in projectManager.GetProjects()) { @@ -42,13 +42,13 @@ public static ImmutableArray FindPotentialProjects(this IProje } public static bool TryResolveAllProjects( - this IProjectSnapshotManager projectManager, + this ProjectSnapshotManager projectManager, string documentFilePath, - out ImmutableArray projects) + out ImmutableArray projects) { var potentialProjects = projectManager.FindPotentialProjects(documentFilePath); - using var builder = new PooledArrayBuilder(capacity: potentialProjects.Length); + using var builder = new PooledArrayBuilder(capacity: potentialProjects.Length); foreach (var project in potentialProjects) { @@ -70,10 +70,10 @@ public static bool TryResolveAllProjects( } public static bool TryResolveDocumentInAnyProject( - this IProjectSnapshotManager projectManager, + this ProjectSnapshotManager projectManager, string documentFilePath, ILogger logger, - [NotNullWhen(true)] out IDocumentSnapshot? document) + [NotNullWhen(true)] out DocumentSnapshot? document) { logger.LogTrace($"Looking for {documentFilePath}."); @@ -104,6 +104,6 @@ public static bool TryResolveDocumentInAnyProject( return false; } - public static ISolutionQueryOperations GetQueryOperations(this IProjectSnapshotManager projectManager) + public static ISolutionQueryOperations GetQueryOperations(this ProjectSnapshotManager projectManager) => new SolutionQueryOperations(projectManager); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/MiscFilesProject.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/MiscFilesProject.cs index f81f4b5909d..cef0f40f76f 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/MiscFilesProject.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/MiscFilesProject.cs @@ -36,9 +36,9 @@ static MiscFilesProject() "Miscellaneous Files"); } - public static IProjectSnapshot GetMiscellaneousProject(this IProjectSnapshotManager projectManager) + public static ProjectSnapshot GetMiscellaneousProject(this ProjectSnapshotManager projectManager) => projectManager.GetRequiredProject(Key); - public static bool IsMiscellaneousProject(this IProjectSnapshot project) + public static bool IsMiscellaneousProject(this ProjectSnapshot project) => project.Key == Key; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs index 07e34949799..393050c39b2 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; /// -/// Maintains the language server's with the semantics of Razor's project model. +/// Maintains the language server's with the semantics of Razor's project model. /// /// /// This service implements to ensure it is created early so it can begin @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; internal partial class RazorProjectService : IRazorProjectService, IRazorProjectInfoListener, IRazorStartupService, IDisposable { private readonly IRazorProjectInfoDriver _projectInfoDriver; - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; private readonly RemoteTextLoaderFactory _remoteTextLoaderFactory; private readonly ILogger _logger; @@ -40,7 +40,7 @@ internal partial class RazorProjectService : IRazorProjectService, IRazorProject private readonly Task _initializeTask; public RazorProjectService( - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, IRazorProjectInfoDriver projectInfoDriver, RemoteTextLoaderFactory remoteTextLoaderFactory, ILoggerFactory loggerFactory) @@ -296,7 +296,7 @@ await _projectManager.UpdateAsync( .ConfigureAwait(false); } - private void ActOnDocumentInMultipleProjects(string filePath, Action action) + private void ActOnDocumentInMultipleProjects(string filePath, Action action) { var textDocumentPath = FilePathNormalizer.Normalize(filePath); if (!_projectManager.TryResolveAllProjects(textDocumentPath, out var projects)) @@ -499,11 +499,11 @@ private void UpdateProjectDocuments( private void MoveDocument( ProjectSnapshotManager.Updater updater, string documentFilePath, - IProjectSnapshot fromProject, - IProjectSnapshot toProject) + ProjectSnapshot fromProject, + ProjectSnapshot toProject) { - Debug.Assert(fromProject.DocumentFilePaths.Contains(documentFilePath, FilePathComparer.Instance)); - Debug.Assert(!toProject.DocumentFilePaths.Contains(documentFilePath, FilePathComparer.Instance)); + Debug.Assert(fromProject.ContainsDocument(documentFilePath)); + Debug.Assert(!toProject.ContainsDocument(documentFilePath)); if (fromProject.GetDocument(documentFilePath) is not DocumentSnapshot documentSnapshot) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs index 2f3370d7187..fa8fc0c94a6 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs @@ -23,7 +23,7 @@ internal sealed class RenameEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions, IDocumentMappingService documentMappingService, IEditMappingService editMappingService, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, IClientConnection clientConnection, ILoggerFactory loggerFactory) : AbstractRazorDelegatingEndpoint( @@ -35,7 +35,7 @@ internal sealed class RenameEndpoint( private readonly IRenameService _renameService = renameService; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions = languageServerFeatureOptions; private readonly IEditMappingService _editMappingService = editMappingService; - private readonly IProjectSnapshotManager _projectManager = projectManager; + private readonly ProjectSnapshotManager _projectManager = projectManager; public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, VSInternalClientCapabilities clientCapabilities) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WorkspaceDiagnosticsRefresher.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WorkspaceDiagnosticsRefresher.cs index 6ab350910be..bde94393175 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WorkspaceDiagnosticsRefresher.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WorkspaceDiagnosticsRefresher.cs @@ -17,14 +17,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer; internal sealed class WorkspaceDiagnosticsRefresher : IRazorStartupService, IDisposable { private readonly AsyncBatchingWorkQueue _queue; - private readonly IProjectSnapshotManager _projectSnapshotManager; + private readonly ProjectSnapshotManager _projectSnapshotManager; private readonly IClientCapabilitiesService _clientCapabilitiesService; private readonly IClientConnection _clientConnection; private bool? _supported; private CancellationTokenSource _disposeTokenSource = new(); public WorkspaceDiagnosticsRefresher( - IProjectSnapshotManager projectSnapshotManager, + ProjectSnapshotManager projectSnapshotManager, IClientCapabilitiesService clientCapabilitiesService, IClientConnection clientConnection, TimeSpan? delay = null) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WorkspaceSemanticTokensRefreshTrigger.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WorkspaceSemanticTokensRefreshTrigger.cs index daaa3ea43bf..ee6b911ceeb 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WorkspaceSemanticTokensRefreshTrigger.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WorkspaceSemanticTokensRefreshTrigger.cs @@ -12,11 +12,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer; internal class WorkspaceSemanticTokensRefreshTrigger : IRazorStartupService { private readonly IWorkspaceSemanticTokensRefreshNotifier _publisher; - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; public WorkspaceSemanticTokensRefreshTrigger( IWorkspaceSemanticTokensRefreshNotifier publisher, - IProjectSnapshotManager projectManager) + ProjectSnapshotManager projectManager) { _publisher = publisher; _projectManager = projectManager; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ITagHelperResolver.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ITagHelperResolver.cs index 59135bb4d30..9e102051866 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ITagHelperResolver.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ITagHelperResolver.cs @@ -13,11 +13,11 @@ internal interface ITagHelperResolver { /// /// Gets the available tag helpers from the specified - /// using the given to provide a + /// using the given to provide a /// . /// ValueTask> GetTagHelpersAsync( Project project, - IProjectSnapshot projectSnapshot, + ProjectSnapshot projectSnapshot, CancellationToken cancellationToken); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshotManager.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshotManager.cs deleted file mode 100644 index 43aaee89071..00000000000 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshotManager.cs +++ /dev/null @@ -1,38 +0,0 @@ -// 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.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor.ProjectSystem; - -namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; - -internal interface IProjectSnapshotManager -{ - event EventHandler PriorityChanged; - event EventHandler Changed; - - bool IsSolutionClosing { get; } - - ImmutableArray GetProjectKeysWithFilePath(string projectFileName); - ImmutableArray GetProjects(); - - bool ContainsProject(ProjectKey projectKey); - bool TryGetProject(ProjectKey projectKey, [NotNullWhen(true)] out IProjectSnapshot? project); - - bool IsDocumentOpen(string documentFilePath); - ImmutableArray GetOpenDocuments(); - - Task UpdateAsync(Action updater, CancellationToken cancellationToken); - Task UpdateAsync(Action updater, TState state, CancellationToken cancellationToken); - Task UpdateAsync(Func updater, CancellationToken cancellationToken); - Task UpdateAsync(Func updater, TState state, CancellationToken cancellationToken); - - Task UpdateAsync(Func updater, CancellationToken cancellationToken); - Task UpdateAsync(Func updater, TState state, CancellationToken cancellationToken); - Task UpdateAsync(Func> updater, CancellationToken cancellationToken); - Task UpdateAsync(Func> updater, TState state, CancellationToken cancellationToken); -} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectChangeEventArgs.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectChangeEventArgs.cs index 20ee7e5b4d8..879600a6945 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectChangeEventArgs.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectChangeEventArgs.cs @@ -10,8 +10,8 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; internal sealed class ProjectChangeEventArgs : EventArgs { public ProjectChangeKind Kind { get; } - public IProjectSnapshot? Older { get; } - public IProjectSnapshot? Newer { get; } + public ProjectSnapshot? Older { get; } + public ProjectSnapshot? Newer { get; } public ProjectKey ProjectKey { get; } public string ProjectFilePath { get; } public string? DocumentFilePath { get; } @@ -19,8 +19,8 @@ internal sealed class ProjectChangeEventArgs : EventArgs private ProjectChangeEventArgs( ProjectChangeKind kind, - IProjectSnapshot? older, - IProjectSnapshot? newer, + ProjectSnapshot? older, + ProjectSnapshot? newer, string? documentFilePath, bool isSolutionClosing) { @@ -38,21 +38,21 @@ private ProjectChangeEventArgs( IsSolutionClosing = isSolutionClosing; } - public static ProjectChangeEventArgs ProjectAdded(IProjectSnapshot project, bool isSolutionClosing) + public static ProjectChangeEventArgs ProjectAdded(ProjectSnapshot project, bool isSolutionClosing) => new(ProjectChangeKind.ProjectAdded, older: null, newer: project, documentFilePath: null, isSolutionClosing); - public static ProjectChangeEventArgs ProjectRemoved(IProjectSnapshot project, bool isSolutionClosing) + public static ProjectChangeEventArgs ProjectRemoved(ProjectSnapshot project, bool isSolutionClosing) => new(ProjectChangeKind.ProjectRemoved, older: project, newer: null, documentFilePath: null, isSolutionClosing); - public static ProjectChangeEventArgs ProjectChanged(IProjectSnapshot older, IProjectSnapshot newer, bool isSolutionClosing) + public static ProjectChangeEventArgs ProjectChanged(ProjectSnapshot older, ProjectSnapshot newer, bool isSolutionClosing) => new(ProjectChangeKind.ProjectChanged, older, newer, documentFilePath: null, isSolutionClosing); - public static ProjectChangeEventArgs DocumentAdded(IProjectSnapshot older, IProjectSnapshot newer, string documentFilePath, bool isSolutionClosing) + public static ProjectChangeEventArgs DocumentAdded(ProjectSnapshot older, ProjectSnapshot newer, string documentFilePath, bool isSolutionClosing) => new(ProjectChangeKind.DocumentAdded, older, newer, documentFilePath, isSolutionClosing); - public static ProjectChangeEventArgs DocumentRemoved(IProjectSnapshot older, IProjectSnapshot newer, string documentFilePath, bool isSolutionClosing) + public static ProjectChangeEventArgs DocumentRemoved(ProjectSnapshot older, ProjectSnapshot newer, string documentFilePath, bool isSolutionClosing) => new(ProjectChangeKind.DocumentRemoved, older, newer, documentFilePath, isSolutionClosing); - public static ProjectChangeEventArgs DocumentChanged(IProjectSnapshot older, IProjectSnapshot newer, string documentFilePath, bool isSolutionClosing) + public static ProjectChangeEventArgs DocumentChanged(ProjectSnapshot older, ProjectSnapshot newer, string documentFilePath, bool isSolutionClosing) => new(ProjectChangeKind.DocumentChanged, older, newer, documentFilePath, isSolutionClosing); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs index b9d89780a05..69f7e3da161 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs @@ -104,7 +104,7 @@ bool IProjectSnapshot.TryGetDocument(string filePath, [NotNullWhen(true)] out ID /// that include directives specified by the provided document. Otherwise returns an empty /// list. ///
- public ImmutableArray GetRelatedDocuments(IDocumentSnapshot document) + public ImmutableArray GetRelatedDocuments(DocumentSnapshot document) { var targetPath = document.TargetPath; @@ -115,7 +115,7 @@ public ImmutableArray GetRelatedDocuments(IDocumentSnapshot d lock (_gate) { - using var builder = new PooledArrayBuilder(capacity: relatedDocuments.Count); + using var builder = new PooledArrayBuilder(capacity: relatedDocuments.Count); foreach (var relatedDocumentFilePath in relatedDocuments) { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshotExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotExtensions.cs similarity index 72% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshotExtensions.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotExtensions.cs index 484c1ed2892..e0b53cdfbfa 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshotExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotExtensions.cs @@ -1,8 +1,6 @@ // 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.Collections.Immutable; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.AspNetCore.Razor.ProjectSystem; @@ -10,7 +8,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -internal static class IProjectSnapshotExtensions +internal static class ProjectSnapshotExtensions { public static IDocumentSnapshot? GetDocument(this IProjectSnapshot project, string filePath) => project.TryGetDocument(filePath, out var result) @@ -20,7 +18,15 @@ internal static class IProjectSnapshotExtensions public static IDocumentSnapshot GetRequiredDocument(this IProjectSnapshot project, string filePath) => project.GetDocument(filePath).AssumeNotNull(); - public static RazorProjectInfo ToRazorProjectInfo(this IProjectSnapshot project) + public static DocumentSnapshot? GetDocument(this ProjectSnapshot project, string filePath) + => project.TryGetDocument(filePath, out var result) + ? result + : null; + + public static DocumentSnapshot GetRequiredDocument(this ProjectSnapshot project, string filePath) + => project.GetDocument(filePath).AssumeNotNull(); + + public static RazorProjectInfo ToRazorProjectInfo(this ProjectSnapshot project) { using var documents = new PooledArrayBuilder(); @@ -43,14 +49,4 @@ public static RazorProjectInfo ToRazorProjectInfo(this IProjectSnapshot project) projectWorkspaceState: project.ProjectWorkspaceState, documents: documents.DrainToImmutable()); } - - public static ImmutableArray GetRelatedDocuments(this IProjectSnapshot projectSnapshot, IDocumentSnapshot document) - { - if (projectSnapshot is not ProjectSnapshot project) - { - throw new InvalidOperationException("This method can only be called with a ProjectSnapshot."); - } - - return project.GetRelatedDocuments(document); - } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.Entry.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.Entry.cs index 48341f3dd5d..c02de7a1bad 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.Entry.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.Entry.cs @@ -7,9 +7,9 @@ internal partial class ProjectSnapshotManager { private sealed record Entry(ProjectState State) { - private IProjectSnapshot? _snapshotUnsafe; + private ProjectSnapshot? _snapshotUnsafe; - public IProjectSnapshot GetSnapshot() + public ProjectSnapshot GetSnapshot() { return _snapshotUnsafe ??= new ProjectSnapshot(State); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.Updater.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.Updater.cs index a726320cc95..ea36430034a 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.Updater.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.Updater.cs @@ -15,17 +15,18 @@ public readonly struct Updater(ProjectSnapshotManager instance) public ImmutableArray GetProjectKeysWithFilePath(string filePath) => instance.GetProjectKeysWithFilePath(filePath); - public ImmutableArray GetProjects() + public ImmutableArray GetProjects() => instance.GetProjects(); public bool ContainsProject(ProjectKey projectKey) => instance.ContainsProject(projectKey); - public bool TryGetProject(ProjectKey projectKey, [NotNullWhen(true)] out IProjectSnapshot? project) + public bool TryGetProject(ProjectKey projectKey, [NotNullWhen(true)] out ProjectSnapshot? project) => instance.TryGetProject(projectKey, out project); public bool IsDocumentOpen(string documentFilePath) => instance.IsDocumentOpen(documentFilePath); + public ImmutableArray GetOpenDocuments() => instance.GetOpenDocuments(); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.cs index dac24b3690c..6b66e7afb66 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.cs @@ -24,7 +24,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; // (language version, extensions, named configuration). // // The implementation will create a ProjectSnapshot for each HostProject. -internal partial class ProjectSnapshotManager : IProjectSnapshotManager, IDisposable +internal partial class ProjectSnapshotManager : IDisposable { private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider; private readonly RazorCompilerOptions _compilerOptions; @@ -120,11 +120,11 @@ public bool IsSolutionClosing } } - public ImmutableArray GetProjects() + public ImmutableArray GetProjects() { using (_readerWriterLock.DisposableRead()) { - using var builder = new PooledArrayBuilder(_projectMap.Count); + using var builder = new PooledArrayBuilder(_projectMap.Count); foreach (var (_, entry) in _projectMap) { @@ -151,7 +151,7 @@ public bool ContainsProject(ProjectKey projectKey) } } - public bool TryGetProject(ProjectKey projectKey, [NotNullWhen(true)] out IProjectSnapshot? project) + public bool TryGetProject(ProjectKey projectKey, [NotNullWhen(true)] out ProjectSnapshot? project) { using (_readerWriterLock.DisposableRead()) { @@ -353,7 +353,7 @@ private void UpdateDocumentText(ProjectKey projectKey, string documentFilePath, } } - private bool TryAddProject(HostProject hostProject, [NotNullWhen(true)] out IProjectSnapshot? newProject, out bool isSolutionClosing) + private bool TryAddProject(HostProject hostProject, [NotNullWhen(true)] out ProjectSnapshot? newProject, out bool isSolutionClosing) { if (_initialized) { @@ -382,7 +382,7 @@ private bool TryAddProject(HostProject hostProject, [NotNullWhen(true)] out IPro return true; } - private bool TryRemoveProject(ProjectKey projectKey, [NotNullWhen(true)] out IProjectSnapshot? oldProject, out bool isSolutionClosing) + private bool TryRemoveProject(ProjectKey projectKey, [NotNullWhen(true)] out ProjectSnapshot? oldProject, out bool isSolutionClosing) { if (_initialized) { @@ -410,8 +410,8 @@ private bool TryRemoveProject(ProjectKey projectKey, [NotNullWhen(true)] out IPr private bool TryUpdateProject( ProjectKey projectKey, Func transformer, - [NotNullWhen(true)] out IProjectSnapshot? oldProject, - [NotNullWhen(true)] out IProjectSnapshot? newProject, + [NotNullWhen(true)] out ProjectSnapshot? oldProject, + [NotNullWhen(true)] out ProjectSnapshot? newProject, out bool isSolutionClosing) => TryUpdateProject(projectKey, transformer, onAfterUpdate: null, out oldProject, out newProject, out isSolutionClosing); @@ -419,8 +419,8 @@ private bool TryUpdateProject( ProjectKey projectKey, Func transformer, Action? onAfterUpdate, - [NotNullWhen(true)] out IProjectSnapshot? oldProject, - [NotNullWhen(true)] out IProjectSnapshot? newProject, + [NotNullWhen(true)] out ProjectSnapshot? oldProject, + [NotNullWhen(true)] out ProjectSnapshot? newProject, out bool isSolutionClosing) { if (_initialized) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshotManagerExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManagerExtensions.cs similarity index 59% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshotManagerExtensions.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManagerExtensions.cs index 0595196af17..627926e6722 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshotManagerExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManagerExtensions.cs @@ -7,25 +7,25 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -internal static class IProjectSnapshotManagerExtensions +internal static class ProjectSnapshotManagerExtensions { - public static IProjectSnapshot? GetProject(this IProjectSnapshotManager projectManager, ProjectKey projectKey) + public static ProjectSnapshot? GetProject(this ProjectSnapshotManager projectManager, ProjectKey projectKey) => projectManager.TryGetProject(projectKey, out var result) ? result : null; - public static IProjectSnapshot GetRequiredProject(this IProjectSnapshotManager projectManager, ProjectKey projectKey) + public static ProjectSnapshot GetRequiredProject(this ProjectSnapshotManager projectManager, ProjectKey projectKey) => projectManager.GetProject(projectKey).AssumeNotNull(); - public static bool ContainsDocument(this IProjectSnapshotManager projectManager, ProjectKey projectKey, string documentFilePath) + public static bool ContainsDocument(this ProjectSnapshotManager projectManager, ProjectKey projectKey, string documentFilePath) => projectManager.TryGetProject(projectKey, out var project) && project.ContainsDocument(documentFilePath); public static bool TryGetDocument( - this IProjectSnapshotManager projectManager, + this ProjectSnapshotManager projectManager, ProjectKey projectKey, string documentFilePath, - [NotNullWhen(true)] out IDocumentSnapshot? document) + [NotNullWhen(true)] out DocumentSnapshot? document) { document = projectManager.TryGetProject(projectKey, out var project) ? project.GetDocument(documentFilePath) @@ -34,20 +34,20 @@ public static bool TryGetDocument( return document is not null; } - public static IDocumentSnapshot? GetDocument(this IProjectSnapshotManager projectManager, ProjectKey projectKey, string documentFilePath) + public static DocumentSnapshot? GetDocument(this ProjectSnapshotManager projectManager, ProjectKey projectKey, string documentFilePath) => projectManager.TryGetDocument(projectKey, documentFilePath, out var result) ? result : null; - public static IDocumentSnapshot GetRequiredDocument(this IProjectSnapshotManager projectManager, ProjectKey projectKey, string documentFilePath) + public static DocumentSnapshot GetRequiredDocument(this ProjectSnapshotManager projectManager, ProjectKey projectKey, string documentFilePath) => projectManager.GetDocument(projectKey, documentFilePath).AssumeNotNull(); - public static IProjectSnapshot? GetProject(this ProjectSnapshotManager.Updater updater, ProjectKey projectKey) + public static ProjectSnapshot? GetProject(this ProjectSnapshotManager.Updater updater, ProjectKey projectKey) => updater.TryGetProject(projectKey, out var result) ? result : null; - public static IProjectSnapshot GetRequiredProject(this ProjectSnapshotManager.Updater updater, ProjectKey projectKey) + public static ProjectSnapshot GetRequiredProject(this ProjectSnapshotManager.Updater updater, ProjectKey projectKey) => updater.GetProject(projectKey).AssumeNotNull(); public static bool ContainsDocument(this ProjectSnapshotManager.Updater updater, ProjectKey projectKey, string documentFilePath) @@ -58,7 +58,7 @@ public static bool TryGetDocument( this ProjectSnapshotManager.Updater updater, ProjectKey projectKey, string documentFilePath, - [NotNullWhen(true)] out IDocumentSnapshot? document) + [NotNullWhen(true)] out DocumentSnapshot? document) { document = updater.TryGetProject(projectKey, out var project) ? project.GetDocument(documentFilePath) @@ -67,11 +67,11 @@ public static bool TryGetDocument( return document is not null; } - public static IDocumentSnapshot? GetDocument(this ProjectSnapshotManager.Updater updater, ProjectKey projectKey, string documentFilePath) + public static DocumentSnapshot? GetDocument(this ProjectSnapshotManager.Updater updater, ProjectKey projectKey, string documentFilePath) => updater.TryGetDocument(projectKey, documentFilePath, out var result) ? result : null; - public static IDocumentSnapshot GetRequiredDocument(this ProjectSnapshotManager.Updater updater, ProjectKey projectKey, string documentFilePath) + public static DocumentSnapshot GetRequiredDocument(this ProjectSnapshotManager.Updater updater, ProjectKey projectKey, string documentFilePath) => updater.GetDocument(projectKey, documentFilePath).AssumeNotNull(); } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/EditorDocumentManagerListener.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/EditorDocumentManagerListener.cs index 86429733b27..40aee7a8f7d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/EditorDocumentManagerListener.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/EditorDocumentManagerListener.cs @@ -40,7 +40,7 @@ private sealed record ProjectRemoved(ProjectKey ProjectKey, IEnumerable private static readonly TimeSpan s_delay = TimeSpan.FromMilliseconds(10); private readonly IEditorDocumentManager _documentManager; - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; private readonly IFallbackProjectManager _fallbackProjectManager; private readonly JoinableTaskContext _joinableTaskContext; private readonly ITelemetryReporter _telemetryReporter; @@ -56,7 +56,7 @@ private sealed record ProjectRemoved(ProjectKey ProjectKey, IEnumerable [ImportingConstructor] public EditorDocumentManagerListener( IEditorDocumentManager documentManager, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, IFallbackProjectManager fallbackProjectManager, JoinableTaskContext joinableTaskContext, ITelemetryReporter telemetryReporter) @@ -249,7 +249,6 @@ static async (updater, state) => var (document, fallbackProjectManager, telemetryReporter, cancellationToken) = state; if (updater.TryGetProject(document.ProjectKey, out var project) && - project is ProjectSnapshot projectSnapshot && fallbackProjectManager.IsFallbackProject(project)) { // The user is opening a document that is part of a fallback project. This is a scenario we are very interested in knowing more about @@ -259,7 +258,7 @@ project is ProjectSnapshot projectSnapshot && telemetryReporter.ReportEvent( "fallbackproject/documentopen", Severity.Normal, - new Property("document.count", projectSnapshot.DocumentCount), + new Property("document.count", project.DocumentCount), new Property("taghelper.count", tagHelpers.Length)); } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/RazorCodeDocumentProvidingSnapshotChangeTrigger.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/RazorCodeDocumentProvidingSnapshotChangeTrigger.cs index bb18153f7fb..2ac21dc2567 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/RazorCodeDocumentProvidingSnapshotChangeTrigger.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/RazorCodeDocumentProvidingSnapshotChangeTrigger.cs @@ -21,12 +21,12 @@ internal class RazorCodeDocumentProvidingSnapshotChangeTrigger : IRazorStartupSe { private readonly HashSet _openDocuments = new(FilePathComparer.Instance); private readonly Dictionary _documentProjectMap = new(FilePathComparer.Instance); - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; public event EventHandler? DocumentReady; [ImportingConstructor] - public RazorCodeDocumentProvidingSnapshotChangeTrigger(IProjectSnapshotManager projectManager) + public RazorCodeDocumentProvidingSnapshotChangeTrigger(ProjectSnapshotManager projectManager) { _projectManager = projectManager; _projectManager.Changed += ProjectManager_Changed; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/BackgroundDocumentGenerator.Comparer.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/BackgroundDocumentGenerator.Comparer.cs index 16d8b09f3b4..2568582c212 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/BackgroundDocumentGenerator.Comparer.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/BackgroundDocumentGenerator.Comparer.cs @@ -9,7 +9,7 @@ namespace Microsoft.VisualStudio.Razor.DynamicFiles; internal partial class BackgroundDocumentGenerator { - private sealed class Comparer : IEqualityComparer<(IProjectSnapshot, IDocumentSnapshot)> + private sealed class Comparer : IEqualityComparer<(ProjectSnapshot, DocumentSnapshot)> { public static readonly Comparer Instance = new(); @@ -17,7 +17,7 @@ private Comparer() { } - public bool Equals((IProjectSnapshot, IDocumentSnapshot) x, (IProjectSnapshot, IDocumentSnapshot) y) + public bool Equals((ProjectSnapshot, DocumentSnapshot) x, (ProjectSnapshot, DocumentSnapshot) y) { var (projectX, documentX) = x; var (projectY, documentY) = y; @@ -28,7 +28,7 @@ public bool Equals((IProjectSnapshot, IDocumentSnapshot) x, (IProjectSnapshot, I return documentKeyX.Equals(documentKeyY); } - public int GetHashCode((IProjectSnapshot, IDocumentSnapshot) obj) + public int GetHashCode((ProjectSnapshot, DocumentSnapshot) obj) { var (project, document) = obj; var documentKey = new DocumentKey(project.Key, document.FilePath); diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/BackgroundDocumentGenerator.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/BackgroundDocumentGenerator.cs index d3a75441354..b7caa97e4f8 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/BackgroundDocumentGenerator.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/BackgroundDocumentGenerator.cs @@ -22,20 +22,20 @@ internal partial class BackgroundDocumentGenerator : IRazorStartupService, IDisp { private static readonly TimeSpan s_delay = TimeSpan.FromSeconds(2); - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; private readonly IFallbackProjectManager _fallbackProjectManager; private readonly IRazorDynamicFileInfoProviderInternal _infoProvider; private readonly ILoggerFactory _loggerFactory; private readonly ILogger _logger; private readonly CancellationTokenSource _disposeTokenSource; - private readonly AsyncBatchingWorkQueue<(IProjectSnapshot, IDocumentSnapshot)> _workQueue; + private readonly AsyncBatchingWorkQueue<(ProjectSnapshot, DocumentSnapshot)> _workQueue; private ImmutableHashSet _suppressedDocuments; private bool _solutionIsClosing; [ImportingConstructor] public BackgroundDocumentGenerator( - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, IFallbackProjectManager fallbackProjectManager, IRazorDynamicFileInfoProviderInternal infoProvider, ILoggerFactory loggerFactory) @@ -45,7 +45,7 @@ public BackgroundDocumentGenerator( // Provided for tests to be able to modify the timer delay protected BackgroundDocumentGenerator( - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, IFallbackProjectManager fallbackProjectManager, IRazorDynamicFileInfoProviderInternal infoProvider, ILoggerFactory loggerFactory, @@ -58,7 +58,7 @@ protected BackgroundDocumentGenerator( _logger = loggerFactory.GetOrCreateLogger(); _disposeTokenSource = new(); - _workQueue = new AsyncBatchingWorkQueue<(IProjectSnapshot, IDocumentSnapshot)>( + _workQueue = new AsyncBatchingWorkQueue<(ProjectSnapshot, DocumentSnapshot)>( delay, processBatchAsync: ProcessBatchAsync, equalityComparer: null, @@ -82,14 +82,14 @@ public void Dispose() protected Task WaitUntilCurrentBatchCompletesAsync() => _workQueue.WaitUntilCurrentBatchCompletesAsync(); - protected virtual async Task ProcessDocumentAsync(IProjectSnapshot project, IDocumentSnapshot document, CancellationToken cancellationToken) + protected virtual async Task ProcessDocumentAsync(ProjectSnapshot project, DocumentSnapshot document, CancellationToken cancellationToken) { await document.GetGeneratedOutputAsync(cancellationToken).ConfigureAwait(false); UpdateFileInfo(project, document); } - public virtual void Enqueue(IProjectSnapshot project, IDocumentSnapshot document) + public virtual void Enqueue(ProjectSnapshot project, DocumentSnapshot document) { if (_disposeTokenSource.IsCancellationRequested) { @@ -110,7 +110,7 @@ public virtual void Enqueue(IProjectSnapshot project, IDocumentSnapshot document _workQueue.AddWork((project, document)); } - protected virtual async ValueTask ProcessBatchAsync(ImmutableArray<(IProjectSnapshot, IDocumentSnapshot)> items, CancellationToken token) + protected virtual async ValueTask ProcessBatchAsync(ImmutableArray<(ProjectSnapshot, DocumentSnapshot)> items, CancellationToken token) { foreach (var (project, document) in items.GetMostRecentUniqueItems(Comparer.Instance)) { @@ -145,7 +145,7 @@ protected virtual async ValueTask ProcessBatchAsync(ImmutableArray<(IProjectSnap } } - private bool Suppressed(IProjectSnapshot project, IDocumentSnapshot document) + private bool Suppressed(ProjectSnapshot project, DocumentSnapshot document) { var filePath = document.FilePath; @@ -160,7 +160,7 @@ private bool Suppressed(IProjectSnapshot project, IDocumentSnapshot document) return false; } - private void UpdateFileInfo(IProjectSnapshot project, IDocumentSnapshot document) + private void UpdateFileInfo(ProjectSnapshot project, DocumentSnapshot document) { var filePath = document.FilePath; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorDynamicFileInfoProvider.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorDynamicFileInfoProvider.cs index cf39e863fed..a278c7e1244 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorDynamicFileInfoProvider.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorDynamicFileInfoProvider.cs @@ -43,7 +43,7 @@ public RazorDynamicFileInfoProvider( ILspEditorFeatureDetector lspEditorFeatureDetector, IFilePathService filePathService, IWorkspaceProvider workspaceProvider, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, FallbackProjectManager fallbackProjectManager) { _factory = factory; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/IProjectWorkspaceStateGenerator.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/IProjectWorkspaceStateGenerator.cs index 8bf2287cc10..78ae929042b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/IProjectWorkspaceStateGenerator.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/IProjectWorkspaceStateGenerator.cs @@ -8,7 +8,7 @@ namespace Microsoft.VisualStudio.Razor; internal interface IProjectWorkspaceStateGenerator { - void EnqueueUpdate(Project? workspaceProject, IProjectSnapshot projectSnapshot); + void EnqueueUpdate(Project? workspaceProject, ProjectSnapshot projectSnapshot); void CancelUpdates(); } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/CSharpVirtualDocumentFactory.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/CSharpVirtualDocumentFactory.cs index ff74e60df97..fa514cf954a 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/CSharpVirtualDocumentFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/CSharpVirtualDocumentFactory.cs @@ -34,7 +34,7 @@ internal class CSharpVirtualDocumentFactory : VirtualDocumentFactoryBase private static IContentType? s_csharpContentType; private readonly FileUriProvider _fileUriProvider; private readonly IFilePathService _filePathService; - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions; private readonly ILogger _logger; private readonly ITelemetryReporter _telemetryReporter; @@ -46,7 +46,7 @@ public CSharpVirtualDocumentFactory( ITextDocumentFactoryService textDocumentFactory, FileUriProvider fileUriProvider, IFilePathService filePathService, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, LanguageServerFeatureOptions languageServerFeatureOptions, ILoggerFactory loggerFactory, ITelemetryReporter telemetryReporter) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/CSharpVirtualDocumentManager.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/CSharpVirtualDocumentManager.cs index 53491d95f28..9ad2b78ef77 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/CSharpVirtualDocumentManager.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/CSharpVirtualDocumentManager.cs @@ -24,7 +24,7 @@ internal class CSharpVirtualDocumentManager : IRazorStartupService, IDisposable [ImportingConstructor] public CSharpVirtualDocumentManager( LSPDocumentManager lspDocumentManager, - IProjectSnapshotManager projectManager) + ProjectSnapshotManager projectManager) { _lspDocumentManager = lspDocumentManager; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget.cs index c5b0175df84..11e7cebb5bb 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget.cs @@ -33,7 +33,7 @@ internal partial class RazorCustomMessageTarget private readonly LSPRequestInvoker _requestInvoker; private readonly ITelemetryReporter _telemetryReporter; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions; - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; private readonly SnippetCompletionItemProvider _snippetCompletionItemProvider; private readonly IWorkspaceProvider _workspaceProvider; private readonly IHtmlDocumentSynchronizer _htmlDocumentSynchronizer; @@ -54,7 +54,7 @@ public RazorCustomMessageTarget( CSharpVirtualDocumentAddListener csharpVirtualDocumentAddListener, ITelemetryReporter telemetryReporter, LanguageServerFeatureOptions languageServerFeatureOptions, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, SnippetCompletionItemProvider snippetCompletionItemProvider, IWorkspaceProvider workspaceProvider, IHtmlDocumentSynchronizer htmlDocumentSynchronizer, diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/ProjectSystem/RazorProjectInfoDriver.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/ProjectSystem/RazorProjectInfoDriver.cs index 8a834193de6..8dc0e4210b1 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/ProjectSystem/RazorProjectInfoDriver.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/ProjectSystem/RazorProjectInfoDriver.cs @@ -12,10 +12,10 @@ namespace Microsoft.VisualStudio.Razor.LanguageClient.ProjectSystem; internal sealed partial class RazorProjectInfoDriver : AbstractRazorProjectInfoDriver { - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; public RazorProjectInfoDriver( - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, ILoggerFactory loggerFactory, TimeSpan? delay = null) : base(loggerFactory, delay) { diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/RazorLanguageServerClient.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/RazorLanguageServerClient.cs index 2bf2206fe25..4000ffbcd44 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/RazorLanguageServerClient.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/RazorLanguageServerClient.cs @@ -32,7 +32,7 @@ namespace Microsoft.VisualStudio.Razor.LanguageClient; [method: ImportingConstructor] internal class RazorLanguageServerClient( RazorCustomMessageTarget customTarget, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, ILoggerFactory loggerFactory, RazorLogHubTraceProvider traceProvider, LanguageServerFeatureOptions languageServerFeatureOptions, @@ -50,7 +50,7 @@ internal class RazorLanguageServerClient( private readonly IClientSettingsManager _clientSettingsManager = clientSettingsManager; private readonly ILspServerActivationTracker _lspServerActivationTracker = lspServerActivationTracker; private readonly RazorCustomMessageTarget _customMessageTarget = customTarget; - private readonly IProjectSnapshotManager _projectManager = projectManager; + private readonly ProjectSnapshotManager _projectManager = projectManager; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions = languageServerFeatureOptions; private readonly VisualStudioHostServicesProvider _vsHostServicesProvider = vsHostServicesProvider; private readonly ILoggerFactory _loggerFactory = loggerFactory; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Guest/ProjectSnapshotSynchronizationService.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Guest/ProjectSnapshotSynchronizationService.cs index 229a61d0d63..b85c86b3717 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Guest/ProjectSnapshotSynchronizationService.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Guest/ProjectSnapshotSynchronizationService.cs @@ -16,14 +16,14 @@ namespace Microsoft.VisualStudio.Razor.LiveShare.Guest; internal class ProjectSnapshotSynchronizationService( CollaborationSession sessionContext, IProjectSnapshotManagerProxy hostProjectManagerProxy, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, ILoggerFactory loggerFactory, JoinableTaskFactory jtf) : ICollaborationService, IAsyncDisposable, System.IAsyncDisposable { private readonly JoinableTaskFactory _jtf = jtf; private readonly CollaborationSession _sessionContext = sessionContext; private readonly IProjectSnapshotManagerProxy _hostProjectManagerProxy = hostProjectManagerProxy; - private readonly IProjectSnapshotManager _projectManager = projectManager; + private readonly ProjectSnapshotManager _projectManager = projectManager; private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); public async Task InitializeAsync(CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Guest/ProjectSnapshotSynchronizationServiceFactory.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Guest/ProjectSnapshotSynchronizationServiceFactory.cs index 6acfccc0f85..fb8c167cd33 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Guest/ProjectSnapshotSynchronizationServiceFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Guest/ProjectSnapshotSynchronizationServiceFactory.cs @@ -16,7 +16,7 @@ namespace Microsoft.VisualStudio.Razor.LiveShare.Guest; [ExportCollaborationService(typeof(ProjectSnapshotSynchronizationService), Scope = SessionScope.Guest)] [method: ImportingConstructor] internal class ProjectSnapshotSynchronizationServiceFactory( - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, ILoggerFactory loggerFactory, JoinableTaskContext joinableTaskContext) : ICollaborationServiceFactory { diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Host/ProjectSnapshotManagerProxy.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Host/ProjectSnapshotManagerProxy.cs index 7ae74da1e67..44b101296f1 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Host/ProjectSnapshotManagerProxy.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Host/ProjectSnapshotManagerProxy.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; -using Microsoft.AspNetCore.Razor.ProjectSystem; +using Microsoft.AspNetCore.Razor.Threading; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.VisualStudio.LiveShare; using Microsoft.VisualStudio.Threading; @@ -19,7 +19,7 @@ internal class ProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy, IColl #pragma warning disable RS0030 // Do not use banned APIs private readonly CollaborationSession _session; - private readonly IProjectSnapshotManager _projectSnapshotManager; + private readonly ProjectSnapshotManager _projectSnapshotManager; private readonly JoinableTaskFactory _jtf; private readonly AsyncSemaphore _latestStateSemaphore; private bool _disposed; @@ -29,7 +29,7 @@ internal class ProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy, IColl public ProjectSnapshotManagerProxy( CollaborationSession session, - IProjectSnapshotManager projectSnapshotManager, + ProjectSnapshotManager projectSnapshotManager, JoinableTaskFactory jtf) { _session = session; @@ -66,7 +66,7 @@ public void Dispose() } // Internal for testing - internal async Task> GetLatestProjectsAsync() + internal async Task> GetLatestProjectsAsync() { if (!_jtf.Context.IsOnMainThread) { @@ -77,7 +77,7 @@ internal async Task> GetLatestProjectsAsync() } // Internal for testing - internal async Task CalculateUpdatedStateAsync(IReadOnlyList projects) + internal async Task CalculateUpdatedStateAsync(IReadOnlyList projects) { using (await _latestStateSemaphore.EnterAsync().ConfigureAwait(false)) { @@ -93,19 +93,19 @@ internal async Task CalculateUpdatedStateAsync } } - private async Task ConvertToProxyAsync(IProjectSnapshot? project) + private Task ConvertToProxyAsync(ProjectSnapshot? project) { if (project is null) { - return null; + return SpecializedTasks.Null(); } - var tagHelpers = await project.GetTagHelpersAsync(CancellationToken.None).ConfigureAwait(false); - var projectWorkspaceState = ProjectWorkspaceState.Create(tagHelpers, project.CSharpLanguageVersion); var projectFilePath = _session.ConvertLocalPathToSharedUri(project.FilePath); var intermediateOutputPath = _session.ConvertLocalPathToSharedUri(project.IntermediateOutputPath); - var projectHandleProxy = new ProjectSnapshotHandleProxy(projectFilePath, intermediateOutputPath, project.Configuration, project.RootNamespace, projectWorkspaceState); - return projectHandleProxy; + var projectHandleProxy = new ProjectSnapshotHandleProxy( + projectFilePath, intermediateOutputPath, project.Configuration, project.RootNamespace, project.ProjectWorkspaceState); + + return Task.FromResult(projectHandleProxy).AsNullable(); } private void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Host/ProjectSnapshotManagerProxyFactory.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Host/ProjectSnapshotManagerProxyFactory.cs index de2ae2041a7..71c5b9d525d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Host/ProjectSnapshotManagerProxyFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LiveShare/Host/ProjectSnapshotManagerProxyFactory.cs @@ -19,7 +19,7 @@ namespace Microsoft.VisualStudio.Razor.LiveShare.Host; Role = ServiceRole.RemoteService)] [method: ImportingConstructor] internal class ProjectSnapshotManagerProxyFactory( - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, JoinableTaskContext joinableTaskContext) : ICollaborationServiceFactory { public Task CreateServiceAsync(CollaborationSession session, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/DefaultWindowsRazorProjectHost.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/DefaultWindowsRazorProjectHost.cs index 07a5297e177..20fdd32d24e 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/DefaultWindowsRazorProjectHost.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/DefaultWindowsRazorProjectHost.cs @@ -31,7 +31,7 @@ namespace Microsoft.VisualStudio.Razor.ProjectSystem; internal class DefaultWindowsRazorProjectHost( IUnconfiguredProjectCommonServices commonServices, [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, - IProjectSnapshotManager projectManager) + ProjectSnapshotManager projectManager) : WindowsRazorProjectHostBase(commonServices, serviceProvider, projectManager) { private const string RootNamespaceProperty = "RootNamespace"; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/FallbackProjectManager.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/FallbackProjectManager.cs index 966f8e68377..8bb6ca0393b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/FallbackProjectManager.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/FallbackProjectManager.cs @@ -28,7 +28,7 @@ namespace Microsoft.VisualStudio.Razor.ProjectSystem; internal sealed class FallbackProjectManager : IFallbackProjectManager { private readonly IServiceProvider _serviceProvider; - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; private readonly IWorkspaceProvider _workspaceProvider; private readonly ITelemetryReporter _telemetryReporter; @@ -38,7 +38,7 @@ internal sealed class FallbackProjectManager : IFallbackProjectManager [ImportingConstructor] public FallbackProjectManager( [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, IWorkspaceProvider workspaceProvider, ITelemetryReporter telemetryReporter) { @@ -70,7 +70,7 @@ private void ProjectManager_Changed(object sender, ProjectChangeEventArgs e) } } - public bool IsFallbackProject(IProjectSnapshot project) + public bool IsFallbackProject(ProjectSnapshot project) => _fallbackProjects.Contains(project.Key); internal void DynamicFileAdded( diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/FallbackWindowsRazorProjectHost.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/FallbackWindowsRazorProjectHost.cs index 04f96124fc5..5ccbeb83ae1 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/FallbackWindowsRazorProjectHost.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/FallbackWindowsRazorProjectHost.cs @@ -44,7 +44,7 @@ internal class FallbackWindowsRazorProjectHost : WindowsRazorProjectHostBase public FallbackWindowsRazorProjectHost( IUnconfiguredProjectCommonServices commonServices, [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, - IProjectSnapshotManager projectManager) + ProjectSnapshotManager projectManager) : base(commonServices, serviceProvider, projectManager) { } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/IFallbackProjectManager.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/IFallbackProjectManager.cs index 8eadd2aa99c..a503f617235 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/IFallbackProjectManager.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/IFallbackProjectManager.cs @@ -7,5 +7,5 @@ namespace Microsoft.VisualStudio.Razor.ProjectSystem; internal interface IFallbackProjectManager { - bool IsFallbackProject(IProjectSnapshot project); + bool IsFallbackProject(ProjectSnapshot project); } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/VisualStudioProjectSnapshotManager.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/VisualStudioProjectSnapshotManager.cs index e72f11e54a3..f9e301a7add 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/VisualStudioProjectSnapshotManager.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/VisualStudioProjectSnapshotManager.cs @@ -9,7 +9,7 @@ namespace Microsoft.VisualStudio.Razor.ProjectSystem; -[Export(typeof(IProjectSnapshotManager))] +[Export(typeof(ProjectSnapshotManager))] [method: ImportingConstructor] internal sealed class VisualStudioProjectSnapshotManager( IProjectEngineFactoryProvider projectEngineFactoryProvider, diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/WindowsRazorProjectHostBase.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/WindowsRazorProjectHostBase.cs index a4c6d03a99e..701c7666d72 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/WindowsRazorProjectHostBase.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/WindowsRazorProjectHostBase.cs @@ -26,7 +26,7 @@ internal abstract partial class WindowsRazorProjectHostBase : OnceInitializedOnc private static readonly DataflowLinkOptions s_dataflowLinkOptions = new DataflowLinkOptions() { PropagateCompletion = true }; private readonly IServiceProvider _serviceProvider; - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; private readonly AsyncSemaphore _lock; private readonly Dictionary _projectSubscriptions = new(); @@ -45,7 +45,7 @@ internal abstract partial class WindowsRazorProjectHostBase : OnceInitializedOnc protected WindowsRazorProjectHostBase( IUnconfiguredProjectCommonServices commonServices, IServiceProvider serviceProvider, - IProjectSnapshotManager projectManager) + ProjectSnapshotManager projectManager) : base(commonServices.ThreadingService.JoinableTaskContext) { CommonServices = commonServices; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectWorkspaceStateGenerator.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectWorkspaceStateGenerator.cs index 535c1ed44c7..763fd47c59f 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectWorkspaceStateGenerator.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectWorkspaceStateGenerator.cs @@ -20,7 +20,7 @@ namespace Microsoft.VisualStudio.Razor; [Export(typeof(IProjectWorkspaceStateGenerator))] [method: ImportingConstructor] internal sealed partial class ProjectWorkspaceStateGenerator( - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, ITagHelperResolver tagHelperResolver, ILoggerFactory loggerFactory, ITelemetryReporter telemetryReporter) @@ -29,7 +29,7 @@ internal sealed partial class ProjectWorkspaceStateGenerator( // SemaphoreSlim is banned. See https://github.com/dotnet/razor/issues/10390 for more info. #pragma warning disable RS0030 // Do not use banned APIs - private readonly IProjectSnapshotManager _projectManager = projectManager; + private readonly ProjectSnapshotManager _projectManager = projectManager; private readonly ITagHelperResolver _tagHelperResolver = tagHelperResolver; private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); private readonly ITelemetryReporter _telemetryReporter = telemetryReporter; @@ -65,7 +65,7 @@ public void Dispose() _blockBackgroundWorkStart?.Set(); } - public void EnqueueUpdate(Project? workspaceProject, IProjectSnapshot projectSnapshot) + public void EnqueueUpdate(Project? workspaceProject, ProjectSnapshot projectSnapshot) { if (_disposed) { @@ -113,7 +113,7 @@ public void CancelUpdates() } } - private async Task UpdateWorkspaceStateAsync(Project? workspaceProject, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken) + private async Task UpdateWorkspaceStateAsync(Project? workspaceProject, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) { var projectKey = projectSnapshot.Key; @@ -253,12 +253,12 @@ private void ReleaseSemaphore(ProjectKey projectKey) } /// - /// Attempts to produce a from the provide and . + /// Attempts to produce a from the provide and . /// Returns if an error is encountered. /// private async Task GetProjectWorkspaceStateAsync( Project? workspaceProject, - IProjectSnapshot projectSnapshot, + ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) { // This is the simplest case. If we don't have a project (likely because it is being removed), diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/OutOfProcTagHelperResolver.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/OutOfProcTagHelperResolver.cs index 34a1ac4217b..d684deead62 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/OutOfProcTagHelperResolver.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/OutOfProcTagHelperResolver.cs @@ -38,7 +38,7 @@ internal class OutOfProcTagHelperResolver( public async ValueTask> GetTagHelpersAsync( Project project, - IProjectSnapshot projectSnapshot, + ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) { // First, try to retrieve tag helpers out-of-proc. If that fails, try in-proc. @@ -70,7 +70,7 @@ public async ValueTask> GetTagHelpersAsync( } } - protected virtual async ValueTask> ResolveTagHelpersOutOfProcessAsync(Project project, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken) + protected virtual async ValueTask> ResolveTagHelpersOutOfProcessAsync(Project project, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) { if (!_resultCache.TryGetId(project.Id, out var lastResultId)) { @@ -176,7 +176,7 @@ protected ImmutableArray ProduceChecksumsFromDelta(ProjectId projectId protected virtual async ValueTask> ResolveTagHelpersInProcessAsync( Project project, - IProjectSnapshot projectSnapshot, + ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) { var projectEngine = await projectSnapshot.GetProjectEngineAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/VisualStudioSolutionCloseChangeTrigger.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/VisualStudioSolutionCloseChangeTrigger.cs index ec566cd10ea..57a6e0be53c 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/VisualStudioSolutionCloseChangeTrigger.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/VisualStudioSolutionCloseChangeTrigger.cs @@ -18,7 +18,7 @@ internal class VisualStudioSolutionCloseChangeTrigger : IRazorStartupService, IV { private IVsSolution? _solution; private readonly IServiceProvider _serviceProvider; - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; private readonly JoinableTaskContext _joinableTaskContext; private uint _cookie; @@ -26,7 +26,7 @@ internal class VisualStudioSolutionCloseChangeTrigger : IRazorStartupService, IV [ImportingConstructor] public VisualStudioSolutionCloseChangeTrigger( [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, JoinableTaskContext joinableTaskContext) { _serviceProvider = serviceProvider; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/VsSolutionUpdatesProjectSnapshotChangeTrigger.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/VsSolutionUpdatesProjectSnapshotChangeTrigger.cs index 1407253ad02..a316f36c575 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/VsSolutionUpdatesProjectSnapshotChangeTrigger.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/VsSolutionUpdatesProjectSnapshotChangeTrigger.cs @@ -20,7 +20,7 @@ namespace Microsoft.VisualStudio.Razor; internal class VsSolutionUpdatesProjectSnapshotChangeTrigger : IRazorStartupService, IVsUpdateSolutionEvents2, IDisposable { private readonly IServiceProvider _serviceProvider; - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; private readonly IProjectWorkspaceStateGenerator _workspaceStateGenerator; private readonly IWorkspaceProvider _workspaceProvider; private readonly JoinableTaskFactory _jtf; @@ -35,7 +35,7 @@ internal class VsSolutionUpdatesProjectSnapshotChangeTrigger : IRazorStartupServ [ImportingConstructor] public VsSolutionUpdatesProjectSnapshotChangeTrigger( [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, IProjectWorkspaceStateGenerator workspaceStateGenerator, IWorkspaceProvider workspaceProvider, JoinableTaskContext joinableTaskContext) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/WorkspaceProjectStateChangeDetector.Comparer.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/WorkspaceProjectStateChangeDetector.Comparer.cs index a99454a01e3..43a97071f31 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/WorkspaceProjectStateChangeDetector.Comparer.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/WorkspaceProjectStateChangeDetector.Comparer.cs @@ -10,7 +10,7 @@ namespace Microsoft.VisualStudio.Razor; internal partial class WorkspaceProjectStateChangeDetector { - private sealed class Comparer : IEqualityComparer<(Project?, IProjectSnapshot)> + private sealed class Comparer : IEqualityComparer<(Project?, ProjectSnapshot)> { public static readonly Comparer Instance = new(); @@ -18,7 +18,7 @@ private Comparer() { } - public bool Equals((Project?, IProjectSnapshot) x, (Project?, IProjectSnapshot) y) + public bool Equals((Project?, ProjectSnapshot) x, (Project?, ProjectSnapshot) y) { var (_, snapshotX) = x; var (_, snapshotY) = y; @@ -26,7 +26,7 @@ public bool Equals((Project?, IProjectSnapshot) x, (Project?, IProjectSnapshot) return FilePathComparer.Instance.Equals(snapshotX.Key.Id, snapshotY.Key.Id); } - public int GetHashCode((Project?, IProjectSnapshot) obj) + public int GetHashCode((Project?, ProjectSnapshot) obj) { var (_, snapshot) = obj; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/WorkspaceProjectStateChangeDetector.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/WorkspaceProjectStateChangeDetector.cs index 45c392df4bc..0cd9fbfb733 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/WorkspaceProjectStateChangeDetector.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/WorkspaceProjectStateChangeDetector.cs @@ -25,19 +25,19 @@ internal partial class WorkspaceProjectStateChangeDetector : IRazorStartupServic private static readonly TimeSpan s_delay = TimeSpan.FromSeconds(1); private readonly IProjectWorkspaceStateGenerator _generator; - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; private readonly LanguageServerFeatureOptions _options; private readonly CodeAnalysis.Workspace _workspace; private readonly CancellationTokenSource _disposeTokenSource; - private readonly AsyncBatchingWorkQueue<(Project?, IProjectSnapshot)> _workQueue; + private readonly AsyncBatchingWorkQueue<(Project?, ProjectSnapshot)> _workQueue; private WorkspaceChangedListener? _workspaceChangedListener; [ImportingConstructor] public WorkspaceProjectStateChangeDetector( IProjectWorkspaceStateGenerator generator, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, LanguageServerFeatureOptions options, IWorkspaceProvider workspaceProvider) : this(generator, projectManager, options, workspaceProvider, s_delay) @@ -46,7 +46,7 @@ public WorkspaceProjectStateChangeDetector( public WorkspaceProjectStateChangeDetector( IProjectWorkspaceStateGenerator generator, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, LanguageServerFeatureOptions options, IWorkspaceProvider workspaceProvider, TimeSpan delay) @@ -56,7 +56,7 @@ public WorkspaceProjectStateChangeDetector( _options = options; _disposeTokenSource = new(); - _workQueue = new AsyncBatchingWorkQueue<(Project?, IProjectSnapshot)>( + _workQueue = new AsyncBatchingWorkQueue<(Project?, ProjectSnapshot)>( delay, ProcessBatchAsync, _disposeTokenSource.Token); @@ -85,7 +85,7 @@ public void Dispose() _disposeTokenSource.Dispose(); } - private ValueTask ProcessBatchAsync(ImmutableArray<(Project? Project, IProjectSnapshot ProjectSnapshot)> items, CancellationToken token) + private ValueTask ProcessBatchAsync(ImmutableArray<(Project? Project, ProjectSnapshot ProjectSnapshot)> items, CancellationToken token) { foreach (var (project, projectSnapshot) in items.GetMostRecentUniqueItems(Comparer.Instance)) { @@ -377,7 +377,7 @@ private void EnqueueUpdateOnProjectAndDependencies(Project project, Solution sol } } - private void EnqueueUpdateOnProjectAndDependencies(ProjectId projectId, Project? project, Solution solution, IProjectSnapshot projectSnapshot) + private void EnqueueUpdateOnProjectAndDependencies(ProjectId projectId, Project? project, Solution solution, ProjectSnapshot projectSnapshot) { EnqueueUpdate(project, projectSnapshot); @@ -394,12 +394,12 @@ private void EnqueueUpdateOnProjectAndDependencies(ProjectId projectId, Project? } } - private void EnqueueUpdate(Project? project, IProjectSnapshot projectSnapshot) + private void EnqueueUpdate(Project? project, ProjectSnapshot projectSnapshot) { _workQueue.AddWork((project, projectSnapshot)); } - private bool TryGetProjectSnapshot(Project? project, [NotNullWhen(true)] out IProjectSnapshot? projectSnapshot) + private bool TryGetProjectSnapshot(Project? project, [NotNullWhen(true)] out ProjectSnapshot? projectSnapshot) { if (project?.CompilationOutputInfo.AssemblyPath is null) { diff --git a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTracker.cs b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTracker.cs index 737bb1f7e2d..e4e4c2ea838 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTracker.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTracker.cs @@ -27,7 +27,7 @@ internal sealed class VisualStudioDocumentTracker : IVisualStudioDocumentTracker private readonly JoinableTaskContext _joinableTaskContext; private readonly string _filePath; private readonly string _projectPath; - private readonly IProjectSnapshotManager _projectManager; + private readonly ProjectSnapshotManager _projectManager; private readonly IWorkspaceEditorSettings _workspaceEditorSettings; private readonly ITextBuffer _textBuffer; private readonly IImportDocumentManager _importDocumentManager; @@ -44,7 +44,7 @@ public VisualStudioDocumentTracker( JoinableTaskContext joinableTaskContext, string filePath, string projectPath, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, IWorkspaceEditorSettings workspaceEditorSettings, IProjectEngineFactoryProvider projectEngineFactoryProvider, ITextBuffer textBuffer, diff --git a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTrackerFactory.cs b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTrackerFactory.cs index 483a0b90f4f..6d101f76ae5 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTrackerFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LegacyEditor.Razor/VisualStudioDocumentTrackerFactory.cs @@ -16,7 +16,7 @@ namespace Microsoft.VisualStudio.LegacyEditor.Razor; [method: ImportingConstructor] internal sealed class VisualStudioDocumentTrackerFactory( JoinableTaskContext joinableTaskContext, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, IWorkspaceEditorSettings workspaceEditorSettings, IProjectPathProvider projectPathProvider, ITextDocumentFactoryService textDocumentFactory, @@ -27,7 +27,7 @@ internal sealed class VisualStudioDocumentTrackerFactory( private readonly ITextDocumentFactoryService _textDocumentFactory = textDocumentFactory; private readonly IProjectPathProvider _projectPathProvider = projectPathProvider; private readonly IImportDocumentManager _importDocumentManager = importDocumentManager; - private readonly IProjectSnapshotManager _projectManager = projectManager; + private readonly ProjectSnapshotManager _projectManager = projectManager; private readonly IWorkspaceEditorSettings _workspaceEditorSettings = workspaceEditorSettings; private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider = projectEngineFactoryProvider; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeDocumentReferenceHolderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeDocumentReferenceHolderTest.cs deleted file mode 100644 index 4144fcedbb4..00000000000 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeDocumentReferenceHolderTest.cs +++ /dev/null @@ -1,190 +0,0 @@ -// 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.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.Test.Common; -using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; -using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Text; -using Xunit; -using Xunit.Abstractions; - -namespace Microsoft.AspNetCore.Razor.LanguageServer; - -public class CodeDocumentReferenceHolderTest(ITestOutputHelper testOutput) : LanguageServerTestBase(testOutput) -{ - private static readonly HostProject s_hostProject = new( - filePath: "C:/path/to/project.csproj", - intermediateOutputPath: "C:/path/to/obj", - configuration: RazorConfiguration.Default, - rootNamespace: "TestNamespace"); - - private static readonly HostDocument s_hostDocument = new("C:/path/to/file.razor", "file.razor"); - -#nullable disable - private TestProjectSnapshotManager _projectManager; - private CodeDocumentReferenceHolder _referenceHolder; -#nullable enable - - protected override Task InitializeAsync() - { - _projectManager = CreateProjectSnapshotManager(); - _referenceHolder = new CodeDocumentReferenceHolder(_projectManager); - - return Task.CompletedTask; - } - - [Fact] - public async Task DocumentProcessed_ReferencesGeneratedCodeDocument() - { - // Arrange - var documentSnapshot = await CreateDocumentSnapshotAsync(); - var codeDocumentReference = await ProcessDocumentAndRetrieveOutputAsync(documentSnapshot, DisposalToken); - - // Act - PerformFullGC(); - - // Assert - Assert.True(codeDocumentReference.TryGetTarget(out _)); - } - - [Fact(Skip = "Weak cache removed")] - public async Task UpdateUnrelatedDocumentText_ReferencesGeneratedCodeDocument() - { - // Arrange - var documentSnapshot = await CreateDocumentSnapshotAsync(); - var unrelatedHostDocument = new HostDocument("C:/path/to/otherfile.razor", "otherfile.razor"); - - await _projectManager.UpdateAsync(updater => - { - updater.AddDocument(s_hostProject.Key, unrelatedHostDocument, TestMocks.CreateTextLoader("

Unrelated

")); - }); - - var unrelatedDocumentSnapshot = _projectManager.GetRequiredDocument(s_hostProject.Key, unrelatedHostDocument.FilePath); - - var mainCodeDocumentReference = await ProcessDocumentAndRetrieveOutputAsync(documentSnapshot, DisposalToken); - var unrelatedCodeDocumentReference = await ProcessDocumentAndRetrieveOutputAsync(unrelatedDocumentSnapshot, DisposalToken); - - // Act - await _projectManager.UpdateAsync(updater => - { - updater.UpdateDocumentText(s_hostProject.Key, unrelatedHostDocument.FilePath, SourceText.From(string.Empty)); - }); - - PerformFullGC(); - - // Assert - Assert.True(mainCodeDocumentReference.TryGetTarget(out _)); - Assert.False(unrelatedCodeDocumentReference.TryGetTarget(out _)); - } - - [Fact(Skip = "Weak cache removed")] - public async Task UpdateDocumentText_DereferencesGeneratedCodeDocument() - { - // Arrange - var documentSnapshot = await CreateDocumentSnapshotAsync(); - var codeDocumentReference = await ProcessDocumentAndRetrieveOutputAsync(documentSnapshot, DisposalToken); - - // Act - - await _projectManager.UpdateAsync(updater => - { - updater.UpdateDocumentText(s_hostProject.Key, s_hostDocument.FilePath, SourceText.From(string.Empty)); - }); - - PerformFullGC(); - - // Assert - Assert.False(codeDocumentReference.TryGetTarget(out _)); - } - - [Fact(Skip = "Weak cache removed")] - public async Task RemoveDocument_DereferencesGeneratedCodeDocument() - { - // Arrange - var documentSnapshot = await CreateDocumentSnapshotAsync(); - var codeDocumentReference = await ProcessDocumentAndRetrieveOutputAsync(documentSnapshot, DisposalToken); - - // Act - await _projectManager.UpdateAsync(updater => - { - updater.RemoveDocument(s_hostProject.Key, s_hostDocument.FilePath); - }); - - PerformFullGC(); - - // Assert - Assert.False(codeDocumentReference.TryGetTarget(out _)); - } - - [Fact(Skip = "Weak cache removed")] - public async Task UpdateProjectConfiguration_DereferencesGeneratedCodeDocument() - { - // Arrange - var documentSnapshot = await CreateDocumentSnapshotAsync(); - var codeDocumentReference = await ProcessDocumentAndRetrieveOutputAsync(documentSnapshot, DisposalToken); - - // Act - await _projectManager.UpdateAsync(updater => - { - updater.UpdateProjectConfiguration(s_hostProject with { Configuration = RazorConfiguration.Default, RootNamespace = "NewRootNamespace" }); - }); - - PerformFullGC(); - - // Assert - Assert.False(codeDocumentReference.TryGetTarget(out _)); - } - - [Fact(Skip = "Weak cache removed")] - public async Task RemoveProject_DereferencesGeneratedCodeDocument() - { - // Arrange - var documentSnapshot = await CreateDocumentSnapshotAsync(); - var codeDocumentReference = await ProcessDocumentAndRetrieveOutputAsync(documentSnapshot, DisposalToken); - - // Act - await _projectManager.UpdateAsync(updater => - { - updater.RemoveProject(s_hostProject.Key); - }); - - PerformFullGC(); - - // Assert - Assert.False(codeDocumentReference.TryGetTarget(out _)); - } - - private Task CreateDocumentSnapshotAsync() - { - return _projectManager.UpdateAsync(updater => - { - updater.AddProject(s_hostProject); - updater.AddDocument(s_hostProject.Key, s_hostDocument, TestMocks.CreateTextLoader("

Hello World

")); - - return updater.GetRequiredDocument(s_hostProject.Key, s_hostDocument.FilePath); - }); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private async Task> ProcessDocumentAndRetrieveOutputAsync(IDocumentSnapshot documentSnapshot, CancellationToken cancellationToken) - { - var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(cancellationToken); - - _referenceHolder.DocumentProcessed(codeDocument, documentSnapshot); - - return new(codeDocument); - } - - private static void PerformFullGC() - { - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - } -} diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs index f1c929f8f37..74d0b684277 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -15,7 +14,6 @@ using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.Diagnostics; -using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; @@ -31,11 +29,56 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics; -public class RazorDiagnosticsPublisherTest(ITestOutputHelper testOutput) : LanguageServerTestBase(testOutput) +public class RazorDiagnosticsPublisherTest : LanguageServerTestBase { + private static readonly HostProject s_hostProject = new("C:/project/project.csproj", "C:/project/obj", RazorConfiguration.Default, "TestRootNamespace"); + private static readonly HostDocument s_openHostDocument = new("C:/project/open_document.cshtml", "C:/project/open_document.cshtml"); + private static readonly HostDocument s_closedHostDocument = new("C:/project/closed_document.cshtml", "C:/project/closed_document.cshtml"); + private static readonly Uri s_openedDocumentUri = new(s_openHostDocument.FilePath); + + private static readonly SourceText s_razorText = SourceText.From(""" + @using Microsoft.AspNetCore.Components.Forms; + + @code { + private string _id { get; set; } + } + +
+
+ + @if (true) + { + + } + +
+
+ """); + + private static readonly SourceText s_razorTextWithError = SourceText.From(""" + @using Microsoft.AspNetCore.Components.Forms; + + @code { + private string _id { get; set; } + } + +
+
+ + @if (true) + { + +
+
+ """); + private static readonly RazorDiagnostic[] s_singleRazorDiagnostic = [ - RazorDiagnosticFactory.CreateDirective_BlockDirectiveCannotBeImported("test") + RazorDiagnosticFactory.CreateParsing_MissingEndTag( + new SourceSpan(s_openHostDocument.FilePath, absoluteIndex: 216, lineIndex: 11, characterIndex: 17, length: 6, lineCount: 1, endCharacterIndex: 0), + "option") ]; private static readonly Diagnostic[] s_singleCSharpDiagnostic = @@ -49,48 +92,39 @@ public class RazorDiagnosticsPublisherTest(ITestOutputHelper testOutput) : Langu } ]; - // These fields are initialized by InitializeAsync() -#nullable disable - private IProjectSnapshotManager _projectManager; - private IDocumentSnapshot _closedDocument; - private IDocumentSnapshot _openedDocument; - private RazorCodeDocument _testCodeDocument; - private Uri _openedDocumentUri; -#nullable enable + private readonly TestProjectSnapshotManager _projectManager; + private readonly DocumentContextFactory _documentContextFactory; - protected override async Task InitializeAsync() + public RazorDiagnosticsPublisherTest(ITestOutputHelper testOutput) : base(testOutput) { - var projectManager = CreateProjectSnapshotManager(); - var hostProject = new HostProject("C:/project/project.csproj", "C:/project/obj", RazorConfiguration.Default, "TestRootNamespace"); - var sourceText = SourceText.From(string.Empty); - var openedHostDocument = new HostDocument("C:/project/open_document.cshtml", "C:/project/open_document.cshtml"); - var closedHostDocument = new HostDocument("C:/project/closed_document.cshtml", "C:/project/closed_document.cshtml"); + _projectManager = CreateProjectSnapshotManager(); + _documentContextFactory = new DocumentContextFactory(_projectManager, LoggerFactory); + } - await projectManager.UpdateAsync(updater => + protected override async Task InitializeAsync() + { + await _projectManager.UpdateAsync(updater => { - updater.AddProject(hostProject); - updater.AddDocument(hostProject.Key, openedHostDocument, sourceText); - updater.OpenDocument(hostProject.Key, openedHostDocument.FilePath, sourceText); - updater.AddDocument(hostProject.Key, closedHostDocument, sourceText); + updater.AddProject(s_hostProject); + updater.AddDocument(s_hostProject.Key, s_openHostDocument, EmptyTextLoader.Instance); + updater.OpenDocument(s_hostProject.Key, s_openHostDocument.FilePath, s_razorText); + updater.AddDocument(s_hostProject.Key, s_closedHostDocument, EmptyTextLoader.Instance); }); + } - var project = projectManager.GetRequiredProject(hostProject.Key); - - _openedDocument = project.GetRequiredDocument(openedHostDocument.FilePath); - _openedDocumentUri = new Uri("C:/project/open_document.cshtml"); - - _closedDocument = project.GetRequiredDocument(closedHostDocument.FilePath); - - _projectManager = projectManager; - _testCodeDocument = TestRazorCodeDocument.CreateEmpty(); + private Task UpdateWithErrorTextAsync() + { + return _projectManager.UpdateAsync(updater => + { + updater.UpdateDocumentText(s_hostProject.Key, s_openHostDocument.FilePath, s_razorTextWithError); + }); } [Fact] public async Task DocumentProcessed_NewWorkQueued_RestartsTimer() { // Arrange - var codeDocument = CreateCodeDocument(s_singleRazorDiagnostic); - var processedOpenDocument = TestDocumentSnapshot.Create(_openedDocument.FilePath, codeDocument); + await UpdateWithErrorTextAsync(); var clientConnectionMock = new StrictMock(); clientConnectionMock @@ -105,17 +139,17 @@ public async Task DocumentProcessed_NewWorkQueued_RestartsTimer() CustomMessageNames.RazorCSharpPullDiagnosticsEndpointName, It.IsAny(), It.IsAny())) - .Returns(Task.FromResult(new SumType?(new FullDocumentDiagnosticReport()))) + .ReturnsAsync(new SumType?(new FullDocumentDiagnosticReport())) .Verifiable(); - var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); - - using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); + using var publisher = CreatePublisher(clientConnectionMock.Object); var publisherAccessor = publisher.GetTestAccessor(); // Act 1 - publisher.DocumentProcessed(_testCodeDocument, processedOpenDocument); + var openDocument = _projectManager.GetRequiredDocument(s_hostProject.Key, s_openHostDocument.FilePath); + var codeDocument = await openDocument.GetGeneratedOutputAsync(DisposalToken); + + publisher.DocumentProcessed(codeDocument, openDocument); await publisherAccessor.WaitForDiagnosticsToPublishAsync(); // Assert 1 @@ -127,7 +161,7 @@ public async Task DocumentProcessed_NewWorkQueued_RestartsTimer() Times.Once); // Act 2 - publisher.DocumentProcessed(_testCodeDocument, processedOpenDocument); + publisher.DocumentProcessed(codeDocument, openDocument); await publisherAccessor.WaitForDiagnosticsToPublishAsync(); // Assert 2 @@ -146,6 +180,11 @@ public async Task DocumentProcessed_NewWorkQueued_RestartsTimer() public async Task PublishDiagnosticsAsync_NewDocumentDiagnosticsGetPublished(bool shouldContainCSharpDiagnostic, bool shouldContainRazorDiagnostic) { // Arrange + if (shouldContainRazorDiagnostic) + { + await UpdateWithErrorTextAsync(); + } + var singleCSharpDiagnostic = new[] { new Diagnostic() @@ -157,8 +196,7 @@ public async Task PublishDiagnosticsAsync_NewDocumentDiagnosticsGetPublished(boo } }; - var codeDocument = CreateCodeDocument(shouldContainRazorDiagnostic ? s_singleRazorDiagnostic : []); - var processedOpenDocument = TestDocumentSnapshot.Create(_openedDocument.FilePath, codeDocument); + var openDocument = _projectManager.GetRequiredDocument(s_hostProject.Key, s_openHostDocument.FilePath); var clientConnectionMock = new StrictMock(); var requestResult = new FullDocumentDiagnosticReport(); @@ -174,9 +212,9 @@ public async Task PublishDiagnosticsAsync_NewDocumentDiagnosticsGetPublished(boo It.IsAny())) .Callback((string method, DocumentDiagnosticParams @params, CancellationToken cancellationToken) => { - Assert.Equal(_openedDocumentUri, @params.TextDocument.Uri); + Assert.Equal(s_openedDocumentUri, @params.TextDocument.Uri); }) - .Returns(Task.FromResult(new SumType?(requestResult))); + .ReturnsAsync(new SumType?(requestResult)); clientConnectionMock .Setup(server => server.SendNotificationAsync( @@ -185,7 +223,7 @@ public async Task PublishDiagnosticsAsync_NewDocumentDiagnosticsGetPublished(boo It.IsAny())) .Callback((string method, PublishDiagnosticParams @params, CancellationToken cancellationToken) => { - Assert.Equal(processedOpenDocument.FilePath.TrimStart('/'), @params.Uri.AbsolutePath); + Assert.Equal(s_openHostDocument.FilePath.TrimStart('/'), @params.Uri.AbsolutePath); Assert.Equal(shouldContainCSharpDiagnostic && shouldContainRazorDiagnostic ? 2 : 1, @params.Diagnostics.Length); if (shouldContainCSharpDiagnostic) { @@ -196,32 +234,26 @@ public async Task PublishDiagnosticsAsync_NewDocumentDiagnosticsGetPublished(boo { var resultRazorDiagnostic = @params.Diagnostics[0]; var razorDiagnostic = s_singleRazorDiagnostic[0]; - Assert.True(processedOpenDocument.TryGetText(out var sourceText)); - var expectedRazorDiagnostic = RazorDiagnosticConverter.Convert(razorDiagnostic, sourceText, _openedDocument); + Assert.True(openDocument.TryGetText(out var sourceText)); + var expectedRazorDiagnostic = RazorDiagnosticConverter.Convert(razorDiagnostic, sourceText, openDocument); Assert.Equal(expectedRazorDiagnostic.Message, resultRazorDiagnostic.Message); Assert.Equal(expectedRazorDiagnostic.Severity, resultRazorDiagnostic.Severity); Assert.Equal(expectedRazorDiagnostic.Range, resultRazorDiagnostic.Range); Assert.NotNull(expectedRazorDiagnostic.Projects); - Assert.Single(expectedRazorDiagnostic.Projects); - var project = expectedRazorDiagnostic.Projects.Single(); - Assert.Equal(_openedDocument.Project.DisplayName, project.ProjectName); - Assert.Equal(_openedDocument.Project.Key.Id, project.ProjectIdentifier); + var project = Assert.Single(expectedRazorDiagnostic.Projects); + Assert.Equal(openDocument.Project.DisplayName, project.ProjectName); + Assert.Equal(openDocument.Project.Key.Id, project.ProjectIdentifier); } }) .Returns(Task.CompletedTask); - var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); - var filePathService = new LSPFilePathService(TestLanguageServerFeatureOptions.Instance); - var documentMappingService = new LspDocumentMappingService(filePathService, documentContextFactory, LoggerFactory); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(documentMappingService, LoggerFactory); - - using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); + using var publisher = CreatePublisher(clientConnectionMock.Object); var publisherAccessor = publisher.GetTestAccessor(); // Act - await publisherAccessor.PublishDiagnosticsAsync(processedOpenDocument, DisposalToken); + await publisherAccessor.PublishDiagnosticsAsync(openDocument, DisposalToken); // Assert clientConnectionMock.VerifyAll(); @@ -231,8 +263,9 @@ public async Task PublishDiagnosticsAsync_NewDocumentDiagnosticsGetPublished(boo public async Task PublishDiagnosticsAsync_NewRazorDiagnosticsGetPublished() { // Arrange - var codeDocument = CreateCodeDocument(s_singleRazorDiagnostic); - var processedOpenDocument = TestDocumentSnapshot.Create(_openedDocument.FilePath, codeDocument); + await UpdateWithErrorTextAsync(); + + var openDocument = _projectManager.GetRequiredDocument(s_hostProject.Key, s_openHostDocument.FilePath); var clientConnectionMock = new StrictMock(); clientConnectionMock @@ -242,9 +275,9 @@ public async Task PublishDiagnosticsAsync_NewRazorDiagnosticsGetPublished() It.IsAny())) .Callback((string method, DocumentDiagnosticParams @params, CancellationToken cancellationToken) => { - Assert.Equal(_openedDocumentUri, @params.TextDocument.Uri); + Assert.Equal(s_openedDocumentUri, @params.TextDocument.Uri); }) - .Returns(Task.FromResult(new SumType?(new FullDocumentDiagnosticReport()))); + .ReturnsAsync(new SumType?(new FullDocumentDiagnosticReport())); clientConnectionMock .Setup(server => server.SendNotificationAsync( @@ -253,31 +286,28 @@ public async Task PublishDiagnosticsAsync_NewRazorDiagnosticsGetPublished() It.IsAny())) .Callback((string method, PublishDiagnosticParams @params, CancellationToken cancellationToken) => { - Assert.Equal(processedOpenDocument.FilePath.TrimStart('/'), @params.Uri.AbsolutePath); + Assert.Equal(openDocument.FilePath.TrimStart('/'), @params.Uri.AbsolutePath); var diagnostic = Assert.Single(@params.Diagnostics); var razorDiagnostic = s_singleRazorDiagnostic[0]; - Assert.True(processedOpenDocument.TryGetText(out var sourceText)); - var expectedDiagnostic = RazorDiagnosticConverter.Convert(razorDiagnostic, sourceText, _openedDocument); + Assert.True(openDocument.TryGetText(out var sourceText)); + var expectedDiagnostic = RazorDiagnosticConverter.Convert(razorDiagnostic, sourceText, openDocument); Assert.Equal(expectedDiagnostic.Message, diagnostic.Message); Assert.Equal(expectedDiagnostic.Severity, diagnostic.Severity); Assert.Equal(expectedDiagnostic.Range, diagnostic.Range); Assert.NotNull(expectedDiagnostic.Projects); - var project = expectedDiagnostic.Projects.Single(); - Assert.Equal(_openedDocument.Project.DisplayName, project.ProjectName); - Assert.Equal(_openedDocument.Project.Key.Id, project.ProjectIdentifier); + var project = Assert.Single(expectedDiagnostic.Projects); + Assert.Equal(openDocument.Project.DisplayName, project.ProjectName); + Assert.Equal(openDocument.Project.Key.Id, project.ProjectIdentifier); }) .Returns(Task.CompletedTask); - var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); - - using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); + using var publisher = CreatePublisher(clientConnectionMock.Object); var publisherAccessor = publisher.GetTestAccessor(); - publisherAccessor.SetPublishedDiagnostics(processedOpenDocument.FilePath, razorDiagnostics: [], csharpDiagnostics: null); + publisherAccessor.SetPublishedDiagnostics(openDocument.FilePath, razorDiagnostics: [], csharpDiagnostics: null); // Act - await publisherAccessor.PublishDiagnosticsAsync(processedOpenDocument, DisposalToken); + await publisherAccessor.PublishDiagnosticsAsync(openDocument, DisposalToken); // Assert clientConnectionMock.VerifyAll(); @@ -287,8 +317,7 @@ public async Task PublishDiagnosticsAsync_NewRazorDiagnosticsGetPublished() public async Task PublishDiagnosticsAsync_NewCSharpDiagnosticsGetPublished() { // Arrange - var codeDocument = CreateCodeDocument([]); - var processedOpenDocument = TestDocumentSnapshot.Create(_openedDocument.FilePath, codeDocument); + var openDocument = _projectManager.GetRequiredDocument(s_hostProject.Key, s_openHostDocument.FilePath); var arranging = true; var clientConnectionMock = new StrictMock(); @@ -299,11 +328,11 @@ public async Task PublishDiagnosticsAsync_NewCSharpDiagnosticsGetPublished() It.IsAny())) .Callback((string method, DocumentDiagnosticParams @params, CancellationToken cancellationToken) => { - Assert.Equal(_openedDocumentUri, @params.TextDocument.Uri); + Assert.Equal(s_openedDocumentUri, @params.TextDocument.Uri); }) - .Returns(Task.FromResult( + .ReturnsAsync( new SumType?( - arranging ? new FullDocumentDiagnosticReport() : new FullDocumentDiagnosticReport { Items = s_singleCSharpDiagnostic.ToArray() }))); + arranging ? new FullDocumentDiagnosticReport() : new FullDocumentDiagnosticReport { Items = s_singleCSharpDiagnostic.ToArray() })); clientConnectionMock.Setup( server => server.SendNotificationAsync( @@ -312,8 +341,8 @@ public async Task PublishDiagnosticsAsync_NewCSharpDiagnosticsGetPublished() It.IsAny())) .Callback((string method, PublishDiagnosticParams @params, CancellationToken cancellationToken) => { - Assert.Equal(processedOpenDocument.FilePath.TrimStart('/'), @params.Uri.AbsolutePath); - Assert.True(processedOpenDocument.TryGetText(out var sourceText)); + Assert.Equal(openDocument.FilePath.TrimStart('/'), @params.Uri.AbsolutePath); + Assert.True(openDocument.TryGetText(out var sourceText)); if (arranging) { Assert.Empty(@params.Diagnostics); @@ -326,17 +355,14 @@ public async Task PublishDiagnosticsAsync_NewCSharpDiagnosticsGetPublished() }) .Returns(Task.CompletedTask); - var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); - - using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); + using var publisher = CreatePublisher(clientConnectionMock.Object); var publisherAccessor = publisher.GetTestAccessor(); - await publisherAccessor.PublishDiagnosticsAsync(processedOpenDocument, DisposalToken); + await publisherAccessor.PublishDiagnosticsAsync(openDocument, DisposalToken); arranging = false; // Act - await publisherAccessor.PublishDiagnosticsAsync(processedOpenDocument, DisposalToken); + await publisherAccessor.PublishDiagnosticsAsync(openDocument, DisposalToken); // Assert clientConnectionMock.VerifyAll(); @@ -346,6 +372,10 @@ public async Task PublishDiagnosticsAsync_NewCSharpDiagnosticsGetPublished() public async Task PublishDiagnosticsAsync_NoopsIfRazorDiagnosticsAreSameAsPreviousPublish() { // Arrange + await UpdateWithErrorTextAsync(); + + var openDocument = _projectManager.GetRequiredDocument(s_hostProject.Key, s_openHostDocument.FilePath); + var clientConnectionMock = new StrictMock(); clientConnectionMock .Setup(server => server.SendRequestAsync?>( @@ -354,32 +384,23 @@ public async Task PublishDiagnosticsAsync_NoopsIfRazorDiagnosticsAreSameAsPrevio It.IsAny())) .Callback((string method, DocumentDiagnosticParams @params, CancellationToken cancellationToken) => { - Assert.Equal(_openedDocumentUri, @params.TextDocument.Uri); + Assert.Equal(s_openedDocumentUri, @params.TextDocument.Uri); }) - .Returns(Task.FromResult(new SumType?(new FullDocumentDiagnosticReport()))); - - var codeDocument = CreateCodeDocument(s_singleRazorDiagnostic); - var processedOpenDocument = TestDocumentSnapshot.Create(_openedDocument.FilePath, codeDocument); + .ReturnsAsync(new SumType?(new FullDocumentDiagnosticReport())); - var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); - var filePathService = new LSPFilePathService(TestLanguageServerFeatureOptions.Instance); - var documentMappingService = new LspDocumentMappingService(filePathService, documentContextFactory, LoggerFactory); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(documentMappingService, LoggerFactory); - - using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); + using var publisher = CreatePublisher(clientConnectionMock.Object); var publisherAccessor = publisher.GetTestAccessor(); - publisherAccessor.SetPublishedDiagnostics(processedOpenDocument.FilePath, s_singleRazorDiagnostic, csharpDiagnostics: null); + publisherAccessor.SetPublishedDiagnostics(openDocument.FilePath, s_singleRazorDiagnostic, csharpDiagnostics: null); // Act & Assert - await publisherAccessor.PublishDiagnosticsAsync(processedOpenDocument, DisposalToken); + await publisherAccessor.PublishDiagnosticsAsync(openDocument, DisposalToken); } [Fact] public async Task PublishDiagnosticsAsync_NoopsIfCSharpDiagnosticsAreSameAsPreviousPublish() { // Arrange - var codeDocument = CreateCodeDocument([]); - var processedOpenDocument = TestDocumentSnapshot.Create(_openedDocument.FilePath, codeDocument); + var openDocument = _projectManager.GetRequiredDocument(s_hostProject.Key, s_openHostDocument.FilePath); var clientConnectionMock = new StrictMock(); var arranging = true; @@ -391,9 +412,9 @@ public async Task PublishDiagnosticsAsync_NoopsIfCSharpDiagnosticsAreSameAsPrevi It.IsAny())) .Callback((string method, DocumentDiagnosticParams @params, CancellationToken cancellationToken) => { - Assert.Equal(_openedDocumentUri, @params.TextDocument.Uri); + Assert.Equal(s_openedDocumentUri, @params.TextDocument.Uri); }) - .Returns(Task.FromResult(new SumType?(new FullDocumentDiagnosticReport()))); + .ReturnsAsync(new SumType?(new FullDocumentDiagnosticReport())); clientConnectionMock .Setup(server => server.SendNotificationAsync( @@ -407,23 +428,20 @@ public async Task PublishDiagnosticsAsync_NoopsIfCSharpDiagnosticsAreSameAsPrevi Assert.Fail("This callback should not have been received since diagnostics are the same as previous published"); } - Assert.Equal(processedOpenDocument.FilePath.TrimStart('/'), @params.Uri.AbsolutePath); - Assert.True(processedOpenDocument.TryGetText(out var sourceText)); + Assert.Equal(openDocument.FilePath.TrimStart('/'), @params.Uri.AbsolutePath); + Assert.True(openDocument.TryGetText(out var sourceText)); Assert.Empty(@params.Diagnostics); }) .Returns(Task.CompletedTask); - var documentContextFactory = new TestDocumentContextFactory(_openedDocument.FilePath, codeDocument); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); - - using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); + using var publisher = CreatePublisher(clientConnectionMock.Object); var publisherAccessor = publisher.GetTestAccessor(); - await publisherAccessor.PublishDiagnosticsAsync(processedOpenDocument, DisposalToken); + await publisherAccessor.PublishDiagnosticsAsync(openDocument, DisposalToken); arranging = false; // Act & Assert - await publisherAccessor.PublishDiagnosticsAsync(processedOpenDocument, DisposalToken); + await publisherAccessor.PublishDiagnosticsAsync(openDocument, DisposalToken); } [Fact] @@ -438,17 +456,14 @@ public void ClearClosedDocuments_ClearsDiagnosticsForClosedDocument() It.IsAny())) .Callback((string method, PublishDiagnosticParams @params, CancellationToken cancellationToken) => { - Assert.Equal(_closedDocument.FilePath.TrimStart('/'), @params.Uri.AbsolutePath); + Assert.Equal(s_closedHostDocument.FilePath.TrimStart('/'), @params.Uri.AbsolutePath); Assert.Empty(@params.Diagnostics); }) .Returns(Task.CompletedTask); - var documentContextFactory = new TestDocumentContextFactory(); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); - - using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); + using var publisher = CreatePublisher(clientConnectionMock.Object); var publisherAccessor = publisher.GetTestAccessor(); - publisherAccessor.SetPublishedDiagnostics(_closedDocument.FilePath, s_singleRazorDiagnostic, s_singleCSharpDiagnostic); + publisherAccessor.SetPublishedDiagnostics(s_closedHostDocument.FilePath, s_singleRazorDiagnostic, s_singleCSharpDiagnostic); // Act publisherAccessor.ClearClosedDocuments(); @@ -461,13 +476,9 @@ public void ClearClosedDocuments_ClearsDiagnosticsForClosedDocument() public void ClearClosedDocuments_NoopsIfDocumentIsStillOpen() { // Arrange - var clientConnectionMock = new StrictMock(); - var documentContextFactory = new TestDocumentContextFactory(); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); - - using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); + using var publisher = CreatePublisher(); var publisherAccessor = publisher.GetTestAccessor(); - publisherAccessor.SetPublishedDiagnostics(_openedDocument.FilePath, s_singleRazorDiagnostic, s_singleCSharpDiagnostic); + publisherAccessor.SetPublishedDiagnostics(s_openHostDocument.FilePath, s_singleRazorDiagnostic, s_singleCSharpDiagnostic); // Act & Assert publisherAccessor.ClearClosedDocuments(); @@ -477,13 +488,9 @@ public void ClearClosedDocuments_NoopsIfDocumentIsStillOpen() public void ClearClosedDocuments_NoopsIfDocumentIsClosedButNoDiagnostics() { // Arrange - var clientConnectionMock = new StrictMock(); - var documentContextFactory = new TestDocumentContextFactory(); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); - - using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); + using var publisher = CreatePublisher(); var publisherAccessor = publisher.GetTestAccessor(); - publisherAccessor.SetPublishedDiagnostics(_closedDocument.FilePath, razorDiagnostics: [], csharpDiagnostics: []); + publisherAccessor.SetPublishedDiagnostics(s_closedHostDocument.FilePath, razorDiagnostics: [], csharpDiagnostics: []); // Act & Assert publisherAccessor.ClearClosedDocuments(); @@ -493,14 +500,10 @@ public void ClearClosedDocuments_NoopsIfDocumentIsClosedButNoDiagnostics() public void ClearClosedDocuments_RestartsTimerIfDocumentsStillOpen() { // Arrange - var clientConnectionMock = new StrictMock(); - var documentContextFactory = new TestDocumentContextFactory(); - var translateDiagnosticsService = new RazorTranslateDiagnosticsService(StrictMock.Of(), LoggerFactory); - - using var publisher = new TestRazorDiagnosticsPublisher(_projectManager, clientConnectionMock.Object, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, documentContextFactory, LoggerFactory); + using var publisher = CreatePublisher(); var publisherAccessor = publisher.GetTestAccessor(); - publisherAccessor.SetPublishedDiagnostics(_closedDocument.FilePath, razorDiagnostics: [], csharpDiagnostics: []); - publisherAccessor.SetPublishedDiagnostics(_openedDocument.FilePath, razorDiagnostics: [], csharpDiagnostics: []); + publisherAccessor.SetPublishedDiagnostics(s_closedHostDocument.FilePath, razorDiagnostics: [], csharpDiagnostics: []); + publisherAccessor.SetPublishedDiagnostics(s_openHostDocument.FilePath, razorDiagnostics: [], csharpDiagnostics: []); // Act publisherAccessor.ClearClosedDocuments(); @@ -509,24 +512,30 @@ public void ClearClosedDocuments_RestartsTimerIfDocumentsStillOpen() Assert.True(publisherAccessor.IsWaitingToClearClosedDocuments); } - private static RazorCodeDocument CreateCodeDocument(IEnumerable diagnostics) + private TestRazorDiagnosticsPublisher CreatePublisher(IClientConnection? clientConnection = null) { - var codeDocument = TestRazorCodeDocument.Create("hello"); - var razorCSharpDocument = new RazorCSharpDocument(codeDocument, "hello", RazorCodeGenerationOptions.Default, diagnostics.ToImmutableArray()); - codeDocument.SetCSharpDocument(razorCSharpDocument); + clientConnection ??= StrictMock.Of(); + + var documentContextFactory = new DocumentContextFactory(_projectManager, LoggerFactory); + var filePathService = new LSPFilePathService(TestLanguageServerFeatureOptions.Instance); + var documentMappingService = new LspDocumentMappingService(filePathService, documentContextFactory, LoggerFactory); + var translateDiagnosticsService = new RazorTranslateDiagnosticsService(documentMappingService, LoggerFactory); - return codeDocument; + return new TestRazorDiagnosticsPublisher(_projectManager, clientConnection, TestLanguageServerFeatureOptions.Instance, translateDiagnosticsService, _documentContextFactory, LoggerFactory); } - private class TestRazorDiagnosticsPublisher( - IProjectSnapshotManager projectManager, + private sealed class TestRazorDiagnosticsPublisher( + ProjectSnapshotManager projectManager, IClientConnection clientConnection, LanguageServerFeatureOptions options, RazorTranslateDiagnosticsService translateDiagnosticsService, IDocumentContextFactory documentContextFactory, - ILoggerFactory loggerFactory) : RazorDiagnosticsPublisher(projectManager, clientConnection, options, - new Lazy(() => translateDiagnosticsService), - new Lazy(() => documentContextFactory), - loggerFactory, - publishDelay: TimeSpan.FromMilliseconds(1)); + ILoggerFactory loggerFactory) : RazorDiagnosticsPublisher( + projectManager, + clientConnection, + options, + translateDiagnosticsService: new Lazy(() => translateDiagnosticsService), + documentContextFactory: new Lazy(() => documentContextFactory), + loggerFactory, + publishDelay: TimeSpan.FromMilliseconds(1)); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentSynchronizerTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentSynchronizerTest.cs index c301c82cad1..6e5683ea8a8 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentSynchronizerTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentSynchronizerTest.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectSystem; +using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; @@ -22,8 +23,6 @@ public class GeneratedDocumentSynchronizerTest : LanguageServerTestBase private readonly GeneratedDocumentSynchronizer _synchronizer; private readonly TestGeneratedDocumentPublisher _publisher; private readonly TestProjectSnapshotManager _projectManager; - private readonly IDocumentSnapshot _document; - private readonly RazorCodeDocument _codeDocument; public GeneratedDocumentSynchronizerTest(ITestOutputHelper testOutput) : base(testOutput) @@ -31,8 +30,6 @@ public GeneratedDocumentSynchronizerTest(ITestOutputHelper testOutput) _publisher = new TestGeneratedDocumentPublisher(); _projectManager = CreateProjectSnapshotManager(); _synchronizer = new GeneratedDocumentSynchronizer(_publisher, TestLanguageServerFeatureOptions.Instance, _projectManager); - _document = TestDocumentSnapshot.Create(s_hostDocument.FilePath); - _codeDocument = CreateCodeDocument("

Hello World

"); } protected override async Task InitializeAsync() @@ -40,7 +37,7 @@ protected override async Task InitializeAsync() await _projectManager.UpdateAsync(updater => { updater.AddProject(s_hostProject); - updater.AddDocument(s_hostProject.Key, s_hostDocument, EmptyTextLoader.Instance); + updater.AddDocument(s_hostProject.Key, s_hostDocument, TestMocks.CreateTextLoader("

Hello World

")); }); } @@ -53,8 +50,11 @@ await _projectManager.UpdateAsync(updater => updater.OpenDocument(s_hostProject.Key, s_hostDocument.FilePath, SourceText.From("

Hello World

")); }); + var document = _projectManager.GetRequiredDocument(s_hostProject.Key, s_hostDocument.FilePath); + var codeDocument = await document.GetGeneratedOutputAsync(DisposalToken); + // Act - _synchronizer.DocumentProcessed(_codeDocument, _document); + _synchronizer.DocumentProcessed(codeDocument, document); // Assert Assert.True(_publisher.PublishedCSharp); @@ -62,13 +62,16 @@ await _projectManager.UpdateAsync(updater => } [Fact] - public void DocumentProcessed_CloseDocument_WithOption_Publishes() + public async Task DocumentProcessed_CloseDocument_WithOption_Publishes() { var options = new TestLanguageServerFeatureOptions(updateBuffersForClosedDocuments: true); var synchronizer = new GeneratedDocumentSynchronizer(_publisher, options, _projectManager); + var document = _projectManager.GetRequiredDocument(s_hostProject.Key, s_hostDocument.FilePath); + var codeDocument = await document.GetGeneratedOutputAsync(DisposalToken); + // Act - synchronizer.DocumentProcessed(_codeDocument, _document); + synchronizer.DocumentProcessed(codeDocument, document); // Assert Assert.True(_publisher.PublishedCSharp); @@ -76,10 +79,13 @@ public void DocumentProcessed_CloseDocument_WithOption_Publishes() } [Fact] - public void DocumentProcessed_CloseDocument_DoesntPublish() + public async Task DocumentProcessed_CloseDocument_DoesntPublish() { + var document = _projectManager.GetRequiredDocument(s_hostProject.Key, s_hostDocument.FilePath); + var codeDocument = await document.GetGeneratedOutputAsync(DisposalToken); + // Act - _synchronizer.DocumentProcessed(_codeDocument, _document); + _synchronizer.DocumentProcessed(codeDocument, document); // Assert Assert.False(_publisher.PublishedCSharp); @@ -87,12 +93,20 @@ public void DocumentProcessed_CloseDocument_DoesntPublish() } [Fact] - public void DocumentProcessed_RemovedDocument_DoesntPublish() + public async Task DocumentProcessed_RemovedDocument_DoesntPublish() { - var document = TestDocumentSnapshot.Create("/path/to/non.existent.file.razor"); + var document = await _projectManager.UpdateAsync(updater => + { + var removedDocument = updater.GetRequiredDocument(s_hostProject.Key, s_hostDocument.FilePath); + updater.RemoveDocument(s_hostProject.Key, s_hostDocument.FilePath); + + return removedDocument; + }); + + var codeDocument = await document.GetGeneratedOutputAsync(DisposalToken); // Act - _synchronizer.DocumentProcessed(_codeDocument, document); + _synchronizer.DocumentProcessed(codeDocument, document); // Assert Assert.False(_publisher.PublishedCSharp); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorEditHelperTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorEditHelperTest.cs index 5267b35abb0..8200e4752b6 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorEditHelperTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorEditHelperTest.cs @@ -38,723 +38,655 @@ public RazorEditHelperTest(ITestOutputHelper testOutputHelper) : base(testOutput [Fact] public Task SimpleEdits_Apply() => TestAsync( - csharpSource: - """ - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @code { - public int NewCounter { get; set; } - } - """); + csharpSource: """ + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @code { + public int NewCounter { get; set; } + } + """); [Fact] public Task MappedAndUnmappedEdits_Apply() => TestAsync( - csharpSource: - """ - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - - void UnmappedMethod() - { - } - } - """, - razorSource: - """ - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - - void Method() - { - } - } - """, - expectedRazorSource: - """ - @code { - public int NewCounter { get; set; } - } - """); + csharpSource: """ + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + + void UnmappedMethod() + { + } + } + """, + razorSource: """ + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + + void Method() + { + } + } + """, + expectedRazorSource: """ + @code { + public int NewCounter { get; set; } + } + """); [Fact] public Task NewUsing_TopOfFile() => TestAsync( - csharpSource: - """ - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - using System; - - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @using System - @code { - public int NewCounter { get; set; } - } - """); + csharpSource: """ + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + using System; + + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @using System + @code { + public int NewCounter { get; set; } + } + """); [Fact] public Task RemovedUsing_IsRemoved() => TestAsync( - csharpSource: - """ - {|mapUsing:using System;|} - - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - {|mapUsing:@using System|} - - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - class MyComponent : ComponentBase - { - public int Counter { get; set; } - } - """, - expectedRazorSource: - """ - - @code { - public int Counter { get; set; } - } - """); + csharpSource: """ + {|mapUsing:using System;|} + + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + {|mapUsing:@using System|} + + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + class MyComponent : ComponentBase + { + public int Counter { get; set; } + } + """, + expectedRazorSource: """ + + @code { + public int Counter { get; set; } + } + """); [Fact] public Task NewUsing_AfterExisting() => TestAsync( - csharpSource: - """ - {|mapUsing:using System;|} - - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - {|mapUsing:@using System|} - - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - using System; - using System.Collections.Generic; - - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @using System - @using System.Collections.Generic - - @code { - public int NewCounter { get; set; } - } - """); + csharpSource: """ + {|mapUsing:using System;|} + + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + {|mapUsing:@using System|} + + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + using System; + using System.Collections.Generic; + + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @using System + @using System.Collections.Generic + + @code { + public int NewCounter { get; set; } + } + """); [Fact] public Task NewUsing_AfterPage() => TestAsync( - csharpSource: - """ - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - @page "/counter" - - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - using System; - using System.Collections.Generic; - - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @page "/counter" - @using System - @using System.Collections.Generic - - @code { - public int NewCounter { get; set; } - } - """); + csharpSource: """ + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + @page "/counter" + + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + using System; + using System.Collections.Generic; + + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @page "/counter" + @using System + @using System.Collections.Generic + + @code { + public int NewCounter { get; set; } + } + """); [Fact] public Task NewUsing_AfterPage2() => TestAsync( - csharpSource: - """ - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - @page "/counter" - -

Counter

-

Current count: @Counter

- - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - using System; - using System.Collections.Generic; - - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @page "/counter" - @using System - @using System.Collections.Generic - -

Counter

-

Current count: @Counter

- - @code { - public int NewCounter { get; set; } - } - """); + csharpSource: """ + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + @page "/counter" + +

Counter

+

Current count: @Counter

+ + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + using System; + using System.Collections.Generic; + + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @page "/counter" + @using System + @using System.Collections.Generic + +

Counter

+

Current count: @Counter

+ + @code { + public int NewCounter { get; set; } + } + """); [Fact] public Task RenamedUsing_Applies() => TestAsync( - csharpSource: - """ - {|mapUsing:using System;|} - {|mapUsing2:using System.Collections.Generic;|} - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - @page "/counter" - {|mapUsing:@using System|} - {|mapUsing2:@using System.Collections.Generic|} - - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - using Renamed; - - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @page "/counter" - @using Renamed - - @code { - public int NewCounter { get; set; } - } - """); + csharpSource: """ + {|mapUsing:using System;|} + {|mapUsing2:using System.Collections.Generic;|} + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + @page "/counter" + {|mapUsing:@using System|} + {|mapUsing2:@using System.Collections.Generic|} + + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + using Renamed; + + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @page "/counter" + @using Renamed + + @code { + public int NewCounter { get; set; } + } + """); [Fact] public Task AddUsing_AfterSystem() => TestAsync( - csharpSource: - """ - {|mapUsing:using System;|} - {|mapUsing2:using System.Collections.Generic;|} - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - @page "/counter" - {|mapUsing:@using System|} - {|mapUsing2:@using System.Collections.Generic|} - - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - using OtherNamespace; - using System; - - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @page "/counter" - @using System - @using OtherNamespace - - @code { - public int NewCounter { get; set; } - } - """); + csharpSource: """ + {|mapUsing:using System;|} + {|mapUsing2:using System.Collections.Generic;|} + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + @page "/counter" + {|mapUsing:@using System|} + {|mapUsing2:@using System.Collections.Generic|} + + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + using OtherNamespace; + using System; + + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @page "/counter" + @using System + @using OtherNamespace + + @code { + public int NewCounter { get; set; } + } + """); [Fact] public Task AddUsing_OrdersSystemCorrectly() => TestAsync( - csharpSource: - """ - {|mapUsing:using System;|} - {|mapUsing2:using MyNamespace;|} - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - @page "/counter" - {|mapUsing:@using System|} - {|mapUsing2:@using MyNamespace|} - - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - using OtherNamespace; - using System; - using System.Collections.Generic; - - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @page "/counter" - @using System - @using System.Collections.Generic - @using OtherNamespace - - @code { - public int NewCounter { get; set; } - } - """); + csharpSource: """ + {|mapUsing:using System;|} + {|mapUsing2:using MyNamespace;|} + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + @page "/counter" + {|mapUsing:@using System|} + {|mapUsing2:@using MyNamespace|} + + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + using OtherNamespace; + using System; + using System.Collections.Generic; + + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @page "/counter" + @using System + @using System.Collections.Generic + @using OtherNamespace + + @code { + public int NewCounter { get; set; } + } + """); [Fact] public Task UsingIndentation_DoesNotApply() => TestAsync( - csharpSource: - """ - {|mapUsing:using System;|} - {|mapUsing2:using System.Collections.Generic;|} - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - @page "/counter" - {|mapUsing:@using System|} - {|mapUsing2:@using System.Collections.Generic|} - - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - using System; - using System.Collections.Generic; + csharpSource: """ + {|mapUsing:using System;|} + {|mapUsing2:using System.Collections.Generic;|} + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + @page "/counter" + {|mapUsing:@using System|} + {|mapUsing2:@using System.Collections.Generic|} + + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + using System; + using System.Collections.Generic; - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @page "/counter" - @using System - @using System.Collections.Generic - - @code { - public int NewCounter { get; set; } - } - """); + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @page "/counter" + @using System + @using System.Collections.Generic + + @code { + public int NewCounter { get; set; } + } + """); [Fact] public Task UsingAliasRemoved_HandledCorrectly() => TestAsync( - csharpSource: - """ - {|mapUsing:using System;|} - {|mapUsing2:using System.Collections.Generic;|} - {|mapUsing3:using Goo = Bar;|} - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - @page "/counter" - {|mapUsing:@using System|} - {|mapUsing2:@using System.Collections.Generic|} - {|mapUsing3:@using Goo = Bar|} - - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - using System; - using System.Collections.Generic; - - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @page "/counter" - @using System - @using System.Collections.Generic - - @code { - public int NewCounter { get; set; } - } - """); + csharpSource: """ + {|mapUsing:using System;|} + {|mapUsing2:using System.Collections.Generic;|} + {|mapUsing3:using Goo = Bar;|} + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + @page "/counter" + {|mapUsing:@using System|} + {|mapUsing2:@using System.Collections.Generic|} + {|mapUsing3:@using Goo = Bar|} + + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + using System; + using System.Collections.Generic; + + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @page "/counter" + @using System + @using System.Collections.Generic + + @code { + public int NewCounter { get; set; } + } + """); [Fact] public Task UsingAliasAdded_HandledCorrectly() => TestAsync( - csharpSource: - """ - {|mapUsing:using System;|} - {|mapUsing2:using System.Collections.Generic;|} - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - @page "/counter" - {|mapUsing:@using System|} - {|mapUsing2:@using System.Collections.Generic|} - - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - using System; - using System.Collections.Generic; - using Goo = Bar; - - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @page "/counter" - @using System - @using System.Collections.Generic - @using Goo = Bar - - @code { - public int NewCounter { get; set; } - } - """); - - [Fact] - public Task UsingStaticRemoved_HandledCorrectly() + csharpSource: """ + {|mapUsing:using System;|} + {|mapUsing2:using System.Collections.Generic;|} + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + @page "/counter" + {|mapUsing:@using System|} + {|mapUsing2:@using System.Collections.Generic|} + + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + using System; + using System.Collections.Generic; + using Goo = Bar; + + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @page "/counter" + @using System + @using System.Collections.Generic + @using Goo = Bar + + @code { + public int NewCounter { get; set; } + } + """); + + [Fact] + public Task UsingStaticRemoved_HandledCorrectly() => TestAsync( - csharpSource: - """ - {|mapUsing:using System;|} - {|mapUsing2:using System.Collections.Generic;|} - {|mapUsing3:using static Test.Bar;|} - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - @page "/counter" - {|mapUsing:@using System|} - {|mapUsing2:@using System.Collections.Generic|} - {|mapUsing3:@using static Test.Bar|} - - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - using System; - using System.Collections.Generic; - - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @page "/counter" - @using System - @using System.Collections.Generic - - @code { - public int NewCounter { get; set; } - } - """); + csharpSource: """ + {|mapUsing:using System;|} + {|mapUsing2:using System.Collections.Generic;|} + {|mapUsing3:using static Test.Bar;|} + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + @page "/counter" + {|mapUsing:@using System|} + {|mapUsing2:@using System.Collections.Generic|} + {|mapUsing3:@using static Test.Bar|} + + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + using System; + using System.Collections.Generic; + + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @page "/counter" + @using System + @using System.Collections.Generic + + @code { + public int NewCounter { get; set; } + } + """); [Fact] public Task UsingStaticAdded_HandledCorrectly() => TestAsync( - csharpSource: - """ - {|mapUsing:using System;|} - {|mapUsing2:using static System.Collections.Generic;|} - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - @page "/counter" - {|mapUsing:@using System|} - {|mapUsing2:@using System.Collections.Generic|} - - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - using System; - using System.Collections.Generic; - using static Test.Bar; - - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @page "/counter" - @using System - @using System.Collections.Generic - @using static Test.Bar - - @code { - public int NewCounter { get; set; } - } - """); + csharpSource: """ + {|mapUsing:using System;|} + {|mapUsing2:using static System.Collections.Generic;|} + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + @page "/counter" + {|mapUsing:@using System|} + {|mapUsing2:@using System.Collections.Generic|} + + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + using System; + using System.Collections.Generic; + using static Test.Bar; + + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @page "/counter" + @using System + @using System.Collections.Generic + @using static Test.Bar + + @code { + public int NewCounter { get; set; } + } + """); [Fact] public Task AddUsingMultipleUsingGroups_AppliesCurrently() => TestAsync( - csharpSource: - """ - {|mapUsing:using System;|} - {|mapUsing2:using MyNamespace;|} - {|mapUsing3:using MyNamespace2;|} - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - @page "/counter" - {|mapUsing:@using System|} - {|mapUsing2:@using MyNamespace|} - -

- - {|mapUsing3:@using MyNamespace2|} - - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - using OtherNamespace; - using System; - using System.Collections.Generic; - using MyNamespace; - using MyNamespace2; - - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @page "/counter" - @using System - @using System.Collections.Generic - @using MyNamespace - @using OtherNamespace - -

- - @using MyNamespace2 - - @code { - public int NewCounter { get; set; } - } - """); + csharpSource: """ + {|mapUsing:using System;|} + {|mapUsing2:using MyNamespace;|} + {|mapUsing3:using MyNamespace2;|} + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + @page "/counter" + {|mapUsing:@using System|} + {|mapUsing2:@using MyNamespace|} + +

+ + {|mapUsing3:@using MyNamespace2|} + + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + using OtherNamespace; + using System; + using System.Collections.Generic; + using MyNamespace; + using MyNamespace2; + + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @page "/counter" + @using System + @using System.Collections.Generic + @using MyNamespace + @using OtherNamespace + +

+ + @using MyNamespace2 + + @code { + public int NewCounter { get; set; } + } + """); [Fact] public Task RemovingMultipleUsingGroups_AppliesCurrently() => TestAsync( - csharpSource: - """ - {|mapUsing:using System;|} - {|mapUsing2:using MyNamespace;|} - {|mapUsing3:using MyNamespace2;|} - class MyComponent : ComponentBase - { - {|map1:public int Counter { get; set; }|} - } - """, - razorSource: - """ - @page "/counter" - {|mapUsing:@using System|} - -

- - {|mapUsing2:@using MyNamespace|} - -

- - {|mapUsing3:@using MyNamespace2|} - - @code { - {|map1:public int Counter { get; set; }|} - } - """, - newCSharpSource: - """ - class MyComponent : ComponentBase - { - public int NewCounter { get; set; } - } - """, - expectedRazorSource: - """ - @page "/counter" - -

- - -

- - - @code { - public int NewCounter { get; set; } - } - """); + csharpSource: """ + {|mapUsing:using System;|} + {|mapUsing2:using MyNamespace;|} + {|mapUsing3:using MyNamespace2;|} + class MyComponent : ComponentBase + { + {|map1:public int Counter { get; set; }|} + } + """, + razorSource: """ + @page "/counter" + {|mapUsing:@using System|} + +

+ + {|mapUsing2:@using MyNamespace|} + +

+ + {|mapUsing3:@using MyNamespace2|} + + @code { + {|map1:public int Counter { get; set; }|} + } + """, + newCSharpSource: """ + class MyComponent : ComponentBase + { + public int NewCounter { get; set; } + } + """, + expectedRazorSource: """ + @page "/counter" + +

+ + +

+ + + @code { + public int NewCounter { get; set; } + } + """); private async Task TestAsync( TestCode csharpSource, @@ -798,7 +730,7 @@ private async Task TestAsync( sourceMappings.Add(new SourceMapping(razorSourceSpan, csharpSourceSpan)); } - var newCsharpSourceText = SourceText.From(newCSharpSource); + var newCSharpSourceText = SourceText.From(newCSharpSource); var changes = GetChanges(csharpSource.Text, newCSharpSource); var codeDocument = CreateCodeDocument(razorSource.Text, tagHelpers: [], filePath: razorPath); @@ -814,7 +746,7 @@ private async Task TestAsync( var snapshot = TestDocumentSnapshot.Create(razorPath, codeDocument); var mappedChanges = await RazorEditHelper.MapCSharpEditsAsync( - changes.Select(c => c.ToRazorTextChange()).ToImmutableArray(), + changes.SelectAsArray(c => c.ToRazorTextChange()), snapshot, _documentMappingService, FailingTelemetryReporter.Instance, diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/OpenDocumentGeneratorTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/OpenDocumentGeneratorTest.cs index 23193fa1bfb..f91dbe54486 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/OpenDocumentGeneratorTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/OpenDocumentGeneratorTest.cs @@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; -using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -176,7 +175,7 @@ await projectManager.UpdateAsync(updater => } private OpenDocumentGenerator CreateOpenDocumentGenerator( - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, params IDocumentProcessedListener[] listeners) { return new OpenDocumentGenerator(listeners, projectManager, TestLanguageServerFeatureOptions.Instance, LoggerFactory); @@ -206,7 +205,7 @@ public Task GetProcessedDocumentAsync(TimeSpan cancelAfter) return _tcs.Task; } - public void DocumentProcessed(RazorCodeDocument codeDocument, IDocumentSnapshot document) + public void DocumentProcessed(RazorCodeDocument codeDocument, DocumentSnapshot document) { _tcs.SetResult(document); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectSystem/IProjectSnapshotManagerExtensionsTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectSystem/IProjectSnapshotManagerExtensionsTest.cs index 64ac49bbeda..f425751c1b4 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectSystem/IProjectSnapshotManagerExtensionsTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectSystem/IProjectSnapshotManagerExtensionsTest.cs @@ -263,7 +263,7 @@ await projectManager.UpdateAsync(updater => return projectManager; } - private static void AssertSnapshotsEqual(IProjectSnapshot first, IProjectSnapshot second) + private static void AssertSnapshotsEqual(ProjectSnapshot first, ProjectSnapshot second) { Assert.Equal(first.FilePath, second.FilePath); Assert.Equal(first.CSharpLanguageVersion, second.CSharpLanguageVersion); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorComponentSearchEngineTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorComponentSearchEngineTest.cs index 9dfc3afdccd..64324e1ba5b 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorComponentSearchEngineTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorComponentSearchEngineTest.cs @@ -40,7 +40,7 @@ public class RazorComponentSearchEngineTest(ITestOutputHelper testOutput) : Lang private static readonly string s_componentFilePath3 = Path.Combine(s_project2BasePath, "Component3.razor"); #nullable disable - private IProjectSnapshotManager _projectManager; + private ProjectSnapshotManager _projectManager; #nullable enable protected override async Task InitializeAsync() diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/TestRazorProjectService.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/TestRazorProjectService.cs index 026a36c8242..cab1787d10b 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/TestRazorProjectService.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/TestRazorProjectService.cs @@ -1,17 +1,12 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System.Collections.Immutable; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.Common; -using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Serialization; using Microsoft.AspNetCore.Razor.Test.Common; -using Microsoft.AspNetCore.Razor.Utilities; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Moq; @@ -20,7 +15,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; internal class TestRazorProjectService( RemoteTextLoaderFactory remoteTextLoaderFactory, - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, ILoggerFactory loggerFactory) : RazorProjectService( projectManager, @@ -28,7 +23,7 @@ internal class TestRazorProjectService( remoteTextLoaderFactory, loggerFactory) { - private readonly IProjectSnapshotManager _projectManager = projectManager; + private readonly ProjectSnapshotManager _projectManager = projectManager; private static IRazorProjectInfoDriver CreateProjectInfoDriver() { @@ -44,17 +39,21 @@ private static IRazorProjectInfoDriver CreateProjectInfoDriver() public async Task AddDocumentToPotentialProjectsAsync(string textDocumentPath, CancellationToken cancellationToken) { + var document = new DocumentSnapshotHandle( + textDocumentPath, textDocumentPath, FileKinds.GetFileKindFromFilePath(textDocumentPath)); + foreach (var projectSnapshot in _projectManager.FindPotentialProjects(textDocumentPath)) { - var normalizedProjectPath = FilePathNormalizer.NormalizeDirectory(projectSnapshot.FilePath); - var documents = ImmutableArray - .CreateRange(projectSnapshot.DocumentFilePaths) - .Add(textDocumentPath) - .Select(d => new DocumentSnapshotHandle(d, d, FileKinds.GetFileKindFromFilePath(d))) - .ToImmutableArray(); - - await ((IRazorProjectInfoListener)this).UpdatedAsync(new RazorProjectInfo(projectSnapshot.Key, projectSnapshot.FilePath, projectSnapshot.Configuration, projectSnapshot.RootNamespace, projectSnapshot.DisplayName, projectSnapshot.ProjectWorkspaceState, - documents), cancellationToken).ConfigureAwait(false); + var projectInfo = projectSnapshot.ToRazorProjectInfo(); + + projectInfo = projectInfo with + { + Documents = projectInfo.Documents.Add(document) + }; + + await ((IRazorProjectInfoListener)this) + .UpdatedAsync(projectInfo, cancellationToken) + .ConfigureAwait(false); } } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WorkspaceSemanticTokensRefreshTriggerTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WorkspaceSemanticTokensRefreshTriggerTest.cs index 3244174c6dd..812bb2c8359 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WorkspaceSemanticTokensRefreshTriggerTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WorkspaceSemanticTokensRefreshTriggerTest.cs @@ -59,6 +59,6 @@ await _projectManager.UpdateAsync(updater => private class TestWorkspaceSemanticTokensRefreshTrigger( IWorkspaceSemanticTokensRefreshNotifier publisher, - IProjectSnapshotManager projectManager) + ProjectSnapshotManager projectManager) : WorkspaceSemanticTokensRefreshTrigger(publisher, projectManager); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs index 008d1f1d059..89ff1d5c8e2 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs @@ -20,12 +20,12 @@ namespace Microsoft.AspNetCore.Razor.ProjectEngineHost; public class ProjectEngineFactoryProviderTest : ToolingTestBase { private readonly ImmutableArray _customFactories; - private readonly IProjectSnapshot _snapshot_For_1_0; - private readonly IProjectSnapshot _snapshot_For_1_1; - private readonly IProjectSnapshot _snapshot_For_2_0; - private readonly IProjectSnapshot _snapshot_For_2_1; - private readonly IProjectSnapshot _snapshot_For_3_0; - private readonly IProjectSnapshot _snapshot_For_UnknownConfiguration; + private readonly ProjectSnapshot _snapshot_For_1_0; + private readonly ProjectSnapshot _snapshot_For_1_1; + private readonly ProjectSnapshot _snapshot_For_2_0; + private readonly ProjectSnapshot _snapshot_For_2_1; + private readonly ProjectSnapshot _snapshot_For_3_0; + private readonly ProjectSnapshot _snapshot_For_UnknownConfiguration; public ProjectEngineFactoryProviderTest(ITestOutputHelper testOutput) : base(testOutput) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestTagHelperResolver.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestTagHelperResolver.cs index bb88bd5f412..d9486acbc93 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestTagHelperResolver.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestTagHelperResolver.cs @@ -17,7 +17,7 @@ internal class TestTagHelperResolver(ImmutableArray tagHelp public ValueTask> GetTagHelpersAsync( Project workspaceProject, - IProjectSnapshot projectSnapshot, + ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) { return new(TagHelpers); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ToolingTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ToolingTestBase.cs index 00ecb453199..63cf6f65bf5 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ToolingTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ToolingTestBase.cs @@ -226,9 +226,15 @@ private protected virtual TestProjectSnapshotManager CreateProjectSnapshotManage => CreateProjectSnapshotManager(projectEngineFactoryProvider, TestLanguageServerFeatureOptions.Instance); private protected virtual TestProjectSnapshotManager CreateProjectSnapshotManager(IProjectEngineFactoryProvider projectEngineFactoryProvider, LanguageServerFeatureOptions languageServerFeatureOptions) - => new( + { + var projectManager = new TestProjectSnapshotManager( projectEngineFactoryProvider, languageServerFeatureOptions, LoggerFactory, DisposalToken); + + AddDisposable(projectManager); + + return projectManager; + } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/WorkspaceTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/WorkspaceTestBase.cs index f24a1540abc..28956d21e2e 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/WorkspaceTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/WorkspaceTestBase.cs @@ -75,7 +75,7 @@ private protected override TestProjectSnapshotManager CreateProjectSnapshotManag => CreateProjectSnapshotManager(ProjectEngineFactoryProvider, LanguageServerFeatureOptions); private protected override TestProjectSnapshotManager CreateProjectSnapshotManager(IProjectEngineFactoryProvider projectEngineFactoryProvider) - => base.CreateProjectSnapshotManager(projectEngineFactoryProvider, LanguageServerFeatureOptions); + => CreateProjectSnapshotManager(projectEngineFactoryProvider, LanguageServerFeatureOptions); protected virtual void ConfigureWorkspace(AdhocWorkspace workspace) { diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/IProjectSnapshotManagerExtensions.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/IProjectSnapshotManagerExtensions.cs index 37913fdaf0b..8d05b12eb14 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/IProjectSnapshotManagerExtensions.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/IProjectSnapshotManagerExtensions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -10,17 +11,17 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces.Test; internal static class IProjectSnapshotManagerExtensions { - public static ISolutionQueryOperations GetQueryOperations(this IProjectSnapshotManager projectManager) + public static ISolutionQueryOperations GetQueryOperations(this ProjectSnapshotManager projectManager) => new TestSolutionQueryOperations(projectManager); } -file sealed class TestSolutionQueryOperations(IProjectSnapshotManager projectManager) : ISolutionQueryOperations +file sealed class TestSolutionQueryOperations(ProjectSnapshotManager projectManager) : ISolutionQueryOperations { - private readonly IProjectSnapshotManager _projectManager = projectManager; + private readonly ProjectSnapshotManager _projectManager = projectManager; public IEnumerable GetProjects() { - return _projectManager.GetProjects(); + return _projectManager.GetProjects().Cast(); } public ImmutableArray GetProjectsContainingDocument(string documentFilePath) diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DocumentGenerator/BackgroundDocumentGeneratorTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DocumentGenerator/BackgroundDocumentGeneratorTest.cs index d4a867ed175..a26479c5d5d 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DocumentGenerator/BackgroundDocumentGeneratorTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DocumentGenerator/BackgroundDocumentGeneratorTest.cs @@ -35,7 +35,7 @@ public class BackgroundDocumentGeneratorTest(ITestOutputHelper testOutput) : Vis private static readonly HostProject s_hostProject2 = TestProjectData.AnotherProject with { Configuration = FallbackRazorConfiguration.MVC_1_0 }; private static IFallbackProjectManager s_fallbackProjectManager = StrictMock.Of(x => - x.IsFallbackProject(It.IsAny()) == false); + x.IsFallbackProject(It.IsAny()) == false); private readonly TestDynamicFileInfoProvider _dynamicFileInfoProvider = new(); @@ -349,7 +349,7 @@ await projectManager.UpdateAsync(updater => } private class TestBackgroundDocumentGenerator( - IProjectSnapshotManager projectManager, + ProjectSnapshotManager projectManager, IFallbackProjectManager fallbackProjectManager, IRazorDynamicFileInfoProviderInternal dynamicFileInfoProvider, ILoggerFactory loggerFactory) @@ -384,10 +384,10 @@ public void UnblockBatchProcessing() _blockBatchProcessingSource.Set(); } - private static DocumentKey GetKey(IProjectSnapshot project, IDocumentSnapshot document) + private static DocumentKey GetKey(ProjectSnapshot project, DocumentSnapshot document) => new(project.Key, document.FilePath); - protected override async ValueTask ProcessBatchAsync(ImmutableArray<(IProjectSnapshot, IDocumentSnapshot)> items, CancellationToken token) + protected override async ValueTask ProcessBatchAsync(ImmutableArray<(ProjectSnapshot, DocumentSnapshot)> items, CancellationToken token) { if (_blockBatchProcessingSource is { } blockEvent) { @@ -403,14 +403,14 @@ protected override async ValueTask ProcessBatchAsync(ImmutableArray<(IProjectSna await base.ProcessBatchAsync(items, token); } - public override void Enqueue(IProjectSnapshot project, IDocumentSnapshot document) + public override void Enqueue(ProjectSnapshot project, DocumentSnapshot document) { PendingWork.Add(GetKey(project, document)); base.Enqueue(project, document); } - protected override Task ProcessDocumentAsync(IProjectSnapshot project, IDocumentSnapshot document, CancellationToken cancellationToken) + protected override Task ProcessDocumentAsync(ProjectSnapshot project, DocumentSnapshot document, CancellationToken cancellationToken) { var key = GetKey(project, document); PendingWork.Remove(key); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Documents/EditorDocumentManagerListenerTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Documents/EditorDocumentManagerListenerTest.cs index 86bf67e42cd..9b4c4b40283 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Documents/EditorDocumentManagerListenerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Documents/EditorDocumentManagerListenerTest.cs @@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Razor.Telemetry; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.Editor; -using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common.VisualStudio; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor; @@ -34,7 +33,7 @@ public class EditorDocumentManagerListenerTest(ITestOutputHelper testOutput) : V targetPath: "/path/to/file1.razor"); private static IFallbackProjectManager s_fallbackProjectManager = StrictMock.Of(x => - x.IsFallbackProject(It.IsAny()) == false); + x.IsFallbackProject(It.IsAny()) == false); [UIFact] public async Task ProjectManager_Changed_RemoveDocument_RemovesDocument() @@ -178,11 +177,6 @@ await projectManager.UpdateAsync(updater => var called = false; listenerAccessor.OnOpened += delegate { called = true; }; - var projectFilePath = "/Path/to/project.csproj"; - var project = StrictMock.Of(p => - p.Key == TestProjectKey.Create("/Path/to/obj") && - p.FilePath == projectFilePath); - // Act await projectManager.UpdateAsync(updater => { diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/CSharpVirtualDocumentFactoryTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/CSharpVirtualDocumentFactoryTest.cs index e57ca4de7b2..d396a3ca370 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/CSharpVirtualDocumentFactoryTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/CSharpVirtualDocumentFactoryTest.cs @@ -78,7 +78,7 @@ public void TryCreateMultipleFor_NonRazorLSPBuffer_ReturnsFalse() _textDocumentFactoryService, uriProvider, _filePathService, - StrictMock.Of(), + CreateProjectSnapshotManager(), TestLanguageServerFeatureOptions.Instance, LoggerFactory, telemetryReporter: null!); @@ -105,7 +105,7 @@ public void TryCreateMultipleFor_NoProjectSnapshotManager_ReturnsFalse() _textDocumentFactoryService, uriProvider, _filePathService, - StrictMock.Of(), + CreateProjectSnapshotManager(), TestLanguageServerFeatureOptions.Instance, LoggerFactory, telemetryReporter: null!); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/ProjectSystem/RazorProjectInfoDriverTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/ProjectSystem/RazorProjectInfoDriverTest.cs index 3d235679229..10b1118c501 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/ProjectSystem/RazorProjectInfoDriverTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/ProjectSystem/RazorProjectInfoDriverTest.cs @@ -249,7 +249,7 @@ await projectManager.UpdateAsync(static updater => } private async Task<(RazorProjectInfoDriver, AbstractRazorProjectInfoDriver.TestAccessor)> CreateDriverAndInitializeAsync( - IProjectSnapshotManager projectManager) + ProjectSnapshotManager projectManager) { var driver = new RazorProjectInfoDriver(projectManager, LoggerFactory, delay: TimeSpan.FromMilliseconds(5)); AddDisposable(driver); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs index c821b0ba9c0..b1421041384 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs @@ -12,7 +12,6 @@ using Microsoft.AspNetCore.Razor.Test.Common.Editor; using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Razor.Workspaces; @@ -64,7 +63,7 @@ public async Task UpdateCSharpBuffer_CannotLookupDocument_NoopsGracefully() new CSharpVirtualDocumentAddListener(LoggerFactory), Mock.Of(MockBehavior.Strict), TestLanguageServerFeatureOptions.Instance, - StrictMock.Of(), + CreateProjectSnapshotManager(), new SnippetCompletionItemProvider(new SnippetCache()), StrictMock.Of(), StrictMock.Of(), @@ -109,7 +108,7 @@ public async Task UpdateCSharpBuffer_UpdatesDocument() new CSharpVirtualDocumentAddListener(LoggerFactory), Mock.Of(MockBehavior.Strict), TestLanguageServerFeatureOptions.Instance, - StrictMock.Of(), + CreateProjectSnapshotManager(), new SnippetCompletionItemProvider(new SnippetCache()), StrictMock.Of(), StrictMock.Of(), @@ -165,7 +164,7 @@ public async Task UpdateCSharpBuffer_UpdatesCorrectDocument() new CSharpVirtualDocumentAddListener(LoggerFactory), Mock.Of(MockBehavior.Strict), new TestLanguageServerFeatureOptions(includeProjectKeyInGeneratedFilePath: true), - StrictMock.Of(), + CreateProjectSnapshotManager(), new SnippetCompletionItemProvider(new SnippetCache()), StrictMock.Of(), StrictMock.Of(), @@ -209,7 +208,7 @@ public async Task ProvideCodeActionsAsync_CannotLookupDocument_ReturnsNullAsync( new CSharpVirtualDocumentAddListener(LoggerFactory), Mock.Of(MockBehavior.Strict), TestLanguageServerFeatureOptions.Instance, - StrictMock.Of(), + CreateProjectSnapshotManager(), new SnippetCompletionItemProvider(new SnippetCache()), StrictMock.Of(), StrictMock.Of(), @@ -291,7 +290,7 @@ async IAsyncEnumerable> csharpVirtualDocumentAddListener, telemetryReporter.Object, TestLanguageServerFeatureOptions.Instance, - StrictMock.Of(), + CreateProjectSnapshotManager(), new SnippetCompletionItemProvider(new SnippetCache()), StrictMock.Of(), StrictMock.Of(), @@ -378,7 +377,7 @@ async IAsyncEnumerable> GetExpectedRe csharpVirtualDocumentAddListener, telemetryReporter.Object, TestLanguageServerFeatureOptions.Instance, - StrictMock.Of(), + CreateProjectSnapshotManager(), new SnippetCompletionItemProvider(new SnippetCache()), StrictMock.Of(), StrictMock.Of(), @@ -420,7 +419,7 @@ public async Task ProvideSemanticTokensAsync_CannotLookupDocument_ReturnsNullAsy new CSharpVirtualDocumentAddListener(LoggerFactory), Mock.Of(MockBehavior.Strict), TestLanguageServerFeatureOptions.Instance, - StrictMock.Of(), + CreateProjectSnapshotManager(), new SnippetCompletionItemProvider(new SnippetCache()), StrictMock.Of(), StrictMock.Of(), @@ -469,7 +468,7 @@ public async Task ProvideSemanticTokensAsync_CannotLookupVirtualDocument_Returns new CSharpVirtualDocumentAddListener(LoggerFactory), Mock.Of(MockBehavior.Strict), TestLanguageServerFeatureOptions.Instance, - StrictMock.Of(), + CreateProjectSnapshotManager(), new SnippetCompletionItemProvider(new SnippetCache()), StrictMock.Of(), StrictMock.Of(), @@ -551,7 +550,7 @@ public async Task ProvideSemanticTokensAsync_ContainsRange_ReturnsSemanticTokens csharpVirtualDocumentAddListener, telemetryReporter.Object, TestLanguageServerFeatureOptions.Instance, - StrictMock.Of(), + CreateProjectSnapshotManager(), new SnippetCompletionItemProvider(new SnippetCache()), StrictMock.Of(), StrictMock.Of(), @@ -634,7 +633,7 @@ public async Task ProvideSemanticTokensAsync_EmptyRange_ReturnsNoSemanticTokens( csharpVirtualDocumentAddListener, telemetryReporter.Object, TestLanguageServerFeatureOptions.Instance, - StrictMock.Of(), + CreateProjectSnapshotManager(), new SnippetCompletionItemProvider(new SnippetCache()), StrictMock.Of(), StrictMock.Of(), diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/FallbackWindowsRazorProjectHostTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/FallbackWindowsRazorProjectHostTest.cs index 171a3f96949..039b1630f41 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/FallbackWindowsRazorProjectHostTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/FallbackWindowsRazorProjectHostTest.cs @@ -644,7 +644,7 @@ private class TestFallbackRazorProjectHost : FallbackWindowsRazorProjectHost internal TestFallbackRazorProjectHost( IUnconfiguredProjectCommonServices commonServices, IServiceProvider serviceProvider, - IProjectSnapshotManager projectManager) + ProjectSnapshotManager projectManager) : base(commonServices, serviceProvider, projectManager) { SkipIntermediateOutputPathExistCheck_TestOnly = true; diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/RazorDynamicFileInfoProviderTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/RazorDynamicFileInfoProviderTest.cs index d38991bd43f..426ec109364 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/RazorDynamicFileInfoProviderTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/RazorDynamicFileInfoProviderTest.cs @@ -30,9 +30,9 @@ public class RazorDynamicFileInfoProviderTest(ITestOutputHelper testOutput) : Vi private RazorDynamicFileInfoProvider _provider; private TestAccessor _testAccessor; private TestProjectSnapshotManager _projectManager; - private IProjectSnapshot _project; - private IDocumentSnapshot _document1; - private IDocumentSnapshot _document2; + private ProjectSnapshot _project; + private DocumentSnapshot _document1; + private DocumentSnapshot _document2; private IDynamicDocumentContainer _lspDocumentContainer; #nullable enable diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/TestProjectWorkspaceStateGenerator.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/TestProjectWorkspaceStateGenerator.cs index 2cabe615d39..8f0f10a8656 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/TestProjectWorkspaceStateGenerator.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/TestProjectWorkspaceStateGenerator.cs @@ -14,7 +14,7 @@ internal class TestProjectWorkspaceStateGenerator : IProjectWorkspaceStateGenera public IReadOnlyList Updates => _updates; - public void EnqueueUpdate(Project? workspaceProject, IProjectSnapshot projectSnapshot) + public void EnqueueUpdate(Project? workspaceProject, ProjectSnapshot projectSnapshot) { var update = new TestUpdate(workspaceProject, projectSnapshot); _updates.Add(update); @@ -33,7 +33,7 @@ public void Clear() _updates.Clear(); } - public record TestUpdate(Project? WorkspaceProject, IProjectSnapshot ProjectSnapshot) + public record TestUpdate(Project? WorkspaceProject, ProjectSnapshot ProjectSnapshot) { public bool IsCancelled { get; set; } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/WorkspaceProjectStateChangeDetectorTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/WorkspaceProjectStateChangeDetectorTest.cs index 6268cfed82b..3ec35888df0 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/WorkspaceProjectStateChangeDetectorTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/WorkspaceProjectStateChangeDetectorTest.cs @@ -742,6 +742,6 @@ public interface IComponent {} Assert.False(result); } - private WorkspaceProjectStateChangeDetector CreateDetector(IProjectWorkspaceStateGenerator generator, IProjectSnapshotManager projectManager) + private WorkspaceProjectStateChangeDetector CreateDetector(IProjectWorkspaceStateGenerator generator, ProjectSnapshotManager projectManager) => new(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, TimeSpan.FromMilliseconds(10)); } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Remote/OutOfProcTagHelperResolverTest.TestResolver.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Remote/OutOfProcTagHelperResolverTest.TestResolver.cs index 2deede00dca..e5c500c67be 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Remote/OutOfProcTagHelperResolverTest.TestResolver.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Remote/OutOfProcTagHelperResolverTest.TestResolver.cs @@ -24,14 +24,14 @@ private class TestResolver( ITelemetryReporter telemetryReporter) : OutOfProcTagHelperResolver(remoteServiceInvoker, loggerFactory, telemetryReporter) { - public Func>>? OnResolveOutOfProcess { get; init; } + public Func>>? OnResolveOutOfProcess { get; init; } - public Func>>? OnResolveInProcess { get; init; } + public Func>>? OnResolveInProcess { get; init; } - protected override ValueTask> ResolveTagHelpersOutOfProcessAsync(Project project, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken) + protected override ValueTask> ResolveTagHelpersOutOfProcessAsync(Project project, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) => OnResolveOutOfProcess?.Invoke(projectSnapshot) ?? default; - protected override ValueTask> ResolveTagHelpersInProcessAsync(Project project, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken) + protected override ValueTask> ResolveTagHelpersInProcessAsync(Project project, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) => OnResolveInProcess?.Invoke(projectSnapshot) ?? default; public ImmutableArray PublicProduceChecksumsFromDelta(ProjectId projectId, int lastResultId, TagHelperDeltaResult deltaResult) diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/RazorProjectSystemInProcess.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/RazorProjectSystemInProcess.cs index 260ef3a33e1..9820d96bc46 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/RazorProjectSystemInProcess.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/RazorProjectSystemInProcess.cs @@ -40,7 +40,7 @@ await Helper.RetryAsync(ct => public async Task WaitForProjectFileAsync(string projectFilePath, CancellationToken cancellationToken) { - var projectManager = await TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); + var projectManager = await TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); Assert.NotNull(projectManager); await Helper.RetryAsync(ct => { @@ -55,7 +55,7 @@ await Helper.RetryAsync(ct => public async Task WaitForComponentTagNameAsync(string projectName, string componentName, CancellationToken cancellationToken) { var projectFilePath = await TestServices.SolutionExplorer.GetProjectFileNameAsync(projectName, cancellationToken); - var projectManager = await TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); + var projectManager = await TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); Assert.NotNull(projectManager); await Helper.RetryAsync(async ct => { @@ -73,7 +73,7 @@ await Helper.RetryAsync(async ct => public async Task WaitForRazorFileInProjectAsync(string projectFilePath, string filePath, CancellationToken cancellationToken) { - var projectManager = await TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); + var projectManager = await TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); Assert.NotNull(projectManager); await Helper.RetryAsync(ct => @@ -88,7 +88,7 @@ await Helper.RetryAsync(ct => public async Task> GetProjectKeyIdsForProjectAsync(string projectFilePath, CancellationToken cancellationToken) { - var projectManager = await TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); + var projectManager = await TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); Assert.NotNull(projectManager); return projectManager.GetProjectKeysWithFilePath(projectFilePath).SelectAsArray(static key => key.Id); From c838a751f8913b3227b2c82735f2b4b667685a6d Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 17 Dec 2024 17:07:01 -0800 Subject: [PATCH 27/42] Remove IProjectSnapshot.GetProjectEngineAsync Retrieving a RazorProjectEngine for a project snapshot is an implementation detail and doesn't need to be exposed on IProjectSnapshot. --- .../DocumentMapping/RazorEditHelper.cs | 1 - .../ProjectSystem/DocumentSnapshot.cs | 2 +- .../ProjectSystem/IProjectSnapshot.cs | 1 - .../ProjectSystem/ProjectSnapshot.cs | 5 ++--- .../Sources/GeneratedOutputSource.cs | 2 +- .../Documents/EditorDocumentManagerListener.cs | 5 ++--- .../Remote/OutOfProcTagHelperResolver.cs | 7 ++----- .../Formatting_NetFx/FormattingTestBase.cs | 3 --- .../ProjectSystem/TestProjectSnapshot.cs | 3 --- .../ProjectSnapshotManagerTest.cs | 18 ++++++------------ 10 files changed, 14 insertions(+), 33 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/RazorEditHelper.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/RazorEditHelper.cs index ee4e06c1f98..58de9eed3b9 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/RazorEditHelper.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/RazorEditHelper.cs @@ -33,7 +33,6 @@ internal static async Task> MapCSharpEditsAsync( ITelemetryReporter telemetryReporter, CancellationToken cancellationToken) { - var codeDocument = await snapshot.GetGeneratedOutputAsync(cancellationToken).ConfigureAwait(false); using var textChangeBuilder = new TextChangeBuilder(documentMappingService); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs index eb09ea14ea3..f932e30690e 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs @@ -64,7 +64,7 @@ async Task GetCSharpSyntaxTreeCoreAsync(CancellationToken cancellati public async Task GenerateDesignTimeOutputAsync(CancellationToken cancellationToken) { var importItems = await Project.GetImportItemsAsync(FilePath, cancellationToken).ConfigureAwait(false); - var projectEngine = await Project.GetProjectEngineAsync(cancellationToken).ConfigureAwait(false); + var projectEngine = Project.ProjectEngine; return await CompilationHelpers .GenerateDesignTimeCodeDocumentAsync(this, projectEngine, importItems, cancellationToken) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs index c8fe9b45bb5..d6be54fab2d 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs @@ -34,7 +34,6 @@ internal interface IProjectSnapshot LanguageVersion CSharpLanguageVersion { get; } ProjectWorkspaceState ProjectWorkspaceState { get; } - ValueTask GetProjectEngineAsync(CancellationToken cancellationToken); ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken); bool ContainsDocument(string filePath); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs index 69f7e3da161..28795d25e24 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshot.cs @@ -38,8 +38,7 @@ internal sealed class ProjectSnapshot(ProjectState state) : IProjectSnapshot, IL public int DocumentCount => _state.Documents.Count; - public ValueTask GetProjectEngineAsync(CancellationToken cancellationToken) - => new(_state.ProjectEngine); + public RazorProjectEngine ProjectEngine => _state.ProjectEngine; public ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken) => new(_state.TagHelpers); @@ -138,7 +137,7 @@ public ValueTask> GetImportItemsAsync(string filePath public async Task> GetImportItemsAsync(HostDocument hostDocument, CancellationToken cancellationToken) { - var projectEngine = await GetProjectEngineAsync(cancellationToken).ConfigureAwait(false); + var projectEngine = ProjectEngine; var projectItem = projectEngine.FileSystem.GetItem(hostDocument.FilePath, hostDocument.FileKind); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs index 71c763bfed8..e2265579f25 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs @@ -30,7 +30,7 @@ public async ValueTask GetValueAsync(DocumentSnapshot documen using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { var project = document.Project; - var projectEngine = await project.GetProjectEngineAsync(cancellationToken).ConfigureAwait(false); + var projectEngine = project.ProjectEngine; var compilerOptions = project.CompilerOptions; var importItems = await project.GetImportItemsAsync(document.HostDocument, cancellationToken).ConfigureAwait(false); diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/EditorDocumentManagerListener.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/EditorDocumentManagerListener.cs index 40aee7a8f7d..a109d3631b4 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/EditorDocumentManagerListener.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/EditorDocumentManagerListener.cs @@ -244,7 +244,7 @@ private Task Document_OpenedAsync(object sender, CancellationToken cancellationT try { return _projectManager.UpdateAsync( - static async (updater, state) => + static (updater, state) => { var (document, fallbackProjectManager, telemetryReporter, cancellationToken) = state; @@ -254,12 +254,11 @@ static async (updater, state) => // The user is opening a document that is part of a fallback project. This is a scenario we are very interested in knowing more about // so fire some telemetry. We can't log details about the project, for PII reasons, but we can use document count and tag helper count // as some kind of measure of complexity. - var tagHelpers = await project.GetTagHelpersAsync(cancellationToken).ConfigureAwait(false); telemetryReporter.ReportEvent( "fallbackproject/documentopen", Severity.Normal, new Property("document.count", project.DocumentCount), - new Property("taghelper.count", tagHelpers.Length)); + new Property("taghelper.count", project.ProjectWorkspaceState.TagHelpers.Length)); } updater.OpenDocument(document.ProjectKey, document.DocumentFilePath, document.EditorTextContainer!.CurrentText); diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/OutOfProcTagHelperResolver.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/OutOfProcTagHelperResolver.cs index d684deead62..859c3adfb2a 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/OutOfProcTagHelperResolver.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/OutOfProcTagHelperResolver.cs @@ -174,12 +174,9 @@ protected ImmutableArray ProduceChecksumsFromDelta(ProjectId projectId return checksums; } - protected virtual async ValueTask> ResolveTagHelpersInProcessAsync( + protected virtual ValueTask> ResolveTagHelpersInProcessAsync( Project project, ProjectSnapshot projectSnapshot, CancellationToken cancellationToken) - { - var projectEngine = await projectSnapshot.GetProjectEngineAsync(cancellationToken).ConfigureAwait(false); - return await project.GetTagHelpersAsync(projectEngine, _telemetryReporter, cancellationToken).ConfigureAwait(false); - } + => project.GetTagHelpersAsync(projectSnapshot.ProjectEngine, _telemetryReporter, cancellationToken); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs index 7d30979e31f..5c745df38a7 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs @@ -351,9 +351,6 @@ internal static IDocumentSnapshot CreateDocumentSnapshot( snapshotMock .Setup(d => d.Project.GetTagHelpersAsync(It.IsAny())) .ReturnsAsync(tagHelpers); - snapshotMock - .Setup(d => d.Project.GetProjectEngineAsync(It.IsAny())) - .ReturnsAsync(projectEngine); snapshotMock .Setup(d => d.FileKind) .Returns(fileKind); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs index fbe8d6d656e..228b56b9704 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs @@ -42,9 +42,6 @@ public static TestProjectSnapshot Create(string filePath, ProjectWorkspaceState? public LanguageVersion CSharpLanguageVersion => RealSnapshot.CSharpLanguageVersion; public ProjectWorkspaceState ProjectWorkspaceState => RealSnapshot.ProjectWorkspaceState; - public ValueTask GetProjectEngineAsync(CancellationToken cancellationToken) - => RealSnapshot.GetProjectEngineAsync(cancellationToken); - public ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken) => RealSnapshot.GetTagHelpersAsync(cancellationToken); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs index 61fcb44e458..f23e24387a0 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs @@ -300,7 +300,7 @@ await _projectManager.UpdateAsync(updater => }); var project = _projectManager.GetRequiredProject(s_hostProject.Key); - var projectEngine = await project.GetProjectEngineAsync(DisposalToken); + var projectEngine = project.ProjectEngine; // Act await _projectManager.UpdateAsync(updater => @@ -309,9 +309,7 @@ await _projectManager.UpdateAsync(updater => }); // Assert - var newProjectEngine = await _projectManager - .GetRequiredProject(s_hostProject.Key) - .GetProjectEngineAsync(DisposalToken); + var newProjectEngine = _projectManager.GetRequiredProject(s_hostProject.Key).ProjectEngine; Assert.Same(projectEngine, newProjectEngine); } @@ -435,7 +433,7 @@ await _projectManager.UpdateAsync(updater => }); var project = _projectManager.GetRequiredProject(s_hostProject.Key); - var projectEngine = await project.GetProjectEngineAsync(DisposalToken); + var projectEngine = project.ProjectEngine; // Act await _projectManager.UpdateAsync(updater => @@ -444,9 +442,7 @@ await _projectManager.UpdateAsync(updater => }); // Assert - var newProjectEngine = await _projectManager - .GetRequiredProject(s_hostProject.Key) - .GetProjectEngineAsync(DisposalToken); + var newProjectEngine = _projectManager.GetRequiredProject(s_hostProject.Key).ProjectEngine; Assert.Same(projectEngine, newProjectEngine); } @@ -687,7 +683,7 @@ await _projectManager.UpdateAsync(updater => }); var project = _projectManager.GetRequiredProject(s_hostProject.Key); - var projectEngine = await project.GetProjectEngineAsync(DisposalToken); + var projectEngine = project.ProjectEngine; // Act await _projectManager.UpdateAsync(updater => @@ -696,9 +692,7 @@ await _projectManager.UpdateAsync(updater => }); // Assert - var newProjectEngine = await _projectManager - .GetRequiredProject(s_hostProjectWithConfigurationChange.Key) - .GetProjectEngineAsync(DisposalToken); + var newProjectEngine = _projectManager.GetRequiredProject(s_hostProjectWithConfigurationChange.Key).ProjectEngine; Assert.NotSame(projectEngine, newProjectEngine); } From 49a973c99a3c32afab5d57f96d6a1c4880f7d11e Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 17 Dec 2024 17:08:49 -0800 Subject: [PATCH 28/42] Remove IProjectSnapshot.ProjectWorkspaceState ProjectWorkspaceState is an implementation detail and does not need to be exposed on IProjectSnapshot. --- .../ProjectSystem/IProjectSnapshot.cs | 1 - .../ProjectSystem/RemoteProjectSnapshot.cs | 2 -- .../ProjectSystem/TestProjectSnapshot.cs | 1 - .../Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestMocks.cs | 2 -- 4 files changed, 6 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs index d6be54fab2d..f4a9e1f4939 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs @@ -32,7 +32,6 @@ internal interface IProjectSnapshot string? RootNamespace { get; } string DisplayName { get; } LanguageVersion CSharpLanguageVersion { get; } - ProjectWorkspaceState ProjectWorkspaceState { get; } ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken); 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 b37c4e28fe1..60286dbc0d4 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs @@ -81,8 +81,6 @@ public ValueTask> GetTagHelpersAsync(Cancell return new(_lazyTagHelpers.GetValueAsync(cancellationToken)); } - public ProjectWorkspaceState ProjectWorkspaceState => throw new InvalidOperationException("Should not be called for cohosted projects."); - public RemoteDocumentSnapshot GetDocument(DocumentId documentId) { var document = _project.GetRequiredDocument(documentId); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs index 228b56b9704..668777f276f 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs @@ -40,7 +40,6 @@ public static TestProjectSnapshot Create(string filePath, ProjectWorkspaceState? public string? RootNamespace => RealSnapshot.RootNamespace; public string DisplayName => RealSnapshot.DisplayName; public LanguageVersion CSharpLanguageVersion => RealSnapshot.CSharpLanguageVersion; - public ProjectWorkspaceState ProjectWorkspaceState => RealSnapshot.ProjectWorkspaceState; public ValueTask> GetTagHelpersAsync(CancellationToken cancellationToken) => RealSnapshot.GetTagHelpersAsync(cancellationToken); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestMocks.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestMocks.cs index 58bcaa318fb..7cd5fd7eec1 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestMocks.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestMocks.cs @@ -108,8 +108,6 @@ public static IProjectSnapshot CreateProjectSnapshot(HostProject hostProject, Pr if (projectWorkspaceState is not null) { - mock.SetupGet(x => x.ProjectWorkspaceState) - .Returns(projectWorkspaceState); mock.SetupGet(x => x.CSharpLanguageVersion) .Returns(projectWorkspaceState.CSharpLanguageVersion); mock.Setup(x => x.GetTagHelpersAsync(It.IsAny())) From 04bf4bf14a02a686d742f0f3da0b153abb190838 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 17 Dec 2024 17:15:07 -0800 Subject: [PATCH 29/42] Move IDocumentSnapshot and IProjectSnapshot to lower tooling layer IDocumentSnapshot and IProjectSnapshot and now more fundamental and below in a lower layer of Razor tooling. --- .../LanguageServer/RazorCSharpFormattingBenchmark.cs | 1 + .../LanguageServer/RazorCodeActionsBenchmark.cs | 1 + .../LanguageServer/RazorCompletionBenchmark.cs | 1 + .../LanguageServer/RazorDiagnosticsBenchmark.cs | 1 + .../LanguageServer/RazorDocumentMappingBenchmark.cs | 2 +- .../LanguageServer/RazorSemanticTokensBenchmark.cs | 1 + .../LanguageServer/RazorSemanticTokensScrollingBenchmark.cs | 1 + .../CodeActions/CodeActionEndpoint.cs | 2 +- .../CodeActions/RoslynCodeActionHelpers.cs | 1 + .../Diagnostics/RazorDiagnosticsPublisher.Comparer.cs | 2 +- .../Diagnostics/RazorDiagnosticsPublisher.cs | 1 + .../AbstractTextDocumentPresentationEndpointBase.cs | 2 +- .../DocumentSnapshotTextLoader.cs | 2 +- .../Formatting/HtmlFormatter.cs | 2 +- .../Formatting/IHtmlFormatter.cs | 2 +- .../LspEditMappingService.cs | 1 + .../OpenDocumentGenerator.Comparer.cs | 2 +- ...ProjectSnapshotManagerExtensions.SolutionQueryOperations.cs | 1 + .../ProjectSystem/IDocumentSnapshot.cs | 3 ++- .../ProjectSystem/IProjectSnapshot.cs | 3 +-- .../CodeActions/CodeActionsService.cs | 2 +- .../CodeActions/Html/HtmlCodeActionProvider.cs | 2 +- .../CodeActions/ICodeActionsService.cs | 2 +- .../CodeActions/Razor/IRoslynCodeActionHelpers.cs | 1 + .../CodeActions/RazorCodeActionContext.cs | 2 +- .../Diagnostics/RazorDiagnosticConverter.cs | 2 +- .../Diagnostics/RazorTranslateDiagnosticsService.cs | 2 +- .../DocumentMapping/AbstractEditMappingService.cs | 1 + .../DocumentMapping/IEditMappingService.cs | 2 +- .../DocumentMapping/RazorEditHelper.cs | 2 +- .../Formatting/FormattingContext.cs | 1 + .../Formatting/RazorFormattingService.cs | 1 + .../GoToDefinition/AbstractRazorComponentDefinitionService.cs | 1 + .../GoToDefinition/IRazorComponentDefinitionService.cs | 1 + .../GoToDefinition/RazorComponentDefinitionHelpers.cs | 2 +- .../IRazorComponentSearchEngine.cs | 1 + .../ProjectEngineHost/IProjectEngineFactoryExtensions.cs | 2 +- .../ProjectSystem/CompilationHelpers.cs | 1 + .../ProjectSystem/DocumentContext.cs | 1 + .../ProjectSystem/DocumentSnapshot.cs | 1 + .../ProjectSystem/GeneratedDocumentTextLoader.cs | 1 + .../ProjectSystem/IDocumentSnapshotExtensions.cs | 1 + .../ProjectSystem/ISolutionQueryOperations.cs | 1 + .../ProjectSystem/ImportHelpers.cs | 1 + .../RazorComponentSearchEngine.cs | 1 + .../Rename/RenameService.cs | 1 + .../Tooltip/Extensions.cs | 1 + .../CodeActions/RoslynCodeActionHelpers.cs | 1 + .../DocumentMapping/RemoteEditMappingService.cs | 1 + .../ProjectSystem/RemoteDocumentSnapshot.cs | 1 + .../ProjectSystem/RemoteSolutionSnapshot.cs | 1 + .../DynamicFiles/DefaultDynamicDocumentContainer.cs | 1 + .../DynamicFiles/RazorDocumentExcerptService.cs | 2 +- .../DynamicFiles/RazorMappingService.cs | 2 +- .../DynamicFiles/RazorSpanMappingService.cs | 2 +- .../CodeActions/CSharp/CSharpCodeActionProviderTest.cs | 2 +- .../CSharp/TypeAccessibilityCodeActionProviderTest.cs | 2 +- .../CodeActions/Html/HtmlCodeActionProviderTest.cs | 2 +- .../CodeActions/Html/HtmlCodeActionResolverTest.cs | 1 + .../Razor/ComponentAccessibilityCodeActionProviderTest.cs | 2 +- .../Razor/ExtractToCodeBehindCodeActionProviderTest.cs | 2 +- .../Razor/ExtractToComponentCodeActionProviderTest.cs | 2 +- .../DocumentSnapshotTextLoaderTest.cs | 2 +- .../Formatting/TestRazorFormattingService.cs | 1 + .../Formatting_NetFx/FormattingContentValidationPassTest.cs | 2 +- .../Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs | 2 +- .../Formatting_NetFx/FormattingTestBase.cs | 1 + .../Formatting_NetFx/TestHtmlFormatter.cs | 2 +- .../Semantic/SemanticTokensTest.cs | 1 + .../LanguageServer/LanguageServerTestBase.cs | 1 + .../Workspaces/DocumentExcerptServiceTestBase.cs | 1 + .../IProjectSnapshotManagerExtensions.cs | 1 + .../DynamicFiles/RazorDocumentExcerptServiceTest.cs | 2 +- 73 files changed, 74 insertions(+), 35 deletions(-) rename src/Razor/src/{Microsoft.CodeAnalysis.Razor.Workspaces => Microsoft.AspNetCore.Razor.ProjectEngineHost}/ProjectSystem/IDocumentSnapshot.cs (94%) rename src/Razor/src/{Microsoft.CodeAnalysis.Razor.Workspaces => Microsoft.AspNetCore.Razor.ProjectEngineHost}/ProjectSystem/IProjectSnapshot.cs (92%) diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCSharpFormattingBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCSharpFormattingBenchmark.cs index fae5c187ea7..1222b581716 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCSharpFormattingBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCSharpFormattingBenchmark.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Formatting; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs index ef7fa382fdc..4a8e0e18694 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Telemetry; using Microsoft.CodeAnalysis.Razor.CodeActions; using Microsoft.CodeAnalysis.Razor.ProjectSystem; diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs index 443af01a3e5..d03f9d83d0b 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs @@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Completion.Delegation; using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Completion; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs index 7071c1986f1..7238051245d 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics; using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Diagnostics; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs index 3913c87233b..ff5de2244d5 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs @@ -10,8 +10,8 @@ using System.Threading.Tasks; using BenchmarkDotNet.Attributes; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; namespace Microsoft.AspNetCore.Razor.Microbenchmarks.LanguageServer; diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs index c55d6db4278..8dfd5e61e7b 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs @@ -11,6 +11,7 @@ using BenchmarkDotNet.Attributes; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.Semantic; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensScrollingBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensScrollingBenchmark.cs index 0d45e306cbb..04d4a56fffe 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensScrollingBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensScrollingBenchmark.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.SemanticTokens; using Microsoft.CodeAnalysis.Text; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs index 324965c53c6..554f6d72d80 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs @@ -7,10 +7,10 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Telemetry; using Microsoft.CodeAnalysis.Razor.CodeActions; using Microsoft.CodeAnalysis.Razor.CodeActions.Models; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/RoslynCodeActionHelpers.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/RoslynCodeActionHelpers.cs index 23920547fbe..d28f404706b 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/RoslynCodeActionHelpers.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/RoslynCodeActionHelpers.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.AspNetCore.Razor.ProjectSystem; namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.Comparer.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.Comparer.cs index 32ce5e35948..c47288aa985 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.Comparer.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.Comparer.cs @@ -2,8 +2,8 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System.Collections.Generic; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.cs index cbc8c84aad6..bf27ed0d68e 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsPublisher.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Utilities; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Diagnostics; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs index 203f8a0d49a..30d06cff670 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs @@ -9,9 +9,9 @@ using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.DocumentPresentation; using Microsoft.CodeAnalysis.Razor.Workspaces; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSnapshotTextLoader.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSnapshotTextLoader.cs index a9963165966..1cb75b4d05c 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSnapshotTextLoader.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSnapshotTextLoader.cs @@ -4,8 +4,8 @@ using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; namespace Microsoft.AspNetCore.Razor.LanguageServer; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormatter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormatter.cs index 16dcfbc0446..cb06f5f7967 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormatter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormatter.cs @@ -8,7 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.Formatting; using Microsoft.CodeAnalysis.Text; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/IHtmlFormatter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/IHtmlFormatter.cs index 06995483bb2..e5807d600bf 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/IHtmlFormatter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/IHtmlFormatter.cs @@ -5,7 +5,7 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LspEditMappingService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LspEditMappingService.cs index bd88b799311..84190a49038 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LspEditMappingService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LspEditMappingService.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/OpenDocumentGenerator.Comparer.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/OpenDocumentGenerator.Comparer.cs index b339ddfbc9a..1af0b5ed560 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/OpenDocumentGenerator.Comparer.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/OpenDocumentGenerator.Comparer.cs @@ -2,8 +2,8 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System.Collections.Generic; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Razor.LanguageServer; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/IProjectSnapshotManagerExtensions.SolutionQueryOperations.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/IProjectSnapshotManagerExtensions.SolutionQueryOperations.cs index 30e2c0072fb..e1d1304794e 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/IProjectSnapshotManagerExtensions.SolutionQueryOperations.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/IProjectSnapshotManagerExtensions.SolutionQueryOperations.cs @@ -5,6 +5,7 @@ using System.Collections.Immutable; using System.Linq; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.ProjectSystem; namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshot.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/ProjectSystem/IDocumentSnapshot.cs similarity index 94% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshot.cs rename to src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/ProjectSystem/IDocumentSnapshot.cs index 0ce7372c92c..a82ec285804 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/ProjectSystem/IDocumentSnapshot.cs @@ -5,9 +5,10 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; +namespace Microsoft.AspNetCore.Razor.ProjectSystem; internal interface IDocumentSnapshot { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/ProjectSystem/IProjectSnapshot.cs similarity index 92% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs rename to src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/ProjectSystem/IProjectSnapshot.cs index f4a9e1f4939..b51400fdc4b 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/ProjectSystem/IProjectSnapshot.cs @@ -7,10 +7,9 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.CSharp; -namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; +namespace Microsoft.AspNetCore.Razor.ProjectSystem; internal interface IProjectSnapshot { 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 e334c974231..f91130f55be 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/CodeActionsService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/CodeActionsService.cs @@ -12,10 +12,10 @@ using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor.CodeActions.Models; using Microsoft.CodeAnalysis.Razor.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Razor.Workspaces; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Html/HtmlCodeActionProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Html/HtmlCodeActionProvider.cs index 4dbe2e9aa41..9dc00f1a2c0 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Html/HtmlCodeActionProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Html/HtmlCodeActionProvider.cs @@ -6,10 +6,10 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.CodeActions.Models; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Formatting; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.VisualStudio.LanguageServer.Protocol; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/ICodeActionsService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/ICodeActionsService.cs index 3cd139b99c1..59f8666c4da 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/ICodeActionsService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/ICodeActionsService.cs @@ -4,8 +4,8 @@ using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.CodeActions.Models; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.VisualStudio.LanguageServer.Protocol; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/IRoslynCodeActionHelpers.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/IRoslynCodeActionHelpers.cs index 2936be19835..71893c035d3 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/IRoslynCodeActionHelpers.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/IRoslynCodeActionHelpers.cs @@ -4,6 +4,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.VisualStudio.LanguageServer.Protocol; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/RazorCodeActionContext.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/RazorCodeActionContext.cs index d8e5f257e94..14e0ba04e91 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/RazorCodeActionContext.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/RazorCodeActionContext.cs @@ -3,7 +3,7 @@ using System; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Text; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Diagnostics/RazorDiagnosticConverter.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Diagnostics/RazorDiagnosticConverter.cs index bbbacbee1d5..b62a841ff24 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Diagnostics/RazorDiagnosticConverter.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Diagnostics/RazorDiagnosticConverter.cs @@ -5,7 +5,7 @@ using System.Collections.Immutable; using System.Globalization; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using LspDiagnostic = Microsoft.VisualStudio.LanguageServer.Protocol.Diagnostic; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Diagnostics/RazorTranslateDiagnosticsService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Diagnostics/RazorTranslateDiagnosticsService.cs index 08879012b37..090d56f5276 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Diagnostics/RazorTranslateDiagnosticsService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Diagnostics/RazorTranslateDiagnosticsService.cs @@ -11,10 +11,10 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractEditMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractEditMappingService.cs index 7296deae4ec..d0bcb0fa462 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractEditMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractEditMappingService.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IEditMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IEditMappingService.cs index a4085302cbb..0f186d239bc 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IEditMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IEditMappingService.cs @@ -3,7 +3,7 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/RazorEditHelper.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/RazorEditHelper.cs index 58de9eed3b9..9b7b2d22948 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/RazorEditHelper.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/RazorEditHelper.cs @@ -8,10 +8,10 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Telemetry; using Microsoft.AspNetCore.Razor.Utilities; using Microsoft.CodeAnalysis.Razor.Formatting; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingContext.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingContext.cs index b1c7ae7f9bd..188b99268ae 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingContext.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/FormattingContext.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingService.cs index fee7a239782..eb980c30486 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Formatting/RazorFormattingService.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/AbstractRazorComponentDefinitionService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/AbstractRazorComponentDefinitionService.cs index ccab0374023..56f2c139a33 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/AbstractRazorComponentDefinitionService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/AbstractRazorComponentDefinitionService.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/IRazorComponentDefinitionService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/IRazorComponentDefinitionService.cs index 6a20fba5fc1..e5c3114e8c5 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/IRazorComponentDefinitionService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/IRazorComponentDefinitionService.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using LspLocation = Microsoft.VisualStudio.LanguageServer.Protocol.Location; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/RazorComponentDefinitionHelpers.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/RazorComponentDefinitionHelpers.cs index 1b261699e0a..3a93c429238 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/RazorComponentDefinitionHelpers.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/GoToDefinition/RazorComponentDefinitionHelpers.cs @@ -8,10 +8,10 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; using LspRange = Microsoft.VisualStudio.LanguageServer.Protocol.Range; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/IRazorComponentSearchEngine.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/IRazorComponentSearchEngine.cs index 45a998e88c1..3977c48b367 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/IRazorComponentSearchEngine.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/IRazorComponentSearchEngine.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.ProjectSystem; namespace Microsoft.CodeAnalysis.Razor.Workspaces; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectEngineHost/IProjectEngineFactoryExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectEngineHost/IProjectEngineFactoryExtensions.cs index 2e3b846d3b6..af1f719d982 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectEngineHost/IProjectEngineFactoryExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectEngineHost/IProjectEngineFactoryExtensions.cs @@ -4,7 +4,7 @@ using System; using System.IO; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.AspNetCore.Razor.ProjectSystem; namespace Microsoft.AspNetCore.Razor.ProjectEngineHost; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs index 94cecd9ced4..22ba0b276bc 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectSystem; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs index e5bc8836804..70bc53b8b3f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs index f932e30690e..2fa5f226817 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentSnapshot.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.ProjectSystem.Legacy; using Microsoft.CodeAnalysis.Text; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/GeneratedDocumentTextLoader.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/GeneratedDocumentTextLoader.cs index f5853dfee17..91bef2c6339 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/GeneratedDocumentTextLoader.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/GeneratedDocumentTextLoader.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs index ca1d6a31b32..9e544f3089a 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectSystem; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ISolutionQueryOperations.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ISolutionQueryOperations.cs index 068a4547d84..3703a0ee9a7 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ISolutionQueryOperations.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ISolutionQueryOperations.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Immutable; +using Microsoft.AspNetCore.Razor.ProjectSystem; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ImportHelpers.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ImportHelpers.cs index 346d5a8a37c..59f3e7c779e 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ImportHelpers.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ImportHelpers.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorComponentSearchEngine.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorComponentSearchEngine.cs index 070970f6b65..3dd695c253c 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorComponentSearchEngine.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorComponentSearchEngine.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Rename/RenameService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Rename/RenameService.cs index 2dd67f4a6ed..fabf46555c2 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Rename/RenameService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Rename/RenameService.cs @@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Tooltip/Extensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Tooltip/Extensions.cs index 2a8038838d4..f1d0064f191 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Tooltip/Extensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Tooltip/Extensions.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.ProjectSystem; namespace Microsoft.CodeAnalysis.Razor.Tooltip; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/CodeActions/RoslynCodeActionHelpers.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/CodeActions/RoslynCodeActionHelpers.cs index 4f46a45d0ea..dd9273321d7 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/CodeActions/RoslynCodeActionHelpers.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/CodeActions/RoslynCodeActionHelpers.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor.CodeActions; using Microsoft.CodeAnalysis.Razor.ProjectSystem; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteEditMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteEditMappingService.cs index 9897a0e4585..4d5ed800e82 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteEditMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentMapping/RemoteEditMappingService.cs @@ -4,6 +4,7 @@ using System; using System.Composition; using System.Diagnostics.CodeAnalysis; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs index dfc1181e92f..d35ac261222 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteDocumentSnapshot.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Threading; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteSolutionSnapshot.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteSolutionSnapshot.cs index f12d8044796..0958e8bd45d 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteSolutionSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteSolutionSnapshot.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Linq; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.ProjectSystem; namespace Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/DefaultDynamicDocumentContainer.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/DefaultDynamicDocumentContainer.cs index 8dde60b23ac..08906c2d987 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/DefaultDynamicDocumentContainer.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/DefaultDynamicDocumentContainer.cs @@ -3,6 +3,7 @@ using System; using Microsoft.AspNetCore.Razor; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Telemetry; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ExternalAccess.Razor; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorDocumentExcerptService.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorDocumentExcerptService.cs index 281cdfc29e6..af00288111d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorDocumentExcerptService.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorDocumentExcerptService.cs @@ -6,11 +6,11 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; namespace Microsoft.VisualStudio.Razor.DynamicFiles; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorMappingService.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorMappingService.cs index 32985cec4cb..0e5168ea236 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorMappingService.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorMappingService.cs @@ -10,13 +10,13 @@ using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Telemetry; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorSpanMappingService.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorSpanMappingService.cs index e8c6ccb04b3..fc05590adcb 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorSpanMappingService.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorSpanMappingService.cs @@ -9,10 +9,10 @@ using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; namespace Microsoft.VisualStudio.Razor.DynamicFiles; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/CSharpCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/CSharpCodeActionProviderTest.cs index 7cf55813d02..656dbcc1e9d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/CSharpCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/CSharpCodeActionProviderTest.cs @@ -8,13 +8,13 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Razor.CodeActions; using Microsoft.CodeAnalysis.Razor.CodeActions.Models; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Testing; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs index e934541a3a7..15114bf7315 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs @@ -9,12 +9,12 @@ using Microsoft.AspNetCore.Mvc.Razor.Extensions; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Razor.CodeActions; using Microsoft.CodeAnalysis.Razor.CodeActions.Models; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.NET.Sdk.Razor.SourceGenerators; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionProviderTest.cs index bdd7465125e..459d3bcb862 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionProviderTest.cs @@ -7,13 +7,13 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Razor.CodeActions; using Microsoft.CodeAnalysis.Razor.CodeActions.Models; using Microsoft.CodeAnalysis.Razor.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Testing; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionResolverTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionResolverTest.cs index cf2f7e6cc45..33a4fe0d171 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionResolverTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/HtmlCodeActionResolverTest.cs @@ -4,6 +4,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.Razor.CodeActions; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs index a42a138f676..e5b55af9331 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs @@ -7,11 +7,11 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Razor.CodeActions; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Razor.Workspaces; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionProviderTest.cs index 29f1d1e6b1c..6605a04a265 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionProviderTest.cs @@ -10,11 +10,11 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; using Microsoft.AspNetCore.Razor.Language.Extensions; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.Razor.CodeActions; using Microsoft.CodeAnalysis.Razor.CodeActions.Models; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Testing; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToComponentCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToComponentCodeActionProviderTest.cs index 105a5614503..34f7c71c032 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToComponentCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToComponentCodeActionProviderTest.cs @@ -10,12 +10,12 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Components; using Microsoft.AspNetCore.Razor.Language.Extensions; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.Razor.CodeActions; using Microsoft.CodeAnalysis.Razor.CodeActions.Models; using Microsoft.CodeAnalysis.Razor.CodeActions.Razor; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Testing; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentSnapshotTextLoaderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentSnapshotTextLoaderTest.cs index a24180b07cb..8cec64475d6 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentSnapshotTextLoaderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentSnapshotTextLoaderTest.cs @@ -3,8 +3,8 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; using Moq; using Xunit; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/TestRazorFormattingService.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/TestRazorFormattingService.cs index 8b29589d7d2..13ead284b32 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/TestRazorFormattingService.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting/TestRazorFormattingService.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Formatting; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs index 778970b06cd..ccc32af100d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingContentValidationPassTest.cs @@ -6,11 +6,11 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Razor.Formatting; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; using Microsoft.NET.Sdk.Razor.SourceGenerators; using Moq; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs index 23379b4a72d..aaa854643d6 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingDiagnosticValidationPassTest.cs @@ -5,11 +5,11 @@ using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Razor.Formatting; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; using Microsoft.NET.Sdk.Razor.SourceGenerators; using Xunit; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs index 5c745df38a7..4c1ab3feb97 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs @@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.IntegrationTests; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/TestHtmlFormatter.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/TestHtmlFormatter.cs index 8652e6efe71..63b265286e0 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/TestHtmlFormatter.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/TestHtmlFormatter.cs @@ -5,8 +5,8 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Threading; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs index 0389bc7d4e0..a82c06a93e0 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs @@ -16,6 +16,7 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Completion; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.AspNetCore.Razor.Utilities; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/LanguageServerTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/LanguageServerTestBase.cs index 6fe88bcace3..f613d6ad2df 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/LanguageServerTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/LanguageServerTestBase.cs @@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; using Microsoft.AspNetCore.Razor.ProjectEngineHost; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/DocumentExcerptServiceTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/DocumentExcerptServiceTestBase.cs index 0e83fdaf113..e4110008180 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/DocumentExcerptServiceTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/Workspaces/DocumentExcerptServiceTestBase.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/IProjectSnapshotManagerExtensions.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/IProjectSnapshotManagerExtensions.cs index 8d05b12eb14..165380d101f 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/IProjectSnapshotManagerExtensions.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/IProjectSnapshotManagerExtensions.cs @@ -5,6 +5,7 @@ using System.Collections.Immutable; using System.Linq; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.ProjectSystem; namespace Microsoft.CodeAnalysis.Razor.Workspaces.Test; diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorDocumentExcerptServiceTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorDocumentExcerptServiceTest.cs index 6a104f675a2..50c604629e5 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorDocumentExcerptServiceTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DynamicFiles/RazorDocumentExcerptServiceTest.cs @@ -2,10 +2,10 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.ExternalAccess.Razor; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.VisualStudio.Razor.DynamicFiles; using Xunit; using Xunit.Abstractions; From f27d76839321acc16f40cf7264daa4b59e0937ee Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 17 Dec 2024 17:27:44 -0800 Subject: [PATCH 30/42] Remove IProjectSnapshot.Configuration The RazorConfiguration of a project snapshot is an implementation detail and doesn't need to be exposed. --- .../ProjectSystem/IProjectSnapshot.cs | 1 - .../IProjectEngineFactoryExtensions.cs | 20 ------------ .../ProjectSystem/RemoteProjectSnapshot.cs | 2 -- .../Formatting_NetFx/FormattingTestBase.cs | 3 -- .../ProjectEngineFactoryProviderTest.cs | 31 +++++++++++++++---- .../ProjectSystem/TestProjectSnapshot.cs | 1 - .../TestMocks.cs | 2 -- 7 files changed, 25 insertions(+), 35 deletions(-) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/ProjectSystem/IProjectSnapshot.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/ProjectSystem/IProjectSnapshot.cs index b51400fdc4b..9ca0249622f 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/ProjectSystem/IProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/ProjectSystem/IProjectSnapshot.cs @@ -15,7 +15,6 @@ internal interface IProjectSnapshot { ProjectKey Key { get; } - RazorConfiguration Configuration { get; } IEnumerable DocumentFilePaths { get; } /// diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectEngineHost/IProjectEngineFactoryExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectEngineHost/IProjectEngineFactoryExtensions.cs index af1f719d982..a7aa36904ff 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectEngineHost/IProjectEngineFactoryExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectEngineHost/IProjectEngineFactoryExtensions.cs @@ -2,32 +2,12 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; -using System.IO; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.ProjectSystem; namespace Microsoft.AspNetCore.Razor.ProjectEngineHost; internal static class IProjectEngineFactoryExtensions { - public static RazorProjectEngine Create( - this IProjectEngineFactory factory, - IProjectSnapshot projectSnapshot, - Action? configure = null) - => factory.Create( - projectSnapshot.Configuration, - RazorProjectFileSystem.Create(Path.GetDirectoryName(projectSnapshot.FilePath)), - configure); - - public static RazorProjectEngine Create( - this IProjectEngineFactoryProvider factoryProvider, - IProjectSnapshot projectSnapshot, - Action? configure = null) - => factoryProvider.Create( - projectSnapshot.Configuration, - rootDirectoryPath: Path.GetDirectoryName(projectSnapshot.FilePath).AssumeNotNull(), - configure); - public static RazorProjectEngine Create( this IProjectEngineFactoryProvider factoryProvider, RazorConfiguration configuration, 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 60286dbc0d4..5c90c69de68 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs @@ -52,8 +52,6 @@ public RemoteProjectSnapshot(Project project, RemoteSolutionSnapshot solutionSna _lazyTagHelpers = AsyncLazy.Create(ComputeTagHelpersAsync); } - public RazorConfiguration Configuration => throw new InvalidOperationException("Should not be called for cohosted projects."); - public IEnumerable DocumentFilePaths => _project.AdditionalDocuments .Where(static d => d.IsRazorDocument()) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs index 4c1ab3feb97..4ec7b41eae1 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs @@ -343,9 +343,6 @@ internal static IDocumentSnapshot CreateDocumentSnapshot( snapshotMock .Setup(d => d.TargetPath) .Returns(path); - snapshotMock - .Setup(d => d.Project.Configuration) - .Returns(projectEngine.Configuration); snapshotMock .Setup(d => d.GetTextAsync(It.IsAny())) .ReturnsAsync(codeDocument.Source.Text); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs index 89ff1d5c8e2..b9272a84492 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs @@ -4,6 +4,7 @@ #nullable disable using System.Collections.Immutable; +using System.IO; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.CodeAnalysis.Razor; @@ -75,7 +76,10 @@ public void Create_CreatesDesignTimeTemplateEngine_ForVersion3_0() // Act var factory = provider.GetFactory(snapshot.Configuration); - var engine = factory.Create(snapshot, b => b.Features.Add(new MyCoolNewFeature())); + var engine = factory.Create( + snapshot.Configuration, + RazorProjectFileSystem.Create(Path.GetDirectoryName(snapshot.FilePath)), + b => b.Features.Add(new MyCoolNewFeature())); // Assert Assert.Single(engine.Engine.Features.OfType()); @@ -94,7 +98,10 @@ public void Create_CreatesDesignTimeTemplateEngine_ForVersion2_1() // Act var factory = provider.GetFactory(snapshot.Configuration); - var engine = factory.Create(snapshot, b => b.Features.Add(new MyCoolNewFeature())); + var engine = factory.Create( + snapshot.Configuration, + RazorProjectFileSystem.Create(Path.GetDirectoryName(snapshot.FilePath)), + b => b.Features.Add(new MyCoolNewFeature())); // Assert Assert.Single(engine.Engine.Features.OfType()); @@ -115,7 +122,10 @@ public void Create_CreatesDesignTimeTemplateEngine_ForVersion2_0() // Act var factory = provider.GetFactory(snapshot.Configuration); - var engine = factory.Create(snapshot, b => b.Features.Add(new MyCoolNewFeature())); + var engine = factory.Create( + snapshot.Configuration, + RazorProjectFileSystem.Create(Path.GetDirectoryName(snapshot.FilePath)), + b => b.Features.Add(new MyCoolNewFeature())); // Assert Assert.Single(engine.Engine.Features.OfType()); @@ -134,7 +144,10 @@ public void Create_CreatesTemplateEngine_ForVersion1_1() // Act var factory = provider.GetFactory(snapshot.Configuration); - var engine = factory.Create(snapshot, b => b.Features.Add(new MyCoolNewFeature())); + var engine = factory.Create( + snapshot.Configuration, + RazorProjectFileSystem.Create(Path.GetDirectoryName(snapshot.FilePath)), + b => b.Features.Add(new MyCoolNewFeature())); // Assert Assert.Single(engine.Engine.Features.OfType()); @@ -153,7 +166,10 @@ public void Create_DoesNotSupportViewComponentTagHelpers_ForVersion1_0() // Act var factory = provider.GetFactory(snapshot.Configuration); - var engine = factory.Create(snapshot, b => b.Features.Add(new MyCoolNewFeature())); + var engine = factory.Create( + snapshot.Configuration, + RazorProjectFileSystem.Create(Path.GetDirectoryName(snapshot.FilePath)), + b => b.Features.Add(new MyCoolNewFeature())); // Assert Assert.Single(engine.Engine.Features.OfType()); @@ -180,7 +196,10 @@ public void Create_ForUnknownConfiguration_UsesFallbackFactory() // Act var factory = provider.GetFactory(snapshot.Configuration); - var engine = factory.Create(snapshot, b => b.Features.Add(new MyCoolNewFeature())); + var engine = factory.Create( + snapshot.Configuration, + RazorProjectFileSystem.Create(Path.GetDirectoryName(snapshot.FilePath)), + b => b.Features.Add(new MyCoolNewFeature())); // Assert Assert.Single(engine.Engine.Features.OfType()); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs index 668777f276f..6000edc05bf 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs @@ -33,7 +33,6 @@ public static TestProjectSnapshot Create(string filePath, ProjectWorkspaceState? public HostProject HostProject => RealSnapshot.HostProject; public ProjectKey Key => RealSnapshot.Key; - public RazorConfiguration Configuration => RealSnapshot.Configuration; public IEnumerable DocumentFilePaths => RealSnapshot.DocumentFilePaths; public string FilePath => RealSnapshot.FilePath; public string IntermediateOutputPath => RealSnapshot.IntermediateOutputPath; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestMocks.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestMocks.cs index 7cd5fd7eec1..98f12fde5f8 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestMocks.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/TestMocks.cs @@ -99,8 +99,6 @@ public static IProjectSnapshot CreateProjectSnapshot(HostProject hostProject, Pr .Returns(hostProject.FilePath); mock.SetupGet(x => x.IntermediateOutputPath) .Returns(hostProject.IntermediateOutputPath); - mock.SetupGet(x => x.Configuration) - .Returns(hostProject.Configuration); mock.SetupGet(x => x.RootNamespace) .Returns(hostProject.RootNamespace); mock.SetupGet(x => x.DisplayName) From 67e32279b9b6e7027800ac5406e51c41d6e00d8a Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 17 Dec 2024 17:27:58 -0800 Subject: [PATCH 31/42] Don't use LINQ Count() method --- .../Diagnostics/DocumentPullDiagnosticsEndpoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs index ad2838c9a73..1c4e9f50f36 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs @@ -199,7 +199,7 @@ private async ValueTask ReportRZ10012TelemetryAsync(DocumentContext documentCont } var tagHelpers = await documentContext.Project.GetTagHelpersAsync(cancellationToken).ConfigureAwait(false); - var tagHelperCount = tagHelpers.Count(); + var tagHelperCount = tagHelpers.Length; var shouldReport = false; ImmutableInterlocked.AddOrUpdate( From 295d4821ff607609e0a03876663c87c19cc8f458 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 17 Dec 2024 18:27:49 -0800 Subject: [PATCH 32/42] Compute test span correctly --- .../RazorDiagnosticsPublisherTest.cs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs index 74d0b684277..8cf66a9058b 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs @@ -55,7 +55,7 @@ public class RazorDiagnosticsPublisherTest : LanguageServerTestBase """); - private static readonly SourceText s_razorTextWithError = SourceText.From(""" + private static readonly TestCode s_razorTestCodeWithError = """ @using Microsoft.AspNetCore.Components.Forms; @code { @@ -67,18 +67,18 @@ public class RazorDiagnosticsPublisherTest : LanguageServerTestBase @if (true) { - - """); + """; + + private static readonly SourceText s_razorTextWithError = SourceText.From(s_razorTestCodeWithError.Text); private static readonly RazorDiagnostic[] s_singleRazorDiagnostic = [ - RazorDiagnosticFactory.CreateParsing_MissingEndTag( - new SourceSpan(s_openHostDocument.FilePath, absoluteIndex: 216, lineIndex: 11, characterIndex: 17, length: 6, lineCount: 1, endCharacterIndex: 0), - "option") + RazorDiagnosticFactory.CreateParsing_MissingEndTag(GetErrorSpan(s_openHostDocument.FilePath, s_razorTextWithError, s_razorTestCodeWithError), "option") ]; private static readonly Diagnostic[] s_singleCSharpDiagnostic = @@ -112,6 +112,14 @@ await _projectManager.UpdateAsync(updater => }); } + private static SourceSpan GetErrorSpan(string filePath, SourceText text, TestCode testCode) + { + var span = testCode.Span; + var location = new SourceLocation(filePath, span.Start, text.GetLinePosition(span.Start)); + + return new SourceSpan(location, span.Length); + } + private Task UpdateWithErrorTextAsync() { return _projectManager.UpdateAsync(updater => From 74167ba6645dea84155560ce5b6b8cacc779bc14 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Wed, 18 Dec 2024 04:20:05 -0800 Subject: [PATCH 33/42] Double-checked lock --- .../ProjectSystem/Sources/GeneratedOutputSource.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs index e2265579f25..487dada6cb4 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/Sources/GeneratedOutputSource.cs @@ -12,6 +12,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem.Sources; internal sealed class GeneratedOutputSource { private readonly SemaphoreSlim _gate = new(initialCount: 1); + private RazorCodeDocument? _output; public bool TryGetValue([NotNullWhen(true)] out RazorCodeDocument? result) @@ -29,6 +30,11 @@ public async ValueTask GetValueAsync(DocumentSnapshot documen using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { + if (TryGetValue(out result)) + { + return result; + } + var project = document.Project; var projectEngine = project.ProjectEngine; var compilerOptions = project.CompilerOptions; From 670eae2ce5bfba280609c3dfcc166b28af963a35 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Wed, 18 Dec 2024 04:21:25 -0800 Subject: [PATCH 34/42] Fix comment --- .../ProjectSystem/RemoteProjectSnapshot.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5c90c69de68..b20805c91df 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/ProjectSystem/RemoteProjectSnapshot.cs @@ -159,7 +159,7 @@ public bool TryGetDocument(string filePath, [NotNullWhen(true)] out IDocumentSna } /// - /// NOTE: This will be removed when that method uses the source generator directly. + /// NOTE: This will be removed when the source generator is used directly. /// public ValueTask GetProjectEngineAsync(CancellationToken cancellationToken) { From f28f239c15b08048d9913dbf2f1e593fbad029cf Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Wed, 18 Dec 2024 04:27:38 -0800 Subject: [PATCH 35/42] Remove unused method --- .../ProjectSystem/CompilationHelpers.cs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs index 22ba0b276bc..4b6cdce04e3 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/CompilationHelpers.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectSystem; @@ -12,21 +11,6 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; internal static class CompilationHelpers { - internal static RazorCodeDocument GenerateCodeDocument( - RazorProjectEngine projectEngine, - RazorCompilerOptions compilerOptions, - RazorSourceDocument source, - string fileKind, - ImmutableArray importSources, - ImmutableArray tagHelpers) - { - var forceRuntimeCodeGeneration = compilerOptions.IsFlagSet(RazorCompilerOptions.ForceRuntimeCodeGeneration); - - return forceRuntimeCodeGeneration - ? projectEngine.Process(source, fileKind, importSources, tagHelpers) - : projectEngine.ProcessDesignTime(source, fileKind, importSources, tagHelpers); - } - internal static async Task GenerateCodeDocumentAsync( IDocumentSnapshot document, RazorProjectEngine projectEngine, From 284c7d7af27fa28bd93144a50de9c059e52cb3cf Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Wed, 18 Dec 2024 14:56:46 -0800 Subject: [PATCH 36/42] Rename method to ProjectState.UpdateRelatedDocumentsIfNecessary --- .../ProjectSystem/ProjectState.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs index 28ede34a5cb..edfec5a2a33 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs @@ -185,7 +185,7 @@ private ProjectState AddDocument(DocumentState state) var importsToRelatedDocuments = AddToImportsToRelatedDocuments(hostDocument); // Then, if this is an import, update any related documents. - documents = UpdateRelatedDocuments(hostDocument, documents); + documents = UpdateRelatedDocumentsIfNecessary(hostDocument, documents); return new(this, HostProject, ProjectWorkspaceState, documents, importsToRelatedDocuments, retainProjectEngine: true); } @@ -204,7 +204,7 @@ public ProjectState RemoveDocument(string documentFilePath) var documents = Documents.Remove(documentFilePath); // If this is an import, update any related documents. - documents = UpdateRelatedDocuments(hostDocument, documents); + documents = UpdateRelatedDocumentsIfNecessary(hostDocument, documents); // Then, compute the effect on the import map var importsToRelatedDocuments = RemoveFromImportsToRelatedDocuments(hostDocument); @@ -259,7 +259,7 @@ private ProjectState WithDocumentText(DocumentState state, Func UpdateDocuments(Func UpdateRelatedDocuments(HostDocument hostDocument, ImmutableDictionary documents) + private ImmutableDictionary UpdateRelatedDocumentsIfNecessary(HostDocument hostDocument, ImmutableDictionary documents) { if (!ImportsToRelatedDocuments.TryGetValue(hostDocument.TargetPath, out var relatedDocuments)) { From f952c9b526ede5176e8073e47bf9f5ede15548a1 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Wed, 18 Dec 2024 15:03:56 -0800 Subject: [PATCH 37/42] Delete unused ExtractToComponentResolverDocumentContextFactory --- ...ToComponentCodeActionResolverTest.NetFx.cs | 78 ------------------- 1 file changed, 78 deletions(-) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToComponentCodeActionResolverTest.NetFx.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToComponentCodeActionResolverTest.NetFx.cs index 6f9af678921..a3b9e0d4f3a 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToComponentCodeActionResolverTest.NetFx.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToComponentCodeActionResolverTest.NetFx.cs @@ -3,20 +3,13 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.Language.Components; using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; using Microsoft.AspNetCore.Razor.LanguageServer.Formatting; -using Microsoft.AspNetCore.Razor.ProjectSystem; -using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; -using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.CodeActions.Razor; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Testing; using Microsoft.VisualStudio.LanguageServer.Protocol; using Roslyn.Test.Utilities; @@ -343,75 +336,4 @@ private async Task TestAsync( var documentText = sourceText.WithChanges(originalDocumentEdits).ToString(); AssertEx.EqualOrDiff(expectedOriginalDocument, documentText); } - - private class ExtractToComponentResolverDocumentContextFactory : TestDocumentContextFactory - { - private readonly List _tagHelperDescriptors; - - public ExtractToComponentResolverDocumentContextFactory - (string filePath, - RazorCodeDocument codeDocument, - TagHelperDescriptor[]? tagHelpers = null) - : base(filePath, codeDocument) - { - _tagHelperDescriptors = CreateTagHelperDescriptors(); - if (tagHelpers is not null) - { - _tagHelperDescriptors.AddRange(tagHelpers); - } - } - - public override bool TryCreate( - Uri documentUri, - VSProjectContext? projectContext, - [NotNullWhen(true)] out DocumentContext? context) - { - if (FilePath is null || CodeDocument is null) - { - context = null; - return false; - } - - var projectWorkspaceState = ProjectWorkspaceState.Create(_tagHelperDescriptors.ToImmutableArray()); - var testDocumentSnapshot = TestDocumentSnapshot.Create(FilePath, CodeDocument, projectWorkspaceState); - - context = CreateDocumentContext(new Uri(FilePath), testDocumentSnapshot); - return true; - } - - private static List CreateTagHelperDescriptors() - { - return BuildTagHelpers().ToList(); - - static IEnumerable BuildTagHelpers() - { - var builder = TagHelperDescriptorBuilder.Create("oncontextmenu", "Microsoft.AspNetCore.Components"); - builder.SetMetadata( - new KeyValuePair(ComponentMetadata.EventHandler.EventArgsType, "Microsoft.AspNetCore.Components.Web.MouseEventArgs"), - new KeyValuePair(ComponentMetadata.SpecialKindKey, ComponentMetadata.EventHandler.TagHelperKind)); - yield return builder.Build(); - - builder = TagHelperDescriptorBuilder.Create("onclick", "Microsoft.AspNetCore.Components"); - builder.SetMetadata( - new KeyValuePair(ComponentMetadata.EventHandler.EventArgsType, "Microsoft.AspNetCore.Components.Web.MouseEventArgs"), - new KeyValuePair(ComponentMetadata.SpecialKindKey, ComponentMetadata.EventHandler.TagHelperKind)); - - yield return builder.Build(); - - builder = TagHelperDescriptorBuilder.Create("oncopy", "Microsoft.AspNetCore.Components"); - builder.SetMetadata( - new KeyValuePair(ComponentMetadata.EventHandler.EventArgsType, "Microsoft.AspNetCore.Components.Web.ClipboardEventArgs"), - new KeyValuePair(ComponentMetadata.SpecialKindKey, ComponentMetadata.EventHandler.TagHelperKind)); - - yield return builder.Build(); - - builder = TagHelperDescriptorBuilder.Create("ref", "Microsoft.AspNetCore.Components"); - builder.SetMetadata( - new KeyValuePair(ComponentMetadata.SpecialKindKey, ComponentMetadata.Ref.TagHelperKind), - new KeyValuePair(ComponentMetadata.Common.DirectiveAttribute, bool.TrueString)); - - yield return builder.Build(); - } - } - } } From 1deb4a0bc77c19d5cf426864017d0a95acd1da8a Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Wed, 18 Dec 2024 15:15:39 -0800 Subject: [PATCH 38/42] Remove all but one ProjectState.Create(...) factory method --- .../ProjectSystem/ProjectState.cs | 24 +--- .../ProjectEngineFactoryProviderTest.cs | 12 +- .../ProjectSystem/TestProjectSnapshot.cs | 8 +- ...SnapshotTest.cs => ProjectSnapshotTest.cs} | 62 +++++---- .../ProjectStateGeneratedOutputTest.cs | 3 +- .../ProjectSystem/ProjectStateTest.cs | 121 ++++++++++++------ 6 files changed, 128 insertions(+), 102 deletions(-) rename src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/{DefaultProjectSnapshotTest.cs => ProjectSnapshotTest.cs} (53%) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs index edfec5a2a33..2298dcaf328 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs @@ -47,12 +47,11 @@ private static readonly ImmutableHashSet s_emptyRelatedDocuments private ProjectState( HostProject hostProject, - ProjectWorkspaceState projectWorkspaceState, RazorCompilerOptions compilerOptions, IProjectEngineFactoryProvider projectEngineFactoryProvider) { HostProject = hostProject; - ProjectWorkspaceState = projectWorkspaceState; + ProjectWorkspaceState = ProjectWorkspaceState.Default; CompilerOptions = compilerOptions; _projectEngineFactoryProvider = projectEngineFactoryProvider; @@ -84,28 +83,9 @@ private ProjectState( public static ProjectState Create( HostProject hostProject, - ProjectWorkspaceState projectWorkspaceState, RazorCompilerOptions compilerOptions, IProjectEngineFactoryProvider projectEngineFactoryProvider) - => new(hostProject, projectWorkspaceState, compilerOptions, projectEngineFactoryProvider); - - public static ProjectState Create(HostProject hostProject, ProjectWorkspaceState projectWorkspaceState) - => new(hostProject, projectWorkspaceState, RazorCompilerOptions.None, ProjectEngineFactories.DefaultProvider); - - public static ProjectState Create( - HostProject hostProject, - ProjectWorkspaceState projectWorkspaceState, - IProjectEngineFactoryProvider projectEngineFactoryProvider) - => new(hostProject, projectWorkspaceState, RazorCompilerOptions.None, projectEngineFactoryProvider); - - public static ProjectState Create( - HostProject hostProject, - RazorCompilerOptions compilerOptions, - IProjectEngineFactoryProvider projectEngineFactoryProvider) - => new(hostProject, ProjectWorkspaceState.Default, compilerOptions, projectEngineFactoryProvider); - - public static ProjectState Create(HostProject hostProject) - => new(hostProject, ProjectWorkspaceState.Default, RazorCompilerOptions.None, ProjectEngineFactories.DefaultProvider); + => new(hostProject, compilerOptions, projectEngineFactoryProvider); public ImmutableArray TagHelpers => ProjectWorkspaceState.TagHelpers; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs index b9272a84492..c63510611e0 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.ProjectEngineHost.Test/ProjectEngineFactoryProviderTest.cs @@ -49,12 +49,12 @@ public ProjectEngineFactoryProviderTest(ITestOutputHelper testOutput) projectFilePath, intermediateOutputPath, new(RazorLanguageVersion.Version_2_1, "Random-0.1", Extensions: []), rootNamespace: null); - _snapshot_For_1_0 = new ProjectSnapshot(ProjectState.Create(hostProject_For_1_0)); - _snapshot_For_1_1 = new ProjectSnapshot(ProjectState.Create(hostProject_For_1_1)); - _snapshot_For_2_0 = new ProjectSnapshot(ProjectState.Create(hostProject_For_2_0)); - _snapshot_For_2_1 = new ProjectSnapshot(ProjectState.Create(hostProject_For_2_1)); - _snapshot_For_3_0 = new ProjectSnapshot(ProjectState.Create(hostProject_For_3_0)); - _snapshot_For_UnknownConfiguration = new ProjectSnapshot(ProjectState.Create(hostProject_For_UnknownConfiguration)); + _snapshot_For_1_0 = new ProjectSnapshot(ProjectState.Create(hostProject_For_1_0, RazorCompilerOptions.None, ProjectEngineFactories.DefaultProvider)); + _snapshot_For_1_1 = new ProjectSnapshot(ProjectState.Create(hostProject_For_1_1, RazorCompilerOptions.None, ProjectEngineFactories.DefaultProvider)); + _snapshot_For_2_0 = new ProjectSnapshot(ProjectState.Create(hostProject_For_2_0, RazorCompilerOptions.None, ProjectEngineFactories.DefaultProvider)); + _snapshot_For_2_1 = new ProjectSnapshot(ProjectState.Create(hostProject_For_2_1, RazorCompilerOptions.None, ProjectEngineFactories.DefaultProvider)); + _snapshot_For_3_0 = new ProjectSnapshot(ProjectState.Create(hostProject_For_3_0, RazorCompilerOptions.None, ProjectEngineFactories.DefaultProvider)); + _snapshot_For_UnknownConfiguration = new ProjectSnapshot(ProjectState.Create(hostProject_For_UnknownConfiguration, RazorCompilerOptions.None, ProjectEngineFactories.DefaultProvider)); _customFactories = [ diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs index 6000edc05bf..d7e22b1143c 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/ProjectSystem/TestProjectSnapshot.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.ProjectEngineHost; using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -25,7 +26,12 @@ private TestProjectSnapshot(ProjectState state) public static TestProjectSnapshot Create(string filePath, ProjectWorkspaceState? projectWorkspaceState = null) { var hostProject = TestHostProject.Create(filePath); - var state = ProjectState.Create(hostProject, projectWorkspaceState ?? ProjectWorkspaceState.Default); + var state = ProjectState.Create(hostProject, RazorCompilerOptions.None, ProjectEngineFactories.DefaultProvider); + + if (projectWorkspaceState is not null) + { + state = state.WithProjectWorkspaceState(projectWorkspaceState); + } return new TestProjectSnapshot(state); } diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectSnapshotTest.cs similarity index 53% rename from src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs rename to src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectSnapshotTest.cs index 0b0e5c0dbc4..c2928efe967 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultProjectSnapshotTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectSnapshotTest.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System.Collections.Immutable; using System.Linq; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectSystem; @@ -12,28 +11,19 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; -public class DefaultProjectSnapshotTest : WorkspaceTestBase +public class ProjectSnapshotTest(ITestOutputHelper testOutput) : WorkspaceTestBase(testOutput) { - private readonly HostDocument[] _documents; - private readonly HostProject _hostProject; - private readonly ProjectWorkspaceState _projectWorkspaceState; + private static readonly HostProject s_hostProject = TestProjectData.SomeProject with { Configuration = FallbackRazorConfiguration.MVC_2_0 }; + private static readonly ProjectWorkspaceState s_projectWorkspaceState = ProjectWorkspaceState.Create([TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly").Build()]); - public DefaultProjectSnapshotTest(ITestOutputHelper testOutput) - : base(testOutput) - { - _hostProject = TestProjectData.SomeProject with { Configuration = FallbackRazorConfiguration.MVC_2_0 }; - _projectWorkspaceState = ProjectWorkspaceState.Create(ImmutableArray.Create( - TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly").Build())); - - _documents = - [ - TestProjectData.SomeProjectFile1, - TestProjectData.SomeProjectFile2, - - // linked file - TestProjectData.AnotherProjectNestedFile3, - ]; - } + private static readonly HostDocument[] s_documents = + [ + TestProjectData.SomeProjectFile1, + TestProjectData.SomeProjectFile2, + + // linked file + TestProjectData.AnotherProjectNestedFile3, + ]; protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder) { @@ -44,10 +34,12 @@ protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder public void ProjectSnapshot_CachesDocumentSnapshots() { // Arrange - var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddEmptyDocument(_documents[0]) - .AddEmptyDocument(_documents[1]) - .AddEmptyDocument(_documents[2]); + var state = ProjectState.Create(s_hostProject, CompilerOptions, ProjectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) + .AddEmptyDocument(s_documents[0]) + .AddEmptyDocument(s_documents[1]) + .AddEmptyDocument(s_documents[2]); + var snapshot = new ProjectSnapshot(state); // Act @@ -65,11 +57,13 @@ public void ProjectSnapshot_CachesDocumentSnapshots() public void GetRelatedDocuments_NonImportDocument_ReturnsEmpty() { // Arrange - var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddEmptyDocument(_documents[0]); + var state = ProjectState.Create(s_hostProject, CompilerOptions, ProjectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) + .AddEmptyDocument(s_documents[0]); + var snapshot = new ProjectSnapshot(state); - var document = snapshot.GetRequiredDocument(_documents[0].FilePath); + var document = snapshot.GetRequiredDocument(s_documents[0].FilePath); // Act var documents = snapshot.GetRelatedDocuments(document); @@ -82,10 +76,12 @@ public void GetRelatedDocuments_NonImportDocument_ReturnsEmpty() public void GetRelatedDocuments_ImportDocument_ReturnsRelated() { // Arrange - var state = ProjectState.Create(_hostProject, _projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) - .AddEmptyDocument(_documents[0]) - .AddEmptyDocument(_documents[1]) + var state = ProjectState.Create(s_hostProject, CompilerOptions, ProjectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) + .AddEmptyDocument(s_documents[0]) + .AddEmptyDocument(s_documents[1]) .AddEmptyDocument(TestProjectData.SomeProjectImportFile); + var snapshot = new ProjectSnapshot(state); var document = snapshot.GetRequiredDocument(TestProjectData.SomeProjectImportFile.FilePath); @@ -96,7 +92,7 @@ public void GetRelatedDocuments_ImportDocument_ReturnsRelated() // Assert Assert.Collection( documents.OrderBy(d => d.FilePath), - d => Assert.Equal(_documents[0].FilePath, d.FilePath), - d => Assert.Equal(_documents[1].FilePath, d.FilePath)); + d => Assert.Equal(s_documents[0].FilePath, d.FilePath), + d => Assert.Equal(s_documents[1].FilePath, d.FilePath)); } } diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs index 3b4e91e6932..e23cccaeeee 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateGeneratedOutputTest.cs @@ -178,7 +178,8 @@ public async Task WithProjectWorkspaceState_CSharpLanguageVersionChange_DoesNotC var projectWorkspaceState = ProjectWorkspaceState.Create(_someTagHelpers, LanguageVersion.CSharp7); var state = ProjectState - .Create(hostProject, projectWorkspaceState, CompilerOptions, ProjectEngineFactoryProvider) + .Create(hostProject, CompilerOptions, ProjectEngineFactoryProvider) + .WithProjectWorkspaceState(projectWorkspaceState) .AddDocument(_hostDocument, TestMocks.CreateTextLoader("@DateTime.Now", VersionStamp.Default)); var output = await GetGeneratedOutputAsync(state, _hostDocument); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs index a917910c7bc..854b3d503ef 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/ProjectStateTest.cs @@ -36,7 +36,9 @@ public class ProjectStateTest(ITestOutputHelper testOutput) : ToolingTestBase(te public void GetImportDocumentTargetPaths_DoesNotIncludeCurrentImport() { // Arrange - var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider); + var state = ProjectState + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState); // Act var paths = state.GetImportDocumentTargetPaths(SomeProjectComponentImportFile1); @@ -49,7 +51,9 @@ public void GetImportDocumentTargetPaths_DoesNotIncludeCurrentImport() public void ProjectState_ConstructedNew() { // Arrange & Act - var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider); + var state = ProjectState + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState); // Assert Assert.Empty(state.Documents); @@ -59,7 +63,9 @@ public void ProjectState_ConstructedNew() public void ProjectState_AddDocument_ToEmpty() { // Arrange - var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider); + var state = ProjectState + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState); // Act var newState = state.AddEmptyDocument(SomeProjectFile1); @@ -73,7 +79,9 @@ public void ProjectState_AddDocument_ToEmpty() public async Task ProjectState_AddDocument_DocumentIsEmpty() { // Arrange - var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider); + var state = ProjectState + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState); // Act var newState = state.AddEmptyDocument(SomeProjectFile1); @@ -88,7 +96,8 @@ public void ProjectState_AddDocument_ToProjectWithDocuments() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -108,7 +117,8 @@ public void ProjectState_AddDocument_TracksImports() { // Arrange & Act var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(SomeProjectFile1) .AddEmptyDocument(SomeProjectFile2) .AddEmptyDocument(SomeProjectNestedFile3) @@ -146,7 +156,8 @@ public void ProjectState_AddDocument_TracksImports_AddImportFile() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(SomeProjectFile1) .AddEmptyDocument(SomeProjectFile2) .AddEmptyDocument(SomeProjectNestedFile3) @@ -187,7 +198,8 @@ public void ProjectState_AddDocument_RetainsComputedState() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -206,7 +218,8 @@ public void ProjectState_AddDocument_DuplicateIgnored() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -222,7 +235,8 @@ public async Task ProjectState_WithDocumentText_Loader() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -239,7 +253,8 @@ public async Task ProjectState_WithDocumentText_Snapshot() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -256,7 +271,8 @@ public void ProjectState_WithDocumentText_Loader_RetainsComputedState() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -273,18 +289,19 @@ public void ProjectState_WithDocumentText_Loader_RetainsComputedState() public void ProjectState_WithDocumentText_Snapshot_RetainsComputedState() { // Arrange - var original = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + var state = ProjectState + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); // Act - var state = original.WithDocumentText(SomeProjectFile2.FilePath, s_text); + var newState = state.WithDocumentText(SomeProjectFile2.FilePath, s_text); // Assert - Assert.Same(original.ProjectEngine, state.ProjectEngine); - AssertSameTagHelpers(original.TagHelpers, state.TagHelpers); - Assert.NotSame(original.Documents[SomeProjectFile2.FilePath], state.Documents[SomeProjectFile2.FilePath]); + Assert.Same(state.ProjectEngine, newState.ProjectEngine); + AssertSameTagHelpers(state.TagHelpers, newState.TagHelpers); + Assert.NotSame(state.Documents[SomeProjectFile2.FilePath], newState.Documents[SomeProjectFile2.FilePath]); } [Fact] @@ -292,7 +309,8 @@ public void ProjectState_WithDocumentText_Loader_NotFoundIgnored() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -308,7 +326,8 @@ public void ProjectState_WithDocumentText_Snapshot_NotFoundIgnored() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -324,7 +343,8 @@ public void ProjectState_RemoveDocument_FromProjectWithDocuments() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -341,7 +361,8 @@ public void ProjectState_RemoveDocument_TracksImports() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(SomeProjectFile1) .AddEmptyDocument(SomeProjectFile2) .AddEmptyDocument(SomeProjectNestedFile3) @@ -380,7 +401,8 @@ public void ProjectState_RemoveDocument_TracksImports_RemoveAllDocuments() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(SomeProjectFile1) .AddEmptyDocument(SomeProjectFile2) .AddEmptyDocument(SomeProjectNestedFile3) @@ -403,7 +425,8 @@ public void ProjectState_RemoveDocument_RetainsComputedState() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -421,7 +444,8 @@ public void ProjectState_RemoveDocument_NotFoundIgnored() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -437,7 +461,8 @@ public void ProjectState_WithHostProject_ConfigurationChange_UpdatesConfiguratio { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -459,7 +484,8 @@ public void ProjectState_WithHostProject_RootNamespaceChange_UpdatesConfiguratio { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -476,7 +502,8 @@ public void ProjectState_WithHostProject_NoConfigurationChange_Ignored() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -492,7 +519,8 @@ public void ProjectState_WithConfiguration_Change_UpdatesAllDocuments() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(SomeProjectFile2) .AddEmptyDocument(AnotherProjectNestedFile3); @@ -520,7 +548,8 @@ public void ProjectState_WithConfiguration_Change_ResetsImportMap() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(SomeProjectFile1); // Act @@ -537,7 +566,8 @@ public void ProjectState_WithProjectWorkspaceState_Changed() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -562,7 +592,8 @@ public void ProjectState_WithProjectWorkspaceState_Changed_TagHelpersChanged() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -583,7 +614,9 @@ public void ProjectState_WithProjectWorkspaceState_Changed_TagHelpersChanged() public void ProjectState_WithProjectWorkspaceState_IdenticalState_Caches() { // Arrange - var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + var state = ProjectState + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(AnotherProjectNestedFile3) .AddEmptyDocument(SomeProjectFile2); @@ -599,7 +632,8 @@ public void ProjectState_WithProjectWorkspaceState_UpdatesAllDocuments() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(SomeProjectFile2) .AddEmptyDocument(AnotherProjectNestedFile3); @@ -627,7 +661,9 @@ public void ProjectState_WithProjectWorkspaceState_UpdatesAllDocuments() public void ProjectState_AddImportDocument_UpdatesRelatedDocuments() { // Arrange - var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + var state = ProjectState + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(SomeProjectFile1) .AddEmptyDocument(SomeProjectFile2) .AddEmptyDocument(SomeProjectNestedFile3) @@ -658,7 +694,9 @@ public void ProjectState_AddImportDocument_UpdatesRelatedDocuments() public void ProjectState_AddImportDocument_UpdatesRelatedDocuments_Nested() { // Arrange - var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + var state = ProjectState + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(SomeProjectFile1) .AddEmptyDocument(SomeProjectFile2) .AddEmptyDocument(SomeProjectNestedFile3) @@ -694,7 +732,9 @@ public void ProjectState_AddImportDocument_UpdatesRelatedDocuments_Nested() public void ProjectState_WithImportDocumentText_UpdatesRelatedDocuments_TextLoader() { // Arrange - var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + var state = ProjectState + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(SomeProjectFile1) .AddEmptyDocument(SomeProjectFile2) .AddEmptyDocument(SomeProjectNestedFile3) @@ -735,7 +775,9 @@ public void ProjectState_WithImportDocumentText_UpdatesRelatedDocuments_TextLoad public void ProjectState_WithImportDocumentText_UpdatesRelatedDocuments_Snapshot() { // Arrange - var state = ProjectState.Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + var state = ProjectState + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(SomeProjectFile1) .AddEmptyDocument(SomeProjectFile2) .AddEmptyDocument(SomeProjectNestedFile3) @@ -777,7 +819,8 @@ public void ProjectState_RemoveImportDocument_UpdatesRelatedDocuments() { // Arrange var state = ProjectState - .Create(s_hostProject, s_projectWorkspaceState, s_projectEngineFactoryProvider) + .Create(s_hostProject, RazorCompilerOptions.None, s_projectEngineFactoryProvider) + .WithProjectWorkspaceState(s_projectWorkspaceState) .AddEmptyDocument(SomeProjectFile1) .AddEmptyDocument(SomeProjectFile2) .AddEmptyDocument(SomeProjectNestedFile3) From d35e12170e364236f686bd17f4dcd5deb4a3bbf4 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Wed, 18 Dec 2024 15:24:44 -0800 Subject: [PATCH 39/42] RazorProjectService: Use TryGetDocument rather than pattern matching --- .../ProjectSystem/RazorProjectService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs index 393050c39b2..49ce3b31c7a 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs @@ -246,7 +246,7 @@ await _projectManager.UpdateAsync( return; } - if (projectSnapshot.GetDocument(textDocumentPath) is not DocumentSnapshot documentSnapshot) + if (!projectSnapshot.TryGetDocument(textDocumentPath, out var documentSnapshot)) { _logger.LogError($"Containing project does not contain document '{textDocumentPath}'"); return; @@ -438,7 +438,7 @@ private void UpdateProjectDocuments( continue; } - if (project.GetDocument(documentFilePath) is not DocumentSnapshot documentSnapshot) + if (!project.TryGetDocument(documentFilePath, out var documentSnapshot)) { continue; } @@ -505,7 +505,7 @@ private void MoveDocument( Debug.Assert(fromProject.ContainsDocument(documentFilePath)); Debug.Assert(!toProject.ContainsDocument(documentFilePath)); - if (fromProject.GetDocument(documentFilePath) is not DocumentSnapshot documentSnapshot) + if (!fromProject.TryGetDocument(documentFilePath, out var documentSnapshot)) { return; } From b51fabc5cc74c3ab39ae58585fc465083aa22f7f Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Wed, 18 Dec 2024 15:27:55 -0800 Subject: [PATCH 40/42] RazorProjectService: Rename for consistency throughout --- .../ProjectSystem/RazorProjectService.cs | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs index 49ce3b31c7a..f107b1f5042 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs @@ -198,10 +198,10 @@ await _projectManager.UpdateAsync( ActOnDocumentInMultipleProjects( filePath, - (projectSnapshot, textDocumentPath) => + (project, textDocumentPath) => { - _logger.LogInformation($"Opening document '{textDocumentPath}' in project '{projectSnapshot.Key}'."); - updater.OpenDocument(projectSnapshot.Key, textDocumentPath, sourceText); + _logger.LogInformation($"Opening document '{textDocumentPath}' in project '{project.Key}'."); + updater.OpenDocument(project.Key, textDocumentPath, sourceText); }); }, cancellationToken) @@ -217,12 +217,12 @@ await _projectManager.UpdateAsync( { ActOnDocumentInMultipleProjects( filePath, - (projectSnapshot, textDocumentPath) => + (project, textDocumentPath) => { var textLoader = _remoteTextLoaderFactory.Create(filePath); - _logger.LogInformation($"Closing document '{textDocumentPath}' in project '{projectSnapshot.Key}'."); + _logger.LogInformation($"Closing document '{textDocumentPath}' in project '{project.Key}'."); - updater.CloseDocument(projectSnapshot.Key, textDocumentPath, textLoader); + updater.CloseDocument(project.Key, textDocumentPath, textLoader); }); }, cancellationToken) @@ -238,15 +238,15 @@ await _projectManager.UpdateAsync( { ActOnDocumentInMultipleProjects( filePath, - (projectSnapshot, textDocumentPath) => + (project, textDocumentPath) => { - if (!projectSnapshot.DocumentFilePaths.Contains(textDocumentPath, FilePathComparer.Instance)) + if (!project.DocumentFilePaths.Contains(textDocumentPath, FilePathComparer.Instance)) { _logger.LogInformation($"Containing project is not tracking document '{textDocumentPath}'"); return; } - if (!projectSnapshot.TryGetDocument(textDocumentPath, out var documentSnapshot)) + if (!project.TryGetDocument(textDocumentPath, out var document)) { _logger.LogError($"Containing project does not contain document '{textDocumentPath}'"); return; @@ -257,18 +257,18 @@ await _projectManager.UpdateAsync( // a remove via the project.razor.bin if (_projectManager.IsDocumentOpen(textDocumentPath)) { - _logger.LogInformation($"Moving document '{textDocumentPath}' from project '{projectSnapshot.Key}' to misc files because it is open."); - if (!projectSnapshot.IsMiscellaneousProject()) + _logger.LogInformation($"Moving document '{textDocumentPath}' from project '{project.Key}' to misc files because it is open."); + if (!project.IsMiscellaneousProject()) { var miscellaneousProject = _projectManager.GetMiscellaneousProject(); - MoveDocument(updater, textDocumentPath, fromProject: projectSnapshot, toProject: miscellaneousProject); + MoveDocument(updater, textDocumentPath, fromProject: project, toProject: miscellaneousProject); } } else { - _logger.LogInformation($"Removing document '{textDocumentPath}' from project '{projectSnapshot.Key}'."); + _logger.LogInformation($"Removing document '{textDocumentPath}' from project '{project.Key}'."); - updater.RemoveDocument(projectSnapshot.Key, documentSnapshot.FilePath); + updater.RemoveDocument(project.Key, document.FilePath); } }); }, @@ -438,12 +438,12 @@ private void UpdateProjectDocuments( continue; } - if (!project.TryGetDocument(documentFilePath, out var documentSnapshot)) + if (!project.TryGetDocument(documentFilePath, out var document)) { continue; } - var currentHostDocument = documentSnapshot.HostDocument; + var currentHostDocument = document.HostDocument; var newFilePath = EnsureFullPath(documentHandle.FilePath, projectDirectory); var newHostDocument = new HostDocument(newFilePath, documentHandle.TargetPath, documentHandle.FileKind); @@ -459,7 +459,7 @@ private void UpdateProjectDocuments( // it has received text change info from LSP. eg, if someone changes the TargetPath of the file while its open in the editor // with unsaved changes, we don't want to reload it from disk. var textLoader = FilePathComparer.Instance.Equals(currentHostDocument.FilePath, newHostDocument.FilePath) - ? new DocumentSnapshotTextLoader(documentSnapshot) + ? new DocumentSnapshotTextLoader(document) : _remoteTextLoaderFactory.Create(newFilePath); updater.RemoveDocument(currentProjectKey, currentHostDocument.FilePath); @@ -505,26 +505,26 @@ private void MoveDocument( Debug.Assert(fromProject.ContainsDocument(documentFilePath)); Debug.Assert(!toProject.ContainsDocument(documentFilePath)); - if (!fromProject.TryGetDocument(documentFilePath, out var documentSnapshot)) + if (!fromProject.TryGetDocument(documentFilePath, out var document)) { return; } - var currentHostDocument = documentSnapshot.HostDocument; + var currentHostDocument = document.HostDocument; - var textLoader = new DocumentSnapshotTextLoader(documentSnapshot); + var textLoader = new DocumentSnapshotTextLoader(document); // If we're moving from the misc files project to a real project, then target path will be the full path to the file // and the next update to the project will update it to be a relative path. To save a bunch of busy work if that is // the only change necessary, we can proactively do that work here. var projectDirectory = FilePathNormalizer.GetNormalizedDirectoryName(toProject.FilePath); - var newTargetPath = documentSnapshot.TargetPath; + var newTargetPath = document.TargetPath; if (FilePathNormalizer.Normalize(newTargetPath).StartsWith(projectDirectory)) { newTargetPath = newTargetPath[projectDirectory.Length..]; } - var newHostDocument = new HostDocument(documentSnapshot.FilePath, newTargetPath, documentSnapshot.FileKind); + var newHostDocument = new HostDocument(document.FilePath, newTargetPath, document.FileKind); _logger.LogInformation($"Moving '{documentFilePath}' from the '{fromProject.Key}' project to '{toProject.Key}' project."); From f3fed12ae7806361a0c762e21067c01f353dca61 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Wed, 18 Dec 2024 15:29:00 -0800 Subject: [PATCH 41/42] ProjectState: Don't perform string replacements unless necessary --- .../ProjectSystem/ProjectState.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs index 2298dcaf328..5ae8d2fbbec 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs @@ -436,8 +436,6 @@ private static void CollectImportDocumentTargetPaths(HostDocument hostDocument, continue; } - var itemTargetPath = filePath.Replace('/', '\\').TrimStart('\\'); - if (FilePathNormalizer.AreFilePathsEquivalent(filePath, targetPath)) { // We've normalized the original importItem.FilePath into the HostDocument.TargetPath. For instance, if the HostDocument.TargetPath @@ -446,6 +444,8 @@ private static void CollectImportDocumentTargetPaths(HostDocument hostDocument, continue; } + var itemTargetPath = filePath.Replace('/', '\\').TrimStart('\\'); + targetPaths.Add(itemTargetPath); } } From f9096fe0c9dce94a5206278939878e8514299bf3 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Mon, 6 Jan 2025 14:37:28 -0800 Subject: [PATCH 42/42] Move FORMAT_FUSE constant to Directory.Build.props Changes in this PR caused the number of projects needing to compile with FORMAT_FUSE from two to four. So, this change pushes FORMAT_FUSE into Directory.Build.props to avoid needing to update four project files. --- Directory.Build.props | 3 +++ .../Microsoft.CodeAnalysis.Razor.Workspaces.csproj | 3 --- .../Microsoft.CodeAnalysis.Remote.Razor.csproj | 3 --- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 164c3653794..8c293b9a383 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -44,6 +44,9 @@ true net472 + + + - diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Microsoft.CodeAnalysis.Remote.Razor.csproj b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Microsoft.CodeAnalysis.Remote.Razor.csproj index 360208de1c6..981af5285e5 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Microsoft.CodeAnalysis.Remote.Razor.csproj +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Microsoft.CodeAnalysis.Remote.Razor.csproj @@ -8,9 +8,6 @@ true false - - -