diff --git a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker_ResolveReferences.cs b/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker_ResolveReferences.cs index 42260d8d26b4561874d310bf34dedd34f5a2e155..829430bc6f641a39ea67fbef3067474b0e9f2d7d 100644 --- a/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker_ResolveReferences.cs +++ b/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker_ResolveReferences.cs @@ -17,10 +17,10 @@ private partial class Worker { private readonly struct ResolvedReferences { - public ImmutableArray ProjectReferences { get; } + public ImmutableHashSet ProjectReferences { get; } public ImmutableArray MetadataReferences { get; } - public ResolvedReferences(ImmutableArray projectReferences, ImmutableArray metadataReferences) + public ResolvedReferences(ImmutableHashSet projectReferences, ImmutableArray metadataReferences) { ProjectReferences = projectReferences; MetadataReferences = metadataReferences; @@ -50,14 +50,14 @@ private class ResolvedReferencesBuilder /// private readonly HashSet _indicesToRemove; - private readonly ImmutableArray.Builder _projectReferences; + private readonly ImmutableHashSet.Builder _projectReferences; public ResolvedReferencesBuilder(IEnumerable metadataReferences) { _metadataReferences = metadataReferences.ToImmutableArray(); _pathToIndicesMap = CreatePathToIndexMap(_metadataReferences); _indicesToRemove = new HashSet(); - _projectReferences = ImmutableArray.CreateBuilder(); + _projectReferences = ImmutableHashSet.CreateBuilder(); } private static ImmutableDictionary> CreatePathToIndexMap(ImmutableArray metadataReferences) @@ -166,7 +166,7 @@ private ImmutableArray GetMetadataReferences() return builder.ToImmutable(); } - private ImmutableArray GetProjectReferences() + private ImmutableHashSet GetProjectReferences() => _projectReferences.ToImmutable(); public ResolvedReferences ToResolvedReferences() diff --git a/src/Workspaces/MSBuildTest/MSBuildWorkspaceTests.cs b/src/Workspaces/MSBuildTest/MSBuildWorkspaceTests.cs index 9ac02ecacd69de7674b96a35063234fcf67f7014..38d09a734a9597ecce44393e42f093b6884f373c 100644 --- a/src/Workspaces/MSBuildTest/MSBuildWorkspaceTests.cs +++ b/src/Workspaces/MSBuildTest/MSBuildWorkspaceTests.cs @@ -3606,6 +3606,28 @@ public async Task TestOpenProjectAsync_MalformedAdditionalFilePath() } } + [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] + [WorkItem(31390, "https://github.com/dotnet/roslyn/issues/31390")] + public async Task TestDuplicateProjectReference() + { + var files = GetDuplicateProjectReferenceSolutionFiles(); + CreateFiles(files); + + var fullPath = GetSolutionFileName(@"CSharpProjectReference.sln"); + + using (var workspace = CreateMSBuildWorkspace()) + { + var solution = await workspace.OpenSolutionAsync(fullPath); + var project = solution.Projects.Single(p => p.FilePath.EndsWith("CSharpProject_ProjectReference.csproj")); + + Assert.Single(project.ProjectReferences); + + var compilation = await project.GetCompilationAsync(); + + Assert.Single(compilation.References.OfType()); + } + } + private class InMemoryAssemblyLoader : IAnalyzerAssemblyLoader { public void AddDependencyLocation(string fullPath) diff --git a/src/Workspaces/MSBuildTest/Resources/ProjectFiles/CSharp/DuplicateProjectReference.csproj b/src/Workspaces/MSBuildTest/Resources/ProjectFiles/CSharp/DuplicateProjectReference.csproj new file mode 100644 index 0000000000000000000000000000000000000000..5d7cd64122a5f179e9d33fca1f9399707a211e45 --- /dev/null +++ b/src/Workspaces/MSBuildTest/Resources/ProjectFiles/CSharp/DuplicateProjectReference.csproj @@ -0,0 +1,63 @@ + + + + + + Debug + AnyCPU + AnyCPU + {3DA47258-9CAB-4FB9-9C04-1F367A2C2700} + Exe + Properties + CSharpProject_ProjectToProjectReference + CSharpProject_ProjectToProjectReference + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + {686dd036-86aa-443e-8a10-ddb43266a8c4} + CSharpProject + + + {686dd036-86aa-443e-8a10-ddb43266a8c4} + CSharpProject + + + + + \ No newline at end of file diff --git a/src/Workspaces/MSBuildTest/TestFiles/Resources.cs b/src/Workspaces/MSBuildTest/TestFiles/Resources.cs index 48540488ba691b906684fac20300b2d90386ea19..8338c9e19aaf7850bb10884b9d079992e891c375 100644 --- a/src/Workspaces/MSBuildTest/TestFiles/Resources.cs +++ b/src/Workspaces/MSBuildTest/TestFiles/Resources.cs @@ -115,6 +115,7 @@ public static class CSharp public static string CircularProjectReferences_CircularCSharpProject2 => GetText("CircularProjectReferences.CircularCSharpProject2.csproj"); public static string CSharpProject => GetText("ProjectFiles.CSharp.CSharpProject.csproj"); public static string DuplicateFile => GetText("ProjectFiles.CSharp.DuplicateFile.csproj"); + public static string DuplicateProjectReference => GetText("ProjectFiles.CSharp.DuplicateProjectReference.csproj"); public static string DuplicatedGuidLibrary1 => GetText("ProjectFiles.CSharp.DuplicatedGuidLibrary1.csproj"); public static string DuplicatedGuidLibrary2 => GetText("ProjectFiles.CSharp.DuplicatedGuidLibrary2.csproj"); public static string DuplicatedGuidLibrary3 => GetText("ProjectFiles.CSharp.DuplicatedGuidLibrary3.csproj"); diff --git a/src/Workspaces/MSBuildTest/WorkspaceTestBase.cs b/src/Workspaces/MSBuildTest/WorkspaceTestBase.cs index c75583bd61aa5f31682d854e023c4df628de235c..b32e3d7d4376758833f0887a022c1e975eab7f24 100644 --- a/src/Workspaces/MSBuildTest/WorkspaceTestBase.cs +++ b/src/Workspaces/MSBuildTest/WorkspaceTestBase.cs @@ -225,6 +225,20 @@ protected FileSet GetProjectReferenceSolutionFiles() (@"CSharpProject\CSharpConsole.cs", Resources.SourceFiles.CSharp.CSharpConsole)); } + protected FileSet GetDuplicateProjectReferenceSolutionFiles() + { + return new FileSet( + (@"NuGet.Config", Resources.NuGet_Config), + (@"Directory.Build.props", Resources.Directory_Build_props), + (@"Directory.Build.targets", Resources.Directory_Build_targets), + (@"CSharpProjectReference.sln", Resources.SolutionFiles.CSharp_ProjectReference), + (@"CSharpProject\CSharpProject.csproj", Resources.ProjectFiles.CSharp.CSharpProject), + (@"CSharpProject\CSharpClass.cs", Resources.SourceFiles.CSharp.CSharpClass), + (@"CSharpProject\Properties\AssemblyInfo.cs", Resources.SourceFiles.CSharp.AssemblyInfo), + (@"CSharpProject\CSharpProject_ProjectReference.csproj", Resources.ProjectFiles.CSharp.DuplicateProjectReference), + (@"CSharpProject\CSharpConsole.cs", Resources.SourceFiles.CSharp.CSharpConsole)); + } + protected FileSet GetAnalyzerReferenceSolutionFiles() { return new FileSet(