From 041bd3ae3dcdd169991f9c07c85079e35a0f67c5 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Wed, 22 Jan 2020 13:35:50 -0800 Subject: [PATCH] Avoid dropping compilations that can be reused --- .../CSharpTest/Workspaces/WorkspaceTests.cs | 1 + .../Solution/ProjectDependencyGraph.cs | 16 ++++++++++++ .../Workspace/Solution/SolutionState.cs | 26 ++++++++++++++----- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests.cs b/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests.cs index f1ddf9fc0da..345009748f4 100644 --- a/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests.cs +++ b/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests.cs @@ -484,6 +484,7 @@ public async Task TestGetCompilationOnCrossLanguageDependentProjectChanged() var solutionZ = workspace.CurrentSolution; var docZ = solutionZ.GetDocument(document1.Id); var docZText = await docZ.GetTextAsync(); + Assert.Equal("public class X { }", docZText.ToString()); var compilation2Z = await solutionZ.GetProject(id2).GetCompilationAsync(); var classDz = compilation2Z.SourceModule.GlobalNamespace.GetTypeMembers("D").Single(); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs index ce7a225f249..781613b127d 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; @@ -652,6 +653,21 @@ private ImmutableHashSet GetProjectsThatDirectlyDependOnThisProject_N .ToImmutableDictionary(); } + /// + /// Gets the list of projects that directly or transitively this project depends on, if it has already been + /// cached. + /// + internal ImmutableHashSet? TryGetProjectsThatThisProjectTransitivelyDependsOn(ProjectId projectId) + { + if (projectId is null) + { + throw new ArgumentNullException(nameof(projectId)); + } + + _transitiveReferencesMap.TryGetValue(projectId, out var projects); + return projects; + } + /// /// Gets the list of projects that directly or transitively this project depends on /// diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs index 6810b03b4d9..c4521a971b7 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs @@ -1812,20 +1812,32 @@ public ImmutableArray GetDocumentIdsWithFilePath(string? filePath) private ImmutableDictionary CreateCompilationTrackerMap(ProjectId projectId, ProjectDependencyGraph dependencyGraph) { var builder = ImmutableDictionary.CreateBuilder(); - var dependencies = dependencyGraph.TryGetProjectsThatTransitivelyDependOnThisProject(projectId); + IEnumerable? dependencies = null; - foreach (var projectIdAndTracker in _projectIdToTrackerMap) + foreach (var (id, tracker) in _projectIdToTrackerMap) { - var id = projectIdAndTracker.Key; - var tracker = projectIdAndTracker.Value; - if (!tracker.HasCompilation) { continue; } - var canReuse = id == projectId || (dependencies is object && !dependencies.Contains(id)); - builder.Add(id, canReuse ? tracker : tracker.Fork(tracker.ProjectState)); + builder.Add(id, CanReuse() ? tracker : tracker.Fork(tracker.ProjectState)); + + // Returns true if 'tracker' can be reused for project 'id' + bool CanReuse() + { + if (id == projectId) + return true; + + var forwardDependencies = dependencyGraph.TryGetProjectsThatThisProjectTransitivelyDependsOn(id); + if (forwardDependencies is object && !forwardDependencies.Contains(projectId)) + { + return true; + } + + dependencies ??= dependencyGraph.GetProjectsThatTransitivelyDependOnThisProject(projectId); + return !dependencies.Contains(id); + } } return builder.ToImmutable(); -- GitLab