提交 b0cc12a5 编写于 作者: J Jason Malinowski

Ensure that MSBuildWorkspace deals with duplicate ProjectReferences

The workspace isn't supposed to allow duplicate ProjectReferences, but
currently due to https://github.com/dotnet/roslyn/issues/12101 it does.
This dedups (correctly) at the surface and also adds a test to ensure
this isn't broken.

Fixes https://github.com/dotnet/roslyn/issues/31390.
上级 d0946907
......@@ -17,10 +17,10 @@ private partial class Worker
{
private readonly struct ResolvedReferences
{
public ImmutableArray<ProjectReference> ProjectReferences { get; }
public ImmutableHashSet<ProjectReference> ProjectReferences { get; }
public ImmutableArray<MetadataReference> MetadataReferences { get; }
public ResolvedReferences(ImmutableArray<ProjectReference> projectReferences, ImmutableArray<MetadataReference> metadataReferences)
public ResolvedReferences(ImmutableHashSet<ProjectReference> projectReferences, ImmutableArray<MetadataReference> metadataReferences)
{
ProjectReferences = projectReferences;
MetadataReferences = metadataReferences;
......@@ -50,14 +50,14 @@ private class ResolvedReferencesBuilder
/// </summary>
private readonly HashSet<int> _indicesToRemove;
private readonly ImmutableArray<ProjectReference>.Builder _projectReferences;
private readonly ImmutableHashSet<ProjectReference>.Builder _projectReferences;
public ResolvedReferencesBuilder(IEnumerable<MetadataReference> metadataReferences)
{
_metadataReferences = metadataReferences.ToImmutableArray();
_pathToIndicesMap = CreatePathToIndexMap(_metadataReferences);
_indicesToRemove = new HashSet<int>();
_projectReferences = ImmutableArray.CreateBuilder<ProjectReference>();
_projectReferences = ImmutableHashSet.CreateBuilder<ProjectReference>();
}
private static ImmutableDictionary<string, HashSet<int>> CreatePathToIndexMap(ImmutableArray<MetadataReference> metadataReferences)
......@@ -166,7 +166,7 @@ private ImmutableArray<MetadataReference> GetMetadataReferences()
return builder.ToImmutable();
}
private ImmutableArray<ProjectReference> GetProjectReferences()
private ImmutableHashSet<ProjectReference> GetProjectReferences()
=> _projectReferences.ToImmutable();
public ResolvedReferences ToResolvedReferences()
......
......@@ -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<CompilationReference>());
}
}
private class InMemoryAssemblyLoader : IAnalyzerAssemblyLoader
{
public void AddDependencyLocation(string fullPath)
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -->
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">AnyCPU</Platform>
<PlatformTarget>AnyCPU</PlatformTarget>
<ProjectGuid>{3DA47258-9CAB-4FB9-9C04-1F367A2C2700}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CSharpProject_ProjectToProjectReference</RootNamespace>
<AssemblyName>CSharpProject_ProjectToProjectReference</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<Compile Include="CSharpConsole.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="CSharpProject.csproj">
<Project>{686dd036-86aa-443e-8a10-ddb43266a8c4}</Project>
<Name>CSharpProject</Name>
</ProjectReference>
<ProjectReference Include="CSharpProject.csproj">
<Project>{686dd036-86aa-443e-8a10-ddb43266a8c4}</Project>
<Name>CSharpProject</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
\ No newline at end of file
......@@ -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");
......
......@@ -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(
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册