private bool ReparseCommandLineIfChanged_NoLock(string commandLine)
        {
            var checksum = Checksum.Create(commandLine);

            if (_commandLineChecksum == checksum)
            {
                return(false);
            }

            _commandLineChecksum = checksum;

            // Dispose the existing stored command-line and then persist the new one so we can
            // recover it later.  Only bother persisting things if we have a non-empty string.

            _commandLineStorage?.Dispose();
            _commandLineStorage = null;
            if (commandLine.Length > 0)
            {
                _commandLineStorage = _temporaryStorageService.CreateTemporaryStreamStorage();
                _commandLineStorage.WriteString(commandLine);
            }

            ReparseCommandLine_NoLock(commandLine);
            return(true);
        }
示例#2
0
        public async Task TestAssetSynchronization()
        {
            var code = @"class Test { void Method() { } }";

            using var workspace = TestWorkspace.CreateCSharp(code);
            var solution = workspace.CurrentSolution;

            // build checksum
            await solution.State.GetChecksumAsync(CancellationToken.None);

            var map = await solution.GetAssetMapAsync(CancellationToken.None);

            using var remoteWorkspace = CreateRemoteWorkspace();

            var sessionId   = Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray()));
            var storage     = new SolutionAssetCache();
            var assetSource = new SimpleAssetSource(workspace.Services.GetService <ISerializerService>(), map);

            var service = new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.GetService <ISerializerService>());
            await service.SynchronizeAssetsAsync(new HashSet <Checksum>(map.Keys), CancellationToken.None);

            foreach (var kv in map)
            {
                Assert.True(storage.TryGetAsset <object>(kv.Key, out _));
            }
        }
示例#3
0
        public void WorkspaceAnalyzer_Serailization_Desktop_Test()
        {
            var hostServices = MefHostServices.Create(
                MefHostServices.DefaultAssemblies.Add(typeof(Host.TemporaryStorageServiceFactory.TemporaryStorageService).Assembly));

            using var tempRoot  = new TempRoot();
            using var workspace = new AdhocWorkspace(hostServices);
            var reference = CreateShadowCopiedAnalyzerReference(tempRoot);

            var assetBuilder = new CustomAssetBuilder(workspace);
            var asset        = assetBuilder.Build(reference, CancellationToken.None);

            // verify checksum from custom asset builder uses different checksum than regular one
            var service          = workspace.Services.GetService <IReferenceSerializationService>();
            var expectedChecksum = Checksum.Create(
                WellKnownSynchronizationKind.AnalyzerReference,
                service.CreateChecksum(reference, usePathFromAssembly: false, CancellationToken.None));

            Assert.Equal(expectedChecksum, asset.Checksum);

            // verify usePathFromAssembly return different checksum for same reference
            var fromFilePath = service.CreateChecksum(reference, usePathFromAssembly: false, CancellationToken.None);
            var fromAssembly = service.CreateChecksum(reference, usePathFromAssembly: true, CancellationToken.None);

            Assert.NotEqual(fromFilePath, fromAssembly);
        }
示例#4
0
        private bool ReparseCommandLineIfChanged_NoLock(ImmutableArray <string> arguments)
        {
            var checksum = Checksum.Create(arguments);

            if (_commandLineChecksum == checksum)
            {
                return(false);
            }

            _commandLineChecksum = checksum;

            // Dispose the existing stored command-line and then persist the new one so we can
            // recover it later.  Only bother persisting things if we have a non-empty string.

            _commandLineStorage?.Dispose();
            _commandLineStorage = null;
            if (!arguments.IsEmpty)
            {
                _commandLineStorage = _temporaryStorageService.CreateTemporaryStreamStorage();
                _commandLineStorage.WriteAllLines(arguments);
            }

            ReparseCommandLine_NoLock(arguments);
            return(true);
        }
示例#5
0
        public async Task TestCleanup()
        {
            var storage = new SolutionAssetCache(
                cleanupInterval: TimeSpan.FromMilliseconds(1),
                purgeAfter: TimeSpan.FromMilliseconds(2),
                gcAfter: TimeSpan.FromMilliseconds(5)
                );

            var checksum = Checksum.Create(
                WellKnownSynchronizationKind.Null,
                ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())
                );
            var data = new object();

            Assert.True(storage.TryAddAsset(checksum, data));

            for (var i = 0; i < 10; i++)
            {
                await Task.Delay(10);

                if (!storage.TryGetAsset(checksum, out object _))
                {
                    // asset is deleted
                    return;
                }
            }

            // it should not reach here
            Assert.True(false, "asset not cleaned up");
        }
示例#6
0
        public Checksum CreateChecksum(AnalyzerReference reference, bool usePathFromAssembly, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            using (var stream = SerializableBytes.CreateWritableStream())
                using (var writer = new ObjectWriter(stream, cancellationToken: cancellationToken))
                {
                    switch (reference)
                    {
                    case AnalyzerFileReference file:
                        WriteAnalyzerFileReferenceMvid(file, writer, usePathFromAssembly, cancellationToken);
                        break;

                    case UnresolvedAnalyzerReference unresolved:
                        WriteUnresolvedAnalyzerReferenceTo(unresolved, writer);
                        break;

                    case AnalyzerReference analyzerReference when analyzerReference.GetType().FullName == VisualStudioUnresolvedAnalyzerReference:
                        WriteUnresolvedAnalyzerReferenceTo(analyzerReference, writer);

                        break;

                    case AnalyzerImageReference _:
                        // TODO: think a way to support this or a way to deal with this kind of situation.
                        // https://github.com/dotnet/roslyn/issues/15783
                        throw new NotSupportedException(nameof(AnalyzerImageReference));

                    default:
                        throw ExceptionUtilities.UnexpectedValue(reference);
                    }

                    stream.Position = 0;
                    return(Checksum.Create(stream));
                }
        }
        private async Task TestAssetAsync(object data)
        {
            var sessionId = 0;
            var checksum  = Checksum.Create(WellKnownSynchronizationKind.Null, ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray()));

            using var workspace = TestWorkspace.CreateCSharp(file: @"");

            using var remoteWorkspace = CreateRemoteWorkspace();

            var storage     = new SolutionAssetCache();
            var assetSource = new SimpleAssetSource(workspace.Services.GetService <ISerializerService>(), new Dictionary <Checksum, object>()
            {
                { checksum, data }
            });

            var provider = new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.GetService <ISerializerService>());
            var stored   = await provider.GetAssetAsync <object>(checksum, CancellationToken.None);

            Assert.Equal(data, stored);

            var stored2 = await provider.GetAssetsAsync <object>(new[] { checksum }, CancellationToken.None);

            Assert.Equal(1, stored2.Count);

            Assert.Equal(checksum, stored2[0].Item1);
            Assert.Equal(data, stored2[0].Item2);
        }
示例#8
0
        public async Task TestAssets()
        {
            var sessionId = 0;
            var checksum  = Checksum.Create(WellKnownSynchronizationKind.Null, ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray()));
            var data      = new object();

            var storage = new AssetStorage();

            _ = new SimpleAssetSource(storage, new Dictionary <Checksum, object>()
            {
                { checksum, data }
            });

            var service = new AssetService(sessionId, storage, new RemoteWorkspace().Services.GetService <ISerializerService>());
            var stored  = await service.GetAssetAsync <object>(checksum, CancellationToken.None);

            Assert.Equal(data, stored);

            var stored2 = await service.GetAssetsAsync <object>(new[] { checksum }, CancellationToken.None);

            Assert.Equal(1, stored2.Count);

            Assert.Equal(checksum, stored2[0].Item1);
            Assert.Equal(data, stored2[0].Item2);
        }
示例#9
0
        public void TestPinnedSolutionInfo()
        {
            var checksum = Checksum.Create(
                WellKnownSynchronizationKind.Null,
                ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())
                );

            VerifyJsonSerialization(
                new PinnedSolutionInfo(
                    scopeId: 10,
                    fromPrimaryBranch: false,
                    workspaceVersion: 100,
                    solutionChecksum: checksum
                    ),
                (x, y) =>
            {
                return((
                           x.ScopeId == y.ScopeId &&
                           x.FromPrimaryBranch == y.FromPrimaryBranch &&
                           x.WorkspaceVersion == y.WorkspaceVersion &&
                           x.SolutionChecksum == y.SolutionChecksum
                           )
                      ? 0
                      : 1);
            }
                );
        }
示例#10
0
 private static Checksum CreateChecksum(WellKnownSynchronizationKind kind, object[] children)
 {
     // given children must be either Checksum or Checksums (collection of a checksum)
     return(Checksum.Create(
                kind,
                children.Select(c => c as Checksum ?? ((ChecksumCollection)c).Checksum)
                ));
 }
示例#11
0
        public void TestChecksum()
        {
            var checksum = Checksum.Create(
                WellKnownSynchronizationKind.Null,
                ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())
                );

            VerifyJsonSerialization(checksum);
        }
示例#12
0
        public Checksum CreateChecksum(object value, CancellationToken cancellationToken)
        {
            var kind = value.GetWellKnownSynchronizationKind();

            using (
                Logger.LogBlock(
                    FunctionId.Serializer_CreateChecksum,
                    s_logKind,
                    kind,
                    cancellationToken
                    )
                )
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (value is IChecksummedObject checksummedObject)
                {
                    return(checksummedObject.Checksum);
                }

                switch (kind)
                {
                case WellKnownSynchronizationKind.Null:
                    return(Checksum.Null);

                case WellKnownSynchronizationKind.CompilationOptions:
                case WellKnownSynchronizationKind.ParseOptions:
                case WellKnownSynchronizationKind.ProjectReference:
                case WellKnownSynchronizationKind.OptionSet:
                    return(Checksum.Create(kind, value, this));

                case WellKnownSynchronizationKind.MetadataReference:
                    return(Checksum.Create(
                               kind,
                               CreateChecksum((MetadataReference)value, cancellationToken)
                               ));

                case WellKnownSynchronizationKind.AnalyzerReference:
                    return(Checksum.Create(
                               kind,
                               CreateChecksum((AnalyzerReference)value, cancellationToken)
                               ));

                case WellKnownSynchronizationKind.SerializableSourceText:
                    return(Checksum.Create(kind, ((SerializableSourceText)value).GetChecksum()));

                case WellKnownSynchronizationKind.SourceText:
                    return(Checksum.Create(kind, ((SourceText)value).GetChecksum()));

                default:
                    // object that is not part of solution is not supported since we don't know what inputs are required to
                    // serialize it
                    throw ExceptionUtilities.UnexpectedValue(kind);
                }
            }
        }
示例#13
0
 private static Checksum CreateChecksumFromStreamWriter(WellKnownSynchronizationKind kind, Action <ObjectWriter, CancellationToken> writer)
 {
     using (var stream = SerializableBytes.CreateWritableStream())
         using (var objectWriter = new ObjectWriter(stream))
         {
             objectWriter.WriteInt32((int)kind);
             writer(objectWriter, CancellationToken.None);
             return(Checksum.Create(stream));
         }
 }
示例#14
0
        public Checksum CreateChecksum(AnalyzerReference reference, CancellationToken cancellationToken)
        {
            using (var stream = SerializableBytes.CreateWritableStream())
                using (var writer = new ObjectWriter(stream, cancellationToken: cancellationToken))
                {
                    WriteTo(reference, writer, cancellationToken);

                    stream.Position = 0;
                    return(Checksum.Create(stream));
                }
        }
        public void TestGetAssets()
        {
            var storage = new SolutionAssetCache();

            var checksum = Checksum.Create(WellKnownSynchronizationKind.Null, ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray()));
            var data     = new object();

            Assert.True(storage.TryAddAsset(checksum, data));

            Assert.True(storage.TryGetAsset(checksum, out object _));
        }
示例#16
0
        private Checksum CreatePortableExecutableReferenceChecksum(PortableExecutableReference reference, CancellationToken cancellationToken)
        {
            using (var stream = SerializableBytes.CreateWritableStream())
                using (var writer = new ObjectWriter(stream, cancellationToken: cancellationToken))
                {
                    WriteMvidsTo(reference, writer, cancellationToken);

                    stream.Position = 0;
                    return(Checksum.Create(stream));
                }
        }
示例#17
0
        public static WorkspaceAnalyzerReferenceAsset Create(
            AnalyzerReference reference,
            ISerializerService serializer,
            IReferenceSerializationService hostSerializationService,
            CancellationToken cancellationToken)
        {
            var checksum = Checksum.Create(
                WellKnownSynchronizationKind.AnalyzerReference,
                hostSerializationService.CreateChecksum(reference, usePathFromAssembly, cancellationToken));

            return(new WorkspaceAnalyzerReferenceAsset(reference, serializer, checksum));
        }
示例#18
0
        private static Checksum CreatePortableExecutableReferenceChecksum(PortableExecutableReference reference, CancellationToken cancellationToken)
        {
            using var stream = SerializableBytes.CreateWritableStream();

            using (var writer = new ObjectWriter(stream, leaveOpen: true, cancellationToken))
            {
                WritePortableExecutableReferencePropertiesTo(reference, writer, cancellationToken);
                WriteMvidsTo(TryGetMetadata(reference), writer, cancellationToken);
            }

            stream.Position = 0;
            return(Checksum.Create(stream));
        }
示例#19
0
        private static Checksum GetMetadataChecksumSlow(Solution solution, PortableExecutableReference reference, CancellationToken cancellationToken)
        {
            return(ChecksumCache.GetOrCreate(reference, _ =>
            {
                var serializer = solution.Workspace.Services.GetService <ISerializerService>();
                var checksum = serializer.CreateChecksum(reference, cancellationToken);

                // Include serialization format version in our checksum.  That way if the
                // version ever changes, all persisted data won't match the current checksum
                // we expect, and we'll recompute things.
                return Checksum.Create(checksum, SerializationFormatChecksum);
            }));
        }
示例#20
0
        private static async Task <AssetProvider> GetAssetProviderAsync(Workspace workspace, Workspace remoteWorkspace, Solution solution, Dictionary <Checksum, object> map = null)
        {
            // make sure checksum is calculated
            await solution.State.GetChecksumAsync(CancellationToken.None);

            map ??= new Dictionary <Checksum, object>();
            await solution.AppendAssetMapAsync(map, CancellationToken.None);

            var sessionId   = Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray()));
            var storage     = new SolutionAssetCache();
            var assetSource = new SimpleAssetSource(workspace.Services.GetService <ISerializerService>(), map);

            return(new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.GetService <ISerializerService>()));
        }
        private static string SafeName(string fullPath)
        {
            var fileName = Path.GetFileName(fullPath);

            // we don't want to build too long a path.  So only take a portion of the text we started with.
            // However, we want to avoid collisions, so ensure we also append a safe short piece of text
            // that is based on the full text.
            const int MaxLength = 20;
            var       prefix    = fileName.Length > MaxLength?fileName.Substring(0, MaxLength) : fileName;

            var suffix   = Checksum.Create(fullPath);
            var fullName = $"{prefix}-{suffix}";

            return(StripInvalidPathChars(fullName));
        }
示例#22
0
        public static async Task <Checksum> GetChecksumAsync(
            Document document, CancellationToken cancellationToken)
        {
            // Since we build the SyntaxTreeIndex from a SyntaxTree, we need our checksum to change
            // any time the SyntaxTree could have changed.  Right now, that can only happen if the
            // text of the document changes, or the ParseOptions change.  So we get the checksums
            // for both of those, and merge them together to make the final checksum.
            var projectChecksumState = await document.Project.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false);

            var parseOptionsChecksum = projectChecksumState.ParseOptions;

            var documentChecksumState = await document.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false);

            var textChecksum = documentChecksumState.Text;

            return(Checksum.Create(WellKnownSynchronizationKind.SyntaxTreeIndex, new[] { textChecksum, parseOptionsChecksum }));
        }
示例#23
0
        private static async Task <Checksum> ComputeSourceSymbolsChecksumAsync(ProjectState projectState, CancellationToken cancellationToken)
        {
            // The SymbolTree for source is built from the source-symbols from the project's compilation's
            // assembly.  Specifically, we only get the name, kind and parent/child relationship of all the
            // child symbols.  So we want to be able to reuse the index as long as none of these have
            // changed.  The only thing that can make those source-symbols change in that manner are if
            // the text of any document changes, or if options for the project change.  So we build our
            // checksum out of that data.
            var serializer            = projectState.LanguageServices.WorkspaceServices.GetService <ISerializerService>();
            var projectStateChecksums = await projectState.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false);

            // Order the documents by FilePath.  Default ordering in the RemoteWorkspace is
            // to be ordered by Guid (which is not consistent across VS sessions).
            var textChecksumsTasks = projectState.DocumentStates.OrderBy(d => d.Value.FilePath, StringComparer.Ordinal).Select(async d =>
            {
                var documentStateChecksum = await d.Value.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false);
                return(documentStateChecksum.Text);
            });

            var compilationOptionsChecksum = projectStateChecksums.CompilationOptions;
            var parseOptionsChecksum       = projectStateChecksums.ParseOptions;
            var textChecksums = await Task.WhenAll(textChecksumsTasks).ConfigureAwait(false);

            var allChecksums = ArrayBuilder <Checksum> .GetInstance();

            try
            {
                allChecksums.AddRange(textChecksums);
                allChecksums.Add(compilationOptionsChecksum);
                allChecksums.Add(parseOptionsChecksum);

                // Include serialization format version in our checksum.  That way if the
                // version ever changes, all persisted data won't match the current checksum
                // we expect, and we'll recompute things.
                allChecksums.Add(SerializationFormatChecksum);

                var checksum = Checksum.Create(WellKnownSynchronizationKind.SymbolTreeInfo, allChecksums);
                return(checksum);
            }
            finally
            {
                allChecksums.Free();
            }
        }
        public static async Task <Checksum> GetChecksumAsync(
            Document document, CancellationToken cancellationToken)
        {
            // Since we build the SyntaxTreeIndex from a SyntaxTree, we need our checksum to change
            // any time the SyntaxTree could have changed.  Right now, that can only happen if the
            // text of the document changes, or the ParseOptions change.  So we get the checksums
            // for both of those, and merge them together to make the final checksum.

            var documentChecksumState = await document.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false);

            var textChecksum = documentChecksumState.Text;

            var parseOptions         = document.Project.ParseOptions;
            var serializer           = new Serializer(document.Project.Solution.Workspace);
            var parseOptionsChecksum = ChecksumCache.GetOrCreate(
                parseOptions, _ => serializer.CreateChecksum(parseOptions, cancellationToken));

            return(Checksum.Create(nameof(SyntaxTreeIndex), new[] { textChecksum, parseOptionsChecksum }));
        }
示例#25
0
        public string?TryGetStorageLocation(SolutionKey solutionKey)
        {
            if (solutionKey.WorkspaceKind is not(WorkspaceKind.RemoteWorkspace or WorkspaceKind.RemoteTemporaryWorkspace or WorkspaceKind.Host))
            {
                return(null);
            }

            if (string.IsNullOrWhiteSpace(solutionKey.FilePath))
            {
                return(null);
            }

            // Ensure that each unique workspace kind for any given solution has a unique
            // folder to store their data in.

            var cacheDirectory = GetCacheDirectory();
            var kind           = StripInvalidPathChars(solutionKey.WorkspaceKind);
            var hash           = StripInvalidPathChars(Checksum.Create(solutionKey.FilePath).ToString());

            return(Path.Combine(cacheDirectory, kind, hash));
示例#26
0
        public string?TryGetStorageLocation(Workspace workspace, SolutionKey solutionKey)
        {
            if (!IsSupported(workspace))
            {
                return(null);
            }

            if (string.IsNullOrWhiteSpace(solutionKey.FilePath))
            {
                return(null);
            }

            // Ensure that each unique workspace kind for any given solution has a unique
            // folder to store their data in.

            var cacheDirectory = GetCacheDirectory();
            var kind           = StripInvalidPathChars(workspace.Kind ?? "");
            var hash           = StripInvalidPathChars(Checksum.Create(solutionKey.FilePath).ToString());

            return(Path.Combine(cacheDirectory, kind, hash));
示例#27
0
        public void WorkspaceAnalyzer_Serialization_Desktop_Test()
        {
            var hostServices = MefHostServices.Create(
                MefHostServices.DefaultAssemblies.Add(typeof(Host.TemporaryStorageServiceFactory.TemporaryStorageService).Assembly));

            using var tempRoot  = new TempRoot();
            using var workspace = new AdhocWorkspace(hostServices);
            var reference = CreateShadowCopiedAnalyzerReference(tempRoot);

            var serializer = workspace.Services.GetService <ISerializerService>();

            var asset = WorkspaceAnalyzerReferenceAsset.Create(reference, serializer, CancellationToken.None);

            // verify checksum from custom asset builder uses different checksum than regular one
            var expectedChecksum = Checksum.Create(
                WellKnownSynchronizationKind.AnalyzerReference,
                serializer.CreateChecksum(reference, CancellationToken.None));

            Assert.Equal(expectedChecksum, asset.Checksum);
        }
示例#28
0
        public async Task TestAssets()
        {
            var sessionId = 0;
            var checksum  = Checksum.Create(WellKnownSynchronizationKind.Null, ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray()));
            var data      = new object();

            var storage = new AssetStorage();
            var source  = new TestAssetSource(storage, checksum, data);

            var service = new AssetService(sessionId, storage);
            var stored  = await service.GetAssetAsync <object>(checksum, CancellationToken.None);

            Assert.Equal(data, stored);

            var stored2 = await service.GetAssetsAsync <object>(new[] { checksum }, CancellationToken.None);

            Assert.Equal(1, stored2.Count);

            Assert.Equal(checksum, stored2[0].Item1);
            Assert.Equal(data, stored2[0].Item2);
        }
示例#29
0
        public static async Task <Checksum> GetSourceSymbolsChecksumAsync(Project project, CancellationToken cancellationToken)
        {
            // The SymbolTree for source is built from the source-symbols from the project's compilation's
            // assembly.  Specifically, we only get the name, kind and parent/child relationship of all the
            // child symbols.  So we want to be able to reuse the index as long as none of these have
            // changed.  The only thing that can make those source-symbols change in that manner are if
            // the text of any document changes, or if options for the project change.  So we build our
            // checksum out of that data.
            var serializer            = new Serializer(project.Solution.Workspace);
            var projectStateChecksums = await project.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false);

            // Order the documents by FilePath.  Default ordering in the RemoteWorkspace is
            // to be ordered by Guid (which is not consistent across VS sessions).
            var textChecksumsTasks = project.Documents.OrderBy(d => d.FilePath).Select(async d =>
            {
                var documentStateChecksum = await d.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false);
                return(documentStateChecksum.Text);
            });

            var compilationOptionsChecksum = projectStateChecksums.CompilationOptions;
            var parseOptionsChecksum       = projectStateChecksums.ParseOptions;
            var textChecksums = await Task.WhenAll(textChecksumsTasks).ConfigureAwait(false);

            var allChecksums = ArrayBuilder <Checksum> .GetInstance();

            try
            {
                allChecksums.AddRange(textChecksums);
                allChecksums.Add(compilationOptionsChecksum);
                allChecksums.Add(parseOptionsChecksum);

                var checksum = Checksum.Create(WellKnownSynchronizationKind.SymbolTreeInfo, allChecksums);
                return(checksum);
            }
            finally
            {
                allChecksums.Free();
            }
        }
示例#30
0
        public static Checksum CreateChecksum(AnalyzerReference reference, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            using var stream = SerializableBytes.CreateWritableStream();

            using (var writer = new ObjectWriter(stream, leaveOpen: true, cancellationToken))
            {
                switch (reference)
                {
                case AnalyzerFileReference file:
                    writer.WriteString(file.FullPath);
                    writer.WriteBoolean(IsAnalyzerReferenceWithShadowCopyLoader(file));
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(reference);
                }
            }

            stream.Position = 0;
            return(Checksum.Create(stream));
        }