using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; using Terminal.Gui.Analyzers.Internal.Attributes; using Terminal.Gui.Analyzers.Internal.Constants; namespace Terminal.Gui.Analyzers.Internal.Generators.EnumExtensions; /// /// Implementation of for types decorated with . /// [Generator] internal sealed class EnumMemberCombinationsGenerator : IIncrementalGenerator { private const string AttributeCodeText = $$""" {{Strings.Templates.StandardHeader}} namespace {{Strings.AnalyzersAttributesNamespace}}; /// /// Designates an enum member for inclusion in generation of bitwise combinations with other members decorated with /// this attribute which have the same value.
///
/// /// /// This attribute is only considered for enum types with the . /// /// /// Masks with more than 8 bits set will /// /// [AttributeUsageAttribute(AttributeTargets.Enum)] internal sealed class {{nameof (GenerateEnumMemberCombinationsAttribute)}} : System.Attribute { public const byte MaximumPopCountLimit = 14; private uint _mask; private uint _maskPopCount; private byte _popCountLimit = 8; public required string GroupTag { get; set; } public required uint Mask { get => _mask; set { _maskPopCount = uint.PopCount(value); PopCountLimitExceeded = _maskPopCount > PopCountLimit; MaximumPopCountLimitExceeded = _maskPopCount > MaximumPopCountLimit; if (PopCountLimitExceeded || MaximumPopCountLimitExceeded) { return; } _mask = value; } } /// /// The maximum number of bits allowed to be set to 1 in . /// /// /// /// Default: 8 (256 possible combinations) /// /// /// Increasing this value is not recommended!
/// Decreasing this value is pointless unless you want to limit maximum possible generated combinations even /// further. ///
/// /// If the result of () exceeds 2 ^ , no /// combinations will be generated for the members which otherwise would have been included by . /// Values exceeding the actual population count of have no effect. /// /// /// This option is set to a sane default of 8, but also has a hard-coded limit of 14 (16384 combinations), as a /// protection against generation of extremely large files. /// /// /// CAUTION: The maximum number of possible combinations possible is equal to 1 << /// (). /// See for hard-coded limit, /// ///
public byte PopCountLimit { get => _popCountLimit; set { _maskPopCount = uint.PopCount(_mask); PopCountLimitExceeded = _maskPopCount > value; MaximumPopCountLimitExceeded = _maskPopCount > MaximumPopCountLimit; if (PopCountLimitExceeded || MaximumPopCountLimitExceeded) { return; } _mask = value; _popCountLimit = value; } } internal bool MaximumPopCountLimitExceeded { get; private set; } internal bool PopCountLimitExceeded { get; private set; } } """; private const string AttributeFullyQualifiedName = $"{Strings.AnalyzersAttributesNamespace}.{AttributeName}"; private const string AttributeName = "GenerateEnumMemberCombinationsAttribute"; /// public void Initialize (IncrementalGeneratorInitializationContext context) { context.RegisterPostInitializationOutput (GenerateAttributeCode); return; static void GenerateAttributeCode (IncrementalGeneratorPostInitializationContext initContext) { #pragma warning disable IDE0061 // Use expression body for local function initContext.AddSource ($"{AttributeFullyQualifiedName}.g.cs", SourceText.From (AttributeCodeText, Encoding.UTF8)); #pragma warning restore IDE0061 // Use expression body for local function } } }