Skip to content
This repository was archived by the owner on Apr 20, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 25 additions & 14 deletions src/Microsoft.DotNet.Compiler.Common/BindingRedirectGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static class BindingRedirectGenerator

private static SHA1 Sha1 { get; } = SHA1.Create();

internal static XDocument GenerateBindingRedirects(this IEnumerable<LibraryExport> dependencies, XDocument document)
public static XDocument GenerateBindingRedirects(this IEnumerable<LibraryExport> dependencies, XDocument document)
{
var redirects = CollectRedirects(dependencies);

Expand Down Expand Up @@ -107,23 +107,34 @@ private static XElement GetOrAddElement(XContainer parent, XName elementName)
return element;
}

private static AssemblyRedirect[] CollectRedirects(IEnumerable<LibraryExport> dependencies)
internal static AssemblyRedirect[] CollectRedirects(IEnumerable<LibraryExport> dependencies)
{
var allRuntimeAssemblies = dependencies
var runtimeAssemblies = dependencies
.SelectMany(d => d.RuntimeAssemblyGroups.GetDefaultAssets())
.Select(GetAssemblyInfo)
.ToArray();
.Select(GetAssemblyInfo);

var assemblyLookup = allRuntimeAssemblies.ToDictionary(r => r.Identity.ToLookupKey());
return CollectRedirects(runtimeAssemblies);
}

internal static AssemblyRedirect[] CollectRedirects(IEnumerable<AssemblyReferenceInfo> runtimeAssemblies)
{
var assemblyLookup = runtimeAssemblies.ToLookup(r => r.Identity.ToLookupKey());

var redirectAssemblies = new HashSet<AssemblyRedirect>();
foreach (var assemblyReferenceInfo in allRuntimeAssemblies)
foreach (var assemblyReferenceInfo in assemblyLookup)
{
foreach (var referenceIdentity in assemblyReferenceInfo.References)
// Using .First here is not exactly valid, but we don't know which one gets copied to
// output so we just use first
var references = assemblyReferenceInfo.First().References;
foreach (var referenceIdentity in references)
{
AssemblyReferenceInfo targetAssemblyIdentity;
if (assemblyLookup.TryGetValue(referenceIdentity.ToLookupKey(), out targetAssemblyIdentity)
&& targetAssemblyIdentity.Identity.Version != referenceIdentity.Version)
var targetAssemblies = assemblyLookup[referenceIdentity.ToLookupKey()];
if (!targetAssemblies.Any())
{
continue;
}
var targetAssemblyIdentity = targetAssemblies.First();
if (targetAssemblyIdentity.Identity.Version != referenceIdentity.Version)
{
if (targetAssemblyIdentity.Identity.PublicKeyToken != null)
{
Expand Down Expand Up @@ -200,7 +211,7 @@ private static string GetPublicKeyToken(byte[] bytes)
return hex.ToString();
}

private struct AssemblyRedirect
internal struct AssemblyRedirect
{
public AssemblyRedirect(AssemblyIdentity from, AssemblyIdentity to)
{
Expand All @@ -213,7 +224,7 @@ public AssemblyRedirect(AssemblyIdentity from, AssemblyIdentity to)
public AssemblyIdentity To { get; set; }
}

private struct AssemblyIdentity
internal struct AssemblyIdentity
{
public AssemblyIdentity(string name, Version version, string culture, string publicKeyToken)
{
Expand All @@ -239,7 +250,7 @@ public override string ToString()
}
}

private struct AssemblyReferenceInfo
internal struct AssemblyReferenceInfo
{
public AssemblyReferenceInfo(AssemblyIdentity identity, AssemblyIdentity[] references)
{
Expand Down
3 changes: 3 additions & 0 deletions src/Microsoft.DotNet.Compiler.Common/Properties/Properties.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("dotnet-compile.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
59 changes: 59 additions & 0 deletions test/dotnet-compile.UnitTests/BindingRedirectGeneratorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.DotNet.Cli.Compiler.Common;
using Xunit;
using FluentAssertions;

using AssemblyReferenceInfo = Microsoft.DotNet.Cli.Compiler.Common.BindingRedirectGenerator.AssemblyReferenceInfo;
using AssemblyIdentity = Microsoft.DotNet.Cli.Compiler.Common.BindingRedirectGenerator.AssemblyIdentity;

namespace Microsoft.DotNet.Tools.Compiler.Tests
{
public class BindingRedirectGeneratorTests
{
[Fact]
public void ResolvesDuplicatesUsingFirstOccurence()
{
var hash = "01234qwerty";
var redirects = BindingRedirectGenerator.CollectRedirects(new[]
{
new AssemblyReferenceInfo(
new AssemblyIdentity("A", new Version(1, 5), "en-US", hash),
new []
{
new AssemblyIdentity("B", new Version(1, 1), "en-US", hash),
}
),
new AssemblyReferenceInfo(
new AssemblyIdentity("B", new Version(1, 4), "en-US", hash), new AssemblyIdentity[] {}
),
new AssemblyReferenceInfo(
new AssemblyIdentity("B", new Version(1, 5), "en-US", hash), new AssemblyIdentity[] {}
),
new AssemblyReferenceInfo(
new AssemblyIdentity("C", new Version(1, 5), "en-US", hash),
new []
{
new AssemblyIdentity("B", new Version(1, 3), "en-US", hash),
}
)
});

redirects.Should().HaveCount(2);
redirects.Should().Contain(r =>
r.From.Version == new Version(1, 1) &&
r.From.Name == "B" &&
r.To.Version == new Version(1, 4) &&
r.To.Name == "B"
);
redirects.Should().Contain(r =>
r.From.Version == new Version(1, 3) &&
r.From.Name == "B" &&
r.To.Version == new Version(1, 4) &&
r.To.Name == "B"
);
}
}
}
6 changes: 6 additions & 0 deletions test/dotnet-compile.UnitTests/project.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
{
"version": "1.0.0-*",
"compilationOptions": {
"keyFile": "../../tools/Key.snk"
},
"dependencies": {
"Microsoft.DotNet.Cli.Utils": {
"target": "project"
},
"Microsoft.DotNet.Compiler.Common": {
"target": "project"
},
"dotnet": {
"target": "project"
},
Expand Down