Skip to content

Commit 599d97c

Browse files
ProjectSnapshotManager: Ensure that Open/CloseDocument always work
It turns out that CloseDocument can easily fail resulting in IsDocumentOpen to report true for documents that are not actually open. This is because the _openDocumentSet is only updated after updating the project with a SourceText or TextLoader. For example, if the project has already been removed, CloseDocument wouldn't update the _openDocumentSet. This change updates _openDocumentSet before updating the document text, which should by more correct.
1 parent 1f0b467 commit 599d97c

File tree

2 files changed

+35
-27
lines changed

2 files changed

+35
-27
lines changed

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

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -301,30 +301,22 @@ private void RemoveDocument(ProjectKey projectKey, string documentFilePath)
301301

302302
private void OpenDocument(ProjectKey projectKey, string documentFilePath, SourceText text)
303303
{
304-
if (TryUpdateProject(
305-
projectKey,
306-
transformer: state => state.WithDocumentText(documentFilePath, text),
307-
onAfterUpdate: () => _openDocumentSet.Add(documentFilePath),
308-
out var oldProject,
309-
out var newProject,
310-
out var isSolutionClosing))
304+
using (_readerWriterLock.DisposableWrite())
311305
{
312-
NotifyListeners(ProjectChangeEventArgs.DocumentChanged(oldProject, newProject, documentFilePath, isSolutionClosing));
306+
_openDocumentSet.Add(documentFilePath);
313307
}
308+
309+
UpdateDocumentText(projectKey, documentFilePath, text);
314310
}
315311

316312
private void CloseDocument(ProjectKey projectKey, string documentFilePath, TextLoader textLoader)
317313
{
318-
if (TryUpdateProject(
319-
projectKey,
320-
transformer: state => state.WithDocumentText(documentFilePath, textLoader),
321-
onAfterUpdate: () => _openDocumentSet.Remove(documentFilePath),
322-
out var oldProject,
323-
out var newProject,
324-
out var isSolutionClosing))
314+
using (_readerWriterLock.DisposableWrite())
325315
{
326-
NotifyListeners(ProjectChangeEventArgs.DocumentChanged(oldProject, newProject, documentFilePath, isSolutionClosing));
316+
_openDocumentSet.Remove(documentFilePath);
327317
}
318+
319+
UpdateDocumentText(projectKey, documentFilePath, textLoader);
328320
}
329321

330322
private void UpdateDocumentText(ProjectKey projectKey, string documentFilePath, SourceText text)
@@ -413,15 +405,6 @@ private bool TryUpdateProject(
413405
[NotNullWhen(true)] out ProjectSnapshot? oldProject,
414406
[NotNullWhen(true)] out ProjectSnapshot? newProject,
415407
out bool isSolutionClosing)
416-
=> TryUpdateProject(projectKey, transformer, onAfterUpdate: null, out oldProject, out newProject, out isSolutionClosing);
417-
418-
private bool TryUpdateProject(
419-
ProjectKey projectKey,
420-
Func<ProjectState, ProjectState> transformer,
421-
Action? onAfterUpdate,
422-
[NotNullWhen(true)] out ProjectSnapshot? oldProject,
423-
[NotNullWhen(true)] out ProjectSnapshot? newProject,
424-
out bool isSolutionClosing)
425408
{
426409
if (_initialized)
427410
{
@@ -459,8 +442,6 @@ private bool TryUpdateProject(
459442
var newEntry = new Entry(newState);
460443
_projectMap[projectKey] = newEntry;
461444

462-
onAfterUpdate?.Invoke();
463-
464445
oldProject = oldEntry.GetSnapshot();
465446
newProject = newEntry.GetSnapshot();
466447

src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/ProjectSnapshotManagerTest.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,4 +892,31 @@ await _projectManager.UpdateAsync(updater =>
892892

893893
textLoader.Verify(d => d.LoadTextAndVersionAsync(It.IsAny<LoadTextOptions>(), It.IsAny<CancellationToken>()), Times.Never());
894894
}
895+
896+
[Fact]
897+
public async Task SolutionClosing_RemovesProjectAndClosesDocument()
898+
{
899+
// Arrange
900+
901+
// Add project and open document.
902+
await _projectManager.UpdateAsync(updater =>
903+
{
904+
updater.AddProject(s_hostProject);
905+
updater.AddDocument(s_hostProject.Key, s_documents[0], EmptyTextLoader.Instance);
906+
updater.OpenDocument(s_hostProject.Key, s_documents[0].FilePath, _sourceText);
907+
});
908+
909+
// Act
910+
await _projectManager.UpdateAsync(updater =>
911+
{
912+
updater.SolutionClosed();
913+
updater.RemoveProject(s_hostProject.Key);
914+
updater.CloseDocument(s_hostProject.Key, s_documents[0].FilePath, EmptyTextLoader.Instance);
915+
});
916+
917+
// Assert
918+
Assert.False(_projectManager.ContainsDocument(s_hostProject.Key, s_documents[0].FilePath));
919+
Assert.False(_projectManager.ContainsProject(s_hostProject.Key));
920+
Assert.False(_projectManager.IsDocumentOpen(s_documents[0].FilePath));
921+
}
895922
}

0 commit comments

Comments
 (0)