Skip to content

Commit 95f862d

Browse files
authored
Update ProjectWorkspaceState and HostProject at the same time (dotnet#11191)
Preparation for ongoing work to hook up the Roslyn tokenizer and dotnet#11182 I suppose. There were three places that `UpdateProjectWorkspaceState` was called: 1. In `RazorProjectService`, just before calling `UpdateProjectConfiguration` 2. In `ProjectWorkspaceStateGenerator`, where we will need to add a call to `UpdateProjectConfiguration` in future, to wire up the tokenizer 3. In our LiveShare bits, in response to events from the above. Previous attempts to plumb through more things for `RazorConfiguration` resulted in RPS failures, that appeared to be simply more compilations of closed files. This makes sense because we were adding another update, which would have triggered another set of `ProjectChanged` events. I thought it would make more sense to combine these two updates together, so no matter which part of the project was being updated, there could be a single `ProjectChanged` notification. This is that.
2 parents f3aa647 + b36e892 commit 95f862d

File tree

25 files changed

+127
-312
lines changed

25 files changed

+127
-312
lines changed

src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorLanguageServerBenchmarkBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ await projectManager.UpdateAsync(
7676
updater.ProjectAdded(hostProject);
7777
var tagHelpers = CommonResources.LegacyTagHelpers;
7878
var projectWorkspaceState = ProjectWorkspaceState.Create(tagHelpers, CodeAnalysis.CSharp.LanguageVersion.CSharp11);
79-
updater.ProjectWorkspaceStateChanged(hostProject.Key, projectWorkspaceState);
79+
updater.ProjectChanged(hostProject, projectWorkspaceState);
8080
updater.DocumentAdded(hostProject.Key, hostDocument, textLoader);
8181
},
8282
CancellationToken.None);

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/RazorProjectService.cs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -369,34 +369,21 @@ private Task AddOrUpdateProjectCoreAsync(
369369
_logger.LogInformation($"Updating project '{project.Key}' TagHelpers ({projectWorkspaceState.TagHelpers.Length}) and C# Language Version ({projectWorkspaceState.CSharpLanguageVersion}).");
370370
}
371371

372-
updater.ProjectWorkspaceStateChanged(project.Key, projectWorkspaceState);
373-
374372
var currentConfiguration = project.Configuration;
375373
var currentRootNamespace = project.RootNamespace;
376-
if (currentConfiguration.ConfigurationName == configuration?.ConfigurationName &&
377-
currentRootNamespace == rootNamespace)
378-
{
379-
_logger.LogTrace($"Updating project '{project.Key}'. The project is already using configuration '{configuration.ConfigurationName}' and root namespace '{rootNamespace}'.");
380-
return;
381-
}
382-
383374
if (configuration is null)
384375
{
385376
configuration = FallbackRazorConfiguration.Latest;
386377
_logger.LogInformation($"Updating project '{project.Key}' to use the latest configuration ('{configuration.ConfigurationName}')'.");
387378
}
388-
else if (currentConfiguration.ConfigurationName != configuration.ConfigurationName)
389-
{
390-
_logger.LogInformation($"Updating project '{project.Key}' to Razor configuration '{configuration.ConfigurationName}' with language version '{configuration.LanguageVersion}'.");
391-
}
392-
393-
if (currentRootNamespace != rootNamespace)
379+
else if (currentConfiguration == configuration &&
380+
currentRootNamespace == rootNamespace)
394381
{
395-
_logger.LogInformation($"Updating project '{project.Key}''s root namespace to '{rootNamespace}'.");
382+
_logger.LogTrace($"Updating project '{project.Key}'. The project is already using configuration '{configuration.ConfigurationName}' and root namespace '{rootNamespace}'.");
396383
}
397384

398385
var hostProject = new HostProject(project.FilePath, project.IntermediateOutputPath, configuration, rootNamespace, displayName);
399-
updater.ProjectConfigurationChanged(hostProject);
386+
updater.ProjectChanged(hostProject, projectWorkspaceState);
400387
},
401388
cancellationToken);
402389
}

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentState.cs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -150,15 +150,6 @@ public bool TryGetTextVersion(out VersionStamp result)
150150
return false;
151151
}
152152

153-
public virtual DocumentState WithConfigurationChange()
154-
{
155-
var state = new DocumentState(HostDocument, Version + 1, _textAndVersion, _textLoader);
156-
157-
// Do not cache computed state
158-
159-
return state;
160-
}
161-
162153
public virtual DocumentState WithImportsChange()
163154
{
164155
var state = new DocumentState(HostDocument, Version + 1, _textAndVersion, _textLoader);
@@ -169,7 +160,7 @@ public virtual DocumentState WithImportsChange()
169160
return state;
170161
}
171162

172-
public virtual DocumentState WithProjectWorkspaceStateChange()
163+
public virtual DocumentState WithProjectChange()
173164
{
174165
var state = new DocumentState(HostDocument, Version + 1, _textAndVersion, _textLoader);
175166

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectDifference.cs

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.Updater.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,8 @@ public void ProjectAdded(HostProject project)
5050
public void ProjectRemoved(ProjectKey projectKey)
5151
=> instance.ProjectRemoved(projectKey);
5252

53-
public void ProjectConfigurationChanged(HostProject project)
54-
=> instance.ProjectConfigurationChanged(project);
55-
56-
public void ProjectWorkspaceStateChanged(ProjectKey projectKey, ProjectWorkspaceState projectWorkspaceState)
57-
=> instance.ProjectWorkspaceStateChanged(projectKey, projectWorkspaceState);
53+
public void ProjectChanged(HostProject project, ProjectWorkspaceState projectWorkspaceState)
54+
=> instance.ProjectChanged(project, projectWorkspaceState);
5855

5956
public void SolutionOpened()
6057
=> instance.SolutionOpened();

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectSnapshotManager.cs

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ private void ProjectAdded(HostProject hostProject)
306306
}
307307
}
308308

309-
private void ProjectConfigurationChanged(HostProject hostProject)
309+
private void ProjectChanged(HostProject hostProject, ProjectWorkspaceState projectWorkspaceState)
310310
{
311311
if (_initialized)
312312
{
@@ -316,25 +316,7 @@ private void ProjectConfigurationChanged(HostProject hostProject)
316316
if (TryUpdate(
317317
hostProject.Key,
318318
documentFilePath: null,
319-
new HostProjectUpdatedAction(hostProject),
320-
out var oldSnapshot,
321-
out var newSnapshot))
322-
{
323-
NotifyListeners(oldSnapshot, newSnapshot, documentFilePath: null, ProjectChangeKind.ProjectChanged);
324-
}
325-
}
326-
327-
private void ProjectWorkspaceStateChanged(ProjectKey projectKey, ProjectWorkspaceState projectWorkspaceState)
328-
{
329-
if (_initialized)
330-
{
331-
_dispatcher.AssertRunningOnDispatcher();
332-
}
333-
334-
if (TryUpdate(
335-
projectKey,
336-
documentFilePath: null,
337-
new ProjectWorkspaceStateChangedAction(projectWorkspaceState),
319+
new ProjectChangeAction(hostProject, projectWorkspaceState),
338320
out var oldSnapshot,
339321
out var newSnapshot))
340322
{
@@ -591,11 +573,8 @@ private static Entry ComputeNewEntry(Entry originalEntry, IUpdateProjectAction a
591573
}
592574
}
593575

594-
case ProjectWorkspaceStateChangedAction(var workspaceState):
595-
return new Entry(originalEntry.State.WithProjectWorkspaceState(workspaceState));
596-
597-
case HostProjectUpdatedAction(var hostProject):
598-
return new Entry(originalEntry.State.WithHostProject(hostProject));
576+
case ProjectChangeAction(var hostProject, var workspaceState):
577+
return new Entry(originalEntry.State.WithHostProjectAndWorkspaceState(hostProject, workspaceState));
599578

600579
default:
601580
throw new InvalidOperationException($"Unexpected action type {action.GetType()}");

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/ProjectState.cs

Lines changed: 19 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the MIT license. See License.txt in the project root for license information.
33

4-
using System;
54
using System.Collections.Generic;
65
using System.Collections.Immutable;
76
using System.IO;
@@ -21,17 +20,6 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem;
2120
// Internal tracker for DefaultProjectSnapshot
2221
internal class ProjectState
2322
{
24-
private const ProjectDifference ClearConfigurationVersionMask = ProjectDifference.ConfigurationChanged;
25-
26-
private const ProjectDifference ClearProjectWorkspaceStateVersionMask =
27-
ProjectDifference.ConfigurationChanged |
28-
ProjectDifference.ProjectWorkspaceStateChanged;
29-
30-
private const ProjectDifference ClearDocumentCollectionVersionMask =
31-
ProjectDifference.ConfigurationChanged |
32-
ProjectDifference.DocumentAdded |
33-
ProjectDifference.DocumentRemoved;
34-
3523
private static readonly ImmutableDictionary<string, DocumentState> s_emptyDocuments = ImmutableDictionary.Create<string, DocumentState>(FilePathNormalizingComparer.Instance);
3624
private static readonly ImmutableDictionary<string, ImmutableArray<string>> s_emptyImportsToRelatedDocuments = ImmutableDictionary.Create<string, ImmutableArray<string>>(FilePathNormalizingComparer.Instance);
3725
private readonly object _lock;
@@ -70,7 +58,7 @@ private ProjectState(
7058

7159
private ProjectState(
7260
ProjectState older,
73-
ProjectDifference difference,
61+
bool numberOfDocumentsMayHaveChanged,
7462
HostProject hostProject,
7563
ProjectWorkspaceState projectWorkspaceState,
7664
ImmutableDictionary<string, DocumentState> documents,
@@ -87,17 +75,19 @@ private ProjectState(
8775

8876
_lock = new object();
8977

90-
if ((difference & ClearDocumentCollectionVersionMask) == 0)
78+
if (numberOfDocumentsMayHaveChanged)
9179
{
92-
// Document collection hasn't changed
93-
DocumentCollectionVersion = older.DocumentCollectionVersion;
80+
DocumentCollectionVersion = Version;
9481
}
9582
else
9683
{
97-
DocumentCollectionVersion = Version;
84+
// Document collection hasn't changed
85+
DocumentCollectionVersion = older.DocumentCollectionVersion;
9886
}
9987

100-
if ((difference & ClearConfigurationVersionMask) == 0 && older._projectEngine != null)
88+
if (older._projectEngine != null &&
89+
HostProject.Configuration == older.HostProject.Configuration &&
90+
CSharpLanguageVersion == older.CSharpLanguageVersion)
10191
{
10292
// Optimistically cache the RazorProjectEngine.
10393
_projectEngine = older.ProjectEngine;
@@ -108,24 +98,14 @@ private ProjectState(
10898
ConfigurationVersion = Version;
10999
}
110100

111-
if ((difference & ClearProjectWorkspaceStateVersionMask) == 0 ||
112-
ProjectWorkspaceState == older.ProjectWorkspaceState ||
113-
ProjectWorkspaceState.Equals(older.ProjectWorkspaceState))
101+
if (ProjectWorkspaceState.Equals(older.ProjectWorkspaceState))
114102
{
115103
ProjectWorkspaceStateVersion = older.ProjectWorkspaceStateVersion;
116104
}
117105
else
118106
{
119107
ProjectWorkspaceStateVersion = Version;
120108
}
121-
122-
if ((difference & ClearProjectWorkspaceStateVersionMask) != 0 &&
123-
CSharpLanguageVersion != older.CSharpLanguageVersion)
124-
{
125-
// C# language version changed. This impacts the ProjectEngine, reset it.
126-
_projectEngine = null;
127-
ConfigurationVersion = Version;
128-
}
129109
}
130110

131111
// Internal set for testing.
@@ -196,16 +176,6 @@ RazorProjectEngine CreateProjectEngine()
196176

197177
public ProjectState WithAddedHostDocument(HostDocument hostDocument, TextLoader loader)
198178
{
199-
if (hostDocument is null)
200-
{
201-
throw new ArgumentNullException(nameof(hostDocument));
202-
}
203-
204-
if (loader is null)
205-
{
206-
throw new ArgumentNullException(nameof(loader));
207-
}
208-
209179
// Ignore attempts to 'add' a document with different data, we only
210180
// care about one, so it might as well be the one we have.
211181
if (Documents.ContainsKey(hostDocument.FilePath))
@@ -229,17 +199,12 @@ public ProjectState WithAddedHostDocument(HostDocument hostDocument, TextLoader
229199
}
230200
}
231201

232-
var state = new ProjectState(this, ProjectDifference.DocumentAdded, HostProject, ProjectWorkspaceState, documents, importsToRelatedDocuments);
202+
var state = new ProjectState(this, numberOfDocumentsMayHaveChanged: true, HostProject, ProjectWorkspaceState, documents, importsToRelatedDocuments);
233203
return state;
234204
}
235205

236206
public ProjectState WithRemovedHostDocument(HostDocument hostDocument)
237207
{
238-
if (hostDocument is null)
239-
{
240-
throw new ArgumentNullException(nameof(hostDocument));
241-
}
242-
243208
if (!Documents.ContainsKey(hostDocument.FilePath))
244209
{
245210
return this;
@@ -261,17 +226,12 @@ public ProjectState WithRemovedHostDocument(HostDocument hostDocument)
261226
var importTargetPaths = GetImportDocumentTargetPaths(hostDocument);
262227
var importsToRelatedDocuments = RemoveFromImportsToRelatedDocuments(ImportsToRelatedDocuments, hostDocument, importTargetPaths);
263228

264-
var state = new ProjectState(this, ProjectDifference.DocumentRemoved, HostProject, ProjectWorkspaceState, documents, importsToRelatedDocuments);
229+
var state = new ProjectState(this, numberOfDocumentsMayHaveChanged: true, HostProject, ProjectWorkspaceState, documents, importsToRelatedDocuments);
265230
return state;
266231
}
267232

268233
public ProjectState WithChangedHostDocument(HostDocument hostDocument, SourceText sourceText, VersionStamp textVersion)
269234
{
270-
if (hostDocument is null)
271-
{
272-
throw new ArgumentNullException(nameof(hostDocument));
273-
}
274-
275235
if (!Documents.TryGetValue(hostDocument.FilePath, out var document))
276236
{
277237
return this;
@@ -287,17 +247,12 @@ public ProjectState WithChangedHostDocument(HostDocument hostDocument, SourceTex
287247
}
288248
}
289249

290-
var state = new ProjectState(this, ProjectDifference.DocumentChanged, HostProject, ProjectWorkspaceState, documents, ImportsToRelatedDocuments);
250+
var state = new ProjectState(this, numberOfDocumentsMayHaveChanged: false, HostProject, ProjectWorkspaceState, documents, ImportsToRelatedDocuments);
291251
return state;
292252
}
293253

294254
public ProjectState WithChangedHostDocument(HostDocument hostDocument, TextLoader loader)
295255
{
296-
if (hostDocument is null)
297-
{
298-
throw new ArgumentNullException(nameof(hostDocument));
299-
}
300-
301256
if (!Documents.TryGetValue(hostDocument.FilePath, out var document))
302257
{
303258
return this;
@@ -313,24 +268,20 @@ public ProjectState WithChangedHostDocument(HostDocument hostDocument, TextLoade
313268
}
314269
}
315270

316-
var state = new ProjectState(this, ProjectDifference.DocumentChanged, HostProject, ProjectWorkspaceState, documents, ImportsToRelatedDocuments);
271+
var state = new ProjectState(this, numberOfDocumentsMayHaveChanged: false, HostProject, ProjectWorkspaceState, documents, ImportsToRelatedDocuments);
317272
return state;
318273
}
319274

320-
public ProjectState WithHostProject(HostProject hostProject)
275+
public ProjectState WithHostProjectAndWorkspaceState(HostProject hostProject, ProjectWorkspaceState projectWorkspaceState)
321276
{
322-
if (hostProject is null)
323-
{
324-
throw new ArgumentNullException(nameof(hostProject));
325-
}
326-
327277
if (HostProject.Configuration.Equals(hostProject.Configuration) &&
328-
HostProject.RootNamespace == hostProject.RootNamespace)
278+
HostProject.RootNamespace == hostProject.RootNamespace &&
279+
ProjectWorkspaceState.Equals(projectWorkspaceState))
329280
{
330281
return this;
331282
}
332283

333-
var documents = Documents.ToImmutableDictionary(kvp => kvp.Key, kvp => kvp.Value.WithConfigurationChange(), FilePathNormalizingComparer.Instance);
284+
var documents = Documents.ToImmutableDictionary(kvp => kvp.Key, kvp => kvp.Value.WithProjectChange(), FilePathNormalizingComparer.Instance);
334285

335286
// If the host project has changed then we need to recompute the imports map
336287
var importsToRelatedDocuments = s_emptyImportsToRelatedDocuments;
@@ -341,25 +292,7 @@ public ProjectState WithHostProject(HostProject hostProject)
341292
importsToRelatedDocuments = AddToImportsToRelatedDocuments(importsToRelatedDocuments, document.Value.HostDocument.FilePath, importTargetPaths);
342293
}
343294

344-
var state = new ProjectState(this, ProjectDifference.ConfigurationChanged, hostProject, ProjectWorkspaceState, documents, importsToRelatedDocuments);
345-
return state;
346-
}
347-
348-
public ProjectState WithProjectWorkspaceState(ProjectWorkspaceState projectWorkspaceState)
349-
{
350-
if (ProjectWorkspaceState == projectWorkspaceState)
351-
{
352-
return this;
353-
}
354-
355-
if (ProjectWorkspaceState.Equals(projectWorkspaceState))
356-
{
357-
return this;
358-
}
359-
360-
var difference = ProjectDifference.ProjectWorkspaceStateChanged;
361-
var documents = Documents.ToImmutableDictionary(kvp => kvp.Key, kvp => kvp.Value.WithProjectWorkspaceStateChange(), FilePathNormalizingComparer.Instance);
362-
var state = new ProjectState(this, difference, HostProject, projectWorkspaceState, documents, ImportsToRelatedDocuments);
295+
var state = new ProjectState(this, numberOfDocumentsMayHaveChanged: true, hostProject, projectWorkspaceState, documents, importsToRelatedDocuments);
363296
return state;
364297
}
365298

@@ -372,7 +305,7 @@ internal static ImmutableDictionary<string, ImmutableArray<string>> AddToImports
372305
{
373306
if (!importsToRelatedDocuments.TryGetValue(importTargetPath, out var relatedDocuments))
374307
{
375-
relatedDocuments = ImmutableArray.Create<string>();
308+
relatedDocuments = [];
376309
}
377310

378311
relatedDocuments = relatedDocuments.Add(documentFilePath);

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/UpdateProjectAction.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,4 @@ internal record ProjectAddedAction(HostProject HostProject) : IUpdateProjectActi
3030

3131
internal record ProjectRemovedAction(ProjectKey ProjectKey) : IUpdateProjectAction;
3232

33-
internal record HostProjectUpdatedAction(HostProject HostProject) : IUpdateProjectAction;
34-
35-
internal record ProjectWorkspaceStateChangedAction(ProjectWorkspaceState WorkspaceState) : IUpdateProjectAction;
33+
internal record ProjectChangeAction(HostProject HostProject, ProjectWorkspaceState WorkspaceState) : IUpdateProjectAction;

0 commit comments

Comments
 (0)