File: Options\OptionSet.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.
 
using System.Diagnostics;
using Microsoft.CodeAnalysis.CodeStyle;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.Options;
 
public abstract partial class OptionSet : IOptionsReader
{
    internal static readonly OptionSet Empty = new EmptyOptionSet();
 
    protected OptionSet()
    {
    }
 
    internal abstract object? GetInternalOptionValue(OptionKey optionKey);
 
    /// <summary>
    /// Gets the value of the option, or the default value if not otherwise set.
    /// </summary>
    public object? GetOption(OptionKey optionKey)
    {
        if (optionKey.Option is IOption2 { Definition.StorageMapping: { } mapping })
        {
            return mapping.ToPublicOptionValue(GetInternalOptionValue(new OptionKey(mapping.InternalOption, optionKey.Language)));
        }
 
        var result = GetInternalOptionValue(optionKey);
        Debug.Assert(IsPublicOptionValue(result));
        return result;
    }
 
    /// <summary>
    /// Gets the value of the option, or the default value if not otherwise set.
    /// </summary>
    public T GetOption<T>(OptionKey optionKey)
        => (T)GetOption(optionKey)!;
 
#pragma warning disable RS0030 // Do not used banned APIs: PerLanguageOption<T>
    /// <summary>
    /// Gets the value of the option, or the default value if not otherwise set.
    /// </summary>
    public T GetOption<T>(Option<T> option)
        => GetOption<T>(new OptionKey(option));
 
    /// <summary>
    /// Creates a new <see cref="OptionSet" /> that contains the changed value.
    /// </summary>
    public OptionSet WithChangedOption<T>(Option<T> option, T value)
        => WithChangedOption(new OptionKey(option), value);
 
    /// <summary>
    /// Gets the value of the option, or the default value if not otherwise set.
    /// </summary>
    public T GetOption<T>(PerLanguageOption<T> option, string? language)
        => GetOption<T>(new OptionKey(option, language));
 
    /// <summary>
    /// Creates a new <see cref="OptionSet" /> that contains the changed value.
    /// </summary>
    public OptionSet WithChangedOption<T>(PerLanguageOption<T> option, string? language, T value)
        => WithChangedOption(new OptionKey(option, language), value);
#pragma warning restore
 
    /// <summary>
    /// Creates a new <see cref="OptionSet" /> that contains the changed value.
    /// </summary>
    public virtual OptionSet WithChangedOption(OptionKey optionAndLanguage, object? value)
    {
        if (optionAndLanguage.Option is IOption2 { Definition.StorageMapping: { } mapping })
        {
            var mappedOptionKey = new OptionKey(mapping.InternalOption, optionAndLanguage.Language);
            var currentValue = GetInternalOptionValue(mappedOptionKey);
            return WithChangedOptionInternal(mappedOptionKey, mapping.UpdateInternalOptionValue(currentValue, value));
        }
 
        return WithChangedOptionInternal(optionAndLanguage, value);
    }
 
    internal virtual OptionSet WithChangedOptionInternal(OptionKey optionKey, object? internalValue)
        => throw ExceptionUtilities.Unreachable();
 
    bool IOptionsReader.TryGetOption<T>(OptionKey2 optionKey, out T value)
    {
        value = (T)GetInternalOptionValue(new OptionKey(optionKey.Option, optionKey.Language))!;
        return true;
    }
 
    /// <summary>
    /// Checks if the value is an internal representation -- does not cover all cases, just code style options.
    /// </summary>
    internal static bool IsInternalOptionValue(object? value)
        => value is not ICodeStyleOption;
 
    /// <summary>
    /// Checks if the value is an public representation -- does not cover all cases, just code style options.
    /// </summary>
    internal static bool IsPublicOptionValue(object? value)
        => value is not ICodeStyleOption2;
}