// 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; using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; namespace Microsoft.CodeAnalysis.Options; internal abstract class OptionDefinition : IEquatable<OptionDefinition?> { // editorconfig name prefixes used for C#/VB specific options: public const string CSharpConfigNamePrefix = "csharp_"; public const string VisualBasicConfigNamePrefix = "visual_basic_"; // editorconfig name prefix use for options that apply to both languages: public const string LanguageAgnosticConfigNamePrefix = "dotnet_"; // editorconfig name prefix for feature options that are read from editorconfig // file but are currently not intended for users to be set in the editorconfig file. public const string InternalConfigNamePrefix = "internal_"; /// <summary> /// Optional group/sub-feature for this option. /// </summary> internal OptionGroup Group { get; } /// <summary> /// A unique name of the option used in editorconfig. /// </summary> public string ConfigName { get; } /// <summary> /// True if the value of the option may be stored in an editorconfig file. /// </summary> public bool IsEditorConfigOption { get; } /// <summary> /// Mapping between the public option storage and internal option storage. /// </summary> public OptionStorageMapping? StorageMapping { get; } /// <summary> /// The untyped/boxed default value of the option. /// </summary> public object? DefaultValue { get; } public OptionDefinition(OptionGroup? group, string configName, object? defaultValue, OptionStorageMapping? storageMapping, bool isEditorConfigOption) { ConfigName = configName; Group = group ?? OptionGroup.Default; StorageMapping = storageMapping; IsEditorConfigOption = isEditorConfigOption; DefaultValue = defaultValue; Debug.Assert(IsSupportedOptionType(Type)); } /// <summary> /// The type of the option value. /// </summary> public abstract Type Type { get; } public IEditorConfigValueSerializer Serializer => SerializerImpl; protected abstract IEditorConfigValueSerializer SerializerImpl { get; } public override bool Equals(object? other) => Equals(other as OptionDefinition); public bool Equals(OptionDefinition? other) => ConfigName == other?.ConfigName; public override int GetHashCode() => ConfigName.GetHashCode(); public override string ToString() => ConfigName; public static bool operator ==(OptionDefinition? left, OptionDefinition? right) => ReferenceEquals(left, right) || left?.Equals(right) == true; public static bool operator !=(OptionDefinition? left, OptionDefinition? right) => !(left == right); public static bool IsSupportedOptionType(Type type) => type == typeof(bool) || type == typeof(string) || type == typeof(int) || type == typeof(long) || type == typeof(bool?) || type == typeof(int?) || type == typeof(long?) || type.IsEnum || Nullable.GetUnderlyingType(type)?.IsEnum == true || #if WORKSPACE typeof(ICodeStyleOption).IsAssignableFrom(type) || #endif typeof(ICodeStyleOption2).IsAssignableFrom(type) || type == typeof(NamingStylePreferences) || type == typeof(ImmutableArray<bool>) || type == typeof(ImmutableArray<string>) || type == typeof(ImmutableArray<int>) || type == typeof(ImmutableArray<long>); } internal sealed class OptionDefinition<T>( T defaultValue, EditorConfigValueSerializer<T>? serializer, OptionGroup? group, string configName, OptionStorageMapping? storageMapping, bool isEditorConfigOption) : OptionDefinition(group, configName, defaultValue, storageMapping, isEditorConfigOption) { public new T DefaultValue { get; } = defaultValue; public new EditorConfigValueSerializer<T> Serializer { get; } = serializer ?? EditorConfigValueSerializer.GetDefault<T>(isEditorConfigOption); public override Type Type => typeof(T); protected override IEditorConfigValueSerializer SerializerImpl => Serializer; } |