Revert "Update project configuration from Roslyn info (#11092)"

This reverts commit a37ee126f8, reversing
changes made to ad74439384.
This commit is contained in:
David Wengier 2024-11-06 08:27:12 +11:00
Родитель c5babf1368
Коммит c9391637d8
44 изменённых файлов: 308 добавлений и 260 удалений

Просмотреть файл

@ -1,13 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
namespace Microsoft.CodeAnalysis.Razor.Compiler.CSharp;
internal static class ParseOptionsExtensions
{
public static bool UseRoslynTokenizer(this ParseOptions parseOptions)
=> parseOptions.Features.TryGetValue("use-roslyn-tokenizer", out var useRoslynTokenizerValue)
&& string.Equals(useRoslynTokenizerValue, "true", StringComparison.OrdinalIgnoreCase);
}

Просмотреть файл

@ -3,7 +3,6 @@
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Razor.Language;
@ -14,14 +13,15 @@ public sealed record class RazorConfiguration(
ImmutableArray<RazorExtension> Extensions,
bool UseConsolidatedMvcViews = true,
bool SuppressAddComponentParameter = false,
LanguageServerFlags? LanguageServerFlags = null,
bool UseRoslynTokenizer = false,
LanguageVersion CSharpLanguageVersion = LanguageVersion.Default)
LanguageServerFlags? LanguageServerFlags = null)
{
public static readonly RazorConfiguration Default = new(
RazorLanguageVersion.Latest,
ConfigurationName: "unnamed",
Extensions: []);
Extensions: [],
UseConsolidatedMvcViews: true,
SuppressAddComponentParameter: false,
LanguageServerFlags: null);
public bool Equals(RazorConfiguration? other)
=> other is not null &&
@ -30,8 +30,6 @@ public sealed record class RazorConfiguration(
SuppressAddComponentParameter == other.SuppressAddComponentParameter &&
LanguageServerFlags == other.LanguageServerFlags &&
UseConsolidatedMvcViews == other.UseConsolidatedMvcViews &&
UseRoslynTokenizer == other.UseRoslynTokenizer &&
CSharpLanguageVersion == other.CSharpLanguageVersion &&
Extensions.SequenceEqual(other.Extensions);
public override int GetHashCode()
@ -43,8 +41,6 @@ public sealed record class RazorConfiguration(
hash.Add(SuppressAddComponentParameter);
hash.Add(UseConsolidatedMvcViews);
hash.Add(LanguageServerFlags);
hash.Add(UseRoslynTokenizer);
hash.Add(CSharpLanguageVersion);
return hash;
}
}

Просмотреть файл

@ -56,7 +56,8 @@ namespace Microsoft.NET.Sdk.Razor.SourceGenerators
var razorConfiguration = new RazorConfiguration(razorLanguageVersion, configurationName ?? "default", Extensions: [], UseConsolidatedMvcViews: true, SuppressAddComponentParameter: !isComponentParameterSupported);
// We use the new tokenizer only when requested for now.
var useRoslynTokenizer = parseOptions.UseRoslynTokenizer();
var useRoslynTokenizer = parseOptions.Features.TryGetValue("use-roslyn-tokenizer", out var useRoslynTokenizerValue)
&& string.Equals(useRoslynTokenizerValue, "true", StringComparison.OrdinalIgnoreCase);
var razorSourceGenerationOptions = new RazorSourceGenerationOptions()
{

Просмотреть файл

@ -75,7 +75,7 @@ public class RazorLanguageServerBenchmarkBase : ProjectSnapshotManagerBenchmarkB
{
updater.ProjectAdded(hostProject);
var tagHelpers = CommonResources.LegacyTagHelpers;
var projectWorkspaceState = ProjectWorkspaceState.Create(tagHelpers);
var projectWorkspaceState = ProjectWorkspaceState.Create(tagHelpers, CodeAnalysis.CSharp.LanguageVersion.CSharp11);
updater.ProjectWorkspaceStateChanged(hostProject.Key, projectWorkspaceState);
updater.DocumentAdded(hostProject.Key, hostDocument, textLoader);
},

Просмотреть файл

@ -1,12 +1,10 @@
{
"__Version": 7,
"__Version": 6,
"ProjectKey": "C:\\Users\\admin\\location\\Kendo.Mvc.Examples\\obj\\Debug\\net7.0\\",
"FilePath": "C:\\Users\\admin\\location\\Kendo.Mvc.Examples\\Kendo.Mvc.Examples.csproj",
"Configuration": {
"ConfigurationName": "MVC-3.0",
"LanguageVersion": "7.0",
"UseRoslynTokenizer": true,
"CSharpLanguageVersion": 1100,
"Extensions": [
"MVC-3.0"
]
@ -159528,7 +159526,8 @@
"Runtime.Name": "Components.None"
}
}
]
],
"CSharpLanguageVersion": 1100
},
"RootNamespace": "Kendo.Mvc.Examples",
"Documents": [

Просмотреть файл

@ -1,12 +1,10 @@
{
"__Version": 7,
"__Version": 6,
"ProjectKey": "C:\\Users\\admin\\location\\blazorserver\\obj\\Debug\\net7.0\\",
"FilePath": "C:\\Users\\admin\\location\\blazorserver\\blazorserver.csproj",
"Configuration": {
"ConfigurationName": "MVC-3.0",
"LanguageVersion": "3.0",
"UseRoslynTokenizer": true,
"CSharpLanguageVersion": 800,
"Extensions": [ "MVC-3.0" ]
},
"ProjectWorkspaceState": {
@ -16127,7 +16125,8 @@
"Runtime.Name": "Components.None"
}
}
]
],
"CSharpLanguageVersion": 800
},
"RootNamespace": "blazorserver",
"Documents": [

Просмотреть файл

@ -366,16 +366,17 @@ internal partial class RazorProjectService : IRazorProjectService, IRazorProject
if (!projectWorkspaceState.Equals(ProjectWorkspaceState.Default))
{
_logger.LogInformation($"Updating project '{project.Key}' TagHelpers ({projectWorkspaceState.TagHelpers.Length}).");
_logger.LogInformation($"Updating project '{project.Key}' TagHelpers ({projectWorkspaceState.TagHelpers.Length}) and C# Language Version ({projectWorkspaceState.CSharpLanguageVersion}).");
}
updater.ProjectWorkspaceStateChanged(project.Key, projectWorkspaceState);
var currentConfiguration = project.Configuration;
var currentRootNamespace = project.RootNamespace;
if (project.Configuration == configuration &&
if (currentConfiguration.ConfigurationName == configuration?.ConfigurationName &&
currentRootNamespace == rootNamespace)
{
_logger.LogTrace($"Skipping configuration update for '{project.Key}' as the configuration and root namespace are unchanged.");
_logger.LogTrace($"Updating project '{project.Key}'. The project is already using configuration '{configuration.ConfigurationName}' and root namespace '{rootNamespace}'.");
return;
}
@ -384,9 +385,14 @@ internal partial class RazorProjectService : IRazorProjectService, IRazorProject
configuration = FallbackRazorConfiguration.Latest;
_logger.LogInformation($"Updating project '{project.Key}' to use the latest configuration ('{configuration.ConfigurationName}')'.");
}
else
else if (currentConfiguration.ConfigurationName != configuration.ConfigurationName)
{
_logger.LogInformation($"Updating project '{project.Key}' to Razor configuration '{configuration.ConfigurationName}', namespace '{rootNamespace}', with language version '{configuration.LanguageVersion}'.");
_logger.LogInformation($"Updating project '{project.Key}' to Razor configuration '{configuration.ConfigurationName}' with language version '{configuration.LanguageVersion}'.");
}
if (currentRootNamespace != rootNamespace)
{
_logger.LogInformation($"Updating project '{project.Key}''s root namespace to '{rootNamespace}'.");
}
var hostProject = new HostProject(project.FilePath, project.IntermediateOutputPath, configuration, rootNamespace, displayName);

Просмотреть файл

@ -5,40 +5,52 @@ using System;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Razor.ProjectSystem;
internal sealed class ProjectWorkspaceState : IEquatable<ProjectWorkspaceState>
{
public static readonly ProjectWorkspaceState Default = new(ImmutableArray<TagHelperDescriptor>.Empty);
public static readonly ProjectWorkspaceState Default = new(ImmutableArray<TagHelperDescriptor>.Empty, LanguageVersion.Default);
public ImmutableArray<TagHelperDescriptor> TagHelpers { get; }
public LanguageVersion CSharpLanguageVersion { get; }
private ProjectWorkspaceState(
ImmutableArray<TagHelperDescriptor> tagHelpers)
ImmutableArray<TagHelperDescriptor> tagHelpers,
LanguageVersion csharpLanguageVersion)
{
TagHelpers = tagHelpers;
CSharpLanguageVersion = csharpLanguageVersion;
}
public static ProjectWorkspaceState Create(
ImmutableArray<TagHelperDescriptor> tagHelpers)
=> tagHelpers.IsEmpty
ImmutableArray<TagHelperDescriptor> tagHelpers,
LanguageVersion csharpLanguageVersion = LanguageVersion.Default)
=> tagHelpers.IsEmpty && csharpLanguageVersion == LanguageVersion.Default
? Default
: new(tagHelpers);
: new(tagHelpers, csharpLanguageVersion);
public static ProjectWorkspaceState Create(LanguageVersion csharpLanguageVersion)
=> csharpLanguageVersion == LanguageVersion.Default
? Default
: new(ImmutableArray<TagHelperDescriptor>.Empty, csharpLanguageVersion);
public override bool Equals(object? obj)
=> obj is ProjectWorkspaceState other && Equals(other);
public bool Equals(ProjectWorkspaceState? other)
=> other is not null &&
TagHelpers.SequenceEqual(other.TagHelpers);
TagHelpers.SequenceEqual(other.TagHelpers) &&
CSharpLanguageVersion == other.CSharpLanguageVersion;
public override int GetHashCode()
{
var hash = HashCodeCombiner.Start();
hash.Add(TagHelpers);
hash.Add(CSharpLanguageVersion);
return hash.CombinedHash;
}

Просмотреть файл

@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Serialization.MessagePack.Formatters.TagHelpers;
using Microsoft.AspNetCore.Razor.Utilities;
using Microsoft.CodeAnalysis.CSharp;
namespace Microsoft.AspNetCore.Razor.Serialization.MessagePack.Formatters;
@ -21,7 +22,7 @@ internal sealed class ProjectWorkspaceStateFormatter : ValueFormatter<ProjectWor
public override ProjectWorkspaceState Deserialize(ref MessagePackReader reader, SerializerCachingOptions options)
{
reader.ReadArrayHeaderAndVerify(2);
reader.ReadArrayHeaderAndVerify(3);
var checksums = reader.Deserialize<ImmutableArray<Checksum>>(options);
@ -46,17 +47,19 @@ internal sealed class ProjectWorkspaceStateFormatter : ValueFormatter<ProjectWor
}
var tagHelpers = builder.DrainToImmutable();
var csharpLanguageVersion = (LanguageVersion)reader.ReadInt32();
return ProjectWorkspaceState.Create(tagHelpers);
return ProjectWorkspaceState.Create(tagHelpers, csharpLanguageVersion);
}
public override void Serialize(ref MessagePackWriter writer, ProjectWorkspaceState value, SerializerCachingOptions options)
{
writer.WriteArrayHeader(2);
writer.WriteArrayHeader(3);
var checksums = value.TagHelpers.SelectAsArray(x => x.Checksum);
writer.Serialize(checksums, options);
writer.Serialize(value.TagHelpers, options);
writer.Write((int)value.CSharpLanguageVersion);
}
}

Просмотреть файл

@ -4,7 +4,6 @@
using MessagePack;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.CSharp;
namespace Microsoft.AspNetCore.Razor.Serialization.MessagePack.Formatters;
@ -12,10 +11,6 @@ internal sealed class RazorConfigurationFormatter : ValueFormatter<RazorConfigur
{
public static readonly ValueFormatter<RazorConfiguration> Instance = new RazorConfigurationFormatter();
// The count of properties in RazorConfiguration that are serialized. The number of Extensions will be added
// to this, for the final serialized value count.
private const int SerializedPropertyCount = 6;
private RazorConfigurationFormatter()
{
}
@ -29,10 +24,8 @@ internal sealed class RazorConfigurationFormatter : ValueFormatter<RazorConfigur
var languageVersionText = CachedStringFormatter.Instance.Deserialize(ref reader, options) ?? string.Empty;
var suppressAddComponentParameter = reader.ReadBoolean();
var useConsolidatedMvcViews = reader.ReadBoolean();
var useRoslynTokenizer = reader.ReadBoolean();
var csharpLanguageVersion = (LanguageVersion)reader.ReadInt32();
count -= SerializedPropertyCount;
count -= 4;
using var builder = new PooledArrayBuilder<RazorExtension>();
@ -53,16 +46,14 @@ internal sealed class RazorConfigurationFormatter : ValueFormatter<RazorConfigur
configurationName,
extensions,
UseConsolidatedMvcViews: useConsolidatedMvcViews,
SuppressAddComponentParameter: suppressAddComponentParameter,
UseRoslynTokenizer: useRoslynTokenizer,
CSharpLanguageVersion: csharpLanguageVersion);
SuppressAddComponentParameter: suppressAddComponentParameter);
}
public override void Serialize(ref MessagePackWriter writer, RazorConfiguration value, SerializerCachingOptions options)
{
// Write SerializedPropertyCount values + 1 value per extension.
// Write 4 values + 1 value per extension.
var extensions = value.Extensions;
var count = extensions.Length + SerializedPropertyCount;
var count = extensions.Length + 4;
writer.WriteArrayHeader(count);
@ -79,10 +70,8 @@ internal sealed class RazorConfigurationFormatter : ValueFormatter<RazorConfigur
writer.Write(value.SuppressAddComponentParameter);
writer.Write(value.UseConsolidatedMvcViews);
writer.Write(value.UseRoslynTokenizer);
writer.Write((int)value.CSharpLanguageVersion);
count -= SerializedPropertyCount;
count -= 4;
for (var i = 0; i < count; i++)
{

Просмотреть файл

@ -9,5 +9,5 @@ internal static class SerializationFormat
// or any of the types that compose it changes. This includes: RazorConfiguration,
// ProjectWorkspaceState, TagHelperDescriptor, and DocumentSnapshotHandle.
// NOTE: If this version is changed, a coordinated insertion is required between Roslyn and Razor for the C# extension.
public const int Version = 7;
public const int Version = 6;
}

Просмотреть файл

@ -18,7 +18,6 @@ using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Compiler.CSharp;
using Microsoft.NET.Sdk.Razor.SourceGenerators;
namespace Microsoft.AspNetCore.Razor.Utilities;
@ -56,9 +55,7 @@ internal static class RazorProjectInfoFactory
return null;
}
var csharpParseOptions = project.ParseOptions as CSharpParseOptions ?? CSharpParseOptions.Default;
var csharpLanguageVersion = csharpParseOptions.LanguageVersion;
var useRoslynTokenizer = csharpParseOptions.UseRoslynTokenizer();
var csharpLanguageVersion = (project.ParseOptions as CSharpParseOptions)?.LanguageVersion ?? LanguageVersion.Default;
var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
if (compilation is null)
@ -79,7 +76,6 @@ internal static class RazorProjectInfoFactory
builder.SetCSharpLanguageVersion(csharpLanguageVersion);
builder.SetSupportLocalizedComponentNames(); // ProjectState in MS.CA.Razor.Workspaces does this, so I'm doing it too!
builder.Features.Add(new ConfigureRazorParserOptions(useRoslynTokenizer, csharpParseOptions));
};
var engineFactory = ProjectEngineFactories.DefaultProvider.GetFactory(configuration);
@ -91,7 +87,7 @@ internal static class RazorProjectInfoFactory
var tagHelpers = await project.GetTagHelpersAsync(engine, NoOpTelemetryReporter.Instance, cancellationToken).ConfigureAwait(false);
var projectWorkspaceState = ProjectWorkspaceState.Create(tagHelpers);
var projectWorkspaceState = ProjectWorkspaceState.Create(tagHelpers, csharpLanguageVersion);
return new RazorProjectInfo(
projectKey: new ProjectKey(intermediateOutputPath),

Просмотреть файл

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.ProjectSystem;
using System;
using System.Buffers;
using System.Diagnostics;
@ -8,7 +9,6 @@ using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.Utilities;

Просмотреть файл

@ -8,6 +8,7 @@ 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;
@ -31,6 +32,7 @@ internal interface IProjectSnapshot
string? RootNamespace { get; }
string DisplayName { get; }
VersionStamp Version { get; }
LanguageVersion CSharpLanguageVersion { get; }
ProjectWorkspaceState ProjectWorkspaceState { get; }
RazorProjectEngine GetProjectEngine();

Просмотреть файл

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Utilities;
using Microsoft.CodeAnalysis.CSharp;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem;
@ -31,6 +32,7 @@ internal sealed class ProjectSnapshot(ProjectState state) : IProjectSnapshot
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;

Просмотреть файл

@ -13,7 +13,6 @@ using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Utilities;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using Microsoft.NET.Sdk.Razor.SourceGenerators;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem;
@ -152,6 +151,14 @@ internal class ProjectState
{
ProjectWorkspaceStateVersion = Version;
}
if ((difference & ClearProjectWorkspaceStateVersionMask) != 0 &&
CSharpLanguageVersion != older.CSharpLanguageVersion)
{
// C# language version changed. This impacts the ProjectEngine, reset it.
_projectEngine = null;
ConfigurationVersion = Version;
}
}
// Internal set for testing.
@ -166,6 +173,8 @@ internal class ProjectState
public ImmutableArray<TagHelperDescriptor> TagHelpers => ProjectWorkspaceState.TagHelpers;
public LanguageVersion CSharpLanguageVersion => ProjectWorkspaceState.CSharpLanguageVersion;
/// <summary>
/// Gets the version of this project, INCLUDING content changes. The <see cref="Version"/> is
/// incremented for each new <see cref="ProjectState"/> instance created.
@ -198,9 +207,8 @@ internal class ProjectState
return _projectEngineFactoryProvider.Create(configuration, rootDirectoryPath, builder =>
{
builder.SetRootNamespace(HostProject.RootNamespace);
builder.SetCSharpLanguageVersion(configuration.CSharpLanguageVersion);
builder.SetCSharpLanguageVersion(CSharpLanguageVersion);
builder.SetSupportLocalizedComponentNames();
builder.Features.Add(new ConfigureRazorParserOptions(useRoslynTokenizer: configuration.UseRoslynTokenizer, CSharpParseOptions.Default));
});
}
}

Просмотреть файл

@ -19,7 +19,6 @@ using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Razor;
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;
@ -52,7 +51,6 @@ internal sealed class RemoteProjectSnapshot : IProjectSnapshot
_lazyProjectEngine = new AsyncLazy<RazorProjectEngine>(async () =>
{
var configuration = await _lazyConfiguration.GetValueAsync();
var csharpParseOptions = project.ParseOptions as CSharpParseOptions ?? CSharpParseOptions.Default;
return ProjectEngineFactories.DefaultProvider.Create(
configuration,
rootDirectoryPath: Path.GetDirectoryName(FilePath).AssumeNotNull(),
@ -61,7 +59,6 @@ internal sealed class RemoteProjectSnapshot : IProjectSnapshot
builder.SetRootNamespace(RootNamespace);
builder.SetCSharpLanguageVersion(CSharpLanguageVersion);
builder.SetSupportLocalizedComponentNames();
builder.Features.Add(new ConfigureRazorParserOptions(useRoslynTokenizer: csharpParseOptions.UseRoslynTokenizer(), csharpParseOptions));
});
},
joinableTaskFactory: null);

Просмотреть файл

@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.VisualStudio.Razor;
internal interface IRoslynProjectChangeProcessor
internal interface IProjectWorkspaceStateGenerator
{
void EnqueueUpdate(Project? workspaceProject, IProjectSnapshot projectSnapshot);

Просмотреть файл

@ -101,7 +101,7 @@ internal class ProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy, IColl
}
var tagHelpers = await project.GetTagHelpersAsync(CancellationToken.None).ConfigureAwait(false);
var projectWorkspaceState = ProjectWorkspaceState.Create(tagHelpers);
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);

Просмотреть файл

@ -8,11 +8,11 @@ using Microsoft.AspNetCore.Razor.PooledObjects;
namespace Microsoft.VisualStudio.Razor;
internal sealed partial class RoslynProjectChangeProcessor
internal sealed partial class ProjectWorkspaceStateGenerator
{
internal TestAccessor GetTestAccessor() => new(this);
internal sealed class TestAccessor(RoslynProjectChangeProcessor instance)
internal sealed class TestAccessor(ProjectWorkspaceStateGenerator instance)
{
public interface IUpdateItem
{

Просмотреть файл

@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace Microsoft.VisualStudio.Razor;
internal sealed partial class RoslynProjectChangeProcessor
internal sealed partial class ProjectWorkspaceStateGenerator
{
private sealed class UpdateItem
{

Просмотреть файл

@ -6,34 +6,32 @@ using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Threading;
using System.Threading.Tasks;
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.CSharp;
using Microsoft.CodeAnalysis.Razor.Compiler.CSharp;
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.VisualStudio.Razor;
[Export(typeof(IRoslynProjectChangeProcessor))]
[Export(typeof(IProjectWorkspaceStateGenerator))]
[method: ImportingConstructor]
internal sealed partial class RoslynProjectChangeProcessor(
internal sealed partial class ProjectWorkspaceStateGenerator(
IProjectSnapshotManager projectManager,
ITagHelperResolver tagHelperResolver,
ILoggerFactory loggerFactory,
ITelemetryReporter telemetryReporter)
: IRoslynProjectChangeProcessor, IDisposable
: IProjectWorkspaceStateGenerator, IDisposable
{
// 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 ITagHelperResolver _tagHelperResolver = tagHelperResolver;
private readonly ILogger _logger = loggerFactory.GetOrCreateLogger<RoslynProjectChangeProcessor>();
private readonly ILogger _logger = loggerFactory.GetOrCreateLogger<ProjectWorkspaceStateGenerator>();
private readonly ITelemetryReporter _telemetryReporter = telemetryReporter;
private readonly SemaphoreSlim _semaphore = new(initialCount: 1);
@ -140,7 +138,9 @@ internal sealed partial class RoslynProjectChangeProcessor(
return;
}
if (await GetProjectWorkspaceStateAndConfigurationAsync(workspaceProject, projectSnapshot, cancellationToken) is not var (workspaceState, configuration))
var workspaceState = await GetProjectWorkspaceStateAsync(workspaceProject, projectSnapshot, cancellationToken);
if (workspaceState is null)
{
_logger.LogTrace($"Didn't receive {nameof(ProjectWorkspaceState)} for '{projectKey}'");
return;
@ -153,15 +153,11 @@ internal sealed partial class RoslynProjectChangeProcessor(
_logger.LogTrace($"Received {nameof(ProjectWorkspaceState)} with {workspaceState.TagHelpers.Length} tag helper(s) for '{projectKey}'");
// We got a possibly changed configuration, but need a host project to update. Fortunately everything will no-op if this
// is unchanged
var hostProject = new HostProject(projectSnapshot.FilePath, projectSnapshot.IntermediateOutputPath, configuration, projectSnapshot.RootNamespace, projectSnapshot.DisplayName);
await _projectManager
.UpdateAsync(
static (updater, state) =>
{
var (projectKey, workspaceState, hostProject, logger, cancellationToken) = state;
var (projectKey, workspaceState, logger, cancellationToken) = state;
if (cancellationToken.IsCancellationRequested)
{
@ -169,10 +165,9 @@ internal sealed partial class RoslynProjectChangeProcessor(
}
logger.LogTrace($"Updating project with {workspaceState.TagHelpers.Length} tag helper(s) for '{projectKey}'");
updater.ProjectConfigurationChanged(hostProject);
updater.ProjectWorkspaceStateChanged(projectKey, workspaceState);
},
state: (projectKey, workspaceState, hostProject, _logger, cancellationToken),
state: (projectKey, workspaceState, _logger, cancellationToken),
cancellationToken)
.ConfigureAwait(false);
}
@ -261,7 +256,7 @@ internal sealed partial class RoslynProjectChangeProcessor(
/// Attempts to produce a <see cref="ProjectWorkspaceState"/> from the provide <see cref="Project"/> and <see cref="IProjectSnapshot"/>.
/// Returns <see langword="null"/> if an error is encountered.
/// </summary>
private async Task<(ProjectWorkspaceState, RazorConfiguration)?> GetProjectWorkspaceStateAndConfigurationAsync(
private async Task<ProjectWorkspaceState?> GetProjectWorkspaceStateAsync(
Project? workspaceProject,
IProjectSnapshot projectSnapshot,
CancellationToken cancellationToken)
@ -270,7 +265,7 @@ internal sealed partial class RoslynProjectChangeProcessor(
// we just a default ProjectWorkspaceState.
if (workspaceProject is null)
{
return (ProjectWorkspaceState.Default, RazorConfiguration.Default);
return ProjectWorkspaceState.Default;
}
_logger.LogTrace($"Starting tag helper discovery for {projectSnapshot.FilePath}");
@ -284,18 +279,9 @@ internal sealed partial class RoslynProjectChangeProcessor(
try
{
var csharpParseOptions = workspaceProject.ParseOptions as CSharpParseOptions ?? CSharpParseOptions.Default;
var csharpLanguageVersion = csharpParseOptions.LanguageVersion;
var useRoslynTokenizer = csharpParseOptions.UseRoslynTokenizer();
var compilation = await workspaceProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var suppressAddComponentParameter = compilation is not null && !compilation.HasAddComponentParameter();
var configuration = projectSnapshot.Configuration with
{
SuppressAddComponentParameter = suppressAddComponentParameter,
UseRoslynTokenizer = useRoslynTokenizer,
CSharpLanguageVersion = csharpLanguageVersion
};
var csharpLanguageVersion = workspaceProject.ParseOptions is CSharpParseOptions csharpParseOptions
? csharpParseOptions.LanguageVersion
: LanguageVersion.Default;
using var _ = StopwatchPool.GetPooledObject(out var watch);
@ -319,7 +305,7 @@ internal sealed partial class RoslynProjectChangeProcessor(
Project: {projectSnapshot.FilePath}
""");
return (ProjectWorkspaceState.Create(tagHelpers), configuration);
return ProjectWorkspaceState.Create(tagHelpers, csharpLanguageVersion);
}
catch (OperationCanceledException)
{

Просмотреть файл

@ -21,7 +21,7 @@ internal class VsSolutionUpdatesProjectSnapshotChangeTrigger : IRazorStartupServ
{
private readonly IServiceProvider _serviceProvider;
private readonly IProjectSnapshotManager _projectManager;
private readonly IRoslynProjectChangeProcessor _projectChangeProcessor;
private readonly IProjectWorkspaceStateGenerator _workspaceStateGenerator;
private readonly IWorkspaceProvider _workspaceProvider;
private readonly JoinableTaskFactory _jtf;
private readonly CancellationTokenSource _disposeTokenSource;
@ -36,13 +36,13 @@ internal class VsSolutionUpdatesProjectSnapshotChangeTrigger : IRazorStartupServ
public VsSolutionUpdatesProjectSnapshotChangeTrigger(
[Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider,
IProjectSnapshotManager projectManager,
IRoslynProjectChangeProcessor projectChangeProcessor,
IProjectWorkspaceStateGenerator workspaceStateGenerator,
IWorkspaceProvider workspaceProvider,
JoinableTaskContext joinableTaskContext)
{
_serviceProvider = serviceProvider;
_projectManager = projectManager;
_projectChangeProcessor = projectChangeProcessor;
_workspaceStateGenerator = workspaceStateGenerator;
_workspaceProvider = workspaceProvider;
_jtf = joinableTaskContext.Factory;
@ -110,7 +110,7 @@ internal class VsSolutionUpdatesProjectSnapshotChangeTrigger : IRazorStartupServ
if (args.SolutionIsClosing)
{
// If the solution is closing, cancel all existing updates.
_projectChangeProcessor.CancelUpdates();
_workspaceStateGenerator.CancelUpdates();
}
}
@ -133,7 +133,7 @@ internal class VsSolutionUpdatesProjectSnapshotChangeTrigger : IRazorStartupServ
{
// Trigger a tag helper update by forcing the project manager to see the workspace Project
// from the current solution.
_projectChangeProcessor.EnqueueUpdate(workspaceProject, projectSnapshot);
_workspaceStateGenerator.EnqueueUpdate(workspaceProject, projectSnapshot);
}
}
}

Просмотреть файл

@ -3,11 +3,12 @@
using System.Collections.Generic;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.VisualStudio.Razor;
internal partial class RoslynProjectChangeDetector
internal partial class WorkspaceProjectStateChangeDetector
{
private sealed class Comparer : IEqualityComparer<(Project?, IProjectSnapshot)>
{
@ -22,14 +23,14 @@ internal partial class RoslynProjectChangeDetector
var (_, snapshotX) = x;
var (_, snapshotY) = y;
return snapshotX.Key.Equals(snapshotY.Key);
return FilePathComparer.Instance.Equals(snapshotX.Key.Id, snapshotY.Key.Id);
}
public int GetHashCode((Project?, IProjectSnapshot) obj)
{
var (_, snapshot) = obj;
return snapshot.Key.GetHashCode();
return FilePathComparer.Instance.GetHashCode(snapshot.Key.Id);
}
}
}

Просмотреть файл

@ -20,11 +20,11 @@ using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.VisualStudio.Razor;
[Export(typeof(IRazorStartupService))]
internal partial class RoslynProjectChangeDetector : IRazorStartupService, IDisposable
internal partial class WorkspaceProjectStateChangeDetector : IRazorStartupService, IDisposable
{
private static readonly TimeSpan s_delay = TimeSpan.FromSeconds(1);
private readonly IRoslynProjectChangeProcessor _processor;
private readonly IProjectWorkspaceStateGenerator _generator;
private readonly IProjectSnapshotManager _projectManager;
private readonly LanguageServerFeatureOptions _options;
private readonly CodeAnalysis.Workspace _workspace;
@ -35,23 +35,23 @@ internal partial class RoslynProjectChangeDetector : IRazorStartupService, IDisp
private WorkspaceChangedListener? _workspaceChangedListener;
[ImportingConstructor]
public RoslynProjectChangeDetector(
IRoslynProjectChangeProcessor processor,
public WorkspaceProjectStateChangeDetector(
IProjectWorkspaceStateGenerator generator,
IProjectSnapshotManager projectManager,
LanguageServerFeatureOptions options,
IWorkspaceProvider workspaceProvider)
: this(processor, projectManager, options, workspaceProvider, s_delay)
: this(generator, projectManager, options, workspaceProvider, s_delay)
{
}
public RoslynProjectChangeDetector(
IRoslynProjectChangeProcessor processor,
public WorkspaceProjectStateChangeDetector(
IProjectWorkspaceStateGenerator generator,
IProjectSnapshotManager projectManager,
LanguageServerFeatureOptions options,
IWorkspaceProvider workspaceProvider,
TimeSpan delay)
{
_processor = processor;
_generator = generator;
_projectManager = projectManager;
_options = options;
@ -94,7 +94,7 @@ internal partial class RoslynProjectChangeDetector : IRazorStartupService, IDisp
return default;
}
_processor.EnqueueUpdate(project, projectSnapshot);
_generator.EnqueueUpdate(project, projectSnapshot);
}
return default;
@ -414,7 +414,7 @@ internal partial class RoslynProjectChangeDetector : IRazorStartupService, IDisp
internal TestAccessor GetTestAccessor() => new(this);
internal sealed class TestAccessor(RoslynProjectChangeDetector instance)
internal sealed class TestAccessor(WorkspaceProjectStateChangeDetector instance)
{
public void CancelExistingWork()
{

Просмотреть файл

@ -12,6 +12,7 @@ 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;
namespace Microsoft.VisualStudio.LegacyEditor.Razor;
@ -49,6 +50,8 @@ internal class EphemeralProjectSnapshot : IProjectSnapshot
public VersionStamp Version => VersionStamp.Default;
public LanguageVersion CSharpLanguageVersion => ProjectWorkspaceState.CSharpLanguageVersion;
public ValueTask<ImmutableArray<TagHelperDescriptor>> GetTagHelpersAsync(CancellationToken cancellationToken) => new(ProjectWorkspaceState.TagHelpers);
public ProjectWorkspaceState ProjectWorkspaceState => ProjectWorkspaceState.Default;

Просмотреть файл

@ -494,7 +494,7 @@ internal class VisualStudioRazorParser : IVisualStudioRazorParser, IDisposable
var projectSnapshot = _documentTracker.ProjectSnapshot;
if (projectSnapshot != null)
{
builder.SetCSharpLanguageVersion(projectSnapshot.Configuration.CSharpLanguageVersion);
builder.SetCSharpLanguageVersion(projectSnapshot.CSharpLanguageVersion);
}
builder.SetRootNamespace(projectSnapshot?.RootNamespace);

Просмотреть файл

@ -9,6 +9,7 @@ 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;
using Microsoft.CodeAnalysis.Text;
using Xunit;
@ -141,14 +142,8 @@ public class OpenDocumentGeneratorTest(ITestOutputHelper testOutput) : LanguageS
updater.DocumentAdded(_hostProject1.Key, _documents[0], _documents[0].CreateEmptyTextLoader());
// Act
var changed = _hostProject1 with
{
Configuration = _hostProject1.Configuration with
{
CSharpLanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8
}
};
updater.ProjectConfigurationChanged(changed);
updater.ProjectWorkspaceStateChanged(_hostProject1.Key,
ProjectWorkspaceState.Create(LanguageVersion.CSharp8));
});
// Assert
@ -171,14 +166,8 @@ public class OpenDocumentGeneratorTest(ITestOutputHelper testOutput) : LanguageS
updater.DocumentOpened(_hostProject1.Key, _documents[0].FilePath, SourceText.From(string.Empty));
// Act
var changed = _hostProject1 with
{
Configuration = _hostProject1.Configuration with
{
CSharpLanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8
}
};
updater.ProjectConfigurationChanged(changed);
updater.ProjectWorkspaceStateChanged(_hostProject1.Key,
ProjectWorkspaceState.Create(LanguageVersion.CSharp8));
});
// Assert

Просмотреть файл

@ -266,7 +266,7 @@ public class IProjectSnapshotManagerExtensionsTest(ITestOutputHelper testOutput)
private static void AssertSnapshotsEqual(IProjectSnapshot first, IProjectSnapshot second)
{
Assert.Equal(first.FilePath, second.FilePath);
Assert.Equal(first.Configuration, second.Configuration);
Assert.Equal(first.CSharpLanguageVersion, second.CSharpLanguageVersion);
Assert.Equal(first.RootNamespace, second.RootNamespace);
}
}

Просмотреть файл

@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer;
using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Text;
using Moq;
@ -65,7 +66,7 @@ public class RazorProjectServiceTest(ITestOutputHelper testOutput) : LanguageSer
updater.ProjectAdded(hostProject);
});
var projectWorkspaceState = ProjectWorkspaceState.Create([new TagHelperDescriptorBuilder(TagHelperConventions.DefaultKind, "TagHelper", "TagHelperAssembly").Build()]);
var projectWorkspaceState = ProjectWorkspaceState.Create(LanguageVersion.LatestMajor);
// Act
await _projectInfoListener.UpdatedAsync(new RazorProjectInfo(

Просмотреть файл

@ -3,6 +3,7 @@
using System.Collections.Immutable;
using System.IO;
using System.Reflection;
using MessagePack;
using MessagePack.Resolvers;
using Microsoft.AspNetCore.Razor.Language;
@ -11,8 +12,10 @@ using Microsoft.AspNetCore.Razor.Serialization;
using Microsoft.AspNetCore.Razor.Serialization.Json;
using Microsoft.AspNetCore.Razor.Serialization.MessagePack.Resolvers;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.CodeAnalysis.Razor.Logging;
using Xunit;
using Xunit.Abstractions;
using MessagePackSerializationFormat = Microsoft.AspNetCore.Razor.Serialization.MessagePack.SerializationFormat;
namespace Microsoft.AspNetCore.Razor.ProjectEngineHost.Test.Serialization;

Просмотреть файл

@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Serialization;
using Microsoft.AspNetCore.Razor.Serialization.Json;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.CodeAnalysis.CSharp;
using Newtonsoft.Json.Linq;
using Xunit;
using Xunit.Abstractions;
@ -25,7 +26,8 @@ public class SerializationTest : ToolingTestBase
_configuration = new(languageVersion, "Custom", [new("TestExtension")]);
_projectWorkspaceState = ProjectWorkspaceState.Create(
tagHelpers: [TagHelperDescriptorBuilder.Create("Test", "TestAssembly").Build()]);
tagHelpers: [TagHelperDescriptorBuilder.Create("Test", "TestAssembly").Build()],
csharpLanguageVersion: LanguageVersion.LatestMajor);
}
[Fact]

Просмотреть файл

@ -77,7 +77,7 @@ public class StreamExtensionTests
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("tag-name"))
.Build();
var projectWorkspaceState = ProjectWorkspaceState.Create([tagHelper]);
var projectWorkspaceState = ProjectWorkspaceState.Create([tagHelper], CodeAnalysis.CSharp.LanguageVersion.Latest);
var projectInfo = new RazorProjectInfo(
new ProjectKey("TestProject"),

Просмотреть файл

@ -44,6 +44,7 @@ internal sealed class TestProjectSnapshot : IProjectSnapshot
public string IntermediateOutputPath => RealSnapshot.IntermediateOutputPath;
public string? RootNamespace => RealSnapshot.RootNamespace;
public string DisplayName => RealSnapshot.DisplayName;
public LanguageVersion CSharpLanguageVersion => RealSnapshot.CSharpLanguageVersion;
public ProjectWorkspaceState ProjectWorkspaceState => RealSnapshot.ProjectWorkspaceState;
public VersionStamp Version => RealSnapshot.Version;

Просмотреть файл

@ -121,6 +121,8 @@ internal static class TestMocks
{
mock.SetupGet(x => x.ProjectWorkspaceState)
.Returns(projectWorkspaceState);
mock.SetupGet(x => x.CSharpLanguageVersion)
.Returns(projectWorkspaceState.CSharpLanguageVersion);
mock.Setup(x => x.GetTagHelpersAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(projectWorkspaceState.TagHelpers);
}

Просмотреть файл

@ -8,6 +8,7 @@ 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.CSharp;
using Xunit;
using Xunit.Abstractions;
@ -183,6 +184,30 @@ public class ProjectStateGeneratedOutputTest : WorkspaceTestBase
Assert.Equal(state.ProjectWorkspaceStateVersion, actualInputVersion);
}
[Fact]
public async Task ProjectWorkspaceStateChange_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(ProjectEngineFactoryProvider, hostProject, originalWorkspaceState)
.WithAddedHostDocument(_hostDocument, TestMocks.CreateTextLoader("@DateTime.Now", VersionStamp.Default));
var changedWorkspaceState = ProjectWorkspaceState.Create(_someTagHelpers, LanguageVersion.CSharp8);
var (originalOutput, originalInputVersion) = await GetOutputAsync(original, _hostDocument, DisposalToken);
// Act
var state = original.WithProjectWorkspaceState(changedWorkspaceState);
// Assert
var (actualOutput, actualInputVersion) = await GetOutputAsync(state, _hostDocument, DisposalToken);
Assert.NotSame(originalOutput, actualOutput);
Assert.NotEqual(originalInputVersion, actualInputVersion);
Assert.Equal(state.ProjectWorkspaceStateVersion, actualInputVersion);
}
[Fact]
public async Task ConfigurationChange_DoesNotCacheOutput()
{

Просмотреть файл

@ -9,6 +9,7 @@ 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.CSharp;
using Microsoft.CodeAnalysis.Text;
using Xunit;
using Xunit.Abstractions;
@ -641,6 +642,45 @@ public class ProjectStateTest : WorkspaceTestBase
Assert.Equal(TestProjectData.SomeProjectFile1.FilePath, documentFilePath);
}
[Fact]
public void ProjectState_WithProjectWorkspaceState_Changed()
{
// Arrange
var original = ProjectState.Create(ProjectEngineFactoryProvider, _hostProject, _projectWorkspaceState)
.WithAddedHostDocument(_documents[2], DocumentState.EmptyLoader)
.WithAddedHostDocument(_documents[1], DocumentState.EmptyLoader);
// Force init
var originalTagHelpers = original.TagHelpers;
var originalProjectWorkspaceStateVersion = original.ProjectWorkspaceStateVersion;
var changed = ProjectWorkspaceState.Create(_projectWorkspaceState.TagHelpers, LanguageVersion.CSharp6);
// Act
var state = original.WithProjectWorkspaceState(changed);
// Assert
Assert.NotEqual(original.Version, state.Version);
Assert.Same(changed, state.ProjectWorkspaceState);
var actualTagHelpers = state.TagHelpers;
var actualProjectWorkspaceStateVersion = state.ProjectWorkspaceStateVersion;
// 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(original.Documents[_documents[1].FilePath], state.Documents[_documents[1].FilePath]);
Assert.NotSame(original.Documents[_documents[2].FilePath], state.Documents[_documents[2].FilePath]);
}
[Fact]
public void ProjectState_WithProjectWorkspaceState_Changed_TagHelpersChanged()
{
@ -687,7 +727,7 @@ public class ProjectStateTest : WorkspaceTestBase
_ = original.TagHelpers;
_ = original.ProjectWorkspaceStateVersion;
var changed = ProjectWorkspaceState.Create(original.TagHelpers);
var changed = ProjectWorkspaceState.Create(original.TagHelpers, original.CSharpLanguageVersion);
// Act
var state = original.WithProjectWorkspaceState(changed);

Просмотреть файл

@ -8,7 +8,7 @@ using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.VisualStudio.Razor.ProjectSystem;
internal class TestRoslynProjectChangeProcessor : IRoslynProjectChangeProcessor
internal class TestProjectWorkspaceStateGenerator : IProjectWorkspaceStateGenerator
{
private readonly List<TestUpdate> _updates = [];

Просмотреть файл

@ -18,7 +18,7 @@ using Xunit.Abstractions;
namespace Microsoft.VisualStudio.Razor.ProjectSystem;
public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
public class WorkspaceProjectStateChangeDetectorTest : VisualStudioWorkspaceTestBase
{
private readonly HostProject _hostProjectOne;
private readonly HostProject _hostProjectTwo;
@ -36,7 +36,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
private readonly DocumentId _backgroundVirtualCSharpDocumentId;
private readonly DocumentId _partialComponentClassDocumentId;
public RoslynProjectChangeDetectorTest(ITestOutputHelper testOutput)
public WorkspaceProjectStateChangeDetectorTest(ITestOutputHelper testOutput)
: base(testOutput)
{
_emptySolution = Workspace.CurrentSolution;
@ -122,9 +122,9 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
public async Task SolutionClosing_StopsActiveWork()
{
// Arrange
var processor = new TestRoslynProjectChangeProcessor();
var generator = new TestProjectWorkspaceStateGenerator();
var projectManager = CreateProjectSnapshotManager();
using var detector = CreateDetector(processor, projectManager);
using var detector = CreateDetector(generator, projectManager);
var detectorAccessor = detector.GetTestAccessor();
var workspaceChangedTask = detectorAccessor.ListenForWorkspaceChangesAsync(
@ -141,7 +141,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
await workspaceChangedTask;
await detectorAccessor.WaitUntilCurrentBatchCompletesAsync();
processor.Clear();
generator.Clear();
// Act
await projectManager.UpdateAsync(updater =>
@ -154,7 +154,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
// Assert
Assert.Empty(processor.Updates);
Assert.Empty(generator.Updates);
}
[UITheory]
@ -164,9 +164,9 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
public async Task WorkspaceChanged_DocumentEvents_EnqueuesUpdatesForDependentProjects(WorkspaceChangeKind kind)
{
// Arrange
var processor = new TestRoslynProjectChangeProcessor();
var generator = new TestProjectWorkspaceStateGenerator();
var projectManager = CreateProjectSnapshotManager();
using var detector = CreateDetector(processor, projectManager);
using var detector = CreateDetector(generator, projectManager);
var detectorAccessor = detector.GetTestAccessor();
await projectManager.UpdateAsync(updater =>
@ -192,10 +192,10 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
await detectorAccessor.WaitUntilCurrentBatchCompletesAsync();
// Assert
Assert.Equal(3, processor.Updates.Count);
Assert.Contains(processor.Updates, u => u.ProjectSnapshot.Key == _projectNumberOne.ToProjectKey());
Assert.Contains(processor.Updates, u => u.ProjectSnapshot.Key == _projectNumberTwo.ToProjectKey());
Assert.Contains(processor.Updates, u => u.ProjectSnapshot.Key == _projectNumberThree.ToProjectKey());
Assert.Equal(3, generator.Updates.Count);
Assert.Contains(generator.Updates, u => u.ProjectSnapshot.Key == _projectNumberOne.ToProjectKey());
Assert.Contains(generator.Updates, u => u.ProjectSnapshot.Key == _projectNumberTwo.ToProjectKey());
Assert.Contains(generator.Updates, u => u.ProjectSnapshot.Key == _projectNumberThree.ToProjectKey());
}
[UITheory]
@ -205,9 +205,9 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
public async Task WorkspaceChanged_ProjectEvents_EnqueuesUpdatesForDependentProjects(WorkspaceChangeKind kind)
{
// Arrange
var processor = new TestRoslynProjectChangeProcessor();
var generator = new TestProjectWorkspaceStateGenerator();
var projectManager = CreateProjectSnapshotManager();
using var detector = CreateDetector(processor, projectManager);
using var detector = CreateDetector(generator, projectManager);
var detectorAccessor = detector.GetTestAccessor();
await projectManager.UpdateAsync(updater =>
@ -233,10 +233,10 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
await detectorAccessor.WaitUntilCurrentBatchCompletesAsync();
// Assert
Assert.Equal(3, processor.Updates.Count);
Assert.Contains(processor.Updates, u => u.ProjectSnapshot.Key == _projectNumberOne.ToProjectKey());
Assert.Contains(processor.Updates, u => u.ProjectSnapshot.Key == _projectNumberTwo.ToProjectKey());
Assert.Contains(processor.Updates, u => u.ProjectSnapshot.Key == _projectNumberThree.ToProjectKey());
Assert.Equal(3, generator.Updates.Count);
Assert.Contains(generator.Updates, u => u.ProjectSnapshot.Key == _projectNumberOne.ToProjectKey());
Assert.Contains(generator.Updates, u => u.ProjectSnapshot.Key == _projectNumberTwo.ToProjectKey());
Assert.Contains(generator.Updates, u => u.ProjectSnapshot.Key == _projectNumberThree.ToProjectKey());
}
[UITheory]
@ -248,9 +248,9 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
public async Task WorkspaceChanged_SolutionEvents_EnqueuesUpdatesForProjectsInSolution(WorkspaceChangeKind kind)
{
// Arrange
var processor = new TestRoslynProjectChangeProcessor();
var generator = new TestProjectWorkspaceStateGenerator();
var projectManager = CreateProjectSnapshotManager();
using var detector = CreateDetector(processor, projectManager);
using var detector = CreateDetector(generator, projectManager);
var detectorAccessor = detector.GetTestAccessor();
await projectManager.UpdateAsync(updater =>
@ -268,7 +268,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
// Assert
Assert.Collection(
processor.Updates,
generator.Updates,
p => Assert.Equal(_projectNumberOne.Id, p.WorkspaceProject?.Id),
p => Assert.Equal(_projectNumberTwo.Id, p.WorkspaceProject?.Id));
}
@ -282,9 +282,9 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
public async Task WorkspaceChanged_SolutionEvents_EnqueuesStateClear_EnqueuesSolutionProjectUpdates(WorkspaceChangeKind kind)
{
// Arrange
var processor = new TestRoslynProjectChangeProcessor();
var generator = new TestProjectWorkspaceStateGenerator();
var projectManager = CreateProjectSnapshotManager();
using var detector = CreateDetector(processor, projectManager);
using var detector = CreateDetector(generator, projectManager);
var detectorAccessor = detector.GetTestAccessor();
await projectManager.UpdateAsync(updater =>
@ -309,7 +309,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
// Assert
Assert.Collection(
processor.Updates,
generator.Updates,
p => Assert.Equal(_projectNumberThree.Id, p.WorkspaceProject?.Id),
p => Assert.Null(p.WorkspaceProject),
p => Assert.Equal(_projectNumberOne.Id, p.WorkspaceProject?.Id),
@ -322,9 +322,9 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
public async Task WorkspaceChanged_ProjectChangeEvents_UpdatesProjectState_AfterDelay(WorkspaceChangeKind kind)
{
// Arrange
var processor = new TestRoslynProjectChangeProcessor();
var generator = new TestProjectWorkspaceStateGenerator();
var projectManager = CreateProjectSnapshotManager();
using var detector = CreateDetector(processor, projectManager);
using var detector = CreateDetector(generator, projectManager);
var detectorAccessor = detector.GetTestAccessor();
await projectManager.UpdateAsync(updater =>
@ -334,7 +334,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
// Stop any existing work and clear out any updates that we might have received.
detectorAccessor.CancelExistingWork();
processor.Clear();
generator.Clear();
// Create a listener for the workspace change we're about to send.
var listenerTask = detectorAccessor.ListenForWorkspaceChangesAsync(kind);
@ -349,7 +349,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
await detectorAccessor.WaitUntilCurrentBatchCompletesAsync();
// Assert
var update = Assert.Single(processor.Updates);
var update = Assert.Single(generator.Updates);
Assert.Equal(_projectNumberOne.Id, update.WorkspaceProject?.Id);
Assert.Equal(_hostProjectOne.FilePath, update.ProjectSnapshot.FilePath);
}
@ -358,9 +358,9 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
public async Task WorkspaceChanged_DocumentChanged_BackgroundVirtualCS_UpdatesProjectState_AfterDelay()
{
// Arrange
var processor = new TestRoslynProjectChangeProcessor();
var generator = new TestProjectWorkspaceStateGenerator();
var projectManager = CreateProjectSnapshotManager();
using var detector = CreateDetector(processor, projectManager);
using var detector = CreateDetector(generator, projectManager);
var detectorAccessor = detector.GetTestAccessor();
Workspace.TryApplyChanges(_solutionWithTwoProjects);
@ -370,7 +370,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
updater.ProjectAdded(_hostProjectOne);
});
processor.Clear();
generator.Clear();
var solution = _solutionWithTwoProjects.WithDocumentText(_backgroundVirtualCSharpDocumentId, SourceText.From("public class Foo{}"));
var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: _solutionWithTwoProjects, newSolution: solution, projectId: _projectNumberOne.Id, _backgroundVirtualCSharpDocumentId);
@ -381,7 +381,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
await detectorAccessor.WaitUntilCurrentBatchCompletesAsync();
// Assert
var update = Assert.Single(processor.Updates);
var update = Assert.Single(generator.Updates);
Assert.Equal(_projectNumberOne.Id, update.WorkspaceProject?.Id);
Assert.Equal(_hostProjectOne.FilePath, update.ProjectSnapshot.FilePath);
}
@ -390,9 +390,9 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
public async Task WorkspaceChanged_DocumentChanged_CSHTML_UpdatesProjectState_AfterDelay()
{
// Arrange
var processor = new TestRoslynProjectChangeProcessor();
var generator = new TestProjectWorkspaceStateGenerator();
var projectManager = CreateProjectSnapshotManager();
using var detector = CreateDetector(processor, projectManager);
using var detector = CreateDetector(generator, projectManager);
var detectorAccessor = detector.GetTestAccessor();
Workspace.TryApplyChanges(_solutionWithTwoProjects);
@ -402,7 +402,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
updater.ProjectAdded(_hostProjectOne);
});
processor.Clear();
generator.Clear();
var solution = _solutionWithTwoProjects.WithDocumentText(_cshtmlDocumentId, SourceText.From("Hello World"));
var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: _solutionWithTwoProjects, newSolution: solution, projectId: _projectNumberOne.Id, _cshtmlDocumentId);
@ -413,7 +413,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
await detectorAccessor.WaitUntilCurrentBatchCompletesAsync();
// Assert
var update = Assert.Single(processor.Updates);
var update = Assert.Single(generator.Updates);
Assert.Equal(_projectNumberOne.Id, update.WorkspaceProject?.Id);
Assert.Equal(_hostProjectOne.FilePath, update.ProjectSnapshot.FilePath);
}
@ -422,9 +422,9 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
public async Task WorkspaceChanged_DocumentChanged_Razor_UpdatesProjectState_AfterDelay()
{
// Arrange
var processor = new TestRoslynProjectChangeProcessor();
var generator = new TestProjectWorkspaceStateGenerator();
var projectManager = CreateProjectSnapshotManager();
using var detector = CreateDetector(processor, projectManager);
using var detector = CreateDetector(generator, projectManager);
var detectorAccessor = detector.GetTestAccessor();
Workspace.TryApplyChanges(_solutionWithTwoProjects);
@ -434,7 +434,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
updater.ProjectAdded(_hostProjectOne);
});
processor.Clear();
generator.Clear();
var solution = _solutionWithTwoProjects.WithDocumentText(_razorDocumentId, SourceText.From("Hello World"));
var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: _solutionWithTwoProjects, newSolution: solution, projectId: _projectNumberOne.Id, _razorDocumentId);
@ -445,7 +445,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
await detectorAccessor.WaitUntilCurrentBatchCompletesAsync();
// Assert
var update = Assert.Single(processor.Updates);
var update = Assert.Single(generator.Updates);
Assert.Equal(_projectNumberOne.Id, update.WorkspaceProject?.Id);
Assert.Equal(_hostProjectOne.FilePath, update.ProjectSnapshot.FilePath);
}
@ -454,9 +454,9 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
public async Task WorkspaceChanged_DocumentChanged_PartialComponent_UpdatesProjectState_AfterDelay()
{
// Arrange
var processor = new TestRoslynProjectChangeProcessor();
var generator = new TestProjectWorkspaceStateGenerator();
var projectManager = CreateProjectSnapshotManager();
using var detector = CreateDetector(processor, projectManager);
using var detector = CreateDetector(generator, projectManager);
var detectorAccessor = detector.GetTestAccessor();
Workspace.TryApplyChanges(_solutionWithTwoProjects);
@ -467,7 +467,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
});
await detectorAccessor.WaitUntilCurrentBatchCompletesAsync();
processor.Clear();
generator.Clear();
var sourceText = SourceText.From($$"""
public partial class TestComponent : {{ComponentsApi.IComponent.MetadataName}} {}
@ -495,7 +495,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
await detectorAccessor.WaitUntilCurrentBatchCompletesAsync();
// Assert
var update = Assert.Single(processor.Updates);
var update = Assert.Single(generator.Updates);
Assert.Equal(_projectNumberOne.Id, update.WorkspaceProject?.Id);
Assert.Equal(_hostProjectOne.FilePath, update.ProjectSnapshot.FilePath);
}
@ -504,9 +504,9 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
public async Task WorkspaceChanged_ProjectRemovedEvent_QueuesProjectStateRemoval()
{
// Arrange
var processor = new TestRoslynProjectChangeProcessor();
var generator = new TestProjectWorkspaceStateGenerator();
var projectManager = CreateProjectSnapshotManager();
using var detector = CreateDetector(processor, projectManager);
using var detector = CreateDetector(generator, projectManager);
var detectorAccessor = detector.GetTestAccessor();
await projectManager.UpdateAsync(updater =>
@ -524,7 +524,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
// Assert
Assert.Single(
processor.Updates,
generator.Updates,
p => p.WorkspaceProject is null);
}
@ -532,9 +532,9 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
public async Task WorkspaceChanged_ProjectAddedEvent_AddsProject()
{
// Arrange
var processor = new TestRoslynProjectChangeProcessor();
var generator = new TestProjectWorkspaceStateGenerator();
var projectManager = CreateProjectSnapshotManager();
using var detector = CreateDetector(processor, projectManager);
using var detector = CreateDetector(generator, projectManager);
var detectorAccessor = detector.GetTestAccessor();
await projectManager.UpdateAsync(updater =>
@ -553,7 +553,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
// Assert
Assert.Single(
processor.Updates,
generator.Updates,
p => p.WorkspaceProject?.Id == _projectNumberThree.Id);
}
@ -576,7 +576,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
await document.GetSemanticModelAsync();
// Act
var result = RoslynProjectChangeDetector.IsPartialComponentClass(document);
var result = WorkspaceProjectStateChangeDetector.IsPartialComponentClass(document);
// Assert
Assert.False(result);
@ -605,7 +605,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
await document.GetSemanticModelAsync();
// Act
var result = RoslynProjectChangeDetector.IsPartialComponentClass(document);
var result = WorkspaceProjectStateChangeDetector.IsPartialComponentClass(document);
// Assert
Assert.True(result);
@ -630,7 +630,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
Assert.NotNull(document);
// Act
var result = RoslynProjectChangeDetector.IsPartialComponentClass(document);
var result = WorkspaceProjectStateChangeDetector.IsPartialComponentClass(document);
// Assert
Assert.False(result);
@ -657,7 +657,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
await document.GetSyntaxRootAsync();
// Act
var result = RoslynProjectChangeDetector.IsPartialComponentClass(document);
var result = WorkspaceProjectStateChangeDetector.IsPartialComponentClass(document);
// Assert
Assert.False(result);
@ -680,7 +680,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
await document.GetSemanticModelAsync();
// Act
var result = RoslynProjectChangeDetector.IsPartialComponentClass(document);
var result = WorkspaceProjectStateChangeDetector.IsPartialComponentClass(document);
// Assert
Assert.False(result);
@ -713,7 +713,7 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
await document.GetSemanticModelAsync();
// Act
var result = RoslynProjectChangeDetector.IsPartialComponentClass(document);
var result = WorkspaceProjectStateChangeDetector.IsPartialComponentClass(document);
// Assert
Assert.True(result);
@ -745,12 +745,12 @@ public class RoslynProjectChangeDetectorTest : VisualStudioWorkspaceTestBase
await document.GetSemanticModelAsync();
// Act
var result = RoslynProjectChangeDetector.IsPartialComponentClass(document);
var result = WorkspaceProjectStateChangeDetector.IsPartialComponentClass(document);
// Assert
Assert.False(result);
}
private RoslynProjectChangeDetector CreateDetector(IRoslynProjectChangeProcessor processor, IProjectSnapshotManager projectManager)
=> new(processor, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, TimeSpan.FromMilliseconds(10));
private WorkspaceProjectStateChangeDetector CreateDetector(IProjectWorkspaceStateGenerator generator, IProjectSnapshotManager projectManager)
=> new(generator, projectManager, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, TimeSpan.FromMilliseconds(10));
}

Просмотреть файл

@ -18,7 +18,7 @@ using Xunit.Abstractions;
namespace Microsoft.VisualStudio.Razor;
public class RoslynProjectChangeProcessorTest : VisualStudioWorkspaceTestBase
public class ProjectWorkspaceStateGeneratorTest : VisualStudioWorkspaceTestBase
{
private readonly TestTagHelperResolver _tagHelperResolver;
private readonly Project _workspaceProject;
@ -26,7 +26,7 @@ public class RoslynProjectChangeProcessorTest : VisualStudioWorkspaceTestBase
private readonly ProjectWorkspaceState _projectWorkspaceStateWithTagHelpers;
private readonly TestProjectSnapshotManager _projectManager;
public RoslynProjectChangeProcessorTest(ITestOutputHelper testOutput)
public ProjectWorkspaceStateGeneratorTest(ITestOutputHelper testOutput)
: base(testOutput)
{
_tagHelperResolver = new TestTagHelperResolver(
@ -53,36 +53,36 @@ public class RoslynProjectChangeProcessorTest : VisualStudioWorkspaceTestBase
public void Dispose_MakesUpdateNoop()
{
// Arrange
using var processor = new RoslynProjectChangeProcessor(
using var generator = new ProjectWorkspaceStateGenerator(
_projectManager, _tagHelperResolver, LoggerFactory, NoOpTelemetryReporter.Instance);
var processorAccessor = processor.GetTestAccessor();
processorAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
var generatorAccessor = generator.GetTestAccessor();
generatorAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
// Act
processor.Dispose();
generator.Dispose();
processor.EnqueueUpdate(_workspaceProject, _projectSnapshot);
generator.EnqueueUpdate(_workspaceProject, _projectSnapshot);
// Assert
Assert.Empty(processorAccessor.GetUpdates());
Assert.Empty(generatorAccessor.GetUpdates());
}
[UIFact]
public void Update_StartsUpdateTask()
{
// Arrange
using var processor = new RoslynProjectChangeProcessor(
using var generator = new ProjectWorkspaceStateGenerator(
_projectManager, _tagHelperResolver, LoggerFactory, NoOpTelemetryReporter.Instance);
var processorAccessor = processor.GetTestAccessor();
processorAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
var generatorAccessor = generator.GetTestAccessor();
generatorAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
// Act
processor.EnqueueUpdate(_workspaceProject, _projectSnapshot);
generator.EnqueueUpdate(_workspaceProject, _projectSnapshot);
// Assert
var update = Assert.Single(processorAccessor.GetUpdates());
var update = Assert.Single(generatorAccessor.GetUpdates());
Assert.False(update.IsCompleted);
}
@ -90,18 +90,18 @@ public class RoslynProjectChangeProcessorTest : VisualStudioWorkspaceTestBase
public void Update_SoftCancelsIncompleteTaskForSameProject()
{
// Arrange
using var processor = new RoslynProjectChangeProcessor(
using var generator = new ProjectWorkspaceStateGenerator(
_projectManager, _tagHelperResolver, LoggerFactory, NoOpTelemetryReporter.Instance);
var processorAccessor = processor.GetTestAccessor();
processorAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
var generatorAccessor = generator.GetTestAccessor();
generatorAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
processor.EnqueueUpdate(_workspaceProject, _projectSnapshot);
generator.EnqueueUpdate(_workspaceProject, _projectSnapshot);
var initialUpdate = Assert.Single(processorAccessor.GetUpdates());
var initialUpdate = Assert.Single(generatorAccessor.GetUpdates());
// Act
processor.EnqueueUpdate(_workspaceProject, _projectSnapshot);
generator.EnqueueUpdate(_workspaceProject, _projectSnapshot);
// Assert
Assert.True(initialUpdate.IsCancellationRequested);
@ -111,11 +111,11 @@ public class RoslynProjectChangeProcessorTest : VisualStudioWorkspaceTestBase
public async Task Update_NullWorkspaceProject_ClearsProjectWorkspaceState()
{
// Arrange
using var processor = new RoslynProjectChangeProcessor(
using var generator = new ProjectWorkspaceStateGenerator(
_projectManager, _tagHelperResolver, LoggerFactory, NoOpTelemetryReporter.Instance);
var processorAccessor = processor.GetTestAccessor();
processorAccessor.NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false);
var generatorAccessor = generator.GetTestAccessor();
generatorAccessor.NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false);
await _projectManager.UpdateAsync(updater =>
{
@ -124,10 +124,10 @@ public class RoslynProjectChangeProcessorTest : VisualStudioWorkspaceTestBase
});
// Act
processor.EnqueueUpdate(workspaceProject: null, _projectSnapshot);
generator.EnqueueUpdate(workspaceProject: null, _projectSnapshot);
// Jump off the UI thread so the background work can complete.
await Task.Run(() => processorAccessor.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));
await Task.Run(() => generatorAccessor.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));
// Assert
var newProjectSnapshot = _projectManager.GetLoadedProject(_projectSnapshot.Key);
@ -139,11 +139,11 @@ public class RoslynProjectChangeProcessorTest : VisualStudioWorkspaceTestBase
public async Task Update_ResolvesTagHelpersAndUpdatesWorkspaceState()
{
// Arrange
using var processor = new RoslynProjectChangeProcessor(
using var generator = new ProjectWorkspaceStateGenerator(
_projectManager, _tagHelperResolver, LoggerFactory, NoOpTelemetryReporter.Instance);
var processorAccessor = processor.GetTestAccessor();
processorAccessor.NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false);
var generatorAccessor = generator.GetTestAccessor();
generatorAccessor.NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false);
await _projectManager.UpdateAsync(updater =>
{
@ -151,10 +151,10 @@ public class RoslynProjectChangeProcessorTest : VisualStudioWorkspaceTestBase
});
// Act
processor.EnqueueUpdate(_workspaceProject, _projectSnapshot);
generator.EnqueueUpdate(_workspaceProject, _projectSnapshot);
// Jump off the UI thread so the background work can complete.
await Task.Run(() => processorAccessor.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));
await Task.Run(() => generatorAccessor.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));
// Assert
var newProjectSnapshot = _projectManager.GetLoadedProject(_projectSnapshot.Key);

Просмотреть файл

@ -89,7 +89,7 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
using (var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(
serviceProvider,
projectManager,
StrictMock.Of<IRoslynProjectChangeProcessor>(),
StrictMock.Of<IProjectWorkspaceStateGenerator>(),
_workspaceProvider,
JoinableTaskContext))
{
@ -128,7 +128,7 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
using var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(
serviceProvider,
projectManager,
StrictMock.Of<IRoslynProjectChangeProcessor>(),
StrictMock.Of<IProjectWorkspaceStateGenerator>(),
_workspaceProvider,
JoinableTaskContext);
@ -158,7 +158,7 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
});
var serviceProvider = VsMocks.CreateServiceProvider();
var roslynProjectChangeProcessor = new TestRoslynProjectChangeProcessor();
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var vsHierarchyMock = new StrictMock<IVsHierarchy>();
var vsProjectMock = vsHierarchyMock.As<IVsProject>();
@ -169,7 +169,7 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
using var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(
serviceProvider,
projectManager,
roslynProjectChangeProcessor,
workspaceStateGenerator,
_workspaceProvider,
JoinableTaskContext);
@ -187,7 +187,7 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
updater.ProjectRemoved(s_someProject.Key);
});
var update = Assert.Single(roslynProjectChangeProcessor.Updates);
var update = Assert.Single(workspaceStateGenerator.Updates);
Assert.NotNull(update.WorkspaceProject);
Assert.Equal(update.WorkspaceProject.Id, _someWorkspaceProject.Id);
Assert.Same(expectedProjectSnapshot, update.ProjectSnapshot);
@ -211,12 +211,12 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
});
var serviceProvider = VsMocks.CreateServiceProvider();
var roslynProjectChangeProcessor = new TestRoslynProjectChangeProcessor();
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
using var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(
serviceProvider,
projectManager,
roslynProjectChangeProcessor,
workspaceStateGenerator,
_workspaceProvider,
JoinableTaskContext);
@ -232,7 +232,7 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
await testAccessor.OnProjectBuiltAsync(vsHierarchyMock.Object, DisposalToken);
// Assert
var update = Assert.Single(roslynProjectChangeProcessor.Updates);
var update = Assert.Single(workspaceStateGenerator.Updates);
Assert.NotNull(update.WorkspaceProject);
Assert.Equal(update.WorkspaceProject.Id, _someWorkspaceProject.Id);
Assert.Same(expectedProjectSnapshot, update.ProjectSnapshot);
@ -262,12 +262,12 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
new HostProject("/Some/Unknown/Path.csproj", "/Some/Unknown/obj", RazorConfiguration.Default, "Path"));
});
var roslynProjectChangeProcessor = new TestRoslynProjectChangeProcessor();
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
using var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(
serviceProvider,
projectManager,
roslynProjectChangeProcessor,
workspaceStateGenerator,
_workspaceProvider,
JoinableTaskContext);
@ -277,7 +277,7 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
await testAccessor.OnProjectBuiltAsync(StrictMock.Of<IVsHierarchy>(), DisposalToken);
// Assert
Assert.Empty(roslynProjectChangeProcessor.Updates);
Assert.Empty(workspaceStateGenerator.Updates);
}
[UIFact]
@ -298,12 +298,12 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
var projectManager = CreateProjectSnapshotManager();
var roslynProjectChangeProcessor = new TestRoslynProjectChangeProcessor();
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
using var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(
serviceProvider,
projectManager,
roslynProjectChangeProcessor,
workspaceStateGenerator,
_workspaceProvider,
JoinableTaskContext);
@ -313,6 +313,6 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : VisualStudioTes
await testAccessor.OnProjectBuiltAsync(StrictMock.Of<IVsHierarchy>(), DisposalToken);
// Assert
Assert.Empty(roslynProjectChangeProcessor.Updates);
Assert.Empty(workspaceStateGenerator.Updates);
}
}

Просмотреть файл

@ -44,8 +44,6 @@ internal static partial class ObjectReaders
var languageVersionText = reader.ReadNonNullString(nameof(RazorConfiguration.LanguageVersion));
var suppressAddComponentParameter = reader.ReadBooleanOrFalse(nameof(RazorConfiguration.SuppressAddComponentParameter));
var useConsolidatedMvcViews = reader.ReadBooleanOrTrue(nameof(RazorConfiguration.UseConsolidatedMvcViews));
var useRoslynTokenizer = reader.ReadBooleanOrFalse(nameof(RazorConfiguration.UseRoslynTokenizer));
var csharpLanguageVersion = (LanguageVersion)reader.ReadInt32OrZero(nameof(RazorConfiguration.CSharpLanguageVersion));
var extensions = reader.ReadImmutableArrayOrEmpty(nameof(RazorConfiguration.Extensions),
static r =>
{
@ -57,7 +55,7 @@ internal static partial class ObjectReaders
? version
: RazorLanguageVersion.Version_2_1;
return new(languageVersion, configurationName, extensions, SuppressAddComponentParameter: suppressAddComponentParameter, UseRoslynTokenizer: useRoslynTokenizer);
return new(languageVersion, configurationName, extensions, SuppressAddComponentParameter: suppressAddComponentParameter);
}
public static RazorDiagnostic ReadDiagnostic(JsonDataReader reader)
@ -104,8 +102,9 @@ internal static partial class ObjectReaders
public static ProjectWorkspaceState ReadProjectWorkspaceStateFromProperties(JsonDataReader reader)
{
var tagHelpers = reader.ReadImmutableArrayOrEmpty(nameof(ProjectWorkspaceState.TagHelpers), static r => ReadTagHelper(r, useCache: true));
var csharpLanguageVersion = (LanguageVersion)reader.ReadInt32OrZero(nameof(ProjectWorkspaceState.CSharpLanguageVersion));
return ProjectWorkspaceState.Create(tagHelpers);
return ProjectWorkspaceState.Create(tagHelpers, csharpLanguageVersion);
}
public static TagHelperDescriptor ReadTagHelper(JsonDataReader reader, bool useCache)

Просмотреть файл

@ -37,8 +37,6 @@ internal static class ObjectWriters
writer.WriteIfNotFalse(nameof(value.SuppressAddComponentParameter), value.SuppressAddComponentParameter);
writer.WriteIfNotTrue(nameof(value.UseConsolidatedMvcViews), value.UseConsolidatedMvcViews);
writer.WriteIfNotFalse(nameof(value.UseRoslynTokenizer), value.UseRoslynTokenizer);
writer.WriteIfNotZero(nameof(value.CSharpLanguageVersion), (int)value.CSharpLanguageVersion);
writer.WriteArrayIfNotNullOrEmpty(nameof(value.Extensions), value.Extensions, static (w, v) => w.Write(v.ExtensionName));
}
@ -86,6 +84,7 @@ internal static class ObjectWriters
public static void WriteProperties(JsonDataWriter writer, ProjectWorkspaceState value)
{
writer.WriteArrayIfNotDefaultOrEmpty(nameof(value.TagHelpers), value.TagHelpers, Write);
writer.WriteIfNotZero(nameof(value.CSharpLanguageVersion), (int)value.CSharpLanguageVersion);
}
public static void Write(JsonDataWriter writer, TagHelperDescriptor? value)

Просмотреть файл

@ -9,5 +9,5 @@ internal static class SerializationFormat
// or any of the types that compose it changes. This includes: RazorConfiguration,
// ProjectWorkspaceState, TagHelperDescriptor, and DocumentSnapshotHandle.
// NOTE: If this version is changed, a coordinated insertion is required between Roslyn and Razor for the C# extension.
public const int Version = 7;
public const int Version = 6;
}