File: Serialization\AbstractOptionsSerializationService.cs
Web Access
Project: src\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Threading;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.Serialization;
 
internal abstract class AbstractOptionsSerializationService : IOptionsSerializationService
{
    public abstract void WriteTo(CompilationOptions options, ObjectWriter writer, CancellationToken cancellationToken);
    public abstract void WriteTo(ParseOptions options, ObjectWriter writer);
 
    public abstract CompilationOptions ReadCompilationOptionsFrom(ObjectReader reader, CancellationToken cancellationToken);
    public abstract ParseOptions ReadParseOptionsFrom(ObjectReader reader, CancellationToken cancellationToken);
 
    protected static void WriteCompilationOptionsTo(CompilationOptions options, ObjectWriter writer, CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();
 
        writer.WriteInt32((int)options.OutputKind);
        writer.WriteBoolean(options.ReportSuppressedDiagnostics);
        writer.WriteString(options.ModuleName);
        writer.WriteString(options.MainTypeName);
        writer.WriteString(options.ScriptClassName);
        writer.WriteInt32((int)options.OptimizationLevel);
        writer.WriteBoolean(options.CheckOverflow);
 
        // REVIEW: is it okay this being not part of snapshot?
        writer.WriteString(options.CryptoKeyContainer);
        writer.WriteString(options.CryptoKeyFile);
 
        writer.WriteSpan(options.CryptoPublicKey.AsSpan());
        writer.WriteBoolean(options.DelaySign.HasValue);
        if (options.DelaySign.HasValue)
        {
            writer.WriteBoolean(options.DelaySign.Value);
        }
 
        writer.WriteInt32((int)options.Platform);
        writer.WriteInt32((int)options.GeneralDiagnosticOption);
 
        writer.WriteInt32(options.WarningLevel);
 
        // REVIEW: I don't think there is a guarantee on ordering of elements in the immutable dictionary.
        //         unfortunately, we need to sort them to make it deterministic
        writer.WriteInt32(options.SpecificDiagnosticOptions.Count);
        foreach (var kv in options.SpecificDiagnosticOptions.OrderBy(o => o.Key))
        {
            writer.WriteString(kv.Key);
            writer.WriteInt32((int)kv.Value);
        }
 
        writer.WriteBoolean(options.ConcurrentBuild);
        writer.WriteBoolean(options.Deterministic);
        writer.WriteBoolean(options.PublicSign);
 
        writer.WriteByte((byte)options.MetadataImportOptions);
 
        // REVIEW: What should I do with these. we probably need to implement either out own one
        //         or somehow share these as service....
        //
        // XmlReferenceResolver xmlReferenceResolver
        // SourceReferenceResolver sourceReferenceResolver
        // MetadataReferenceResolver metadataReferenceResolver
        // AssemblyIdentityComparer assemblyIdentityComparer
        // StrongNameProvider strongNameProvider
    }
 
    protected static (
        OutputKind outputKind,
        bool reportSuppressedDiagnostics,
        string moduleName,
        string mainTypeName,
        string scriptClassName,
        OptimizationLevel optimizationLevel,
        bool checkOverflow,
        string cryptoKeyContainer,
        string cryptoKeyFile,
        ImmutableArray<byte> cryptoPublicKey,
        bool? delaySign,
        Platform platform,
        ReportDiagnostic generalDiagnosticOption,
        int warningLevel,
        IEnumerable<KeyValuePair<string, ReportDiagnostic>> specificDiagnosticOptions,
        bool concurrentBuild,
        bool deterministic,
        bool publicSign,
        MetadataImportOptions metadataImportOptions,
        XmlReferenceResolver xmlReferenceResolver,
        SourceReferenceResolver sourceReferenceResolver,
        MetadataReferenceResolver metadataReferenceResolver,
        AssemblyIdentityComparer assemblyIdentityComparer,
        StrongNameProvider strongNameProvider) ReadCompilationOptionsPieces(
        ObjectReader reader,
        CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();
 
        var outputKind = (OutputKind)reader.ReadInt32();
        var reportSuppressedDiagnostics = reader.ReadBoolean();
        var moduleName = reader.ReadString();
        var mainTypeName = reader.ReadString();
 
        var scriptClassName = reader.ReadString();
        var optimizationLevel = (OptimizationLevel)reader.ReadInt32();
        var checkOverflow = reader.ReadBoolean();
 
        // REVIEW: is it okay this being not part of snapshot?
        var cryptoKeyContainer = reader.ReadString();
        var cryptoKeyFile = reader.ReadString();
 
        var cryptoPublicKey = reader.ReadByteArray().ToImmutableArrayOrEmpty();
 
        bool? delaySign = reader.ReadBoolean() ? reader.ReadBoolean() : null;
 
        var platform = (Platform)reader.ReadInt32();
        var generalDiagnosticOption = (ReportDiagnostic)reader.ReadInt32();
 
        var warningLevel = reader.ReadInt32();
 
        // REVIEW: I don't think there is a guarantee on ordering of elements in the immutable dictionary.
        //         unfortunately, we need to sort them to make it deterministic
        //         not sure why CompilationOptions uses SequencialEqual to check options equality
        //         when ordering can change result of it even if contents are same.
        var count = reader.ReadInt32();
        List<KeyValuePair<string, ReportDiagnostic>> specificDiagnosticOptionsList = null;
 
        if (count > 0)
        {
            specificDiagnosticOptionsList = new List<KeyValuePair<string, ReportDiagnostic>>(count);
 
            for (var i = 0; i < count; i++)
            {
                var key = reader.ReadString();
                var value = (ReportDiagnostic)reader.ReadInt32();
 
                specificDiagnosticOptionsList.Add(KeyValuePairUtil.Create(key, value));
            }
        }
 
        var specificDiagnosticOptions = specificDiagnosticOptionsList ?? [];
 
        var concurrentBuild = reader.ReadBoolean();
        var deterministic = reader.ReadBoolean();
        var publicSign = reader.ReadBoolean();
 
        var metadataImportOptions = (MetadataImportOptions)reader.ReadByte();
 
        // REVIEW: What should I do with these. are these service required when compilation is built ourselves, not through
        //         compiler.
        var xmlReferenceResolver = XmlFileResolver.Default;
        var sourceReferenceResolver = SourceFileResolver.Default;
        var assemblyIdentityComparer = DesktopAssemblyIdentityComparer.Default;
        var strongNameProvider = new DesktopStrongNameProvider(ImmutableArray<string>.Empty, Path.GetTempPath());
 
        return (
            outputKind,
            reportSuppressedDiagnostics,
            moduleName,
            mainTypeName,
            scriptClassName,
            optimizationLevel,
            checkOverflow,
            cryptoKeyContainer,
            cryptoKeyFile,
            cryptoPublicKey,
            delaySign,
            platform,
            generalDiagnosticOption,
            warningLevel,
            specificDiagnosticOptions,
            concurrentBuild,
            deterministic,
            publicSign,
            metadataImportOptions,
            xmlReferenceResolver,
            sourceReferenceResolver,
            metadataReferenceResolver: null,
            assemblyIdentityComparer,
            strongNameProvider);
    }
 
    protected static void WriteParseOptionsTo(ParseOptions options, ObjectWriter writer)
    {
        writer.WriteInt32((int)options.Kind);
        writer.WriteInt32((int)options.DocumentationMode);
 
        // REVIEW: I don't think there is a guarantee on ordering of elements in the readonly dictionary.
        //         unfortunately, we need to sort them to make it deterministic
        writer.WriteInt32(options.Features.Count);
        foreach (var kv in options.Features.OrderBy(o => o.Key))
        {
            writer.WriteString(kv.Key);
            writer.WriteString(kv.Value);
        }
    }
 
    protected static (SourceCodeKind kind, DocumentationMode documentationMode, IEnumerable<KeyValuePair<string, string>> features) ReadParseOptionsPieces(
        ObjectReader reader,
        CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();
 
        var kind = (SourceCodeKind)reader.ReadInt32();
        var documentationMode = (DocumentationMode)reader.ReadInt32();
 
        // REVIEW: I don't think there is a guarantee on ordering of elements in the immutable dictionary.
        //         unfortunately, we need to sort them to make it deterministic
        //         not sure why ParseOptions uses SequencialEqual to check options equality
        //         when ordering can change result of it even if contents are same.
        var count = reader.ReadInt32();
        List<KeyValuePair<string, string>> featuresList = null;
 
        if (count > 0)
        {
            featuresList = new List<KeyValuePair<string, string>>(count);
 
            for (var i = 0; i < count; i++)
            {
                var key = reader.ReadString();
                var value = reader.ReadString();
 
                featuresList.Add(KeyValuePairUtil.Create(key, value));
            }
        }
 
        var features = featuresList ?? [];
        return (kind, documentationMode, features);
    }
}