Simplify the project snapshot manager API a bit and break a few dependencies (#9864)

One of the key challenges in rationalizing our various DI containers is
`ProjectSnapshotManager`. The position of this service in the dependency
graph creates cycles that are currently broken by indirecting through
yet another DI container -- the Roslyn workspace. This change mostly
represents simplifications and removal of odd dependencies that get us
closer to being able to remove the usage of Roslyn workspace.

I recommend reviewing this commit by commit. Here is a summary of the
changes:

* 7467492a6e70a3b21ef61f59aac391aa9ca93613: I've converted
`ProjectSnapshotManager` to an interface, `IProjectSnapshotManager`.

* c56c2076d64985f01fc3612aae3452d2ada8daad: I clarified the
`IProjectSnapshotManager.GetLoadedProject(...)` API by splitting it into
two:
    * `IProjectSnapshot GetLoadedProject(ProjectKey projectKey)`
Importantly, this marks the return type as non-nullable. Previously, it
returned `IProjectSnapshot?` and callers had to check for null. Now it
throws on null.
* `bool TryGetLoadedProject(ProjectKey projectKey, [NotNullWhen(true)]
out IProjectSnapshot? project)`
      This follows the standard `TryGet*` pattern.

The bulk of this commit is an audit of all callers to
`GetLoadedProject(...)`.

* 550d9a66c31b382c33f2915dba94922f7ef57e5b: I removed the
`ErrorReporter` property from `ProjectSnapshotManagerBase`. There was
really only one case outside of `DefaultProjectSnapshotManager` where
this was used, and I updated that to just import an `IErrorReporter`
directly. (Further work on `IErrorReporter` should be to replace it with
`IRazorLoggerFactory` and friends.)

* 4b04b6a9ab51ca76982c3a4b4c88d4cc98138439: I removed the `Workspace`
property from `ProjectSnapshotManagerBase`. It turns out that some
services were importing `IProjectManagerSnapshotAccessor` just to get at
the `Workspace` property, not because they actually needed to interact
with the `ProjectSnapshotManager`. This is the cause of a few of the
dependency cycles mentioned above. In order to satisfy services needing
to access the Roslyn workspace, I've introduced a new
`IWorkspaceProvider` service that can be imported.
This commit is contained in:
Dustin Campbell 2024-01-29 10:58:37 -08:00 коммит произвёл GitHub
Родитель 1789ca8211 4b04b6a9ab
Коммит 6b95f2b9d9
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
64 изменённых файлов: 599 добавлений и 469 удалений

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

@ -6,7 +6,6 @@ using System.Collections.Immutable;
using System.IO;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Text;
@ -60,15 +59,10 @@ public abstract partial class ProjectSnapshotManagerBenchmarkBase
internal DefaultProjectSnapshotManager CreateProjectSnapshotManager()
{
var services = TestServices.Create([], []);
return new DefaultProjectSnapshotManager(
new TestErrorReporter(),
triggers: [],
#pragma warning disable CA2000 // Dispose objects before losing scope
new AdhocWorkspace(services),
StaticProjectEngineFactoryProvider.Instance,
new TestProjectSnapshotManagerDispatcher());
#pragma warning restore CA2000 // Dispose objects before losing scope
projectEngineFactoryProvider: StaticProjectEngineFactoryProvider.Instance,
dispatcher: new TestProjectSnapshotManagerDispatcher(),
errorReporter: new TestErrorReporter());
}
}

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

@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer;
internal class CodeDocumentReferenceHolder : DocumentProcessedListener
{
private Dictionary<DocumentKey, RazorCodeDocument> _codeDocumentCache;
private ProjectSnapshotManager? _projectManager;
private IProjectSnapshotManager? _projectManager;
public CodeDocumentReferenceHolder()
{
@ -29,7 +29,7 @@ internal class CodeDocumentReferenceHolder : DocumentProcessedListener
_codeDocumentCache[key] = codeDocument;
}
public override void Initialize(ProjectSnapshotManager projectManager)
public override void Initialize(IProjectSnapshotManager projectManager)
{
_projectManager = projectManager;
_projectManager.Changed += ProjectManager_Changed;

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

@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer;
internal class DefaultRazorComponentSearchEngine : RazorComponentSearchEngine
{
private readonly ProjectSnapshotManager _projectSnapshotManager;
private readonly IProjectSnapshotManager _projectSnapshotManager;
private readonly ILogger _logger;
public DefaultRazorComponentSearchEngine(

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

@ -33,7 +33,7 @@ internal class RazorDiagnosticsPublisher : DocumentProcessedListener
private readonly IClientConnection _clientConnection;
private readonly Dictionary<string, IDocumentSnapshot> _work;
private readonly ILogger _logger;
private ProjectSnapshotManager? _projectManager;
private IProjectSnapshotManager? _projectManager;
private readonly LanguageServerFeatureOptions _languageServerFeatureOptions;
private readonly Lazy<RazorTranslateDiagnosticsService> _razorTranslateDiagnosticsService;
private readonly Lazy<IDocumentContextFactory> _documentContextFactory;
@ -93,7 +93,7 @@ internal class RazorDiagnosticsPublisher : DocumentProcessedListener
// Used in tests to ensure we can control when background work completes.
public ManualResetEventSlim? NotifyBackgroundWorkCompleting { get; set; }
public override void Initialize(ProjectSnapshotManager projectManager)
public override void Initialize(IProjectSnapshotManager projectManager)
{
if (projectManager is null)
{

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

@ -97,8 +97,8 @@ internal sealed class DocumentContextFactory(
return _snapshotResolver.TryResolveDocumentInAnyProject(filePath, out documentSnapshot);
}
var project = _projectSnapshotManagerAccessor.Instance.GetLoadedProject(projectContext.ToProjectKey());
if (project?.GetDocument(filePath) is { } document)
if (_projectSnapshotManagerAccessor.Instance.TryGetLoadedProject(projectContext.ToProjectKey(), out var project) &&
project.GetDocument(filePath) is { } document)
{
documentSnapshot = document;
return true;

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

@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer;
internal abstract class DocumentProcessedListener
{
public abstract void Initialize(ProjectSnapshotManager projectManager);
public abstract void Initialize(IProjectSnapshotManager projectManager);
public abstract void DocumentProcessed(RazorCodeDocument codeDocument, IDocumentSnapshot documentSnapshot);
}

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

@ -61,8 +61,7 @@ internal sealed partial class DocumentVersionCache() : IDocumentVersionCache, IP
// Any event that has a project may have changed the state of the documents
// and therefore requires us to mark all existing documents as latest.
var project = ProjectSnapshotManager.GetLoadedProject(args.ProjectKey);
if (project is null)
if (!ProjectSnapshotManager.TryGetLoadedProject(args.ProjectKey, out var project))
{
// Project no longer loaded, so there's no work to do.
return;

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

@ -24,7 +24,7 @@ internal class GeneratedDocumentSynchronizer : DocumentProcessedListener
_dispatcher = dispatcher;
}
public override void Initialize(ProjectSnapshotManager projectManager)
public override void Initialize(IProjectSnapshotManager projectManager)
{
}

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

@ -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;
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
@ -13,17 +12,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer;
internal sealed class LspProjectSnapshotManagerAccessor(
IEnumerable<IProjectSnapshotChangeTrigger> changeTriggers,
IOptionsMonitor<RazorLSPOptions> optionsMonitor,
IAdhocWorkspaceFactory workspaceFactory,
ProjectSnapshotManagerDispatcher dispatcher,
IErrorReporter errorReporter) : IProjectSnapshotManagerAccessor, IDisposable
IErrorReporter errorReporter) : IProjectSnapshotManagerAccessor
{
private readonly IEnumerable<IProjectSnapshotChangeTrigger> _changeTriggers = changeTriggers;
private readonly IOptionsMonitor<RazorLSPOptions> _optionsMonitor = optionsMonitor;
private readonly IAdhocWorkspaceFactory _workspaceFactory = workspaceFactory;
private readonly ProjectSnapshotManagerDispatcher _dispatcher = dispatcher;
private readonly IErrorReporter _errorReporter = errorReporter;
private ProjectSnapshotManagerBase? _instance;
private bool _disposed;
public ProjectSnapshotManagerBase Instance
{
@ -32,29 +28,15 @@ internal sealed class LspProjectSnapshotManagerAccessor(
if (_instance is null)
{
var projectEngineFactoryProvider = new LspProjectEngineFactoryProvider(_optionsMonitor);
var workspace = _workspaceFactory.Create();
_instance = new DefaultProjectSnapshotManager(
_errorReporter,
_changeTriggers,
workspace,
projectEngineFactoryProvider,
_dispatcher);
_dispatcher,
_errorReporter);
}
return _instance;
}
}
public void Dispose()
{
if (_disposed)
{
return;
}
_disposed = true;
_instance?.Workspace.Dispose();
}
}

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

@ -0,0 +1,37 @@
// 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 Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.AspNetCore.Razor.LanguageServer;
internal sealed class LspWorkspaceProvider(IAdhocWorkspaceFactory workspaceFactory) : IWorkspaceProvider, IDisposable
{
private readonly IAdhocWorkspaceFactory _workspaceFactory = workspaceFactory;
private Workspace? _workspace;
private bool _disposed;
void IDisposable.Dispose()
{
if (_disposed)
{
return;
}
_workspace?.Dispose();
_disposed = true;
}
public Workspace GetWorkspace()
{
if (_disposed)
{
throw new ObjectDisposedException(nameof(LspWorkspaceProvider));
}
return _workspace ??= _workspaceFactory.Create();
}
}

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

@ -91,7 +91,7 @@ internal class RazorProjectService(
// from Misc Project to a real one, and means the newly added document could actually already be open.
// If it is, we need to make sure we start generating it so we're ready to handle requests that could start coming in.
if (projectSnapshotManager.IsDocumentOpen(textDocumentPath) &&
projectSnapshotManager.GetLoadedProject(projectSnapshot.Key) is { } project &&
projectSnapshotManager.TryGetLoadedProject(projectSnapshot.Key, out var project) &&
project.GetDocument(textDocumentPath) is { } document)
{
_ = document.GetGeneratedOutputAsync();
@ -164,7 +164,7 @@ internal class RazorProjectService(
if (_projectSnapshotManagerAccessor.Instance.IsDocumentOpen(textDocumentPath))
{
_logger.LogInformation("Moving document '{textDocumentPath}' from project '{projectKey}' to misc files because it is open.", textDocumentPath, projectSnapshot.Key);
var miscellaneousProject = (ProjectSnapshot)_snapshotResolver.GetMiscellaneousProject();
var miscellaneousProject = _snapshotResolver.GetMiscellaneousProject();
if (projectSnapshot != miscellaneousProject)
{
MoveDocument(textDocumentPath, projectSnapshot, miscellaneousProject);
@ -235,9 +235,7 @@ internal class RazorProjectService(
{
_projectSnapshotManagerDispatcher.AssertDispatcherThread();
var project = (ProjectSnapshot?)_projectSnapshotManagerAccessor.Instance.GetLoadedProject(projectKey);
if (project is null)
if (!_projectSnapshotManagerAccessor.Instance.TryGetLoadedProject(projectKey, out var project))
{
// Never tracked the project to begin with, noop.
_logger.LogInformation("Failed to update untracked project '{projectKey}'.", projectKey);
@ -254,10 +252,10 @@ internal class RazorProjectService(
_projectSnapshotManagerAccessor.Instance.ProjectWorkspaceStateChanged(project.Key, projectWorkspaceState);
var currentHostProject = project.HostProject;
var currentConfiguration = currentHostProject.Configuration;
var currentConfiguration = project.Configuration;
var currentRootNamespace = project.RootNamespace;
if (currentConfiguration.ConfigurationName == configuration?.ConfigurationName &&
currentHostProject.RootNamespace == rootNamespace)
currentRootNamespace == rootNamespace)
{
_logger.LogTrace("Updating project '{key}'. The project is already using configuration '{configuration.ConfigurationName}' and root namespace '{rootNamespace}'.",
project.Key, configuration.ConfigurationName, rootNamespace);
@ -275,7 +273,7 @@ internal class RazorProjectService(
project.Key, configuration.ConfigurationName, configuration.LanguageVersion);
}
if (currentHostProject.RootNamespace != rootNamespace)
if (currentRootNamespace != rootNamespace)
{
_logger.LogInformation("Updating project '{key}''s root namespace to '{rootNamespace}'.", project.Key, rootNamespace);
}
@ -288,11 +286,11 @@ internal class RazorProjectService(
{
_logger.LogDebug("UpdateProjectDocuments for {projectKey} with {documentCount} documents.", projectKey, documents.Length);
var project = (ProjectSnapshot)_projectSnapshotManagerAccessor.Instance.GetLoadedProject(projectKey).AssumeNotNull();
var currentHostProject = project.HostProject;
var project = _projectSnapshotManagerAccessor.Instance.GetLoadedProject(projectKey);
var currentProjectKey = project.Key;
var projectDirectory = FilePathNormalizer.GetNormalizedDirectoryName(project.FilePath);
var documentMap = documents.ToDictionary(document => EnsureFullPath(document.FilePath, projectDirectory), FilePathComparer.Instance);
var miscellaneousProject = (ProjectSnapshot)_snapshotResolver.GetMiscellaneousProject();
var miscellaneousProject = _snapshotResolver.GetMiscellaneousProject();
// "Remove" any unnecessary documents by putting them into the misc project
foreach (var documentFilePath in project.DocumentFilePaths)
@ -308,7 +306,7 @@ internal class RazorProjectService(
MoveDocument(documentFilePath, project, miscellaneousProject);
}
project = (ProjectSnapshot)_projectSnapshotManagerAccessor.Instance.GetLoadedProject(projectKey).AssumeNotNull();
project = _projectSnapshotManagerAccessor.Instance.GetLoadedProject(projectKey);
// Update existing documents
foreach (var documentFilePath in project.DocumentFilePaths)
@ -338,14 +336,14 @@ internal class RazorProjectService(
_logger.LogTrace("Updating document '{newHostDocument.FilePath}''s file kind to '{newHostDocument.FileKind}' and target path to '{newHostDocument.TargetPath}'.",
newHostDocument.FilePath, newHostDocument.FileKind, newHostDocument.TargetPath);
_projectSnapshotManagerAccessor.Instance.DocumentRemoved(currentHostProject.Key, currentHostDocument);
_projectSnapshotManagerAccessor.Instance.DocumentRemoved(currentProjectKey, currentHostDocument);
var remoteTextLoader = _remoteTextLoaderFactory.Create(newFilePath);
_projectSnapshotManagerAccessor.Instance.DocumentAdded(currentHostProject.Key, newHostDocument, remoteTextLoader);
_projectSnapshotManagerAccessor.Instance.DocumentAdded(currentProjectKey, newHostDocument, remoteTextLoader);
}
project = (ProjectSnapshot)_projectSnapshotManagerAccessor.Instance.GetLoadedProject(project.Key).AssumeNotNull();
miscellaneousProject = (ProjectSnapshot)_snapshotResolver.GetMiscellaneousProject();
project = _projectSnapshotManagerAccessor.Instance.GetLoadedProject(project.Key);
miscellaneousProject = _snapshotResolver.GetMiscellaneousProject();
// Add (or migrate from misc) any new documents
foreach (var documentKvp in documentMap)
@ -367,13 +365,13 @@ internal class RazorProjectService(
var remoteTextLoader = _remoteTextLoaderFactory.Create(documentFilePath);
var newHostDocument = new HostDocument(documentFilePath, documentHandle.TargetPath, documentHandle.FileKind);
_logger.LogInformation("Adding new document '{documentFilePath}' to project '{key}'.", documentFilePath, currentHostProject.Key);
_projectSnapshotManagerAccessor.Instance.DocumentAdded(currentHostProject.Key, newHostDocument, remoteTextLoader);
_logger.LogInformation("Adding new document '{documentFilePath}' to project '{key}'.", documentFilePath, currentProjectKey);
_projectSnapshotManagerAccessor.Instance.DocumentAdded(currentProjectKey, newHostDocument, remoteTextLoader);
}
}
}
private void MoveDocument(string documentFilePath, IProjectSnapshot fromProject, ProjectSnapshot toProject)
private void MoveDocument(string documentFilePath, IProjectSnapshot fromProject, IProjectSnapshot toProject)
{
Debug.Assert(fromProject.DocumentFilePaths.Contains(documentFilePath, FilePathComparer.Instance));
Debug.Assert(!toProject.DocumentFilePaths.Contains(documentFilePath, FilePathComparer.Instance));
@ -424,7 +422,7 @@ internal class RazorProjectService(
?? miscellaneousProject;
var textLoader = new DocumentSnapshotTextLoader(documentSnapshot);
var defaultToProject = (ProjectSnapshot)toProject;
var defaultToProject = toProject;
var newHostDocument = new HostDocument(documentSnapshot.FilePath, documentSnapshot.TargetPath, documentSnapshot.FileKind);
_logger.LogInformation("Migrating '{documentFilePath}' from the '{project.Key}' project to '{toProject.KEy}' project.",
@ -454,13 +452,13 @@ internal class RazorProjectService(
}
// Remove from miscellaneous project
var defaultMiscProject = (ProjectSnapshot)miscellaneousProject;
var defaultMiscProject = miscellaneousProject;
_projectSnapshotManagerAccessor.Instance.DocumentRemoved(defaultMiscProject.Key, documentSnapshot.State.HostDocument);
// Add to new project
var textLoader = new DocumentSnapshotTextLoader(documentSnapshot);
var defaultProject = (ProjectSnapshot)projectSnapshot;
var defaultProject = projectSnapshot;
var newHostDocument = new HostDocument(documentSnapshot.FilePath, documentSnapshot.TargetPath);
_logger.LogInformation("Migrating '{documentFilePath}' from the '{miscellaneousProject.Key}' project to '{projectSnapshot.Key}' project.",
documentFilePath, miscellaneousProject.Key, projectSnapshot.Key);

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

@ -64,11 +64,10 @@ internal sealed class SnapshotResolver : ISnapshotResolver
public IProjectSnapshot GetMiscellaneousProject()
{
var miscellaneousProject = _projectSnapshotManagerAccessor.Instance.GetLoadedProject(MiscellaneousHostProject.Key);
if (miscellaneousProject is null)
if (!_projectSnapshotManagerAccessor.Instance.TryGetLoadedProject(MiscellaneousHostProject.Key, out var miscellaneousProject))
{
_projectSnapshotManagerAccessor.Instance.ProjectAdded(MiscellaneousHostProject);
miscellaneousProject = _projectSnapshotManagerAccessor.Instance.GetLoadedProject(MiscellaneousHostProject.Key).AssumeNotNull();
miscellaneousProject = _projectSnapshotManagerAccessor.Instance.GetLoadedProject(MiscellaneousHostProject.Key);
}
return miscellaneousProject;

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

@ -118,6 +118,7 @@ internal partial class RazorLanguageServer : AbstractLanguageServer<RazorRequest
}
services.AddSingleton<IAdhocWorkspaceFactory, AdhocWorkspaceFactory>();
services.AddSingleton<IWorkspaceProvider, LspWorkspaceProvider>();
var featureOptions = _featureOptions ?? new DefaultLanguageServerFeatureOptions();
services.AddSingleton(featureOptions);

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

@ -29,7 +29,7 @@ internal sealed class RenameEndpoint : AbstractRazorDelegatingEndpoint<RenamePar
{
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private readonly IDocumentContextFactory _documentContextFactory;
private readonly ProjectSnapshotManager _projectSnapshotManager;
private readonly IProjectSnapshotManager _projectSnapshotManager;
private readonly RazorComponentSearchEngine _componentSearchEngine;
private readonly LanguageServerFeatureOptions _languageServerFeatureOptions;
private readonly IRazorDocumentMappingService _documentMappingService;

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

@ -28,7 +28,7 @@ internal class DefaultRazorDynamicFileInfoProvider : RazorDynamicFileInfoProvide
private readonly RazorDocumentServiceProviderFactory _factory;
private readonly LSPEditorFeatureDetector _lspEditorFeatureDetector;
private readonly FilePathService _filePathService;
private readonly IProjectSnapshotManagerAccessor _projectSnapshotManagerAccessor;
private readonly IWorkspaceProvider _workspaceProvider;
private readonly FallbackProjectManager _fallbackProjectManager;
[ImportingConstructor]
@ -36,14 +36,14 @@ internal class DefaultRazorDynamicFileInfoProvider : RazorDynamicFileInfoProvide
RazorDocumentServiceProviderFactory factory,
LSPEditorFeatureDetector lspEditorFeatureDetector,
FilePathService filePathService,
IProjectSnapshotManagerAccessor projectSnapshotManagerAccessor,
IWorkspaceProvider workspaceProvider,
FallbackProjectManager fallbackProjectManager)
{
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
_lspEditorFeatureDetector = lspEditorFeatureDetector ?? throw new ArgumentNullException(nameof(lspEditorFeatureDetector));
_filePathService = filePathService ?? throw new ArgumentNullException(nameof(filePathService));
_projectSnapshotManagerAccessor = projectSnapshotManagerAccessor ?? throw new ArgumentNullException(nameof(projectSnapshotManagerAccessor));
_fallbackProjectManager = fallbackProjectManager ?? throw new ArgumentNullException(nameof(fallbackProjectManager));
_factory = factory;
_lspEditorFeatureDetector = lspEditorFeatureDetector;
_filePathService = filePathService;
_workspaceProvider = workspaceProvider;
_fallbackProjectManager = fallbackProjectManager;
_entries = new ConcurrentDictionary<Key, Entry>();
_createEmptyEntry = (key) => new Entry(CreateEmptyInfo(key));
}
@ -329,10 +329,7 @@ internal class DefaultRazorDynamicFileInfoProvider : RazorDynamicFileInfoProvide
private ProjectId? TryFindProjectIdForProjectKey(ProjectKey key)
{
if (_projectSnapshotManagerAccessor.Instance.Workspace is not { } workspace)
{
throw new InvalidOperationException("Can not map a ProjectKey to a ProjectId before the project is initialized");
}
var workspace = _workspaceProvider.GetWorkspace();
foreach (var project in workspace.CurrentSolution.Projects)
{
@ -347,10 +344,7 @@ internal class DefaultRazorDynamicFileInfoProvider : RazorDynamicFileInfoProvide
public ProjectKey? TryFindProjectKeyForProjectId(ProjectId projectId)
{
if (_projectSnapshotManagerAccessor.Instance.Workspace is not { } workspace)
{
throw new InvalidOperationException("Can not map a ProjectId to a ProjectKey before the project is initialized");
}
var workspace = _workspaceProvider.GetWorkspace();
var project = workspace.CurrentSolution.GetProject(projectId);
if (project is null ||

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

@ -0,0 +1,9 @@
// 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.Workspaces;
internal interface IWorkspaceProvider
{
Workspace GetWorkspace();
}

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

@ -37,19 +37,18 @@ internal class DefaultProjectSnapshotManager : ProjectSnapshotManagerBase
// We have a queue for changes because if one change results in another change aka, add -> open we want to make sure the "add" finishes running first before "open" is notified.
private readonly Queue<ProjectChangeEventArgs> _notificationWork = new();
private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider;
private readonly IErrorReporter _errorReporter;
private readonly ProjectSnapshotManagerDispatcher _dispatcher;
public DefaultProjectSnapshotManager(
IErrorReporter errorReporter,
IEnumerable<IProjectSnapshotChangeTrigger> triggers,
Workspace workspace,
IProjectEngineFactoryProvider projectEngineFactoryProvider,
ProjectSnapshotManagerDispatcher dispatcher)
ProjectSnapshotManagerDispatcher dispatcher,
IErrorReporter errorReporter)
{
ErrorReporter = errorReporter ?? throw new ArgumentNullException(nameof(errorReporter));
Workspace = workspace ?? throw new ArgumentNullException(nameof(workspace));
_projectEngineFactoryProvider = projectEngineFactoryProvider ?? throw new ArgumentNullException(nameof(projectEngineFactoryProvider));
_dispatcher = dispatcher ?? throw new ArgumentException(nameof(dispatcher));
_projectEngineFactoryProvider = projectEngineFactoryProvider;
_dispatcher = dispatcher;
_errorReporter = errorReporter;
using (_rwLocker.EnterReadLock())
{
@ -93,19 +92,32 @@ internal class DefaultProjectSnapshotManager : ProjectSnapshotManagerBase
return _openDocuments_needsLock.ToImmutableArray();
}
internal override Workspace Workspace { get; }
internal override IErrorReporter ErrorReporter { get; }
public override IProjectSnapshot? GetLoadedProject(ProjectKey projectKey)
public override IProjectSnapshot GetLoadedProject(ProjectKey projectKey)
{
using var _ = _rwLocker.EnterReadLock();
if (_projects_needsLock.TryGetValue(projectKey, out var entry))
using (_rwLocker.EnterReadLock())
{
return entry.GetSnapshot();
if (_projects_needsLock.TryGetValue(projectKey, out var entry))
{
return entry.GetSnapshot();
}
}
return null;
throw new InvalidOperationException($"No project snapshot exists with the key, '{projectKey}'");
}
public override bool TryGetLoadedProject(ProjectKey projectKey, [NotNullWhen(true)] out IProjectSnapshot? project)
{
using (_rwLocker.EnterReadLock())
{
if (_projects_needsLock.TryGetValue(projectKey, out var entry))
{
project = entry.GetSnapshot();
return true;
}
}
project = null;
return false;
}
public override ImmutableArray<ProjectKey> GetAllProjectKeys(string projectFileName)
@ -347,33 +359,24 @@ internal class DefaultProjectSnapshotManager : ProjectSnapshotManagerBase
internal override void ReportError(Exception exception)
{
if (exception is null)
{
throw new ArgumentNullException(nameof(exception));
}
ErrorReporter.ReportError(exception);
_errorReporter.ReportError(exception);
}
internal override void ReportError(Exception exception, IProjectSnapshot project)
{
if (exception is null)
{
throw new ArgumentNullException(nameof(exception));
}
ErrorReporter.ReportError(exception, project);
_errorReporter.ReportError(exception, project);
}
internal override void ReportError(Exception exception, ProjectKey projectKey)
{
if (exception is null)
if (TryGetLoadedProject(projectKey, out var project))
{
throw new ArgumentNullException(nameof(exception));
_errorReporter.ReportError(exception, project);
}
else
{
_errorReporter.ReportError(exception);
}
var snapshot = GetLoadedProject(projectKey);
ErrorReporter.ReportError(exception, snapshot);
}
private void NotifyListeners(IProjectSnapshot? older, IProjectSnapshot? newer, string? documentFilePath, ProjectChangeKind kind)

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

@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem;
[Shared]
[ExportLanguageServiceFactory(typeof(ProjectSnapshotManager), RazorLanguage.Name)]
[ExportLanguageServiceFactory(typeof(IProjectSnapshotManager), RazorLanguage.Name)]
[method: ImportingConstructor]
internal class DefaultProjectSnapshotManagerFactory(
[ImportMany] IEnumerable<IProjectSnapshotChangeTrigger> triggers,
@ -20,9 +20,8 @@ internal class DefaultProjectSnapshotManagerFactory(
{
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
=> new DefaultProjectSnapshotManager(
errorReporter,
triggers,
languageServices.WorkspaceServices.Workspace,
projectEngineFactoryProvider,
dispatcher);
dispatcher,
errorReporter);
}

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

@ -22,25 +22,29 @@ internal sealed class FallbackProjectManager(
ProjectConfigurationFilePathStore projectConfigurationFilePathStore,
LanguageServerFeatureOptions languageServerFeatureOptions,
IProjectSnapshotManagerAccessor projectSnapshotManagerAccessor,
IWorkspaceProvider workspaceProvider,
ITelemetryReporter telemetryReporter)
{
private readonly ProjectConfigurationFilePathStore _projectConfigurationFilePathStore = projectConfigurationFilePathStore;
private readonly LanguageServerFeatureOptions _languageServerFeatureOptions = languageServerFeatureOptions;
private readonly IProjectSnapshotManagerAccessor _projectSnapshotManagerAccessor = projectSnapshotManagerAccessor;
private readonly IWorkspaceProvider _workspaceProvider = workspaceProvider;
private readonly ITelemetryReporter _telemetryReporter = telemetryReporter;
internal void DynamicFileAdded(ProjectId projectId, ProjectKey razorProjectKey, string projectFilePath, string filePath)
{
try
{
var project = _projectSnapshotManagerAccessor.Instance.GetLoadedProject(razorProjectKey);
if (project is ProjectSnapshot { HostProject: FallbackHostProject })
if (_projectSnapshotManagerAccessor.Instance.TryGetLoadedProject(razorProjectKey, out var project))
{
// If this is a fallback project, then Roslyn may not track documents in the project, so these dynamic file notifications
// are the only way to know about files in the project.
AddFallbackDocument(razorProjectKey, filePath, projectFilePath);
if (project is ProjectSnapshot { HostProject: FallbackHostProject })
{
// If this is a fallback project, then Roslyn may not track documents in the project, so these dynamic file notifications
// are the only way to know about files in the project.
AddFallbackDocument(razorProjectKey, filePath, projectFilePath);
}
}
else if (project is null)
else
{
// We have been asked to provide dynamic file info, which means there is a .razor or .cshtml file in the project
// but for some reason our project system doesn't know about the project. In these cases (often when people don't
@ -58,8 +62,8 @@ internal sealed class FallbackProjectManager(
{
try
{
var project = _projectSnapshotManagerAccessor.Instance.GetLoadedProject(razorProjectKey);
if (project is ProjectSnapshot { HostProject: FallbackHostProject })
if (_projectSnapshotManagerAccessor.Instance.TryGetLoadedProject(razorProjectKey, out var project) &&
project is ProjectSnapshot { HostProject: FallbackHostProject })
{
// If this is a fallback project, then Roslyn may not track documents in the project, so these dynamic file notifications
// are the only way to know about files in the project.
@ -156,10 +160,7 @@ internal sealed class FallbackProjectManager(
private Project? TryFindProjectForProjectId(ProjectId projectId)
{
if (_projectSnapshotManagerAccessor.Instance.Workspace is not { } workspace)
{
throw new InvalidOperationException("Can not map a ProjectId to a ProjectKey before the project is initialized");
}
var workspace = _workspaceProvider.GetWorkspace();
var project = workspace.CurrentSolution.GetProject(projectId);
if (project is null ||

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

@ -0,0 +1,23 @@
// 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 Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem;
internal interface IProjectSnapshotManager : ILanguageService
{
event EventHandler<ProjectChangeEventArgs> Changed;
ImmutableArray<IProjectSnapshot> GetProjects();
bool IsDocumentOpen(string documentFilePath);
IProjectSnapshot GetLoadedProject(ProjectKey projectKey);
bool TryGetLoadedProject(ProjectKey projectKey, [NotNullWhen(true)] out IProjectSnapshot? project);
ImmutableArray<ProjectKey> GetAllProjectKeys(string projectFileName);
}

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

@ -1,21 +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 Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem;
internal abstract class ProjectSnapshotManager : ILanguageService
{
public abstract event EventHandler<ProjectChangeEventArgs> Changed;
public abstract ImmutableArray<IProjectSnapshot> GetProjects();
public abstract bool IsDocumentOpen(string documentFilePath);
public abstract IProjectSnapshot? GetLoadedProject(ProjectKey projectKey);
public abstract ImmutableArray<ProjectKey> GetAllProjectKeys(string projectFileName);
}

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

@ -3,16 +3,25 @@
using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem;
internal abstract class ProjectSnapshotManagerBase : ProjectSnapshotManager
internal abstract class ProjectSnapshotManagerBase : IProjectSnapshotManager
{
internal abstract Workspace Workspace { get; }
public abstract event EventHandler<ProjectChangeEventArgs> Changed;
internal abstract IErrorReporter ErrorReporter { get; }
public abstract ImmutableArray<IProjectSnapshot> GetProjects();
public abstract bool IsDocumentOpen(string documentFilePath);
public abstract IProjectSnapshot GetLoadedProject(ProjectKey projectKey);
public abstract bool TryGetLoadedProject(ProjectKey projectKey, [NotNullWhen(true)] out IProjectSnapshot? project);
public abstract ImmutableArray<ProjectKey> GetAllProjectKeys(string projectFileName);
internal abstract ImmutableArray<string> GetOpenDocuments();

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

@ -24,8 +24,10 @@ internal class WorkspaceProjectStateChangeDetector : IProjectSnapshotChangeTrigg
private readonly object _disposedLock = new();
private readonly object _workQueueAccessLock = new();
private readonly IProjectWorkspaceStateGenerator _workspaceStateGenerator;
private readonly ProjectSnapshotManagerDispatcher _dispatcher;
private readonly LanguageServerFeatureOptions _options;
private readonly IWorkspaceProvider _workspaceProvider;
private readonly ProjectSnapshotManagerDispatcher _dispatcher;
private readonly IErrorReporter _errorReporter;
private BatchingWorkQueue? _workQueue;
private ProjectSnapshotManagerBase? _projectManager;
private bool _disposed;
@ -36,24 +38,28 @@ internal class WorkspaceProjectStateChangeDetector : IProjectSnapshotChangeTrigg
[ImportingConstructor]
public WorkspaceProjectStateChangeDetector(
IProjectWorkspaceStateGenerator workspaceStateGenerator,
LanguageServerFeatureOptions options,
IWorkspaceProvider workspaceProvider,
ProjectSnapshotManagerDispatcher dispatcher,
LanguageServerFeatureOptions options)
IErrorReporter errorReporter)
{
_workspaceStateGenerator = workspaceStateGenerator ?? throw new ArgumentNullException(nameof(workspaceStateGenerator));
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
_options = options ?? throw new ArgumentNullException(nameof(options));
_workspaceStateGenerator = workspaceStateGenerator;
_options = options;
_workspaceProvider = workspaceProvider;
_dispatcher = dispatcher;
_errorReporter = errorReporter;
}
// Internal for testing
internal WorkspaceProjectStateChangeDetector(
IProjectWorkspaceStateGenerator workspaceStateGenerator,
ProjectSnapshotManagerDispatcher dispatcher,
LanguageServerFeatureOptions options,
IWorkspaceProvider workspaceProvider,
IErrorReporter errorReporter,
ProjectSnapshotManagerDispatcher dispatcher,
BatchingWorkQueue workQueue)
: this(workspaceStateGenerator, options, workspaceProvider, dispatcher, errorReporter)
{
_workspaceStateGenerator = workspaceStateGenerator;
_dispatcher = dispatcher;
_options = options;
_workQueue = workQueue;
}
@ -66,11 +72,13 @@ internal class WorkspaceProjectStateChangeDetector : IProjectSnapshotChangeTrigg
EnsureWorkQueue();
projectManager.Changed += ProjectManager_Changed;
projectManager.Workspace.WorkspaceChanged += Workspace_WorkspaceChanged;
var workspace = _workspaceProvider.GetWorkspace();
workspace.WorkspaceChanged += Workspace_WorkspaceChanged;
// This will usually no-op, in the case that another project snapshot change trigger
// immediately adds projects we want to be able to handle those projects.
InitializeSolution(projectManager.Workspace.CurrentSolution);
InitializeSolution(workspace.CurrentSolution);
}
private void EnsureWorkQueue()
@ -87,7 +95,7 @@ internal class WorkspaceProjectStateChangeDetector : IProjectSnapshotChangeTrigg
_workQueue ??= new BatchingWorkQueue(
s_batchingDelay,
FilePathComparer.Instance,
projectManager.ErrorReporter);
_errorReporter);
}
}
}
@ -412,7 +420,8 @@ internal class WorkspaceProjectStateChangeDetector : IProjectSnapshotChangeTrigg
case ProjectChangeKind.ProjectAdded:
case ProjectChangeKind.DocumentRemoved:
case ProjectChangeKind.DocumentAdded:
var currentSolution = ProjectSnapshotManager.Workspace.CurrentSolution;
var workspace = _workspaceProvider.GetWorkspace();
var currentSolution = workspace.CurrentSolution;
var associatedWorkspaceProject = currentSolution.Projects
.FirstOrDefault(project => e.ProjectKey == ProjectKey.From(project));
@ -483,8 +492,7 @@ internal class WorkspaceProjectStateChangeDetector : IProjectSnapshotChangeTrigg
return false;
}
projectSnapshot = ProjectSnapshotManager.GetLoadedProject(projectKey);
return projectSnapshot is not null;
return ProjectSnapshotManager.TryGetLoadedProject(projectKey, out projectSnapshot);
}
public void Dispose()

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

@ -22,11 +22,11 @@ namespace Microsoft.CodeAnalysis.Remote.Razor;
[Export(typeof(ITagHelperResolver))]
[method: ImportingConstructor]
internal class OutOfProcTagHelperResolver(
IProjectSnapshotManagerAccessor projectManagerAccessor,
IWorkspaceProvider workspaceProvider,
IErrorReporter errorReporter,
ITelemetryReporter telemetryReporter) : ITagHelperResolver
{
private readonly IProjectSnapshotManagerAccessor _projectManagerAccessor = projectManagerAccessor;
private readonly IWorkspaceProvider _workspaceProvider = workspaceProvider;
private readonly IErrorReporter _errorReporter = errorReporter;
private readonly CompilationTagHelperResolver _innerResolver = new(telemetryReporter);
private readonly TagHelperResultCache _resultCache = new();
@ -71,8 +71,10 @@ internal class OutOfProcTagHelperResolver(
// when it's disconnected (user stops the process).
//
// This will change in the future to an easier to consume API but for VS RTM this is what we have.
var workspace = _workspaceProvider.GetWorkspace();
var remoteClient = await RazorRemoteHostClient.TryGetClientAsync(
_projectManagerAccessor.Instance.Workspace.Services,
workspace.Services,
RazorServiceDescriptors.TagHelperProviderServiceDescriptors,
RazorRemoteServiceCallbackDispatcherRegistry.Empty,
cancellationToken);

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

@ -8,7 +8,6 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Editor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
@ -190,15 +189,16 @@ internal class DefaultVisualStudioDocumentTracker : VisualStudioDocumentTracker
_ = OnContextChangedAsync(ContextChangeKind.ProjectChanged);
}
private IProjectSnapshot? GetOrCreateProject(string projectPath)
private IProjectSnapshot GetOrCreateProject(string projectPath)
{
_dispatcher.AssertDispatcherThread();
var projectManager = _projectManagerAccessor.Instance;
var projectKey = projectManager.GetAllProjectKeys(projectPath).FirstOrDefault();
var projectKeys = projectManager.GetAllProjectKeys(projectPath);
if (projectManager.GetLoadedProject(projectKey) is not { } project)
if (projectKeys.Length == 0 ||
!projectManager.TryGetLoadedProject(projectKeys[0], out var project))
{
return new EphemeralProjectSnapshot(_projectEngineFactoryProvider, projectPath);
}
@ -249,7 +249,10 @@ internal class DefaultVisualStudioDocumentTracker : VisualStudioDocumentTracker
string.Equals(_projectPath, e.ProjectFilePath, StringComparison.OrdinalIgnoreCase))
{
// This will be the new snapshot unless the project was removed.
_projectSnapshot = _projectManagerAccessor.Instance.GetLoadedProject(e.ProjectKey);
if (!_projectManagerAccessor.Instance.TryGetLoadedProject(e.ProjectKey, out _projectSnapshot))
{
_projectSnapshot = null;
}
switch (e.Kind)
{

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

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Razor;
using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.Threading;
namespace Microsoft.VisualStudio.Editor.Razor.Documents;
@ -28,7 +29,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents;
[Export(typeof(IProjectSnapshotChangeTrigger))]
internal class EditorDocumentManagerListener : IPriorityProjectSnapshotChangeTrigger
{
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private readonly IWorkspaceProvider _workspaceProvider;
private readonly ProjectSnapshotManagerDispatcher _dispatcher;
private readonly JoinableTaskContext _joinableTaskContext;
private readonly ITelemetryReporter _telemetryReporter;
private readonly EventHandler? _onChangedOnDisk;
@ -43,11 +45,16 @@ internal class EditorDocumentManagerListener : IPriorityProjectSnapshotChangeTri
public ProjectSnapshotManagerBase ProjectManager => _projectManager ?? throw new InvalidOperationException($"{nameof(ProjectManager)} called before {nameof(Initialize)}");
[ImportingConstructor]
public EditorDocumentManagerListener(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, JoinableTaskContext joinableTaskContext, ITelemetryReporter telemetryReporter)
public EditorDocumentManagerListener(
IWorkspaceProvider workspaceProvider,
ProjectSnapshotManagerDispatcher dispatcher,
JoinableTaskContext joinableTaskContext,
ITelemetryReporter telemetryReporter)
{
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
_joinableTaskContext = joinableTaskContext ?? throw new ArgumentNullException(nameof(joinableTaskContext));
_telemetryReporter = telemetryReporter ?? throw new ArgumentNullException(nameof(telemetryReporter));
_workspaceProvider = workspaceProvider;
_dispatcher = dispatcher;
_joinableTaskContext = joinableTaskContext;
_telemetryReporter = telemetryReporter;
_onChangedOnDisk = Document_ChangedOnDisk;
_onChangedInEditor = Document_ChangedInEditor;
@ -57,7 +64,8 @@ internal class EditorDocumentManagerListener : IPriorityProjectSnapshotChangeTri
// For testing purposes only.
internal EditorDocumentManagerListener(
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
IWorkspaceProvider workspaceProvider,
ProjectSnapshotManagerDispatcher dispatcher,
JoinableTaskContext joinableTaskContext,
EditorDocumentManager documentManager,
EventHandler? onChangedOnDisk,
@ -65,7 +73,8 @@ internal class EditorDocumentManagerListener : IPriorityProjectSnapshotChangeTri
EventHandler onOpened,
EventHandler? onClosed)
{
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
_workspaceProvider = workspaceProvider;
_dispatcher = dispatcher;
_joinableTaskContext = joinableTaskContext;
_documentManager = documentManager;
_onChangedOnDisk = onChangedOnDisk;
@ -80,7 +89,9 @@ internal class EditorDocumentManagerListener : IPriorityProjectSnapshotChangeTri
public void Initialize(ProjectSnapshotManagerBase projectManager)
{
_projectManager = projectManager;
_documentManager = projectManager.Workspace.Services.GetRequiredService<EditorDocumentManager>();
var workspace = _workspaceProvider.GetWorkspace();
_documentManager = workspace.Services.GetRequiredService<EditorDocumentManager>();
_projectManager.Changed += ProjectManager_Changed;
}
@ -174,7 +185,7 @@ internal class EditorDocumentManagerListener : IPriorityProjectSnapshotChangeTri
// This event is called by the EditorDocumentManager, which runs on the UI thread.
// However, due to accessing the project snapshot manager, we need to switch to
// running on the project snapshot manager's specialized thread.
await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
await _dispatcher.RunOnDispatcherThreadAsync(() =>
{
ProjectManager.DocumentChanged(document.ProjectKey, document.DocumentFilePath, document.TextLoader);
}, cancellationToken).ConfigureAwait(false);
@ -202,7 +213,7 @@ internal class EditorDocumentManagerListener : IPriorityProjectSnapshotChangeTri
// This event is called by the EditorDocumentManager, which runs on the UI thread.
// However, due to accessing the project snapshot manager, we need to switch to
// running on the project snapshot manager's specialized thread.
await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
await _dispatcher.RunOnDispatcherThreadAsync(() =>
{
var document = (EditorDocument)sender;
ProjectManager.DocumentChanged(document.ProjectKey, document.DocumentFilePath, document.EditorTextContainer!.CurrentText);
@ -232,12 +243,12 @@ internal class EditorDocumentManagerListener : IPriorityProjectSnapshotChangeTri
// This event is called by the EditorDocumentManager, which runs on the UI thread.
// However, due to accessing the project snapshot manager, we need to switch to
// running on the project snapshot manager's specialized thread.
await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
await _dispatcher.RunOnDispatcherThreadAsync(() =>
{
var document = (EditorDocument)sender;
var project = ProjectManager.GetLoadedProject(document.ProjectKey);
if (project is ProjectSnapshot { HostProject: FallbackHostProject } projectSnapshot)
if (ProjectManager.TryGetLoadedProject(document.ProjectKey, out var project) &&
project is ProjectSnapshot { HostProject: FallbackHostProject } projectSnapshot)
{
// 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
@ -275,7 +286,7 @@ internal class EditorDocumentManagerListener : IPriorityProjectSnapshotChangeTri
// This event is called by the EditorDocumentManager, which runs on the UI thread.
// However, due to accessing the project snapshot manager, we need to switch to
// running on the project snapshot manager's specialized thread.
await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
await _dispatcher.RunOnDispatcherThreadAsync(() =>
{
var document = (EditorDocument)sender;
ProjectManager.DocumentClosed(document.ProjectKey, document.DocumentFilePath, document.TextLoader);

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

@ -77,7 +77,18 @@ internal class RazorCodeDocumentProvidingSnapshotChangeTrigger : IProjectSnapsho
}
var project = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
() => _projectManager?.GetLoadedProject(projectKey), cancellationToken);
() =>
{
if (_projectManager is { } projectManager &&
projectManager.TryGetLoadedProject(projectKey, out var project))
{
return project;
}
else
{
return null;
}
}, cancellationToken);
if (project is null)
{

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

@ -231,8 +231,7 @@ internal abstract class WindowsRazorProjectHostBase : OnceInitializedOnceDispose
var projectKeys = projectManager.GetAllProjectKeys(oldProjectFilePath);
foreach (var projectKey in projectKeys)
{
var current = projectManager.GetLoadedProject(projectKey);
if (current?.Configuration is not null)
if (projectManager.TryGetLoadedProject(projectKey, out var current))
{
UninitializeProjectUnsafe(projectKey);
@ -268,8 +267,7 @@ internal abstract class WindowsRazorProjectHostBase : OnceInitializedOnceDispose
protected void UninitializeProjectUnsafe(ProjectKey projectKey)
{
var projectManager = GetProjectManager();
var current = projectManager.GetLoadedProject(projectKey);
if (current is not null)
if (projectManager.TryGetLoadedProject(projectKey, out _))
{
projectManager.ProjectRemoved(projectKey);
ProjectConfigurationFilePathStore.Remove(projectKey);
@ -280,8 +278,7 @@ internal abstract class WindowsRazorProjectHostBase : OnceInitializedOnceDispose
{
var projectManager = GetProjectManager();
var current = projectManager.GetLoadedProject(project.Key);
if (current is null)
if (!projectManager.TryGetLoadedProject(project.Key, out _))
{
// Just in case we somehow got in a state where VS didn't tell us that solution close was finished, lets just
// ensure we're going to actually do something with the new project that we've just been told about.

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

@ -56,7 +56,7 @@ internal sealed class VisualStudioProjectSnapshotManagerAccessor(
return (ProjectSnapshotManagerBase)_workspace.Services
.GetLanguageServices(RazorLanguage.Name)
.GetRequiredService<ProjectSnapshotManager>();
.GetRequiredService<IProjectSnapshotManager>();
}
}
}

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

@ -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.
using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.VisualStudio.LanguageServices.Razor;
[Export(typeof(IWorkspaceProvider))]
[method: ImportingConstructor]
internal sealed class VisualStudioWorkspaceProvider(VisualStudioWorkspace workspace) : IWorkspaceProvider
{
public Workspace GetWorkspace() => workspace;
}

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

@ -9,6 +9,7 @@ using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.Editor.Razor;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
@ -18,59 +19,27 @@ using Task = System.Threading.Tasks.Task;
namespace Microsoft.VisualStudio.LanguageServices.Razor;
[Export(typeof(IProjectSnapshotChangeTrigger))]
internal class VsSolutionUpdatesProjectSnapshotChangeTrigger : IProjectSnapshotChangeTrigger, IVsUpdateSolutionEvents2, IDisposable
[method: ImportingConstructor]
internal class VsSolutionUpdatesProjectSnapshotChangeTrigger(
[Import(typeof(SVsServiceProvider))] IServiceProvider services,
TextBufferProjectService projectService,
IProjectWorkspaceStateGenerator workspaceStateGenerator,
IWorkspaceProvider workspaceProvider,
ProjectSnapshotManagerDispatcher dispatcher,
JoinableTaskContext joinableTaskContext) : IProjectSnapshotChangeTrigger, IVsUpdateSolutionEvents2, IDisposable
{
private readonly IServiceProvider _services;
private readonly TextBufferProjectService _projectService;
private readonly IProjectWorkspaceStateGenerator _workspaceStateGenerator;
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private readonly JoinableTaskContext _joinableTaskContext;
private readonly IServiceProvider _services = services;
private readonly TextBufferProjectService _projectService = projectService;
private readonly IProjectWorkspaceStateGenerator _workspaceStateGenerator = workspaceStateGenerator;
private readonly IWorkspaceProvider _workspaceProvider = workspaceProvider;
private readonly ProjectSnapshotManagerDispatcher _dispatcher = dispatcher;
private readonly JoinableTaskContext _joinableTaskContext = joinableTaskContext;
private ProjectSnapshotManagerBase? _projectManager;
private CancellationTokenSource? _activeSolutionCancellationTokenSource;
private CancellationTokenSource? _activeSolutionCancellationTokenSource = new();
private uint _updateCookie;
private IVsSolutionBuildManager? _solutionBuildManager;
[ImportingConstructor]
public VsSolutionUpdatesProjectSnapshotChangeTrigger(
[Import(typeof(SVsServiceProvider))] IServiceProvider services,
TextBufferProjectService projectService,
IProjectWorkspaceStateGenerator workspaceStateGenerator,
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
JoinableTaskContext joinableTaskContext)
{
if (services is null)
{
throw new ArgumentNullException(nameof(services));
}
if (projectService is null)
{
throw new ArgumentNullException(nameof(projectService));
}
if (workspaceStateGenerator is null)
{
throw new ArgumentNullException(nameof(workspaceStateGenerator));
}
if (projectSnapshotManagerDispatcher is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
}
if (joinableTaskContext is null)
{
throw new ArgumentNullException(nameof(joinableTaskContext));
}
_services = services;
_projectService = projectService;
_workspaceStateGenerator = workspaceStateGenerator;
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
_joinableTaskContext = joinableTaskContext;
_activeSolutionCancellationTokenSource = new CancellationTokenSource();
}
internal Task? CurrentUpdateTaskForTests { get; private set; }
public void Initialize(ProjectSnapshotManagerBase projectManager)
@ -142,7 +111,7 @@ internal class VsSolutionUpdatesProjectSnapshotChangeTrigger : IProjectSnapshotC
internal Task OnProjectBuiltAsync(IVsHierarchy projectHierarchy, CancellationToken cancellationToken)
{
var projectFilePath = _projectService.GetProjectPath(projectHierarchy);
return _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() =>
return _dispatcher.RunOnDispatcherThreadAsync(() =>
{
if (_projectManager is null)
{
@ -152,10 +121,10 @@ internal class VsSolutionUpdatesProjectSnapshotChangeTrigger : IProjectSnapshotC
var projectKeys = _projectManager.GetAllProjectKeys(projectFilePath);
foreach (var projectKey in projectKeys)
{
var projectSnapshot = _projectManager?.GetLoadedProject(projectKey);
if (projectSnapshot is not null)
if (_projectManager.TryGetLoadedProject(projectKey, out var projectSnapshot))
{
var workspaceProject = _projectManager?.Workspace.CurrentSolution.Projects.FirstOrDefault(wp => ProjectKey.From(wp) == projectSnapshot.Key);
var workspace = _workspaceProvider.GetWorkspace();
var workspaceProject = workspace.CurrentSolution.Projects.FirstOrDefault(wp => ProjectKey.From(wp) == projectSnapshot.Key);
if (workspaceProject is not null)
{
// Trigger a tag helper update by forcing the project manager to see the workspace Project

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

@ -17,7 +17,7 @@ internal class DefaultProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy
{
private readonly CollaborationSession _session;
private readonly ProjectSnapshotManagerDispatcher _dispatcher;
private readonly ProjectSnapshotManager _projectSnapshotManager;
private readonly IProjectSnapshotManager _projectSnapshotManager;
private readonly JoinableTaskFactory _joinableTaskFactory;
private readonly AsyncSemaphore _latestStateSemaphore;
private bool _disposed;
@ -29,7 +29,7 @@ internal class DefaultProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy
public DefaultProjectSnapshotManagerProxy(
CollaborationSession session,
ProjectSnapshotManagerDispatcher dispatcher,
ProjectSnapshotManager projectSnapshotManager,
IProjectSnapshotManager projectSnapshotManager,
JoinableTaskFactory joinableTaskFactory)
{
if (session is null)

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

@ -25,7 +25,7 @@ public class CodeDocumentReferenceHolderTest : LanguageServerTestBase
public CodeDocumentReferenceHolderTest(ITestOutputHelper testOutput)
: base(testOutput)
{
_projectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
_projectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
_projectManager.AllowNotifyListeners = true;
_referenceHolder = new CodeDocumentReferenceHolder();
_referenceHolder.Initialize(_projectManager);
@ -165,7 +165,7 @@ public class CodeDocumentReferenceHolderTest : LanguageServerTestBase
_projectManager.ProjectAdded(_hostProject);
var textLoader = new SourceTextLoader("<p>Hello World</p>", _hostDocument.FilePath);
_projectManager.DocumentAdded(_hostProject.Key, _hostDocument, textLoader);
var project = _projectManager.GetLoadedProject(_hostProject.Key).AssumeNotNull();
var project = _projectManager.GetLoadedProject(_hostProject.Key);
return project.GetDocument(_hostDocument.FilePath).AssumeNotNull();
}, cancellationToken);
}

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

@ -23,7 +23,7 @@ public class DefaultWorkspaceSemanticTokensRefreshTriggerTest : LanguageServerTe
public DefaultWorkspaceSemanticTokensRefreshTriggerTest(ITestOutputHelper testOutput)
: base(testOutput)
{
_projectManager = TestProjectSnapshotManager.Create(ErrorReporter, new TestDispatcher());
_projectManager = TestProjectSnapshotManager.Create(new TestDispatcher(), ErrorReporter);
_projectManager.AllowNotifyListeners = true;
_hostProject = new HostProject("/path/to/project.csproj", "/path/to/obj", RazorConfiguration.Default, "TestRootNamespace");
_projectManager.ProjectAdded(_hostProject);

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

@ -49,7 +49,7 @@ public class RazorDiagnosticsPublisherTest : LanguageServerTestBase
}
];
private readonly ProjectSnapshotManager _projectManager;
private readonly IProjectSnapshotManager _projectManager;
private readonly IDocumentSnapshot _closedDocument;
private readonly IDocumentSnapshot _openedDocument;
private readonly RazorCodeDocument _testCodeDocument;
@ -58,7 +58,7 @@ public class RazorDiagnosticsPublisherTest : LanguageServerTestBase
public RazorDiagnosticsPublisherTest(ITestOutputHelper testOutput)
: base(testOutput)
{
var testProjectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var testProjectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var hostProject = new HostProject("C:/project/project.csproj", "C:/project/obj", RazorConfiguration.Default, "TestRootNamespace");
testProjectManager.ProjectAdded(hostProject);
var sourceText = SourceText.From(string.Empty);

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

@ -31,7 +31,7 @@ public class DocumentContextFactoryTest : LanguageServerTestBase
{
_documentVersionCache = new DocumentVersionCache();
_projectSnapshotManagerBase = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
_projectSnapshotManagerBase = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
_projectSnapshotManagerAccessor = new TestProjectSnapshotManagerAccessor(_projectSnapshotManagerBase);
}

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

@ -317,7 +317,7 @@ public class DocumentVersionCacheTest(ITestOutputHelper testOutput) : LanguageSe
private TestProjectSnapshotManager CreateProjectSnapshotManager()
{
var result = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var result = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
result.AllowNotifyListeners = true;
return result;

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

@ -25,7 +25,7 @@ public class GeneratedDocumentPublisherTest : LanguageServerTestBase
: base(testOutput)
{
_serverClient = new TestClient();
_projectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
_projectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
_projectManager.AllowNotifyListeners = true;
_hostProject = new HostProject("/path/to/project.csproj", "/path/to/obj", RazorConfiguration.Default, "TestRootNamespace");
_hostProject2 = new HostProject("/path/to/project2.csproj", "/path/to/obj2", RazorConfiguration.Default, "TestRootNamespace");

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

@ -42,7 +42,7 @@ public class OpenDocumentGeneratorTest : LanguageServerTestBase
public async Task DocumentAdded_IgnoresClosedDocument()
{
// Arrange
var projectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var projectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var listener = new TestDocumentProcessedListener();
var queue = new TestOpenDocumentGenerator(Dispatcher, ErrorReporter, listener);
@ -66,7 +66,7 @@ public class OpenDocumentGeneratorTest : LanguageServerTestBase
public async Task DocumentChanged_IgnoresClosedDocument()
{
// Arrange
var projectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var projectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var listener = new TestDocumentProcessedListener();
var queue = new TestOpenDocumentGenerator(Dispatcher, ErrorReporter, listener);
@ -91,7 +91,7 @@ public class OpenDocumentGeneratorTest : LanguageServerTestBase
public async Task DocumentChanged_ProcessesOpenDocument()
{
// Arrange
var projectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var projectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var listener = new TestDocumentProcessedListener();
var queue = new TestOpenDocumentGenerator(Dispatcher, ErrorReporter, listener);
@ -119,7 +119,7 @@ public class OpenDocumentGeneratorTest : LanguageServerTestBase
public async Task ProjectChanged_IgnoresClosedDocument()
{
// Arrange
var projectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var projectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var listener = new TestDocumentProcessedListener();
var queue = new TestOpenDocumentGenerator(Dispatcher, ErrorReporter, listener);
@ -145,7 +145,7 @@ public class OpenDocumentGeneratorTest : LanguageServerTestBase
public async Task ProjectChanged_ProcessesOpenDocument()
{
// Arrange
var projectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var projectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var listener = new TestDocumentProcessedListener();
var queue = new TestOpenDocumentGenerator(Dispatcher, ErrorReporter, listener);
@ -210,7 +210,7 @@ public class OpenDocumentGeneratorTest : LanguageServerTestBase
_tcs.SetResult(document);
}
public override void Initialize(ProjectSnapshotManager projectManager)
public override void Initialize(IProjectSnapshotManager projectManager)
{
}
}

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

@ -34,7 +34,7 @@ public class RazorProjectServiceTest(ITestOutputHelper testOutput) : LanguageSer
public async Task UpdateProject_UpdatesProjectWorkspaceState()
{
// Arrange
var projectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var projectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var hostProject = new HostProject("C:/path/to/project.csproj", "C:/path/to/obj", RazorConfiguration.Default, "TestRootNamespace");
projectManager.ProjectAdded(hostProject);
var projectService = CreateProjectService(new TestSnapshotResolver(), projectManager);
@ -59,7 +59,7 @@ public class RazorProjectServiceTest(ITestOutputHelper testOutput) : LanguageSer
public async Task UpdateProject_UpdatingDocument_MapsRelativeFilePathToActualDocument()
{
// Arrange
var projectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var projectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var hostProject = new HostProject("C:/path/to/project.csproj", "C:/path/to/obj", RazorConfiguration.Default, "TestRootNamespace");
projectManager.ProjectAdded(hostProject);
var hostDocument = new HostDocument("C:/path/to/file.cshtml", "file.cshtml", FileKinds.Legacy);
@ -88,7 +88,7 @@ public class RazorProjectServiceTest(ITestOutputHelper testOutput) : LanguageSer
public async Task UpdateProject_AddsNewDocuments()
{
// Arrange
var projectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var projectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var hostProject = new HostProject("C:/path/to/project.csproj", "C:/path/to/obj", RazorConfiguration.Default, "TestRootNamespace");
projectManager.ProjectAdded(hostProject);
var hostDocument = new HostDocument("C:/path/to/file.cshtml", "file.cshtml", FileKinds.Legacy);
@ -117,7 +117,7 @@ public class RazorProjectServiceTest(ITestOutputHelper testOutput) : LanguageSer
public async Task UpdateProject_MovesDocumentsFromMisc()
{
// Arrange
var projectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var projectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var hostDocument = new HostDocument("C:/path/to/file.cshtml", "file.cshtml", FileKinds.Legacy);
var miscProject = TestProjectSnapshot.Create("C:/__MISC_PROJECT__");
projectManager.ProjectAdded(miscProject.HostProject);
@ -157,7 +157,7 @@ public class RazorProjectServiceTest(ITestOutputHelper testOutput) : LanguageSer
public async Task UpdateProject_MovesExistingDocumentToMisc()
{
// Arrange
var projectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var projectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
IProjectSnapshot miscProject = TestProjectSnapshot.Create("C:/__MISC_PROJECT__");
var miscHostProject = new HostProject(miscProject.FilePath, miscProject.IntermediateOutputPath, RazorConfiguration.Default, "TestRootNamespace");
projectManager.ProjectAdded(miscHostProject);
@ -197,7 +197,7 @@ public class RazorProjectServiceTest(ITestOutputHelper testOutput) : LanguageSer
public async Task UpdateProject_KnownDocuments()
{
// Arrange
var projectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var projectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var hostProject = new HostProject("path/to/project.csproj", "path/to/obj", RazorConfiguration.Default, "TestRootNamespace");
projectManager.ProjectAdded(hostProject);
var document = new HostDocument("path/to/file.cshtml", "file.cshtml", FileKinds.Legacy);
@ -230,7 +230,7 @@ public class RazorProjectServiceTest(ITestOutputHelper testOutput) : LanguageSer
public async Task UpdateProject_UpdatesLegacyDocumentsAsComponents()
{
// Arrange
var projectManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var projectManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var hostProject = new HostProject("C:/path/to/project.csproj", "C:/path/to/obj", RazorConfiguration.Default, "TestRootNamespace");
projectManager.ProjectAdded(hostProject);
var legacyDocument = new HostDocument("C:/path/to/file.cshtml", "file.cshtml", FileKinds.Legacy);
@ -260,13 +260,19 @@ public class RazorProjectServiceTest(ITestOutputHelper testOutput) : LanguageSer
{
// Arrange
var projectFilePath = "C:/path/to/project.csproj";
var ownerProject = TestProjectSnapshot.Create(projectFilePath);
IProjectSnapshot ownerProject = TestProjectSnapshot.Create(projectFilePath);
var projectSnapshotManager = new Mock<ProjectSnapshotManagerBase>(MockBehavior.Strict);
var expectedRootNamespace = "NewRootNamespace";
projectSnapshotManager.Setup(manager => manager.GetLoadedProject(ownerProject.Key))
projectSnapshotManager
.Setup(manager => manager.GetLoadedProject(ownerProject.Key))
.Returns(ownerProject);
projectSnapshotManager.Setup(manager => manager.ProjectWorkspaceStateChanged(It.IsAny<ProjectKey>(), It.IsAny<ProjectWorkspaceState>()));
projectSnapshotManager.Setup(manager => manager.ProjectConfigurationChanged(It.IsAny<HostProject>()))
projectSnapshotManager
.Setup(manager => manager.TryGetLoadedProject(ownerProject.Key, out ownerProject))
.Returns(true);
projectSnapshotManager
.Setup(manager => manager.ProjectWorkspaceStateChanged(It.IsAny<ProjectKey>(), It.IsAny<ProjectWorkspaceState>()));
projectSnapshotManager
.Setup(manager => manager.ProjectConfigurationChanged(It.IsAny<HostProject>()))
.Callback<HostProject>((hostProject) => Assert.Equal(expectedRootNamespace, hostProject.RootNamespace));
var projectService = CreateProjectService(new TestSnapshotResolver(), projectSnapshotManager.Object);
@ -289,12 +295,18 @@ public class RazorProjectServiceTest(ITestOutputHelper testOutput) : LanguageSer
{
// Arrange
var projectFilePath = "C:/path/to/project.csproj";
var ownerProject = TestProjectSnapshot.Create(projectFilePath);
IProjectSnapshot ownerProject = TestProjectSnapshot.Create(projectFilePath);
var projectSnapshotManager = new Mock<ProjectSnapshotManagerBase>(MockBehavior.Strict);
projectSnapshotManager.Setup(manager => manager.GetLoadedProject(ownerProject.Key))
projectSnapshotManager
.Setup(manager => manager.GetLoadedProject(ownerProject.Key))
.Returns(ownerProject);
projectSnapshotManager.Setup(manager => manager.ProjectWorkspaceStateChanged(It.IsAny<ProjectKey>(), It.IsAny<ProjectWorkspaceState>()));
projectSnapshotManager.Setup(manager => manager.ProjectConfigurationChanged(It.IsAny<HostProject>()))
projectSnapshotManager
.Setup(manager => manager.TryGetLoadedProject(ownerProject.Key, out ownerProject))
.Returns(true);
projectSnapshotManager
.Setup(manager => manager.ProjectWorkspaceStateChanged(It.IsAny<ProjectKey>(), It.IsAny<ProjectWorkspaceState>()));
projectSnapshotManager
.Setup(manager => manager.ProjectConfigurationChanged(It.IsAny<HostProject>()))
.Throws(new XunitException("Should not have been called."));
var projectService = CreateProjectService(new TestSnapshotResolver(), projectSnapshotManager.Object);
@ -314,12 +326,18 @@ public class RazorProjectServiceTest(ITestOutputHelper testOutput) : LanguageSer
{
// Arrange
var projectFilePath = "C:/path/to/project.csproj";
var ownerProject = TestProjectSnapshot.Create(projectFilePath);
IProjectSnapshot ownerProject = TestProjectSnapshot.Create(projectFilePath);
var projectSnapshotManager = new Mock<ProjectSnapshotManagerBase>(MockBehavior.Strict);
projectSnapshotManager.Setup(manager => manager.GetLoadedProject(ownerProject.Key))
projectSnapshotManager
.Setup(manager => manager.GetLoadedProject(ownerProject.Key))
.Returns(ownerProject);
projectSnapshotManager.Setup(manager => manager.ProjectWorkspaceStateChanged(It.IsAny<ProjectKey>(), It.IsAny<ProjectWorkspaceState>()));
projectSnapshotManager.Setup(manager => manager.ProjectConfigurationChanged(It.IsAny<HostProject>()))
projectSnapshotManager
.Setup(manager => manager.TryGetLoadedProject(ownerProject.Key, out ownerProject))
.Returns(true);
projectSnapshotManager
.Setup(manager => manager.ProjectWorkspaceStateChanged(It.IsAny<ProjectKey>(), It.IsAny<ProjectWorkspaceState>()));
projectSnapshotManager
.Setup(manager => manager.ProjectConfigurationChanged(It.IsAny<HostProject>()))
.Callback<HostProject>((hostProject) =>
{
Assert.Same(FallbackRazorConfiguration.Latest, hostProject.Configuration);
@ -346,12 +364,18 @@ public class RazorProjectServiceTest(ITestOutputHelper testOutput) : LanguageSer
{
// Arrange
var projectFilePath = "C:/path/to/project.csproj";
var ownerProject = TestProjectSnapshot.Create(projectFilePath);
IProjectSnapshot ownerProject = TestProjectSnapshot.Create(projectFilePath);
var projectSnapshotManager = new Mock<ProjectSnapshotManagerBase>(MockBehavior.Strict);
projectSnapshotManager.Setup(manager => manager.GetLoadedProject(ownerProject.Key))
projectSnapshotManager
.Setup(manager => manager.GetLoadedProject(ownerProject.Key))
.Returns(ownerProject);
projectSnapshotManager.Setup(manager => manager.ProjectWorkspaceStateChanged(It.IsAny<ProjectKey>(), It.IsAny<ProjectWorkspaceState>()));
projectSnapshotManager.Setup(manager => manager.ProjectConfigurationChanged(It.IsAny<HostProject>()))
projectSnapshotManager
.Setup(manager => manager.TryGetLoadedProject(ownerProject.Key, out ownerProject))
.Returns(true);
projectSnapshotManager
.Setup(manager => manager.ProjectWorkspaceStateChanged(It.IsAny<ProjectKey>(), It.IsAny<ProjectWorkspaceState>()));
projectSnapshotManager
.Setup(manager => manager.ProjectConfigurationChanged(It.IsAny<HostProject>()))
.Callback<HostProject>((hostProject) =>
{
Assert.Same(FallbackRazorConfiguration.MVC_1_1, hostProject.Configuration);
@ -379,9 +403,15 @@ public class RazorProjectServiceTest(ITestOutputHelper testOutput) : LanguageSer
// Arrange
var projectSnapshotManager = new Mock<ProjectSnapshotManagerBase>(MockBehavior.Strict);
var projectKey = TestProjectKey.Create("C:/path/to/obj");
projectSnapshotManager.Setup(manager => manager.GetLoadedProject(projectKey))
projectSnapshotManager
.Setup(manager => manager.GetLoadedProject(projectKey))
.Returns<IProjectSnapshot>(null);
projectSnapshotManager.Setup(manager => manager.ProjectConfigurationChanged(It.IsAny<HostProject>()))
IProjectSnapshot projectResult = null;
projectSnapshotManager
.Setup(manager => manager.TryGetLoadedProject(projectKey, out projectResult))
.Returns(false);
projectSnapshotManager
.Setup(manager => manager.ProjectConfigurationChanged(It.IsAny<HostProject>()))
.Throws(new XunitException("Should not have been called."));
var projectService = CreateProjectService(new TestSnapshotResolver(), projectSnapshotManager.Object);

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

@ -38,7 +38,7 @@ public class SnapshotResolverTest(ITestOutputHelper testOutput) : LanguageServer
// Arrange
var documentFilePath = @"C:\path\to\document.cshtml";
var normalizedFilePath = "C:/path/to/document.cshtml";
var projectSnapshotManagerAccessor = new TestProjectSnapshotManagerAccessor(TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher));
var projectSnapshotManagerAccessor = new TestProjectSnapshotManagerAccessor(TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter));
var snapshotResolver = new SnapshotResolver(projectSnapshotManagerAccessor, LoggerFactory);
var miscProject = snapshotResolver.GetMiscellaneousProject();
@ -62,7 +62,7 @@ public class SnapshotResolverTest(ITestOutputHelper testOutput) : LanguageServer
{
// Arrange
var documentFilePath = @"C:\path\to\document.cshtml";
var projectSnapshotManagerAccessor = new TestProjectSnapshotManagerAccessor(TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher));
var projectSnapshotManagerAccessor = new TestProjectSnapshotManagerAccessor(TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter));
var snapshotResolver = new SnapshotResolver(projectSnapshotManagerAccessor, LoggerFactory);
// Act
@ -78,7 +78,7 @@ public class SnapshotResolverTest(ITestOutputHelper testOutput) : LanguageServer
{
// Arrange
var documentFilePath = "C:/path/to/document.cshtml";
var snapshotResolver = new SnapshotResolver(new TestProjectSnapshotManagerAccessor(TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher)), LoggerFactory);
var snapshotResolver = new SnapshotResolver(new TestProjectSnapshotManagerAccessor(TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter)), LoggerFactory);
// Act
var result = snapshotResolver.TryResolveAllProjects(documentFilePath, out var projects);
@ -93,7 +93,7 @@ public class SnapshotResolverTest(ITestOutputHelper testOutput) : LanguageServer
{
// Arrange
var documentFilePath = "C:/path/to/document.cshtml";
var snapshotResolver = new SnapshotResolver(new TestProjectSnapshotManagerAccessor(TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher)), LoggerFactory);
var snapshotResolver = new SnapshotResolver(new TestProjectSnapshotManagerAccessor(TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter)), LoggerFactory);
_ = snapshotResolver.GetMiscellaneousProject();
// Act
@ -124,7 +124,7 @@ public class SnapshotResolverTest(ITestOutputHelper testOutput) : LanguageServer
{
// Arrange
var documentFilePath = "C:/path/to/document.cshtml";
var snapshotManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var snapshotManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var snapshotResolver = new SnapshotResolver(new TestProjectSnapshotManagerAccessor(snapshotManager), LoggerFactory);
snapshotManager.ProjectAdded(TestProjectSnapshot.Create("C:/other/path/to/project.csproj").HostProject);
@ -141,7 +141,7 @@ public class SnapshotResolverTest(ITestOutputHelper testOutput) : LanguageServer
{
// Arrange
var documentFilePath = "C:/path/to/document.cshtml";
var snapshotManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var snapshotManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var expectedProject = snapshotManager.CreateAndAddProject("C:/path/to/project.csproj");
snapshotManager.CreateAndAddProject("C:/path/to/other/project.csproj");
snapshotManager.CreateAndAddDocument(expectedProject, documentFilePath);
@ -163,7 +163,7 @@ public class SnapshotResolverTest(ITestOutputHelper testOutput) : LanguageServer
var documentFilePath = Path.Combine(TempDirectory.Instance.DirectoryPath, "file.cshtml");
documentFilePath = FilePathNormalizer.Normalize(documentFilePath);
var snapshotManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var snapshotManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var snapshotResolver = new SnapshotResolver(new TestProjectSnapshotManagerAccessor(snapshotManager), LoggerFactory);
var miscProject = (ProjectSnapshot)snapshotResolver.GetMiscellaneousProject();
snapshotManager.CreateAndAddDocument(miscProject, documentFilePath);
@ -182,7 +182,7 @@ public class SnapshotResolverTest(ITestOutputHelper testOutput) : LanguageServer
{
// Arrange
var documentFilePath = "c:/path/to/document.cshtml";
var snapshotManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var snapshotManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var snapshotResolver = new SnapshotResolver(new TestProjectSnapshotManagerAccessor(snapshotManager), LoggerFactory);
var ownerProject = snapshotManager.CreateAndAddProject("C:/Path/To/project.csproj");
@ -200,7 +200,7 @@ public class SnapshotResolverTest(ITestOutputHelper testOutput) : LanguageServer
public void GetMiscellaneousProject_ProjectLoaded_ReturnsExistingProject()
{
// Arrange
var snapshotManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var snapshotManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var snapshotResolver = new SnapshotResolver(new TestProjectSnapshotManagerAccessor(snapshotManager), LoggerFactory);
// Act
@ -215,7 +215,7 @@ public class SnapshotResolverTest(ITestOutputHelper testOutput) : LanguageServer
public void GetMiscellaneousProject_ProjectNotLoaded_CreatesProjectAndReturnsCreatedProject()
{
// Arrange
var snapshotManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var snapshotManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var snapshotResolver = new SnapshotResolver(new TestProjectSnapshotManagerAccessor(snapshotManager), LoggerFactory);
// Act
@ -233,7 +233,7 @@ public class SnapshotResolverTest(ITestOutputHelper testOutput) : LanguageServer
{
filePath = FilePathNormalizer.Normalize(filePath);
snapshotManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
snapshotManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
var snapshotResolver = new SnapshotResolver(new TestProjectSnapshotManagerAccessor(snapshotManager), LoggerFactory);
if (addToMiscellaneous)

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

@ -3,32 +3,25 @@
using Microsoft.AspNetCore.Razor.LanguageServer;
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.AspNetCore.Razor.Test.Common.LanguageServer;
internal class TestProjectSnapshotManager : DefaultProjectSnapshotManager
{
private TestProjectSnapshotManager(
IErrorReporter errorReporter,
Workspace workspace,
IProjectEngineFactoryProvider projectEngineFactoryProvider,
ProjectSnapshotManagerDispatcher dispatcher)
: base(errorReporter, triggers: [], workspace, projectEngineFactoryProvider, dispatcher)
ProjectSnapshotManagerDispatcher dispatcher,
IErrorReporter errorReporter)
: base(triggers: [], projectEngineFactoryProvider, dispatcher, errorReporter)
{
}
public static TestProjectSnapshotManager Create(IErrorReporter errorReporter, ProjectSnapshotManagerDispatcher dispatcher)
{
var services = TestServices.Create(workspaceServices: [], razorLanguageServices: []);
var workspace = TestWorkspace.Create(services);
var testProjectManager = new TestProjectSnapshotManager(errorReporter, workspace, ProjectEngineFactories.DefaultProvider, dispatcher);
return testProjectManager;
}
public static TestProjectSnapshotManager Create(ProjectSnapshotManagerDispatcher dispatcher, IErrorReporter errorReporter)
=> new TestProjectSnapshotManager(ProjectEngineFactories.DefaultProvider, dispatcher, errorReporter);
public bool AllowNotifyListeners { get; set; }
@ -55,4 +48,9 @@ internal class TestProjectSnapshotManager : DefaultProjectSnapshotManager
base.NotifyListeners(e);
}
}
private sealed class TestWorkspaceProvider(Workspace workspace) : IWorkspaceProvider
{
public Workspace GetWorkspace() => workspace;
}
}

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

@ -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;
using System.Linq;
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.CodeAnalysis;
@ -12,15 +11,13 @@ using Moq;
namespace Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem;
internal class TestProjectSnapshotManager(
Workspace workspace,
IProjectEngineFactoryProvider projectEngineFactoryProvider,
ProjectSnapshotManagerDispatcher dispatcher)
: DefaultProjectSnapshotManager(
Mock.Of<IErrorReporter>(MockBehavior.Strict),
Array.Empty<IProjectSnapshotChangeTrigger>(),
workspace,
triggers: [],
projectEngineFactoryProvider,
dispatcher)
dispatcher,
Mock.Of<IErrorReporter>(MockBehavior.Strict))
{
public bool AllowNotifyListeners { get; set; }

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

@ -8,22 +8,19 @@ using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Xunit.Abstractions;
namespace Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
public abstract class WorkspaceTestBase : ToolingTestBase
public abstract class WorkspaceTestBase(ITestOutputHelper testOutput) : ToolingTestBase(testOutput)
{
private bool _initialized;
private HostServices? _hostServices;
private Workspace? _workspace;
private IWorkspaceProvider? _workspaceProvider;
private IProjectEngineFactoryProvider? _projectEngineFactoryProvider;
protected WorkspaceTestBase(ITestOutputHelper testOutput)
: base(testOutput)
{
}
protected HostServices HostServices
{
get
@ -42,6 +39,15 @@ public abstract class WorkspaceTestBase : ToolingTestBase
}
}
private protected IWorkspaceProvider WorkspaceProvider
{
get
{
EnsureInitialized();
return _workspaceProvider;
}
}
private protected IProjectEngineFactoryProvider ProjectEngineFactoryProvider
{
get
@ -67,13 +73,14 @@ public abstract class WorkspaceTestBase : ToolingTestBase
{
}
[MemberNotNull(nameof(_hostServices), nameof(_workspace), nameof(_projectEngineFactoryProvider))]
[MemberNotNull(nameof(_hostServices), nameof(_workspace), nameof(_workspaceProvider), nameof(_projectEngineFactoryProvider))]
private void EnsureInitialized()
{
if (_initialized)
{
_hostServices.AssumeNotNull();
_workspace.AssumeNotNull();
_workspaceProvider.AssumeNotNull();
_projectEngineFactoryProvider.AssumeNotNull();
return;
}
@ -92,6 +99,12 @@ public abstract class WorkspaceTestBase : ToolingTestBase
_hostServices = TestServices.Create(workspaceServices, languageServices);
_workspace = TestWorkspace.Create(_hostServices, ConfigureWorkspace);
AddDisposable(_workspace);
_workspaceProvider = new TestWorkspaceProvider(_workspace);
_initialized = true;
}
private sealed class TestWorkspaceProvider(Workspace workspace) : IWorkspaceProvider
{
public Workspace GetWorkspace() => workspace;
}
}

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

@ -29,11 +29,11 @@ public class FallbackProjectManagerTest : WorkspaceTestBase
_projectConfigurationFilePathStore = new TestProjectConfigurationFilePathStore();
var dispatcher = Mock.Of<ProjectSnapshotManagerDispatcher>(MockBehavior.Strict);
_projectSnapshotManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, dispatcher);
_projectSnapshotManager = new TestProjectSnapshotManager(ProjectEngineFactoryProvider, dispatcher);
var projectSnapshotManagerAccessor = Mock.Of<IProjectSnapshotManagerAccessor>(a => a.Instance == _projectSnapshotManager, MockBehavior.Strict);
_fallbackProjectManger = new FallbackProjectManager(_projectConfigurationFilePathStore, languageServerFeatureOptions, projectSnapshotManagerAccessor, NoOpTelemetryReporter.Instance);
_fallbackProjectManger = new FallbackProjectManager(_projectConfigurationFilePathStore, languageServerFeatureOptions, projectSnapshotManagerAccessor, WorkspaceProvider, NoOpTelemetryReporter.Instance);
}
[Fact]

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

@ -1,10 +1,7 @@
// 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;
using System.Linq;
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
@ -21,12 +18,11 @@ public partial class OutOfProcTagHelperResolverTest
return dispatcher.Object;
});
private class TestProjectSnapshotManager(Workspace workspace, IProjectEngineFactoryProvider projectEngineFactoryProvider) : DefaultProjectSnapshotManager(
Mock.Of<IErrorReporter>(MockBehavior.Strict),
Enumerable.Empty<IProjectSnapshotChangeTrigger>(),
workspace,
private class TestProjectSnapshotManager(IProjectEngineFactoryProvider projectEngineFactoryProvider) : DefaultProjectSnapshotManager(
triggers: [],
projectEngineFactoryProvider,
s_projectSnapshotManagerDispatcher.Value)
s_projectSnapshotManagerDispatcher.Value,
Mock.Of<IErrorReporter>(MockBehavior.Strict))
{
}
}

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

@ -20,10 +20,10 @@ namespace Microsoft.CodeAnalysis.Remote.Razor;
public partial class OutOfProcTagHelperResolverTest
{
private class TestResolver(
IProjectSnapshotManagerAccessor projectManagerAccessor,
IWorkspaceProvider workspaceProvider,
IErrorReporter errorReporter,
ITelemetryReporter telemetryReporter)
: OutOfProcTagHelperResolver(projectManagerAccessor, errorReporter, telemetryReporter)
: OutOfProcTagHelperResolver(workspaceProvider, errorReporter, telemetryReporter)
{
public Func<IProjectSnapshot, ValueTask<ImmutableArray<TagHelperDescriptor>>>? OnResolveOutOfProcess { get; init; }

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

@ -27,6 +27,7 @@ public partial class OutOfProcTagHelperResolverTest : TagHelperDescriptorTestBas
private readonly HostProject _hostProject_For_NonSerializableConfiguration;
private readonly Project _workspaceProject;
private readonly IProjectSnapshotManagerAccessor _projectManagerAccessor;
private readonly IWorkspaceProvider _workspaceProvider;
public OutOfProcTagHelperResolverTest(ITestOutputHelper testOutput)
: base(testOutput)
@ -45,6 +46,13 @@ public partial class OutOfProcTagHelperResolverTest : TagHelperDescriptorTestBas
var workspace = new AdhocWorkspace();
AddDisposable(workspace);
var workspaceProviderMock = new Mock<IWorkspaceProvider>(MockBehavior.Strict);
workspaceProviderMock
.Setup(x => x.GetWorkspace())
.Returns(workspace);
_workspaceProvider = workspaceProviderMock.Object;
var info = ProjectInfo.Create(ProjectId.CreateNewId("Test"), VersionStamp.Default, "Test", "Test", LanguageNames.CSharp, filePath: "Test.csproj");
_workspaceProject = workspace.CurrentSolution.AddProject(info).GetProject(info.Id).AssumeNotNull();
@ -55,7 +63,7 @@ public partial class OutOfProcTagHelperResolverTest : TagHelperDescriptorTestBas
CreateFactory("Test-2"));
var projectEngineFactoryProvider = new ProjectEngineFactoryProvider(customFactories);
var projectManager = new TestProjectSnapshotManager(workspace, projectEngineFactoryProvider);
var projectManager = new TestProjectSnapshotManager(projectEngineFactoryProvider);
var projectManagerAccessorMock = new Mock<IProjectSnapshotManagerAccessor>(MockBehavior.Strict);
projectManagerAccessorMock
@ -80,11 +88,11 @@ public partial class OutOfProcTagHelperResolverTest : TagHelperDescriptorTestBas
// Arrange
_projectManagerAccessor.Instance.ProjectAdded(_hostProject_For_2_0);
var projectSnapshot = _projectManagerAccessor.Instance.GetLoadedProject(_hostProject_For_2_0.Key).AssumeNotNull();
var projectSnapshot = _projectManagerAccessor.Instance.GetLoadedProject(_hostProject_For_2_0.Key);
var calledOutOfProcess = false;
var resolver = new TestResolver(_projectManagerAccessor, ErrorReporter, NoOpTelemetryReporter.Instance)
var resolver = new TestResolver(_workspaceProvider, ErrorReporter, NoOpTelemetryReporter.Instance)
{
OnResolveOutOfProcess = (p) =>
{
@ -109,11 +117,11 @@ public partial class OutOfProcTagHelperResolverTest : TagHelperDescriptorTestBas
// Arrange
_projectManagerAccessor.Instance.ProjectAdded(_hostProject_For_NonSerializableConfiguration);
var projectSnapshot = _projectManagerAccessor.Instance.GetLoadedProject(_hostProject_For_2_0.Key).AssumeNotNull();
var projectSnapshot = _projectManagerAccessor.Instance.GetLoadedProject(_hostProject_For_2_0.Key);
var calledInProcess = false;
var resolver = new TestResolver(_projectManagerAccessor, ErrorReporter, NoOpTelemetryReporter.Instance)
var resolver = new TestResolver(_workspaceProvider, ErrorReporter, NoOpTelemetryReporter.Instance)
{
OnResolveInProcess = (p) =>
{
@ -138,13 +146,13 @@ public partial class OutOfProcTagHelperResolverTest : TagHelperDescriptorTestBas
// Arrange
_projectManagerAccessor.Instance.ProjectAdded(_hostProject_For_2_0);
var projectSnapshot = _projectManagerAccessor.Instance.GetLoadedProject(_hostProject_For_2_0.Key).AssumeNotNull();
var projectSnapshot = _projectManagerAccessor.Instance.GetLoadedProject(_hostProject_For_2_0.Key);
var calledOutOfProcess = false;
var calledInProcess = false;
var cancellationToken = new CancellationToken(canceled: true);
var resolver = new TestResolver(_projectManagerAccessor, ErrorReporter, NoOpTelemetryReporter.Instance)
var resolver = new TestResolver(_workspaceProvider, ErrorReporter, NoOpTelemetryReporter.Instance)
{
OnResolveInProcess = (p) =>
{
@ -172,7 +180,7 @@ public partial class OutOfProcTagHelperResolverTest : TagHelperDescriptorTestBas
public void CalculateTagHelpersFromDelta_NewProject()
{
// Arrange
var resolver = new TestResolver(_projectManagerAccessor, ErrorReporter, NoOpTelemetryReporter.Instance);
var resolver = new TestResolver(_workspaceProvider, ErrorReporter, NoOpTelemetryReporter.Instance);
var initialDelta = new TagHelperDeltaResult(IsDelta: false, ResultId: 1, Project1TagHelperChecksums, ImmutableArray<Checksum>.Empty);
// Act
@ -186,7 +194,7 @@ public partial class OutOfProcTagHelperResolverTest : TagHelperDescriptorTestBas
public void CalculateTagHelpersFromDelta_DeltaFailedToApplyToKnownProject()
{
// Arrange
var resolver = new TestResolver(_projectManagerAccessor, ErrorReporter, NoOpTelemetryReporter.Instance);
var resolver = new TestResolver(_workspaceProvider, ErrorReporter, NoOpTelemetryReporter.Instance);
var initialDelta = new TagHelperDeltaResult(IsDelta: false, ResultId: 1, Project1TagHelperChecksums, ImmutableArray<Checksum>.Empty);
resolver.PublicProduceChecksumsFromDelta(Project1Id, lastResultId: -1, initialDelta);
var newTagHelperSet = ImmutableArray.Create(TagHelper1_Project1.Checksum);
@ -203,7 +211,7 @@ public partial class OutOfProcTagHelperResolverTest : TagHelperDescriptorTestBas
public void CalculateTagHelpersFromDelta_NoopResult()
{
// Arrange
var resolver = new TestResolver(_projectManagerAccessor, ErrorReporter, NoOpTelemetryReporter.Instance);
var resolver = new TestResolver(_workspaceProvider, ErrorReporter, NoOpTelemetryReporter.Instance);
var initialDelta = new TagHelperDeltaResult(IsDelta: false, ResultId: 1, Project1TagHelperChecksums, ImmutableArray<Checksum>.Empty);
resolver.PublicProduceChecksumsFromDelta(Project1Id, lastResultId: -1, initialDelta);
var noopDelta = new TagHelperDeltaResult(IsDelta: true, initialDelta.ResultId, ImmutableArray<Checksum>.Empty, ImmutableArray<Checksum>.Empty);
@ -219,7 +227,7 @@ public partial class OutOfProcTagHelperResolverTest : TagHelperDescriptorTestBas
public void CalculateTagHelpersFromDelta_ReplacedTagHelpers()
{
// Arrange
var resolver = new TestResolver(_projectManagerAccessor, ErrorReporter, NoOpTelemetryReporter.Instance);
var resolver = new TestResolver(_workspaceProvider, ErrorReporter, NoOpTelemetryReporter.Instance);
var initialDelta = new TagHelperDeltaResult(IsDelta: false, ResultId: 1, Project1TagHelperChecksums, ImmutableArray<Checksum>.Empty);
resolver.PublicProduceChecksumsFromDelta(Project1Id, lastResultId: -1, initialDelta);
var changedDelta = new TagHelperDeltaResult(IsDelta: true, initialDelta.ResultId + 1, ImmutableArray.Create(TagHelper2_Project2.Checksum), ImmutableArray.Create(TagHelper2_Project1.Checksum));

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

@ -44,11 +44,23 @@ public class DefaultRazorDocumentManagerTest : ProjectSnapshotManagerDispatcherT
c => c.IsOfType(It.IsAny<string>()) == false,
MockBehavior.Strict);
var projectManager = Mock.Of<ProjectSnapshotManagerBase>(
p => p.GetProjects() == ImmutableArray<IProjectSnapshot>.Empty &&
p.GetLoadedProject(It.IsAny<ProjectKey>()) == null &&
p.GetAllProjectKeys(It.IsAny<string>()) == ImmutableArray<ProjectKey>.Empty,
MockBehavior.Strict);
var projectManagerMock = new Mock<ProjectSnapshotManagerBase>(MockBehavior.Strict);
projectManagerMock
.Setup(p => p.GetAllProjectKeys(It.IsAny<string>()))
.Returns(ImmutableArray<ProjectKey>.Empty);
projectManagerMock
.Setup(p => p.GetProjects())
.Returns(ImmutableArray<IProjectSnapshot>.Empty);
IProjectSnapshot projectResult = null;
projectManagerMock
.Setup(p => p.GetLoadedProject(It.IsAny<ProjectKey>()))
.Returns(projectResult);
projectManagerMock
.Setup(p => p.TryGetLoadedProject(It.IsAny<ProjectKey>(), out projectResult))
.Returns(false);
var projectManager = projectManagerMock.Object;
var projectManagerAccessorMock = new Mock<IProjectSnapshotManagerAccessor>(MockBehavior.Strict);
projectManagerAccessorMock
@ -64,7 +76,6 @@ public class DefaultRazorDocumentManagerTest : ProjectSnapshotManagerDispatcherT
importDocumentManager.Setup(m => m.OnSubscribed(It.IsAny<VisualStudioDocumentTracker>())).Verifiable();
importDocumentManager.Setup(m => m.OnUnsubscribed(It.IsAny<VisualStudioDocumentTracker>())).Verifiable();
_importDocumentManager = importDocumentManager.Object;
}
[UIFact]

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

@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.Editor;
using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem;
@ -54,7 +53,7 @@ public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDisp
_workspaceEditorSettings = new DefaultWorkspaceEditorSettings(Mock.Of<IClientSettingsManager>(MockBehavior.Strict));
_projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, Dispatcher) { AllowNotifyListeners = true };
_projectManager = new TestProjectSnapshotManager(ProjectEngineFactoryProvider, Dispatcher) { AllowNotifyListeners = true };
var projectManagerAccessorMock = new Mock<IProjectSnapshotManagerAccessor>(MockBehavior.Strict);
projectManagerAccessorMock
@ -166,7 +165,7 @@ public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDisp
// Arrange
_projectManager.ProjectAdded(_hostProject);
var e = new ProjectChangeEventArgs(null!, _projectManager.GetLoadedProject(_hostProject.Key)!, ProjectChangeKind.ProjectAdded);
var e = new ProjectChangeEventArgs(null!, _projectManager.GetLoadedProject(_hostProject.Key), ProjectChangeKind.ProjectAdded);
var called = false;
_documentTracker.ContextChanged += (sender, args) =>
@ -189,7 +188,7 @@ public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDisp
// Arrange
_projectManager.ProjectAdded(_hostProject);
var e = new ProjectChangeEventArgs(null!, _projectManager.GetLoadedProject(_hostProject.Key)!, ProjectChangeKind.ProjectChanged);
var e = new ProjectChangeEventArgs(null!, _projectManager.GetLoadedProject(_hostProject.Key), ProjectChangeKind.ProjectChanged);
var called = false;
_documentTracker.ContextChanged += (sender, args) =>
@ -239,7 +238,7 @@ public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDisp
// Arrange
_projectManager.ProjectAdded(_otherHostProject);
var e = new ProjectChangeEventArgs(null!, _projectManager.GetLoadedProject(_otherHostProject.Key)!, ProjectChangeKind.ProjectChanged);
var e = new ProjectChangeEventArgs(null!, _projectManager.GetLoadedProject(_otherHostProject.Key), ProjectChangeKind.ProjectChanged);
var called = false;
_documentTracker.ContextChanged += (sender, args) => called = true;

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

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Threading;
using Moq;
@ -56,8 +57,10 @@ public class EditorDocumentManagerListenerTest : ProjectSnapshotManagerDispatche
.Setup(e => e.RemoveDocument(It.IsAny<EditorDocument>()))
.Callback<EditorDocument>(doc => Assert.Same(document, doc));
var workspaceProvider = Mock.Of<IWorkspaceProvider>(MockBehavior.Strict);
var listener = new EditorDocumentManagerListener(
Dispatcher, JoinableTaskFactory.Context, editorDocumentManger.Object, changedOnDisk, changedInEditor, opened, closed);
workspaceProvider, Dispatcher, JoinableTaskContext, editorDocumentManger.Object, changedOnDisk, changedInEditor, opened, closed);
var projectFilePath = "/Path/to/project.csproj";
var project = Mock.Of<IProjectSnapshot>(p => p.Key == TestProjectKey.Create("/Path/to/obj") && p.FilePath == projectFilePath, MockBehavior.Strict);
@ -84,8 +87,10 @@ public class EditorDocumentManagerListenerTest : ProjectSnapshotManagerDispatche
.Setup(e => e.RemoveDocument(It.IsAny<EditorDocument>()))
.Callback<EditorDocument>(doc => Assert.Same(document, doc));
var workspaceProvider = Mock.Of<IWorkspaceProvider>(MockBehavior.Strict);
var listener = new EditorDocumentManagerListener(
Dispatcher, JoinableTaskFactory.Context, editorDocumentManger.Object, changedOnDisk, changedInEditor, opened, closed);
workspaceProvider, Dispatcher, JoinableTaskContext, editorDocumentManger.Object, changedOnDisk, changedInEditor, opened, closed);
var projectFilePath = "/Path/to/project.csproj";
var project = Mock.Of<IProjectSnapshot>(p =>
@ -118,8 +123,10 @@ public class EditorDocumentManagerListenerTest : ProjectSnapshotManagerDispatche
Assert.Same(closed, onClosed);
});
var workspaceProvider = Mock.Of<IWorkspaceProvider>(MockBehavior.Strict);
var listener = new EditorDocumentManagerListener(
Dispatcher, JoinableTaskFactory.Context, editorDocumentManger.Object, changedOnDisk, changedInEditor, opened, closed);
workspaceProvider, Dispatcher, JoinableTaskContext, editorDocumentManger.Object, changedOnDisk, changedInEditor, opened, closed);
var projectFilePath = "/Path/to/project.csproj";
var project = Mock.Of<IProjectSnapshot>(p => p.Key == TestProjectKey.Create("/Path/to/obj") && p.FilePath == projectFilePath, MockBehavior.Strict);
@ -140,8 +147,10 @@ public class EditorDocumentManagerListenerTest : ProjectSnapshotManagerDispatche
.Setup(e => e.GetOrCreateDocument(It.IsAny<DocumentKey>(), It.IsAny<string>(), It.IsAny<ProjectKey>(), It.IsAny<EventHandler>(), It.IsAny<EventHandler>(), It.IsAny<EventHandler>(), It.IsAny<EventHandler>()))
.Returns(GetEditorDocument(isOpen: true));
var workspaceProvider = Mock.Of<IWorkspaceProvider>(MockBehavior.Strict);
var listener = new EditorDocumentManagerListener(
Dispatcher, JoinableTaskFactory.Context, editorDocumentManger.Object, onChangedOnDisk: null, onChangedInEditor: null, onOpened: opened, onClosed: null);
workspaceProvider, Dispatcher, JoinableTaskContext, editorDocumentManger.Object, onChangedOnDisk: null, onChangedInEditor: null, onOpened: opened, onClosed: null);
var projectFilePath = "/Path/to/project.csproj";
var project = Mock.Of<IProjectSnapshot>(p => p.Key == TestProjectKey.Create("/Path/to/obj") && p.FilePath == projectFilePath, MockBehavior.Strict);
@ -158,7 +167,7 @@ public class EditorDocumentManagerListenerTest : ProjectSnapshotManagerDispatche
var document = new EditorDocument(
documentManager ?? Mock.Of<EditorDocumentManager>(MockBehavior.Strict),
Dispatcher,
JoinableTaskFactory.Context,
JoinableTaskContext,
_projectFilePath,
_documentFilePath,
_projectKey,

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

@ -26,7 +26,6 @@ public class ProjectWorkspaceStateGeneratorTest : ProjectSnapshotManagerDispatch
{
private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider;
private readonly TestTagHelperResolver _tagHelperResolver;
private readonly Workspace _workspace;
private readonly Project _workspaceProject;
private readonly ProjectSnapshot _projectSnapshot;
private readonly ProjectWorkspaceState _projectWorkspaceStateWithTagHelpers;
@ -40,10 +39,11 @@ public class ProjectWorkspaceStateGeneratorTest : ProjectSnapshotManagerDispatch
ImmutableArray.Create(TagHelperDescriptorBuilder.Create("ResolvableTagHelper", "TestAssembly").Build()));
var testServices = TestServices.Create([], []);
_workspace = TestWorkspace.Create(testServices);
AddDisposable(_workspace);
var workspace = TestWorkspace.Create(testServices);
AddDisposable(workspace);
var projectId = ProjectId.CreateNewId("Test");
var solution = _workspace.CurrentSolution.AddProject(ProjectInfo.Create(
var solution = workspace.CurrentSolution.AddProject(ProjectInfo.Create(
projectId,
VersionStamp.Default,
"Test",
@ -59,7 +59,7 @@ public class ProjectWorkspaceStateGeneratorTest : ProjectSnapshotManagerDispatch
private IProjectSnapshotManagerAccessor CreateProjectManagerAccessor()
{
var projectManager = new TestProjectSnapshotManager(_workspace, _projectEngineFactoryProvider, Dispatcher);
var projectManager = new TestProjectSnapshotManager(_projectEngineFactoryProvider, Dispatcher);
var mock = new Mock<IProjectSnapshotManagerAccessor>(MockBehavior.Strict);
mock.SetupGet(x => x.Instance).Returns(projectManager);

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

@ -86,7 +86,7 @@ public class CSharpVirtualDocumentFactoryTest : ToolingTestBase
var uriProvider = Mock.Of<FileUriProvider>(provider => provider.GetOrCreate(_razorLSPBuffer) == uri, MockBehavior.Strict);
Mock.Get(uriProvider).Setup(p => p.AddOrUpdate(It.IsAny<ITextBuffer>(), It.IsAny<Uri>())).Verifiable();
var projectSnapshotManager = TestProjectSnapshotManager.Create(ErrorReporter, new TestDispatcher());
var projectSnapshotManager = TestProjectSnapshotManager.Create(new TestDispatcher(), ErrorReporter);
var project = projectSnapshotManager.CreateAndAddProject(@"C:\path\to\project.csproj");
projectSnapshotManager.CreateAndAddDocument(project, @"C:\path\to\file.razor");
var projectSnapshotManagerAccessor = Mock.Of<IProjectSnapshotManagerAccessor>(a => a.Instance == projectSnapshotManager, MockBehavior.Strict);
@ -110,7 +110,7 @@ public class CSharpVirtualDocumentFactoryTest : ToolingTestBase
var uriProvider = Mock.Of<FileUriProvider>(provider => provider.GetOrCreate(_razorLSPBuffer) == uri, MockBehavior.Strict);
Mock.Get(uriProvider).Setup(p => p.AddOrUpdate(It.IsAny<ITextBuffer>(), It.IsAny<Uri>())).Verifiable();
var projectSnapshotManager = TestProjectSnapshotManager.Create(ErrorReporter, new TestDispatcher());
var projectSnapshotManager = TestProjectSnapshotManager.Create(new TestDispatcher(), ErrorReporter);
var project = TestProjectSnapshot.Create(@"C:\path\to\project1.csproj", @"C:\path\to\obj1", Array.Empty<string>(), RazorConfiguration.Default, projectWorkspaceState: null);
projectSnapshotManager.ProjectAdded(project.HostProject);
projectSnapshotManager.CreateAndAddDocument(project, @"C:\path\to\file.razor");

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

@ -645,7 +645,7 @@ public class RazorProjectInfoPublisherTest(ITestOutputHelper testOutput) : Langu
internal ProjectSnapshotManagerBase CreateProjectSnapshotManager(bool allowNotifyListeners = false)
{
var snapshotManager = TestProjectSnapshotManager.Create(ErrorReporter, Dispatcher);
var snapshotManager = TestProjectSnapshotManager.Create(Dispatcher, ErrorReporter);
snapshotManager.AllowNotifyListeners = allowNotifyListeners;
return snapshotManager;

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

@ -53,7 +53,7 @@ public class BackgroundDocumentGeneratorTest : ProjectSnapshotManagerDispatcherW
public async Task ProcessDocument_LongDocumentParse_DoesNotUpdateAfterSuppress()
{
// Arrange
var projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, Dispatcher);
var projectManager = new TestProjectSnapshotManager(ProjectEngineFactoryProvider, Dispatcher);
projectManager.ProjectAdded(_hostProject1);
// We utilize a task completion source here so we can "fake" a document parse taking a significant amount of time
@ -99,7 +99,7 @@ public class BackgroundDocumentGeneratorTest : ProjectSnapshotManagerDispatcherW
public async Task ProcessDocument_SwallowsIOExceptions()
{
// Arrange
var projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, Dispatcher);
var projectManager = new TestProjectSnapshotManager(ProjectEngineFactoryProvider, Dispatcher);
projectManager.ProjectAdded(_hostProject1);
var textLoader = new Mock<TextLoader>(MockBehavior.Strict);
@ -130,7 +130,7 @@ public class BackgroundDocumentGeneratorTest : ProjectSnapshotManagerDispatcherW
public async Task ProcessDocument_SwallowsUnauthorizedAccessExceptions()
{
// Arrange
var projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, Dispatcher);
var projectManager = new TestProjectSnapshotManager(ProjectEngineFactoryProvider, Dispatcher);
projectManager.ProjectAdded(_hostProject1);
var textLoader = new Mock<TextLoader>(MockBehavior.Strict);
@ -161,7 +161,7 @@ public class BackgroundDocumentGeneratorTest : ProjectSnapshotManagerDispatcherW
public async Task Queue_ProcessesNotifications_AndGoesBackToSleep()
{
// Arrange
var projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, Dispatcher);
var projectManager = new TestProjectSnapshotManager(ProjectEngineFactoryProvider, Dispatcher);
projectManager.ProjectAdded(_hostProject1);
projectManager.ProjectAdded(_hostProject2);
projectManager.DocumentAdded(_hostProject1.Key, _documents[0], null);
@ -200,7 +200,7 @@ public class BackgroundDocumentGeneratorTest : ProjectSnapshotManagerDispatcherW
public async Task Queue_ProcessesNotifications_AndRestarts()
{
// Arrange
var projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, Dispatcher);
var projectManager = new TestProjectSnapshotManager(ProjectEngineFactoryProvider, Dispatcher);
projectManager.ProjectAdded(_hostProject1);
projectManager.ProjectAdded(_hostProject2);
projectManager.DocumentAdded(_hostProject1.Key, _documents[0], null);
@ -263,7 +263,7 @@ public class BackgroundDocumentGeneratorTest : ProjectSnapshotManagerDispatcherW
public async Task DocumentChanged_ReparsesRelatedFiles()
{
// Arrange
var projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, Dispatcher)
var projectManager = new TestProjectSnapshotManager(ProjectEngineFactoryProvider, Dispatcher)
{
AllowNotifyListeners = true,
};
@ -326,7 +326,7 @@ public class BackgroundDocumentGeneratorTest : ProjectSnapshotManagerDispatcherW
public async Task DocumentRemoved_ReparsesRelatedFiles()
{
// Arrange
var projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, Dispatcher)
var projectManager = new TestProjectSnapshotManager(ProjectEngineFactoryProvider, Dispatcher)
{
AllowNotifyListeners = true,
};

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

@ -51,7 +51,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
_hostProject2 = new HostProject(TestProjectData.AnotherProject.FilePath, TestProjectData.AnotherProject.IntermediateOutputPath, FallbackRazorConfiguration.MVC_2_1, TestProjectData.AnotherProject.RootNamespace);
_hostProjectWithConfigurationChange = new HostProject(TestProjectData.SomeProject.FilePath, TestProjectData.SomeProject.IntermediateOutputPath, FallbackRazorConfiguration.MVC_1_0, TestProjectData.SomeProject.RootNamespace);
_projectManager = new TestProjectSnapshotManager(triggers: [], Workspace, ProjectEngineFactoryProvider, Dispatcher);
_projectManager = new TestProjectSnapshotManager(triggers: [], ProjectEngineFactoryProvider, Dispatcher);
_projectWorkspaceStateWithTagHelpers = ProjectWorkspaceState.Create(someTagHelpers);
@ -70,7 +70,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
var triggers = new[] { defaultPriorityTrigger, highPriorityTrigger };
// Act
var projectManager = new TestProjectSnapshotManager(triggers, Workspace, ProjectEngineFactoryProvider, Dispatcher);
var projectManager = new TestProjectSnapshotManager(triggers, ProjectEngineFactoryProvider, Dispatcher);
// Assert
Assert.Equal(new[] { "highPriority", "lowPriority" }, initializedOrder);
@ -649,10 +649,9 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
private class TestProjectSnapshotManager(
IEnumerable<IProjectSnapshotChangeTrigger> triggers,
Workspace workspace,
IProjectEngineFactoryProvider projectEngineFactoryProvider,
ProjectSnapshotManagerDispatcher dispatcher)
: DefaultProjectSnapshotManager(Mock.Of<IErrorReporter>(MockBehavior.Strict), triggers, workspace, projectEngineFactoryProvider, dispatcher)
: DefaultProjectSnapshotManager(triggers, projectEngineFactoryProvider, dispatcher, Mock.Of<IErrorReporter>(MockBehavior.Strict))
{
public ProjectChangeKind? ListenersNotifiedOf { get; private set; }

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

@ -40,7 +40,7 @@ public class DefaultRazorDynamicFileInfoProviderTest : WorkspaceTestBase
{
_documentServiceFactory = new DefaultRazorDocumentServiceProviderFactory();
_editorFeatureDetector = Mock.Of<LSPEditorFeatureDetector>(MockBehavior.Strict);
_projectSnapshotManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, new TestProjectSnapshotManagerDispatcher())
_projectSnapshotManager = new TestProjectSnapshotManager(ProjectEngineFactoryProvider, new TestProjectSnapshotManagerDispatcher())
{
AllowNotifyListeners = true
};
@ -59,9 +59,9 @@ public class DefaultRazorDynamicFileInfoProviderTest : WorkspaceTestBase
var projectSnapshotManagerAccessor = Mock.Of<IProjectSnapshotManagerAccessor>(a => a.Instance == _projectSnapshotManager, MockBehavior.Strict);
var projectConfigurationFilePathStore = Mock.Of<ProjectConfigurationFilePathStore>(MockBehavior.Strict);
var fallbackProjectManager = new FallbackProjectManager(projectConfigurationFilePathStore, languageServerFeatureOptions, projectSnapshotManagerAccessor, NoOpTelemetryReporter.Instance);
var fallbackProjectManager = new FallbackProjectManager(projectConfigurationFilePathStore, languageServerFeatureOptions, projectSnapshotManagerAccessor, WorkspaceProvider, NoOpTelemetryReporter.Instance);
_provider = new DefaultRazorDynamicFileInfoProvider(_documentServiceFactory, _editorFeatureDetector, filePathService, projectSnapshotManagerAccessor, fallbackProjectManager);
_provider = new DefaultRazorDynamicFileInfoProvider(_documentServiceFactory, _editorFeatureDetector, filePathService, WorkspaceProvider, fallbackProjectManager);
_testAccessor = _provider.GetTestAccessor();
_provider.Initialize(_projectSnapshotManager);

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

@ -37,7 +37,7 @@ public class DefaultWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatch
public DefaultWindowsRazorProjectHostTest(ITestOutputHelper testOutput)
: base(testOutput)
{
_projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, Dispatcher);
_projectManager = new TestProjectSnapshotManager(ProjectEngineFactoryProvider, Dispatcher);
var projectManagerAccessorMock = new Mock<IProjectSnapshotManagerAccessor>(MockBehavior.Strict);
projectManagerAccessorMock
@ -1247,15 +1247,13 @@ public class DefaultWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatch
}
private class TestProjectSnapshotManager(
Workspace workspace,
IProjectEngineFactoryProvider projectEngineFactoryProvider,
ProjectSnapshotManagerDispatcher dispatcher)
: DefaultProjectSnapshotManager(
Mock.Of<IErrorReporter>(MockBehavior.Strict),
triggers: [],
workspace,
projectEngineFactoryProvider,
dispatcher)
dispatcher,
Mock.Of<IErrorReporter>(MockBehavior.Strict))
{
}
}

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

@ -35,7 +35,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
public FallbackWindowsRazorProjectHostTest(ITestOutputHelper testOutput)
: base(testOutput)
{
_projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, Dispatcher);
_projectManager = new TestProjectSnapshotManager(ProjectEngineFactoryProvider, Dispatcher);
var projectManagerAccessorMock = new Mock<IProjectSnapshotManagerAccessor>(MockBehavior.Strict);
projectManagerAccessorMock
@ -674,14 +674,12 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
}
private class TestProjectSnapshotManager(
Workspace workspace,
IProjectEngineFactoryProvider projectEngineFactoryProvider,
ProjectSnapshotManagerDispatcher dispatcher) : DefaultProjectSnapshotManager(
Mock.Of<IErrorReporter>(MockBehavior.Strict),
triggers: [],
workspace,
projectEngineFactoryProvider,
dispatcher)
triggers: [],
projectEngineFactoryProvider,
dispatcher,
Mock.Of<IErrorReporter>(MockBehavior.Strict))
{
}
}

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

@ -140,12 +140,12 @@ public class WorkspaceProjectStateChangeDetectorTest : WorkspaceTestBase
{
// Arrange
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, s_dispatcher, TestLanguageServerFeatureOptions.Instance, _workQueue);
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, ErrorReporter, s_dispatcher, _workQueue);
_workQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
_workQueueTestAccessor.NotifyBackgroundWorkStarting = new ManualResetEventSlim(initialState: false);
Workspace.TryApplyChanges(_solutionWithTwoProjects);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace, ProjectEngineFactoryProvider);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, ProjectEngineFactoryProvider);
await s_dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(_hostProjectOne), DisposalToken);
workspaceStateGenerator.ClearQueue();
_workQueueTestAccessor.NotifyBackgroundWorkStarting.Wait();
@ -178,13 +178,13 @@ public class WorkspaceProjectStateChangeDetectorTest : WorkspaceTestBase
{
// Arrange
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, s_dispatcher, TestLanguageServerFeatureOptions.Instance, _workQueue)
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, ErrorReporter, s_dispatcher, _workQueue)
{
NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false),
};
_workQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace, ProjectEngineFactoryProvider);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, ProjectEngineFactoryProvider);
await s_dispatcher.RunOnDispatcherThreadAsync(() =>
{
@ -228,13 +228,13 @@ public class WorkspaceProjectStateChangeDetectorTest : WorkspaceTestBase
{
// Arrange
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, s_dispatcher, TestLanguageServerFeatureOptions.Instance, _workQueue)
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, ErrorReporter, s_dispatcher, _workQueue)
{
NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false),
};
_workQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace, ProjectEngineFactoryProvider);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, ProjectEngineFactoryProvider);
await s_dispatcher.RunOnDispatcherThreadAsync(() =>
{
@ -280,11 +280,11 @@ public class WorkspaceProjectStateChangeDetectorTest : WorkspaceTestBase
{
// Arrange
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, s_dispatcher, TestLanguageServerFeatureOptions.Instance, _workQueue)
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, ErrorReporter, s_dispatcher, _workQueue)
{
NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false),
};
var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace, ProjectEngineFactoryProvider);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, ProjectEngineFactoryProvider);
await s_dispatcher.RunOnDispatcherThreadAsync(() =>
{
projectManager.ProjectAdded(_hostProjectOne);
@ -315,12 +315,12 @@ public class WorkspaceProjectStateChangeDetectorTest : WorkspaceTestBase
{
// Arrange
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, s_dispatcher, TestLanguageServerFeatureOptions.Instance, _workQueue)
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, ErrorReporter, s_dispatcher, _workQueue)
{
NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false),
};
var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace, ProjectEngineFactoryProvider);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, ProjectEngineFactoryProvider);
await s_dispatcher.RunOnDispatcherThreadAsync(() =>
{
@ -360,10 +360,10 @@ public class WorkspaceProjectStateChangeDetectorTest : WorkspaceTestBase
{
// Arrange
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, s_dispatcher, TestLanguageServerFeatureOptions.Instance, _workQueue);
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, ErrorReporter, s_dispatcher, _workQueue);
_workQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace, ProjectEngineFactoryProvider);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, ProjectEngineFactoryProvider);
await s_dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(_hostProjectOne), DisposalToken);
var solution = _solutionWithTwoProjects.WithProjectAssemblyName(_projectNumberOne.Id, "Changed");
@ -390,11 +390,11 @@ public class WorkspaceProjectStateChangeDetectorTest : WorkspaceTestBase
{
// Arrange
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, s_dispatcher, TestLanguageServerFeatureOptions.Instance, _workQueue);
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, ErrorReporter, s_dispatcher, _workQueue);
_workQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
Workspace.TryApplyChanges(_solutionWithTwoProjects);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace, ProjectEngineFactoryProvider);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, ProjectEngineFactoryProvider);
await s_dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(_hostProjectOne), DisposalToken);
workspaceStateGenerator.ClearQueue();
@ -422,11 +422,11 @@ public class WorkspaceProjectStateChangeDetectorTest : WorkspaceTestBase
{
// Arrange
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, s_dispatcher, TestLanguageServerFeatureOptions.Instance, _workQueue);
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, ErrorReporter, s_dispatcher, _workQueue);
_workQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
Workspace.TryApplyChanges(_solutionWithTwoProjects);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace, ProjectEngineFactoryProvider);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, ProjectEngineFactoryProvider);
await s_dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(_hostProjectOne), DisposalToken);
workspaceStateGenerator.ClearQueue();
@ -454,11 +454,11 @@ public class WorkspaceProjectStateChangeDetectorTest : WorkspaceTestBase
{
// Arrange
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, s_dispatcher, TestLanguageServerFeatureOptions.Instance, _workQueue);
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, ErrorReporter, s_dispatcher, _workQueue);
_workQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
Workspace.TryApplyChanges(_solutionWithTwoProjects);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace, ProjectEngineFactoryProvider);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, ProjectEngineFactoryProvider);
await s_dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(_hostProjectOne), DisposalToken);
workspaceStateGenerator.ClearQueue();
@ -486,11 +486,11 @@ public class WorkspaceProjectStateChangeDetectorTest : WorkspaceTestBase
{
// Arrange
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, s_dispatcher, TestLanguageServerFeatureOptions.Instance, _workQueue);
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, ErrorReporter, s_dispatcher, _workQueue);
_workQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
Workspace.TryApplyChanges(_solutionWithTwoProjects);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace, ProjectEngineFactoryProvider);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, ProjectEngineFactoryProvider);
await s_dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(_hostProjectOne), DisposalToken);
workspaceStateGenerator.ClearQueue();
@ -535,11 +535,11 @@ public class WorkspaceProjectStateChangeDetectorTest : WorkspaceTestBase
{
// Arrange
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, s_dispatcher, TestLanguageServerFeatureOptions.Instance, _workQueue)
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, ErrorReporter, s_dispatcher, _workQueue)
{
NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false),
};
var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace, ProjectEngineFactoryProvider);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, ProjectEngineFactoryProvider);
await s_dispatcher.RunOnDispatcherThreadAsync(() =>
{
projectManager.ProjectAdded(_hostProjectOne);
@ -564,11 +564,11 @@ public class WorkspaceProjectStateChangeDetectorTest : WorkspaceTestBase
{
// Arrange
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, s_dispatcher, TestLanguageServerFeatureOptions.Instance, _workQueue)
var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, TestLanguageServerFeatureOptions.Instance, WorkspaceProvider, ErrorReporter, s_dispatcher, _workQueue)
{
NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false),
};
var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace, ProjectEngineFactoryProvider);
var projectManager = new TestProjectSnapshotManager(new[] { detector }, ProjectEngineFactoryProvider);
await s_dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(_hostProjectThree), DisposalToken);
var solution = _solutionWithOneProject;
@ -776,14 +776,12 @@ public class WorkspaceProjectStateChangeDetectorTest : WorkspaceTestBase
private class TestProjectSnapshotManager(
IEnumerable<IProjectSnapshotChangeTrigger> triggers,
Workspace workspace,
IProjectEngineFactoryProvider projectEngineFactoryProvider)
: DefaultProjectSnapshotManager(
Mock.Of<IErrorReporter>(MockBehavior.Strict),
triggers,
workspace,
projectEngineFactoryProvider,
s_dispatcher)
s_dispatcher,
Mock.Of<IErrorReporter>(MockBehavior.Strict))
{
}

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

@ -16,6 +16,7 @@ using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.Editor.Razor;
using Microsoft.VisualStudio.LanguageServices.Razor.Test;
using Microsoft.VisualStudio.Shell.Interop;
@ -34,6 +35,7 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : ToolingTestBase
private readonly HostProject _someOtherProject;
private Project _someWorkspaceProject;
private readonly CodeAnalysis.Workspace _workspace;
private readonly IWorkspaceProvider _workspaceProvider;
public VsSolutionUpdatesProjectSnapshotChangeTriggerTest(ITestOutputHelper testOutput)
: base(testOutput)
@ -59,6 +61,13 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : ToolingTestBase
.WithAssemblyPath(Path.Combine(_someProject.IntermediateOutputPath, "SomeProject.dll"))));
});
AddDisposable(_workspace);
var workspaceProviderMock = new Mock<IWorkspaceProvider>(MockBehavior.Strict);
workspaceProviderMock
.Setup(x => x.GetWorkspace())
.Returns(_workspace);
_workspaceProvider = workspaceProviderMock.Object;
}
[Fact]
@ -79,8 +88,9 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : ToolingTestBase
services.Object,
Mock.Of<TextBufferProjectService>(MockBehavior.Strict),
Mock.Of<IProjectWorkspaceStateGenerator>(MockBehavior.Strict),
_workspaceProvider,
s_dispatcher,
JoinableTaskFactory.Context);
JoinableTaskContext);
// Act
trigger.Initialize(Mock.Of<ProjectSnapshotManagerBase>(MockBehavior.Strict));
@ -99,21 +109,23 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : ToolingTestBase
.Setup(b => b.AdviseUpdateSolutionEvents(It.IsAny<VsSolutionUpdatesProjectSnapshotChangeTrigger>(), out cookie))
.Returns(VSConstants.S_OK);
var context = JoinableTaskFactory.Context;
var services = new Mock<IServiceProvider>(MockBehavior.Strict);
services.Setup(s => s.GetService(It.Is<Type>(f => f == typeof(SVsSolutionBuildManager)))).Callback(() => Assert.True(context.IsOnMainThread)).Returns(buildManager.Object);
services
.Setup(s => s.GetService(It.Is<Type>(f => f == typeof(SVsSolutionBuildManager))))
.Callback(() => Assert.True(JoinableTaskContext.IsOnMainThread))
.Returns(buildManager.Object);
var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(
services.Object,
Mock.Of<TextBufferProjectService>(MockBehavior.Strict),
Mock.Of<IProjectWorkspaceStateGenerator>(MockBehavior.Strict),
_workspaceProvider,
s_dispatcher,
context);
JoinableTaskContext);
await Task.Run(() =>
{
Assert.False(context.IsOnMainThread);
Assert.False(JoinableTaskContext.IsOnMainThread);
trigger.Initialize(Mock.Of<ProjectSnapshotManagerBase>(MockBehavior.Strict));
return Task.CompletedTask;
});
@ -123,7 +135,7 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : ToolingTestBase
public async Task SolutionClosing_CancelsActiveWork()
{
// Arrange
var projectManager = new TestProjectSnapshotManager(_workspace, ProjectEngineFactories.DefaultProvider, s_dispatcher)
var projectManager = new TestProjectSnapshotManager(ProjectEngineFactories.DefaultProvider, s_dispatcher)
{
AllowNotifyListeners = true,
};
@ -140,7 +152,13 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : ToolingTestBase
projectService.Setup(p => p.GetProjectPath(It.IsAny<IVsHierarchy>())).Returns(expectedProjectPath);
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(TestServiceProvider.Instance, projectService.Object, workspaceStateGenerator, s_dispatcher, JoinableTaskFactory.Context);
var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(
TestServiceProvider.Instance,
projectService.Object,
workspaceStateGenerator,
_workspaceProvider,
s_dispatcher,
JoinableTaskContext);
trigger.Initialize(projectManager);
trigger.UpdateProjectCfg_Done(Mock.Of<IVsHierarchy>(MockBehavior.Strict), pCfgProj: default, pCfgSln: default, dwAction: default, fSuccess: default, fCancel: default);
await trigger.CurrentUpdateTaskForTests;
@ -163,7 +181,7 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : ToolingTestBase
public async Task OnProjectBuiltAsync_KnownProject_EnqueuesProjectStateUpdate()
{
// Arrange
var projectManager = new TestProjectSnapshotManager(_workspace, ProjectEngineFactories.DefaultProvider, s_dispatcher);
var projectManager = new TestProjectSnapshotManager(ProjectEngineFactories.DefaultProvider, s_dispatcher);
var expectedProjectPath = _someProject.FilePath;
var expectedProjectSnapshot = await s_dispatcher.RunOnDispatcherThreadAsync(() =>
{
@ -177,7 +195,13 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : ToolingTestBase
projectService.Setup(p => p.GetProjectPath(It.IsAny<IVsHierarchy>())).Returns(expectedProjectPath);
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(TestServiceProvider.Instance, projectService.Object, workspaceStateGenerator, s_dispatcher, JoinableTaskFactory.Context);
var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(
TestServiceProvider.Instance,
projectService.Object,
workspaceStateGenerator,
_workspaceProvider,
s_dispatcher,
JoinableTaskContext);
trigger.Initialize(projectManager);
// Act
@ -206,7 +230,7 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : ToolingTestBase
var projectEngineFactoryProvider = Mock.Of<IProjectEngineFactoryProvider>(MockBehavior.Strict);
var projectSnapshot = new ProjectSnapshot(
IProjectSnapshot projectSnapshot = new ProjectSnapshot(
ProjectState.Create(
projectEngineFactoryProvider,
new HostProject("/Some/Unknown/Path.csproj", "/Some/Unknown/obj", RazorConfiguration.Default, "Path"),
@ -217,16 +241,24 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : ToolingTestBase
projectService.Setup(p => p.GetProjectPath(It.IsAny<IVsHierarchy>())).Returns(expectedProjectPath);
var projectManager = new Mock<ProjectSnapshotManagerBase>(MockBehavior.Strict);
projectManager.SetupGet(p => p.Workspace).Returns(_workspace);
projectManager
.Setup(p => p.GetAllProjectKeys(projectSnapshot.FilePath))
.Returns(ImmutableArray.Create(projectSnapshot.Key));
projectManager
.Setup(p => p.GetLoadedProject(projectSnapshot.Key))
.Returns(projectSnapshot);
projectManager
.Setup(p => p.TryGetLoadedProject(projectSnapshot.Key, out projectSnapshot))
.Returns(true);
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(services.Object, projectService.Object, workspaceStateGenerator, s_dispatcher, JoinableTaskFactory.Context);
var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(
services.Object,
projectService.Object,
workspaceStateGenerator,
_workspaceProvider,
s_dispatcher,
JoinableTaskContext);
trigger.Initialize(projectManager.Object);
// Act
@ -255,13 +287,18 @@ public class VsSolutionUpdatesProjectSnapshotChangeTriggerTest : ToolingTestBase
projectService.Setup(p => p.GetProjectPath(It.IsAny<IVsHierarchy>())).Returns(expectedProjectPath);
var projectManager = new Mock<ProjectSnapshotManagerBase>(MockBehavior.Strict);
projectManager.SetupGet(p => p.Workspace).Returns(_workspace);
projectManager
.Setup(p => p.GetAllProjectKeys(expectedProjectPath))
.Returns(ImmutableArray<ProjectKey>.Empty);
var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(services.Object, projectService.Object, workspaceStateGenerator, s_dispatcher, JoinableTaskFactory.Context);
var trigger = new VsSolutionUpdatesProjectSnapshotChangeTrigger(
services.Object,
projectService.Object,
workspaceStateGenerator,
_workspaceProvider,
s_dispatcher,
JoinableTaskContext);
trigger.Initialize(projectManager.Object);
// Act

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

@ -30,7 +30,7 @@ public class ProjectSnapshotSynchronizationServiceTest : ProjectSnapshotManagerD
{
_sessionContext = new TestCollaborationSession(isHost: false);
var projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, new TestProjectSnapshotManagerDispatcher());
var projectManager = new TestProjectSnapshotManager(ProjectEngineFactoryProvider, new TestProjectSnapshotManagerDispatcher());
var projectManagerAccessorMock = new Mock<IProjectSnapshotManagerAccessor>(MockBehavior.Strict);
projectManagerAccessorMock

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

@ -5,6 +5,7 @@
using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
@ -193,32 +194,29 @@ public class DefaultProjectSnapshotManagerProxyTest : ProjectSnapshotManagerDisp
Assert.Same(state1, state2);
}
private class TestProjectSnapshotManager(params IProjectSnapshot[] projects) : ProjectSnapshotManager
private class TestProjectSnapshotManager(params IProjectSnapshot[] projects) : IProjectSnapshotManager
{
private ImmutableArray<IProjectSnapshot> _projects = projects.ToImmutableArray();
public override ImmutableArray<IProjectSnapshot> GetProjects() => _projects;
public ImmutableArray<IProjectSnapshot> GetProjects() => _projects;
public override event EventHandler<ProjectChangeEventArgs> Changed;
public event EventHandler<ProjectChangeEventArgs> Changed;
public void TriggerChanged(ProjectChangeEventArgs args)
{
Changed?.Invoke(this, args);
}
public override IProjectSnapshot GetLoadedProject(ProjectKey projectKey)
{
throw new NotImplementedException();
}
public IProjectSnapshot GetLoadedProject(ProjectKey projectKey)
=> throw new NotImplementedException();
public override ImmutableArray<ProjectKey> GetAllProjectKeys(string projectFileName)
{
throw new NotImplementedException();
}
public ImmutableArray<ProjectKey> GetAllProjectKeys(string projectFileName)
=> throw new NotImplementedException();
public override bool IsDocumentOpen(string documentFilePath)
{
throw new NotImplementedException();
}
public bool IsDocumentOpen(string documentFilePath)
=> throw new NotImplementedException();
public bool TryGetLoadedProject(ProjectKey projectKey, [NotNullWhen(true)] out IProjectSnapshot project)
=> throw new NotImplementedException();
}
}

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

@ -47,9 +47,7 @@ internal partial class RazorProjectSystemInProcess
return Task.FromResult(false);
}
var project = projectSnapshotManager.GetLoadedProject(projectKeys[0]);
return Task.FromResult(project is not null);
return Task.FromResult(projectSnapshotManager.TryGetLoadedProject(projectKeys[0], out _));
}, TimeSpan.FromMilliseconds(100), cancellationToken);
}
@ -61,13 +59,13 @@ internal partial class RazorProjectSystemInProcess
await Helper.RetryAsync(ct =>
{
var projectKeys = projectSnapshotManager.GetAllProjectKeys(projectFilePath);
if (projectKeys.Length == 0)
if (projectKeys.Length == 0 ||
!projectSnapshotManager.TryGetLoadedProject(projectKeys[0], out var project))
{
return Task.FromResult(false);
}
var project = projectSnapshotManager.GetLoadedProject(projectKeys[0]);
var document = project?.GetDocument(filePath);
var document = project.GetDocument(filePath);
return Task.FromResult(document is not null);
}, TimeSpan.FromMilliseconds(100), cancellationToken);