diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PackageIdentity.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PackageIdentity.cs
index 5a82223b0..52ab88b06 100644
--- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PackageIdentity.cs
+++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PackageIdentity.cs
@@ -5,13 +5,17 @@
using System;
using NuGet.Versioning;
+#if !NETCOREAPP
+using System.Collections.Generic;
+#endif
+
namespace Microsoft.CodeAnalysis.Testing
{
///
/// Represents the core identity of a NuGet package.
///
///
- public sealed class PackageIdentity
+ public sealed class PackageIdentity : IEquatable
{
///
/// Initializes a new instance of the class with the specified name and version.
@@ -41,6 +45,28 @@ public PackageIdentity(string id, string version)
///
public string Version { get; }
+ public override int GetHashCode()
+ {
+#if NETCOREAPP
+ return HashCode.Combine(Id, Version);
+#else
+ var hashCode = -612338121;
+ hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(Id);
+ hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(Version);
+ return hashCode;
+#endif
+ }
+
+ public override bool Equals(object? obj)
+ => Equals(obj as PackageIdentity);
+
+ public bool Equals(PackageIdentity? other)
+ {
+ return other is not null
+ && Id == other.Id
+ && Version == other.Version;
+ }
+
internal NuGet.Packaging.Core.PackageIdentity ToNuGetIdentity()
{
return new NuGet.Packaging.Core.PackageIdentity(Id, NuGetVersion.Parse(Version));
diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt
index 5748c37c5..ae5efba29 100644
--- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt
+++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/PublicAPI.Unshipped.txt
@@ -144,6 +144,7 @@ Microsoft.CodeAnalysis.Testing.Model.EvaluatedProjectState.Sources.get -> System
Microsoft.CodeAnalysis.Testing.Model.EvaluatedProjectState.WithAdditionalDiagnostics(System.Collections.Immutable.ImmutableArray additionalDiagnostics) -> Microsoft.CodeAnalysis.Testing.Model.EvaluatedProjectState
Microsoft.CodeAnalysis.Testing.Model.EvaluatedProjectState.WithSources(System.Collections.Immutable.ImmutableArray<(string filename, Microsoft.CodeAnalysis.Text.SourceText content)> sources) -> Microsoft.CodeAnalysis.Testing.Model.EvaluatedProjectState
Microsoft.CodeAnalysis.Testing.PackageIdentity
+Microsoft.CodeAnalysis.Testing.PackageIdentity.Equals(Microsoft.CodeAnalysis.Testing.PackageIdentity other) -> bool
Microsoft.CodeAnalysis.Testing.PackageIdentity.Id.get -> string
Microsoft.CodeAnalysis.Testing.PackageIdentity.PackageIdentity(string id, string version) -> void
Microsoft.CodeAnalysis.Testing.PackageIdentity.Version.get -> string
@@ -176,6 +177,7 @@ Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.AddLanguageSpecificAssemblies
Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.AddPackages(System.Collections.Immutable.ImmutableArray packages) -> Microsoft.CodeAnalysis.Testing.ReferenceAssemblies
Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.Assemblies.get -> System.Collections.Immutable.ImmutableArray
Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.AssemblyIdentityComparer.get -> Microsoft.CodeAnalysis.AssemblyIdentityComparer
+Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.Equals(Microsoft.CodeAnalysis.Testing.ReferenceAssemblies other) -> bool
Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.FacadeAssemblies.get -> System.Collections.Immutable.ImmutableArray
Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.LanguageSpecificAssemblies.get -> System.Collections.Immutable.ImmutableDictionary>
Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.Net
@@ -246,6 +248,10 @@ abstract Microsoft.CodeAnalysis.Testing.CodeActionTest.SyntaxKindType
override Microsoft.CodeAnalysis.Testing.DiagnosticResult.ToString() -> string
override Microsoft.CodeAnalysis.Testing.EmptyDiagnosticAnalyzer.Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext context) -> void
override Microsoft.CodeAnalysis.Testing.EmptyDiagnosticAnalyzer.SupportedDiagnostics.get -> System.Collections.Immutable.ImmutableArray
+override Microsoft.CodeAnalysis.Testing.PackageIdentity.Equals(object obj) -> bool
+override Microsoft.CodeAnalysis.Testing.PackageIdentity.GetHashCode() -> int
+override Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.Equals(object obj) -> bool
+override Microsoft.CodeAnalysis.Testing.ReferenceAssemblies.GetHashCode() -> int
static Microsoft.CodeAnalysis.Testing.AnalyzerTest.Verify.get -> TVerifier
static Microsoft.CodeAnalysis.Testing.AnalyzerVerifier.Diagnostic() -> Microsoft.CodeAnalysis.Testing.DiagnosticResult
static Microsoft.CodeAnalysis.Testing.AnalyzerVerifier.Diagnostic(Microsoft.CodeAnalysis.DiagnosticDescriptor descriptor) -> Microsoft.CodeAnalysis.Testing.DiagnosticResult
diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/ReferenceAssemblies.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/ReferenceAssemblies.cs
index c842bc515..39b0e0bae 100644
--- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/ReferenceAssemblies.cs
+++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/ReferenceAssemblies.cs
@@ -25,7 +25,7 @@
namespace Microsoft.CodeAnalysis.Testing
{
- public sealed partial class ReferenceAssemblies
+ public sealed partial class ReferenceAssemblies : IEquatable
{
private const string ReferenceAssembliesPackageVersion = "1.0.2";
@@ -37,6 +37,8 @@ public sealed partial class ReferenceAssemblies
private static ImmutableHashSet s_emptyPackages
= ImmutableHashSet.Create(PackageIdentityComparer.Default);
+ private static ImmutableHashSet s_knownAssemblies = ImmutableHashSet.Empty;
+
private readonly Dictionary> _references
= new();
@@ -123,14 +125,83 @@ public static ReferenceAssemblies Default
public string? NuGetConfigFilePath { get; }
+ private static ReferenceAssemblies GetOrAddReferenceAssemblies(ReferenceAssemblies value)
+ {
+ if (s_knownAssemblies.TryGetValue(value, out var existingValue))
+ {
+ return existingValue;
+ }
+
+ if (ImmutableInterlocked.Update(
+ ref s_knownAssemblies,
+ static (knownAssemblies, value) => knownAssemblies.Add(value),
+ value))
+ {
+ return value;
+ }
+
+ if (!s_knownAssemblies.TryGetValue(value, out existingValue))
+ {
+ throw new InvalidOperationException();
+ }
+
+ return existingValue;
+ }
+
+ public override int GetHashCode()
+ {
+#if NETCOREAPP
+ var hash = default(HashCode);
+ hash.Add(TargetFramework);
+ hash.Add(AssemblyIdentityComparer);
+ hash.Add(ReferenceAssemblyPackage);
+ hash.Add(ReferenceAssemblyPath);
+ hash.Add(Assemblies, ImmutableArrayEqualityComparer.Instance);
+ hash.Add(FacadeAssemblies, ImmutableArrayEqualityComparer.Instance);
+ hash.Add(LanguageSpecificAssemblies, ImmutableDictionaryWithImmutableArrayValuesEqualityComparer.Instance);
+ hash.Add(Packages, ImmutableArrayEqualityComparer.Instance);
+ hash.Add(NuGetConfigFilePath);
+ return hash.ToHashCode();
+#else
+ var hashCode = -450793227;
+ hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(TargetFramework);
+ hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(AssemblyIdentityComparer);
+ hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(ReferenceAssemblyPackage);
+ hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(ReferenceAssemblyPath);
+ hashCode = (hashCode * -1521134295) + ImmutableArrayEqualityComparer.Instance.GetHashCode(Assemblies);
+ hashCode = (hashCode * -1521134295) + ImmutableArrayEqualityComparer.Instance.GetHashCode(FacadeAssemblies);
+ hashCode = (hashCode * -1521134295) + ImmutableDictionaryWithImmutableArrayValuesEqualityComparer.Instance.GetHashCode(LanguageSpecificAssemblies);
+ hashCode = (hashCode * -1521134295) + ImmutableArrayEqualityComparer.Instance.GetHashCode(Packages);
+ hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(NuGetConfigFilePath);
+ return hashCode;
+#endif
+ }
+
+ public override bool Equals(object? obj)
+ => Equals(obj as ReferenceAssemblies);
+
+ public bool Equals(ReferenceAssemblies? other)
+ {
+ return other is not null
+ && TargetFramework == other.TargetFramework
+ && EqualityComparer.Default.Equals(AssemblyIdentityComparer, other.AssemblyIdentityComparer)
+ && EqualityComparer.Default.Equals(ReferenceAssemblyPackage, other.ReferenceAssemblyPackage)
+ && ReferenceAssemblyPath == other.ReferenceAssemblyPath
+ && ImmutableArrayEqualityComparer.Instance.Equals(Assemblies, other.Assemblies)
+ && ImmutableArrayEqualityComparer.Instance.Equals(FacadeAssemblies, other.FacadeAssemblies)
+ && ImmutableDictionaryWithImmutableArrayValuesEqualityComparer.Instance.Equals(LanguageSpecificAssemblies, other.LanguageSpecificAssemblies)
+ && ImmutableArrayEqualityComparer.Instance.Equals(Packages, other.Packages)
+ && NuGetConfigFilePath == other.NuGetConfigFilePath;
+ }
+
public ReferenceAssemblies WithAssemblyIdentityComparer(AssemblyIdentityComparer assemblyIdentityComparer)
- => new(TargetFramework, assemblyIdentityComparer, ReferenceAssemblyPackage, ReferenceAssemblyPath, Assemblies, FacadeAssemblies, LanguageSpecificAssemblies, Packages, NuGetConfigFilePath);
+ => GetOrAddReferenceAssemblies(new(TargetFramework, assemblyIdentityComparer, ReferenceAssemblyPackage, ReferenceAssemblyPath, Assemblies, FacadeAssemblies, LanguageSpecificAssemblies, Packages, NuGetConfigFilePath));
public ReferenceAssemblies WithAssemblies(ImmutableArray assemblies)
- => new(TargetFramework, AssemblyIdentityComparer, ReferenceAssemblyPackage, ReferenceAssemblyPath, assemblies, FacadeAssemblies, LanguageSpecificAssemblies, Packages, NuGetConfigFilePath);
+ => GetOrAddReferenceAssemblies(new(TargetFramework, AssemblyIdentityComparer, ReferenceAssemblyPackage, ReferenceAssemblyPath, assemblies, FacadeAssemblies, LanguageSpecificAssemblies, Packages, NuGetConfigFilePath));
public ReferenceAssemblies WithFacadeAssemblies(ImmutableArray facadeAssemblies)
- => new(TargetFramework, AssemblyIdentityComparer, ReferenceAssemblyPackage, ReferenceAssemblyPath, Assemblies, facadeAssemblies, LanguageSpecificAssemblies, Packages, NuGetConfigFilePath);
+ => GetOrAddReferenceAssemblies(new(TargetFramework, AssemblyIdentityComparer, ReferenceAssemblyPackage, ReferenceAssemblyPath, Assemblies, facadeAssemblies, LanguageSpecificAssemblies, Packages, NuGetConfigFilePath));
public ReferenceAssemblies AddAssemblies(ImmutableArray assemblies)
=> WithAssemblies(Assemblies.AddRange(assemblies));
@@ -139,7 +210,7 @@ public ReferenceAssemblies AddFacadeAssemblies(ImmutableArray facadeAsse
=> WithFacadeAssemblies(FacadeAssemblies.AddRange(facadeAssemblies));
public ReferenceAssemblies WithLanguageSpecificAssemblies(ImmutableDictionary> languageSpecificAssemblies)
- => new(TargetFramework, AssemblyIdentityComparer, ReferenceAssemblyPackage, ReferenceAssemblyPath, Assemblies, FacadeAssemblies, languageSpecificAssemblies, Packages, NuGetConfigFilePath);
+ => GetOrAddReferenceAssemblies(new(TargetFramework, AssemblyIdentityComparer, ReferenceAssemblyPackage, ReferenceAssemblyPath, Assemblies, FacadeAssemblies, languageSpecificAssemblies, Packages, NuGetConfigFilePath));
public ReferenceAssemblies WithLanguageSpecificAssemblies(string language, ImmutableArray assemblies)
=> WithLanguageSpecificAssemblies(LanguageSpecificAssemblies.SetItem(language, assemblies));
@@ -155,13 +226,13 @@ public ReferenceAssemblies AddLanguageSpecificAssemblies(string language, Immuta
}
public ReferenceAssemblies WithPackages(ImmutableArray packages)
- => new(TargetFramework, AssemblyIdentityComparer, ReferenceAssemblyPackage, ReferenceAssemblyPath, Assemblies, FacadeAssemblies, LanguageSpecificAssemblies, packages, NuGetConfigFilePath);
+ => GetOrAddReferenceAssemblies(new(TargetFramework, AssemblyIdentityComparer, ReferenceAssemblyPackage, ReferenceAssemblyPath, Assemblies, FacadeAssemblies, LanguageSpecificAssemblies, packages, NuGetConfigFilePath));
public ReferenceAssemblies AddPackages(ImmutableArray packages)
=> WithPackages(Packages.AddRange(packages));
public ReferenceAssemblies WithNuGetConfigFilePath(string nugetConfigFilePath)
- => new(TargetFramework, AssemblyIdentityComparer, ReferenceAssemblyPackage, ReferenceAssemblyPath, Assemblies, FacadeAssemblies, LanguageSpecificAssemblies, Packages, nugetConfigFilePath);
+ => GetOrAddReferenceAssemblies(new(TargetFramework, AssemblyIdentityComparer, ReferenceAssemblyPackage, ReferenceAssemblyPath, Assemblies, FacadeAssemblies, LanguageSpecificAssemblies, Packages, nugetConfigFilePath));
public async Task> ResolveAsync(string? language, CancellationToken cancellationToken)
{
@@ -1353,5 +1424,140 @@ public static bool IsPackageBased(string targetFramework)
return framework.IsPackageBased;
}
}
+
+ private sealed class ImmutableArrayEqualityComparer : IEqualityComparer>
+ {
+ public static readonly ImmutableArrayEqualityComparer Instance = new();
+
+ private ImmutableArrayEqualityComparer()
+ {
+ }
+
+ public bool Equals(ImmutableArray x, ImmutableArray y)
+ {
+ if (x.IsDefault)
+ {
+ return y.IsDefault;
+ }
+ else if (y.IsDefault)
+ {
+ return false;
+ }
+
+ if (x.Length != y.Length)
+ {
+ return false;
+ }
+
+ for (var i = 0; i < x.Length; i++)
+ {
+ if (!EqualityComparer.Default.Equals(x[i], y[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int GetHashCode(ImmutableArray obj)
+ {
+ if (obj.IsDefault)
+ {
+ return 0;
+ }
+
+#if NETCOREAPP
+ var hash = default(HashCode);
+ foreach (var item in obj)
+ {
+ hash.Add(item);
+ }
+
+ return hash.ToHashCode();
+#else
+ var hashCode = -450793227;
+ foreach (var item in obj)
+ {
+ hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(item);
+ }
+
+ return hashCode;
+#endif
+ }
+ }
+
+ private sealed class ImmutableDictionaryWithImmutableArrayValuesEqualityComparer : IEqualityComparer>?>
+ {
+ public static readonly ImmutableDictionaryWithImmutableArrayValuesEqualityComparer Instance = new();
+
+ private ImmutableDictionaryWithImmutableArrayValuesEqualityComparer()
+ {
+ }
+
+ public bool Equals(ImmutableDictionary>? x, ImmutableDictionary>? y)
+ {
+ if (x is null)
+ {
+ return y is null;
+ }
+ else if (y is null)
+ {
+ return false;
+ }
+
+ if (x.Count != y.Count)
+ {
+ return false;
+ }
+
+ foreach (var (key, valueX) in x)
+ {
+ // Use a separate lookup in 'y' since ImmutableDictionary<,> can reorder pairs where the key has the
+ // same hash code.
+ if (!y.TryGetValue(key, out var valueY))
+ {
+ return false;
+ }
+
+ if (!ImmutableArrayEqualityComparer.Instance.Equals(valueX, valueY))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int GetHashCode(ImmutableDictionary>? obj)
+ {
+ if (obj is null)
+ {
+ return 0;
+ }
+
+#if NETCOREAPP
+ var hash = default(HashCode);
+ foreach (var (key, _) in obj)
+ {
+ // Intentionally ignore values since ImmutableDictionary<,> can reorder pairs where the key has the
+ // same hash code.
+ hash.Add(key);
+ }
+
+ return hash.ToHashCode();
+#else
+ var hashCode = -450793227;
+ foreach (var (key, _) in obj)
+ {
+ // Intentionally ignore values since ImmutableDictionary<,> can reorder pairs where the key has the
+ // same hash code.
+ hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(key);
+ }
+
+ return hashCode;
+#endif
+ }
+ }
}
}