Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't await FallbackProjectManager updates #10196

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ public void SuppressDocument(ProjectKey projectKey, string documentFilePath)
}
}

public async Task<RazorDynamicFileInfo?> GetDynamicFileInfoAsync(ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken)
public Task<RazorDynamicFileInfo?> GetDynamicFileInfoAsync(ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken)
{
if (projectFilePath is null)
{
Expand All @@ -249,20 +249,18 @@ public void SuppressDocument(ProjectKey projectKey, string documentFilePath)
var projectKey = TryFindProjectKeyForProjectId(projectId);
if (projectKey is not { } razorProjectKey)
{
return null;
return Task.FromResult<RazorDynamicFileInfo?>(null);
}

await _fallbackProjectManager
.DynamicFileAddedAsync(projectId, razorProjectKey, projectFilePath, filePath, cancellationToken)
.ConfigureAwait(false);
_fallbackProjectManager.DynamicFileAdded(projectId, razorProjectKey, projectFilePath, filePath, cancellationToken);

var key = new Key(projectId, filePath);
var entry = _entries.GetOrAdd(key, _createEmptyEntry);

return entry.Current;
return Task.FromResult<RazorDynamicFileInfo?>(entry.Current);
}

public async Task RemoveDynamicFileInfoAsync(ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken)
public Task RemoveDynamicFileInfoAsync(ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken)
{
if (projectFilePath is null)
{
Expand All @@ -277,12 +275,10 @@ public async Task RemoveDynamicFileInfoAsync(ProjectId projectId, string? projec
var projectKey = TryFindProjectKeyForProjectId(projectId);
if (projectKey is not { } razorProjectKey)
{
return;
return Task.CompletedTask;
}

await _fallbackProjectManager
.DynamicFileRemovedAsync(projectId, razorProjectKey, projectFilePath, filePath, cancellationToken)
.ConfigureAwait(false);
_fallbackProjectManager.DynamicFileRemoved(projectId, razorProjectKey, projectFilePath, filePath, cancellationToken);

// ---------------------------------------------------------- NOTE & CAUTION --------------------------------------------------------------
//
Expand All @@ -296,6 +292,8 @@ await _fallbackProjectManager

var key = new Key(projectId, filePath);
_entries.TryRemove(key, out _);

return Task.CompletedTask;
}

public static string GetProjectSystemFilePath(Uri uri)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
using System.ComponentModel.Composition;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.AspNetCore.Razor.Utilities;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.Editor.Razor;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Threading;

namespace Microsoft.CodeAnalysis.Razor.ProjectSystem;

Expand All @@ -36,7 +36,7 @@ internal sealed class FallbackProjectManager(
private readonly IWorkspaceProvider _workspaceProvider = workspaceProvider;
private readonly ITelemetryReporter _telemetryReporter = telemetryReporter;

internal async Task DynamicFileAddedAsync(
internal void DynamicFileAdded(
ProjectId projectId,
ProjectKey razorProjectKey,
string projectFilePath,
Expand All @@ -51,15 +51,15 @@ internal async Task DynamicFileAddedAsync(
{
// 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.
await AddFallbackDocumentAsync(razorProjectKey, filePath, projectFilePath, cancellationToken).ConfigureAwait(false);
AddFallbackDocument(razorProjectKey, filePath, projectFilePath, cancellationToken);
}
}
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
// use the Razor or Web SDK) we spin up a fallback experience for them
await AddFallbackProjectAsync(projectId, filePath, cancellationToken).ConfigureAwait(false);
AddFallbackProject(projectId, filePath, cancellationToken);
}
}
catch (Exception ex)
Expand All @@ -68,7 +68,7 @@ internal async Task DynamicFileAddedAsync(
}
}

internal async Task DynamicFileRemovedAsync(
internal void DynamicFileRemoved(
ProjectId projectId,
ProjectKey razorProjectKey,
string projectFilePath,
Expand All @@ -82,7 +82,7 @@ internal async Task DynamicFileRemovedAsync(
{
// 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.
await RemoveFallbackDocumentAsync(projectId, filePath, projectFilePath, cancellationToken).ConfigureAwait(false);
RemoveFallbackDocument(projectId, filePath, projectFilePath, cancellationToken);
}
}
catch (Exception ex)
Expand All @@ -91,7 +91,7 @@ internal async Task DynamicFileRemovedAsync(
}
}

private async Task AddFallbackProjectAsync(ProjectId projectId, string filePath, CancellationToken cancellationToken)
private void AddFallbackProject(ProjectId projectId, string filePath, CancellationToken cancellationToken)
{
var project = TryFindProjectForProjectId(projectId);
if (project?.FilePath is null)
Expand All @@ -113,19 +113,18 @@ private async Task AddFallbackProjectAsync(ProjectId projectId, string filePath,
// the project will be updated, and it will no longer be a fallback project.
var hostProject = new FallbackHostProject(project.FilePath, intermediateOutputPath, FallbackRazorConfiguration.Latest, rootNamespace, project.Name);

await UpdateProjectManagerAsync(
updater => updater.ProjectAdded(hostProject),
cancellationToken)
.ConfigureAwait(false);
EnqueueProjectManagerUpdate(
updater => updater.ProjectAdded(hostProject),
cancellationToken);

await AddFallbackDocumentAsync(hostProject.Key, filePath, project.FilePath, cancellationToken).ConfigureAwait(false);
AddFallbackDocument(hostProject.Key, filePath, project.FilePath, cancellationToken);

var configurationFilePath = Path.Combine(intermediateOutputPath, _languageServerFeatureOptions.ProjectConfigurationFileName);

_projectConfigurationFilePathStore.Set(hostProject.Key, configurationFilePath);
}

private async Task AddFallbackDocumentAsync(ProjectKey projectKey, string filePath, string projectFilePath, CancellationToken cancellationToken)
private void AddFallbackDocument(ProjectKey projectKey, string filePath, string projectFilePath, CancellationToken cancellationToken)
{
var hostDocument = CreateHostDocument(filePath, projectFilePath);
if (hostDocument is null)
Expand All @@ -135,10 +134,9 @@ private async Task AddFallbackDocumentAsync(ProjectKey projectKey, string filePa

var textLoader = new FileTextLoader(filePath, defaultEncoding: null);

await UpdateProjectManagerAsync(
updater => updater.DocumentAdded(projectKey, hostDocument, textLoader),
cancellationToken)
.ConfigureAwait(false);
EnqueueProjectManagerUpdate(
updater => updater.DocumentAdded(projectKey, hostDocument, textLoader),
cancellationToken);
}

private static HostDocument? CreateHostDocument(string filePath, string projectFilePath)
Expand All @@ -157,7 +155,7 @@ await UpdateProjectManagerAsync(
return hostDocument;
}

private async Task RemoveFallbackDocumentAsync(ProjectId projectId, string filePath, string projectFilePath, CancellationToken cancellationToken)
private void RemoveFallbackDocument(ProjectId projectId, string filePath, string projectFilePath, CancellationToken cancellationToken)
{
var project = TryFindProjectForProjectId(projectId);
if (project is null)
Expand All @@ -173,15 +171,14 @@ private async Task RemoveFallbackDocumentAsync(ProjectId projectId, string fileP
return;
}

await UpdateProjectManagerAsync(
updater => updater.DocumentRemoved(projectKey, hostDocument),
cancellationToken)
.ConfigureAwait(false);
EnqueueProjectManagerUpdate(
updater => updater.DocumentRemoved(projectKey, hostDocument),
cancellationToken);
}

private Task UpdateProjectManagerAsync(Action<ProjectSnapshotManager.Updater> action, CancellationToken cancellationToken)
private void EnqueueProjectManagerUpdate(Action<ProjectSnapshotManager.Updater> action, CancellationToken cancellationToken)
{
return _projectManager
_projectManager
.UpdateAsync(
static (updater, state) =>
{
Expand All @@ -191,7 +188,8 @@ private Task UpdateProjectManagerAsync(Action<ProjectSnapshotManager.Updater> ac
action(updater);
},
state: (_serviceProvider, action),
cancellationToken);
cancellationToken)
.Forget();
}

private Project? TryFindProjectForProjectId(ProjectId projectId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,15 @@ await _projectManager.UpdateAsync(updater =>
new CompilationOutputInfo().WithAssemblyPath(Path.Combine(SomeProject.IntermediateOutputPath, "SomeProject.dll")));
Workspace.TryApplyChanges(Workspace.CurrentSolution.AddProject(projectInfo));

await _fallbackProjectManger.DynamicFileAddedAsync(
projectId,
hostProject.Key,
SomeProject.FilePath,
SomeProjectFile1.FilePath,
DisposalToken);
await RunOnDispatcherAsync(() =>
{
_fallbackProjectManger.DynamicFileAdded(
projectId,
hostProject.Key,
SomeProject.FilePath,
SomeProjectFile1.FilePath,
DisposalToken);
});

var project = Assert.Single(_projectManager.GetProjects());
Assert.IsNotType<FallbackHostProject>(((ProjectSnapshot)project).HostProject);
Expand All @@ -93,12 +96,15 @@ public async Task DynamicFileAdded_UnknownProject_Adds()

Workspace.TryApplyChanges(Workspace.CurrentSolution.AddProject(projectInfo));

await _fallbackProjectManger.DynamicFileAddedAsync(
projectId,
SomeProject.Key,
SomeProject.FilePath,
SomeProjectFile1.FilePath,
DisposalToken);
await RunOnDispatcherAsync(() =>
{
_fallbackProjectManger.DynamicFileAdded(
projectId,
SomeProject.Key,
SomeProject.FilePath,
SomeProjectFile1.FilePath,
DisposalToken);
});

var project = Assert.Single(_projectManager.GetProjects());
Assert.Equal("DisplayName", project.DisplayName);
Expand All @@ -122,12 +128,15 @@ public async Task DynamicFileAdded_UnknownToKnownProject_NotFallbackHostProject(

Workspace.TryApplyChanges(Workspace.CurrentSolution.AddProject(projectInfo));

await _fallbackProjectManger.DynamicFileAddedAsync(
await RunOnDispatcherAsync(() =>
{
_fallbackProjectManger.DynamicFileAdded(
projectId,
SomeProject.Key,
SomeProject.FilePath,
SomeProjectFile1.FilePath,
DisposalToken);
});

var project = Assert.Single(_projectManager.GetProjects());
Assert.IsType<FallbackHostProject>(((ProjectSnapshot)project).HostProject);
Expand Down Expand Up @@ -159,26 +168,35 @@ public async Task DynamicFileAdded_TrackedProject_AddsDocuments()

Workspace.TryApplyChanges(Workspace.CurrentSolution.AddProject(projectInfo));

await _fallbackProjectManger.DynamicFileAddedAsync(
projectId,
SomeProject.Key,
SomeProject.FilePath,
SomeProjectFile1.FilePath,
DisposalToken);
await RunOnDispatcherAsync(() =>
{
_fallbackProjectManger.DynamicFileAdded(
projectId,
SomeProject.Key,
SomeProject.FilePath,
SomeProjectFile1.FilePath,
DisposalToken);
});

await _fallbackProjectManger.DynamicFileAddedAsync(
projectId,
SomeProject.Key,
SomeProject.FilePath,
SomeProjectFile2.FilePath,
DisposalToken);
await RunOnDispatcherAsync(() =>
{
_fallbackProjectManger.DynamicFileAdded(
projectId,
SomeProject.Key,
SomeProject.FilePath,
SomeProjectFile2.FilePath,
DisposalToken);
});

await _fallbackProjectManger.DynamicFileAddedAsync(
projectId,
SomeProject.Key,
SomeProject.FilePath,
SomeProjectNestedComponentFile3.FilePath,
DisposalToken);
await RunOnDispatcherAsync(() =>
{
_fallbackProjectManger.DynamicFileAdded(
projectId,
SomeProject.Key,
SomeProject.FilePath,
SomeProjectNestedComponentFile3.FilePath,
DisposalToken);
});

var project = Assert.Single(_projectManager.GetProjects());

Expand All @@ -204,27 +222,36 @@ public async Task DynamicFileAdded_TrackedProject_IgnoresDocumentFromOutsideCone

Workspace.TryApplyChanges(Workspace.CurrentSolution.AddProject(projectInfo));

await _fallbackProjectManger.DynamicFileAddedAsync(
projectId,
SomeProject.Key,
SomeProject.FilePath,
SomeProjectFile1.FilePath,
DisposalToken);
await RunOnDispatcherAsync(() =>
{
_fallbackProjectManger.DynamicFileAdded(
projectId,
SomeProject.Key,
SomeProject.FilePath,
SomeProjectFile1.FilePath,
DisposalToken);
});

// These two represent linked files, or shared project items
await _fallbackProjectManger.DynamicFileAddedAsync(
projectId,
SomeProject.Key,
SomeProject.FilePath,
AnotherProjectFile2.FilePath,
DisposalToken);
await RunOnDispatcherAsync(() =>
{
_fallbackProjectManger.DynamicFileAdded(
projectId,
SomeProject.Key,
SomeProject.FilePath,
AnotherProjectFile2.FilePath,
DisposalToken);
});

await _fallbackProjectManger.DynamicFileAddedAsync(
projectId,
SomeProject.Key,
SomeProject.FilePath,
AnotherProjectComponentFile1.FilePath,
DisposalToken);
await RunOnDispatcherAsync(() =>
{
_fallbackProjectManger.DynamicFileAdded(
projectId,
SomeProject.Key,
SomeProject.FilePath,
AnotherProjectComponentFile1.FilePath,
DisposalToken);
});

var project = Assert.Single(_projectManager.GetProjects());

Expand All @@ -245,12 +272,15 @@ public async Task DynamicFileAdded_UnknownProject_SetsConfigurationFileStore()

Workspace.TryApplyChanges(Workspace.CurrentSolution.AddProject(projectInfo));

await _fallbackProjectManger.DynamicFileAddedAsync(
projectId,
SomeProject.Key,
SomeProject.FilePath,
SomeProjectFile1.FilePath,
DisposalToken);
await RunOnDispatcherAsync(() =>
{
_fallbackProjectManger.DynamicFileAdded(
projectId,
SomeProject.Key,
SomeProject.FilePath,
SomeProjectFile1.FilePath,
DisposalToken);
});

var kvp = Assert.Single(_projectConfigurationFilePathStore.GetMappings());
Assert.Equal(SomeProject.Key, kvp.Key);
Expand Down
Loading