diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs index 0bd0edb555cd9ce74e0833b7d83f609cb572c063..90daf1913729ed85a9d4814078e60966a9c64ccd 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs @@ -419,7 +419,23 @@ private SolutionState AddProject(ProjectId projectId, ProjectState projectState) var newStateMap = _projectIdToProjectStateMap.Add(projectId, projectState); var newDependencyGraph = _dependencyGraph .WithAdditionalProjects(SpecializedCollections.SingletonEnumerable(projectId)) - .WithAdditionalProjectReferences(projectId, projectState.ProjectReferences.Select(r => r.ProjectId).ToList()); + .WithAdditionalProjectReferences(projectId, + projectState.ProjectReferences.Where(r => _projectIdToProjectStateMap.ContainsKey(r.ProjectId)).Select(r => r.ProjectId).ToList()); + + // It's possible that another project already in newStateMap has a reference to this project that we're adding, since we allow + // dangling references like that. If so, we'll need to link those in too. + foreach (var newState in newStateMap) + { + foreach (var projectReference in newState.Value.ProjectReferences) + { + if (projectReference.ProjectId == projectId) + { + newDependencyGraph = newDependencyGraph.WithAdditionalProjectReferences(newState.Key, ImmutableArray.Create(projectId)); + break; + } + } + } + var newTrackerMap = CreateCompilationTrackerMap(projectId, newDependencyGraph); var newLinkedFilesMap = CreateLinkedFilesMapWithAddedProject(newStateMap[projectId]); diff --git a/src/Workspaces/CoreTest/SolutionTests/ProjectDependencyGraphTests.cs b/src/Workspaces/CoreTest/SolutionTests/ProjectDependencyGraphTests.cs index 488d052cd1f44cb76d164e6e8cae4db95b3a25cc..925ddfe807f0d3da718cf7e4646d5bb8940e4dbe 100644 --- a/src/Workspaces/CoreTest/SolutionTests/ProjectDependencyGraphTests.cs +++ b/src/Workspaces/CoreTest/SolutionTests/ProjectDependencyGraphTests.cs @@ -178,7 +178,6 @@ void VerifyAllTransitiveReferences() VerifyDirectReferences(solution, "A", new string[] { "B", "C" }); } - [Fact, Trait(Traits.Feature, Traits.Features.Workspace)] public void TestTransitiveReferencesIncrementalUpdateWithProjectThatHasUnknownReferences() { @@ -208,6 +207,32 @@ public void TestTransitiveReferencesIncrementalUpdateWithProjectThatHasUnknownRe VerifyTransitiveReferences(solution, dependencyGraph, project: "A", expectedResults: new string[] { "B" }); } + [Fact, Trait(Traits.Feature, Traits.Features.Workspace)] + public void TestTransitiveReferencesWithDanglingProjectReference() + { + // We are going to create a solution with the references: + // + // A -> B + // + // but we're going to add A as a reference with B not existing yet. Then we'll add in B and ask. + + var solution = CreateSolution(); + var projectAId = ProjectId.CreateNewId("A"); + var projectBId = ProjectId.CreateNewId("B"); + + var projectAInfo = ProjectInfo.Create(projectAId, VersionStamp.Create(), "A", "A", LanguageNames.CSharp, + projectReferences: new[] { new ProjectReference(projectBId) }); + + solution = solution.AddProject(projectAInfo); + + VerifyDirectReferences(solution, "A", new string[] { }); + VerifyTransitiveReferences(solution, "A", new string[] { }); + + solution = solution.AddProject(projectBId, "B", "B", LanguageNames.CSharp); + + VerifyTransitiveReferences(solution, "A", new string[] { "B" }); + } + private void VerifyDirectReferences(Solution solution, string project, string[] expectedResults) { var projectDependencyGraph = solution.GetProjectDependencyGraph();