diff --git a/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs b/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs
index 5937e1dec48d6..7bb2618b19b0a 100644
--- a/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs
+++ b/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs
@@ -70,7 +70,7 @@ protected virtual Checksum CreateChecksum(AnalyzerReference reference)
{
case AnalyzerFileReference fileReference:
writer.WriteString(fileReference.FullPath);
- writer.WriteGuid(IsolatedAnalyzerReferenceSet.TryGetAnalyzerFileReferenceMvid(fileReference));
+ writer.WriteGuid(IsolatedAnalyzerReferenceSet.TryGetFileReferenceMvid(fileReference.FullPath));
break;
case AnalyzerImageReference analyzerImageReference:
diff --git a/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerReferenceSet.Core.cs b/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerReferenceSet.Core.cs
index cf92f4720e2ad..b013c9736ed04 100644
--- a/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerReferenceSet.Core.cs
+++ b/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerReferenceSet.Core.cs
@@ -7,6 +7,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Runtime.CompilerServices;
using System.Runtime.Loader;
using System.Threading;
using System.Threading.Tasks;
@@ -82,7 +83,11 @@ internal sealed partial class IsolatedAnalyzerReferenceSet
///
/// Guarded by . Note that while the gate is static, this is instance data on the . And we only want to mutate that instance data from one thread at a
- /// time.
+ /// time.
+ ///
+ /// Stored as an so this can safely be used as a key in caches that map from a list
+ /// of items to some value (for example in an .
+ ///
private readonly Dictionary> _analyzerReferences = [];
private IsolatedAnalyzerReferenceSet(
@@ -304,7 +309,7 @@ static void PopulateFilePathToMvidMap(
// Can ignore all other analyzer reference types. This is only about analyzer references changing on disk.
var analyzerReference = GetUnderlyingAnalyzerReference(initialReference);
if (analyzerReference is AnalyzerFileReference analyzerFileReference)
- pathToMvidMap[analyzerFileReference.FullPath] = TryGetAnalyzerFileReferenceMvid(analyzerFileReference);
+ pathToMvidMap[analyzerFileReference.FullPath] = TryGetFileReferenceMvid(analyzerFileReference.FullPath);
}
}
}
diff --git a/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerReferenceSet.Desktop.cs b/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerReferenceSet.Desktop.cs
index 48f925592c3b8..06505901c4213 100644
--- a/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerReferenceSet.Desktop.cs
+++ b/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerReferenceSet.Desktop.cs
@@ -5,6 +5,7 @@
#if !NET
using System;
+using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
diff --git a/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerReferenceSet.cs b/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerReferenceSet.cs
index 73b337dbacd3f..dc661417bc6c9 100644
--- a/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerReferenceSet.cs
+++ b/src/Workspaces/Core/Portable/Workspace/IsolatedAnalyzerReferenceSet.cs
@@ -51,11 +51,11 @@ private static async ValueTask> DefaultCreateI
return await getReferencesAsync().ConfigureAwait(false);
}
- public static Guid TryGetAnalyzerFileReferenceMvid(AnalyzerFileReference file)
+ public static Guid TryGetFileReferenceMvid(string filePath)
{
try
{
- return AssemblyUtilities.ReadMvid(file.FullPath);
+ return AssemblyUtilities.ReadMvid(filePath);
}
catch
{
diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs b/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs
index 8c96d86647948..40abdf29896e9 100644
--- a/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs
+++ b/src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs
@@ -8,6 +8,7 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Shared.Extensions;
@@ -568,16 +569,38 @@ public static Checksum GetOrCreate(TValue value, Func.GetOrCreate(value, checksumCreator, arg);
}
+ public static ChecksumCollection GetOrCreateChecksumCollection(
+ ImmutableArray references, ISerializerService serializer, CancellationToken cancellationToken) where TReference : class
+ {
+ // Grab the internal array from the immutable array. This is safe as the callers can't modify it, and we just
+ // want the internal reference object to use as the key in the cache.
+ return GetOrCreateChecksumCollection(
+ ImmutableCollectionsMarshal.AsArray(references)!, serializer, cancellationToken);
+ }
+
public static ChecksumCollection GetOrCreateChecksumCollection(
IReadOnlyList references, ISerializerService serializer, CancellationToken cancellationToken) where TReference : class
{
+ // Cache both at the list-of-references level...
return StronglyTypedChecksumCache, ChecksumCollection>.GetOrCreate(
references,
static (references, tuple) =>
{
+ var (serializer, cancellationToken) = tuple;
var checksums = new FixedSizeArrayBuilder(references.Count);
foreach (var reference in references)
- checksums.Add(tuple.serializer.CreateChecksum(reference, tuple.cancellationToken));
+ {
+ // ... and cache at the individual reference level.
+ var checksum = GetOrCreate(
+ reference,
+ static (reference, arg) =>
+ {
+ var (serializer, cancellationToken) = arg;
+ return serializer.CreateChecksum(reference, cancellationToken);
+ },
+ arg: (serializer, cancellationToken));
+ checksums.Add(checksum);
+ }
return new ChecksumCollection(checksums.MoveToImmutable());
},