Remove the Analyzers directory

This commit is contained in:
Brandon Thetford
2024-07-09 21:51:26 -07:00
parent b55e3a9b19
commit 1fa3a6bbe3
47 changed files with 0 additions and 3290 deletions

View File

@@ -1,23 +0,0 @@
<Project>
<PropertyGroup>
<Nullable>enable</Nullable>
<AnalysisLevel>latest-recommended</AnalysisLevel>
<WarningLevel>8</WarningLevel>
<CharacterSet>UTF-8</CharacterSet>
<Deterministic>true</Deterministic>
<UTF8OutPut>true</UTF8OutPut>
<DefineConstants>$(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL;CODE_ANALYSIS</DefineConstants>
<NoLogo>True</NoLogo>
<DefineTrace>True</DefineTrace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
<PackageReference Include="JetBrains.ExternalAnnotations" Version="10.2.149" />
</ItemGroup>
<ItemGroup>
<Using Include="System.Buffers" />
<Using Include="System.Collections.Specialized" />
<Using Include="System.Numerics" />
<Using Include="System.Runtime.CompilerServices" />
</ItemGroup>
</Project>

View File

@@ -1,23 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using Terminal.Gui.Analyzers.Internal.Attributes;
namespace Terminal.Gui.Analyzers.Internal.Debugging;
static class Program
{
static void Main (string [] args)
{
}
}
[GenerateEnumExtensionMethods]
[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "It's not that deep")]
public enum TestEnum
{
Zero = 0,
One,
Two = 2,
Three,
Six = 6
}

View File

@@ -1,29 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.10.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Terminal.Gui.Analyzers.Internal\Terminal.Gui.Analyzers.Internal.csproj">
<PrivateAssets>all</PrivateAssets>
<OutputItemType>Analyzer</OutputItemType>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Update="JetBrains.Annotations" Version="2024.2.0" />
</ItemGroup>
</Project>

View File

@@ -1,42 +0,0 @@
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
internal sealed class SignedEnumMemberValues
{
internal const int Bit31 = ~0b_01111111_11111111_11111111_11111111;
internal const int Bit30 = 0b_01000000_00000000_00000000_00000000;
internal const int Bit29 = 0b_00100000_00000000_00000000_00000000;
internal const int Bit28 = 0b_00010000_00000000_00000000_00000000;
internal const int Bit27 = 0b_00001000_00000000_00000000_00000000;
internal const int Bit26 = 0b_00000100_00000000_00000000_00000000;
internal const int Bit25 = 0b_00000010_00000000_00000000_00000000;
internal const int Bit24 = 0b_00000001_00000000_00000000_00000000;
internal const int Bit23 = 0b_00000000_10000000_00000000_00000000;
internal const int Bit22 = 0b_00000000_01000000_00000000_00000000;
internal const int Bit21 = 0b_00000000_00100000_00000000_00000000;
internal const int Bit20 = 0b_00000000_00010000_00000000_00000000;
internal const int Bit19 = 0b_00000000_00001000_00000000_00000000;
internal const int Bit18 = 0b_00000000_00000100_00000000_00000000;
internal const int Bit17 = 0b_00000000_00000010_00000000_00000000;
internal const int Bit16 = 0b_00000000_00000001_00000000_00000000;
internal const int Bit15 = 0b_00000000_00000000_10000000_00000000;
internal const int Bit14 = 0b_00000000_00000000_01000000_00000000;
internal const int Bit13 = 0b_00000000_00000000_00100000_00000000;
internal const int Bit12 = 0b_00000000_00000000_00010000_00000000;
internal const int Bit11 = 0b_00000000_00000000_00001000_00000000;
internal const int Bit10 = 0b_00000000_00000000_00000100_00000000;
internal const int Bit09 = 0b_00000000_00000000_00000010_00000000;
internal const int Bit08 = 0b_00000000_00000000_00000001_00000000;
internal const int Bit07 = 0b_00000000_00000000_00000000_10000000;
internal const int Bit06 = 0b_00000000_00000000_00000000_01000000;
internal const int Bit05 = 0b_00000000_00000000_00000000_00100000;
internal const int Bit04 = 0b_00000000_00000000_00000000_00010000;
internal const int Bit03 = 0b_00000000_00000000_00000000_00001000;
internal const int Bit02 = 0b_00000000_00000000_00000000_00000100;
internal const int Bit01 = 0b_00000000_00000000_00000000_00000010;
internal const int Bit00 = 0b_00000000_00000000_00000000_00000001;
internal const int All_0 = 0;
internal const int All_1 = ~All_0;
internal const int Alternating_01 = 0b_01010101_01010101_01010101_01010101;
internal const int Alternating_10 = ~Alternating_01;
internal const int EvenBytesHigh = 0b_00000000_11111111_00000000_11111111;
internal const int OddBytesHigh = ~EvenBytesHigh;
}

View File

@@ -1,51 +0,0 @@
using Terminal.Gui.Analyzers.Internal.Attributes;
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// Same as <see cref="BasicEnum"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute"/> applied.
/// </summary>
[GenerateEnumExtensionMethods]
[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum BetterEnum
{
Bit31 = -0b_10000000_00000000_00000000_00000000,
Bit30 = 0b_01000000_00000000_00000000_00000000,
Bit29 = 0b_00100000_00000000_00000000_00000000,
Bit28 = 0b_00010000_00000000_00000000_00000000,
Bit27 = 0b_00001000_00000000_00000000_00000000,
Bit26 = 0b_00000100_00000000_00000000_00000000,
Bit25 = 0b_00000010_00000000_00000000_00000000,
Bit24 = 0b_00000001_00000000_00000000_00000000,
Bit23 = 0b_00000000_10000000_00000000_00000000,
Bit22 = 0b_00000000_01000000_00000000_00000000,
Bit21 = 0b_00000000_00100000_00000000_00000000,
Bit20 = 0b_00000000_00010000_00000000_00000000,
Bit19 = 0b_00000000_00001000_00000000_00000000,
Bit18 = 0b_00000000_00000100_00000000_00000000,
Bit17 = 0b_00000000_00000010_00000000_00000000,
Bit16 = 0b_00000000_00000001_00000000_00000000,
Bit15 = 0b_00000000_00000000_10000000_00000000,
Bit14 = 0b_00000000_00000000_01000000_00000000,
Bit13 = 0b_00000000_00000000_00100000_00000000,
Bit12 = 0b_00000000_00000000_00010000_00000000,
Bit11 = 0b_00000000_00000000_00001000_00000000,
Bit10 = 0b_00000000_00000000_00000100_00000000,
Bit09 = 0b_00000000_00000000_00000010_00000000,
Bit08 = 0b_00000000_00000000_00000001_00000000,
Bit07 = 0b_00000000_00000000_00000000_10000000,
Bit06 = 0b_00000000_00000000_00000000_01000000,
Bit05 = 0b_00000000_00000000_00000000_00100000,
Bit04 = 0b_00000000_00000000_00000000_00010000,
Bit03 = 0b_00000000_00000000_00000000_00001000,
Bit02 = 0b_00000000_00000000_00000000_00000100,
Bit01 = 0b_00000000_00000000_00000000_00000010,
Bit00 = 0b_00000000_00000000_00000000_00000001,
All_0 = 0,
All_1 = ~All_0,
Alternating_01 = 0b_01010101_01010101_01010101_01010101,
Alternating_10 = ~Alternating_01,
EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
OddBytesHigh = ~EvenBytesHigh,
}

View File

@@ -1,51 +0,0 @@
using Terminal.Gui.Analyzers.Internal.Attributes;
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// Same as <see cref="BasicEnum_ExplicitInt"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute"/> applied.
/// </summary>
[GenerateEnumExtensionMethods]
[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum BetterEnum_ExplicitInt
{
Bit31 = BasicEnum_ExplicitInt.Bit31,
Bit30 = BasicEnum_ExplicitInt.Bit30,
Bit29 = BasicEnum_ExplicitInt.Bit29,
Bit28 = BasicEnum_ExplicitInt.Bit28,
Bit27 = BasicEnum_ExplicitInt.Bit27,
Bit26 = BasicEnum_ExplicitInt.Bit26,
Bit25 = BasicEnum_ExplicitInt.Bit25,
Bit24 = BasicEnum_ExplicitInt.Bit24,
Bit23 = BasicEnum_ExplicitInt.Bit23,
Bit22 = BasicEnum_ExplicitInt.Bit22,
Bit21 = BasicEnum_ExplicitInt.Bit21,
Bit20 = BasicEnum_ExplicitInt.Bit20,
Bit19 = BasicEnum_ExplicitInt.Bit19,
Bit18 = BasicEnum_ExplicitInt.Bit18,
Bit17 = BasicEnum_ExplicitInt.Bit17,
Bit16 = BasicEnum_ExplicitInt.Bit16,
Bit15 = BasicEnum_ExplicitInt.Bit15,
Bit14 = BasicEnum_ExplicitInt.Bit14,
Bit13 = BasicEnum_ExplicitInt.Bit13,
Bit12 = BasicEnum_ExplicitInt.Bit12,
Bit11 = BasicEnum_ExplicitInt.Bit11,
Bit10 = BasicEnum_ExplicitInt.Bit10,
Bit09 = BasicEnum_ExplicitInt.Bit09,
Bit08 = BasicEnum_ExplicitInt.Bit08,
Bit07 = BasicEnum_ExplicitInt.Bit07,
Bit06 = BasicEnum_ExplicitInt.Bit06,
Bit05 = BasicEnum_ExplicitInt.Bit05,
Bit04 = BasicEnum_ExplicitInt.Bit04,
Bit03 = BasicEnum_ExplicitInt.Bit03,
Bit02 = BasicEnum_ExplicitInt.Bit02,
Bit01 = BasicEnum_ExplicitInt.Bit01,
Bit00 = BasicEnum_ExplicitInt.Bit00,
All_0 = BasicEnum_ExplicitInt.All_0,
All_1 = BasicEnum_ExplicitInt.All_1,
Alternating_01 = BasicEnum_ExplicitInt.Alternating_01,
Alternating_10 = BasicEnum_ExplicitInt.Alternating_10,
EvenBytesHigh = BasicEnum_ExplicitInt.EvenBytesHigh,
OddBytesHigh = BasicEnum_ExplicitInt.OddBytesHigh
}

View File

@@ -1,52 +0,0 @@
// ReSharper disable EnumUnderlyingTypeIsInt
using Terminal.Gui.Analyzers.Internal.Attributes;
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// Same as <see cref="BetterEnum_ExplicitInt"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute.FastIsDefined"/> = <see langword="false" />.
/// </summary>
[GenerateEnumExtensionMethods (FastIsDefined = false)]
[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum BetterEnum_ExplicitInt_NoFastIsDefined : int
{
Bit31 = -0b_10000000_00000000_00000000_00000000,
Bit30 = 0b_01000000_00000000_00000000_00000000,
Bit29 = 0b_00100000_00000000_00000000_00000000,
Bit28 = 0b_00010000_00000000_00000000_00000000,
Bit27 = 0b_00001000_00000000_00000000_00000000,
Bit26 = 0b_00000100_00000000_00000000_00000000,
Bit25 = 0b_00000010_00000000_00000000_00000000,
Bit24 = 0b_00000001_00000000_00000000_00000000,
Bit23 = 0b_00000000_10000000_00000000_00000000,
Bit22 = 0b_00000000_01000000_00000000_00000000,
Bit21 = 0b_00000000_00100000_00000000_00000000,
Bit20 = 0b_00000000_00010000_00000000_00000000,
Bit19 = 0b_00000000_00001000_00000000_00000000,
Bit18 = 0b_00000000_00000100_00000000_00000000,
Bit17 = 0b_00000000_00000010_00000000_00000000,
Bit16 = 0b_00000000_00000001_00000000_00000000,
Bit15 = 0b_00000000_00000000_10000000_00000000,
Bit14 = 0b_00000000_00000000_01000000_00000000,
Bit13 = 0b_00000000_00000000_00100000_00000000,
Bit12 = 0b_00000000_00000000_00010000_00000000,
Bit11 = 0b_00000000_00000000_00001000_00000000,
Bit10 = 0b_00000000_00000000_00000100_00000000,
Bit09 = 0b_00000000_00000000_00000010_00000000,
Bit08 = 0b_00000000_00000000_00000001_00000000,
Bit07 = 0b_00000000_00000000_00000000_10000000,
Bit06 = 0b_00000000_00000000_00000000_01000000,
Bit05 = 0b_00000000_00000000_00000000_00100000,
Bit04 = 0b_00000000_00000000_00000000_00010000,
Bit03 = 0b_00000000_00000000_00000000_00001000,
Bit02 = 0b_00000000_00000000_00000000_00000100,
Bit01 = 0b_00000000_00000000_00000000_00000010,
Bit00 = 0b_00000000_00000000_00000000_00000001,
All_0 = 0,
All_1 = ~All_0,
Alternating_01 = 0b_01010101_01010101_01010101_01010101,
Alternating_10 = ~Alternating_01,
EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
OddBytesHigh = ~EvenBytesHigh,
}

View File

@@ -1,51 +0,0 @@
using Terminal.Gui.Analyzers.Internal.Attributes;
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// Same as <see cref="BasicEnum_ExplicitUInt"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute"/> applied.
/// </summary>
[GenerateEnumExtensionMethods]
[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum BetterEnum_ExplicitUInt : uint
{
Bit31 = 0b_10000000_00000000_00000000_00000000u,
Bit30 = 0b_01000000_00000000_00000000_00000000u,
Bit29 = 0b_00100000_00000000_00000000_00000000u,
Bit28 = 0b_00010000_00000000_00000000_00000000u,
Bit27 = 0b_00001000_00000000_00000000_00000000u,
Bit26 = 0b_00000100_00000000_00000000_00000000u,
Bit25 = 0b_00000010_00000000_00000000_00000000u,
Bit24 = 0b_00000001_00000000_00000000_00000000u,
Bit23 = 0b_00000000_10000000_00000000_00000000u,
Bit22 = 0b_00000000_01000000_00000000_00000000u,
Bit21 = 0b_00000000_00100000_00000000_00000000u,
Bit20 = 0b_00000000_00010000_00000000_00000000u,
Bit19 = 0b_00000000_00001000_00000000_00000000u,
Bit18 = 0b_00000000_00000100_00000000_00000000u,
Bit17 = 0b_00000000_00000010_00000000_00000000u,
Bit16 = 0b_00000000_00000001_00000000_00000000u,
Bit15 = 0b_00000000_00000000_10000000_00000000u,
Bit14 = 0b_00000000_00000000_01000000_00000000u,
Bit13 = 0b_00000000_00000000_00100000_00000000u,
Bit12 = 0b_00000000_00000000_00010000_00000000u,
Bit11 = 0b_00000000_00000000_00001000_00000000u,
Bit10 = 0b_00000000_00000000_00000100_00000000u,
Bit09 = 0b_00000000_00000000_00000010_00000000u,
Bit08 = 0b_00000000_00000000_00000001_00000000u,
Bit07 = 0b_00000000_00000000_00000000_10000000u,
Bit06 = 0b_00000000_00000000_00000000_01000000u,
Bit05 = 0b_00000000_00000000_00000000_00100000u,
Bit04 = 0b_00000000_00000000_00000000_00010000u,
Bit03 = 0b_00000000_00000000_00000000_00001000u,
Bit02 = 0b_00000000_00000000_00000000_00000100u,
Bit01 = 0b_00000000_00000000_00000000_00000010u,
Bit00 = 0b_00000000_00000000_00000000_00000001u,
All_0 = 0,
All_1 = ~All_0,
Alternating_01 = 0b_01010101_01010101_01010101_01010101,
Alternating_10 = ~Alternating_01,
EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
OddBytesHigh = ~EvenBytesHigh,
}

View File

@@ -1,51 +0,0 @@
using Terminal.Gui.Analyzers.Internal.Attributes;
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// Same as <see cref="BetterEnum_ExplicitUInt"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute.FastIsDefined"/> = <see langword="false" />.
/// </summary>
[GenerateEnumExtensionMethods (FastIsDefined = false)]
[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum BetterEnum_ExplicitUInt_NoFastIsDefined : uint
{
Bit31 = 0b_10000000_00000000_00000000_00000000u,
Bit30 = 0b_01000000_00000000_00000000_00000000u,
Bit29 = 0b_00100000_00000000_00000000_00000000u,
Bit28 = 0b_00010000_00000000_00000000_00000000u,
Bit27 = 0b_00001000_00000000_00000000_00000000u,
Bit26 = 0b_00000100_00000000_00000000_00000000u,
Bit25 = 0b_00000010_00000000_00000000_00000000u,
Bit24 = 0b_00000001_00000000_00000000_00000000u,
Bit23 = 0b_00000000_10000000_00000000_00000000u,
Bit22 = 0b_00000000_01000000_00000000_00000000u,
Bit21 = 0b_00000000_00100000_00000000_00000000u,
Bit20 = 0b_00000000_00010000_00000000_00000000u,
Bit19 = 0b_00000000_00001000_00000000_00000000u,
Bit18 = 0b_00000000_00000100_00000000_00000000u,
Bit17 = 0b_00000000_00000010_00000000_00000000u,
Bit16 = 0b_00000000_00000001_00000000_00000000u,
Bit15 = 0b_00000000_00000000_10000000_00000000u,
Bit14 = 0b_00000000_00000000_01000000_00000000u,
Bit13 = 0b_00000000_00000000_00100000_00000000u,
Bit12 = 0b_00000000_00000000_00010000_00000000u,
Bit11 = 0b_00000000_00000000_00001000_00000000u,
Bit10 = 0b_00000000_00000000_00000100_00000000u,
Bit09 = 0b_00000000_00000000_00000010_00000000u,
Bit08 = 0b_00000000_00000000_00000001_00000000u,
Bit07 = 0b_00000000_00000000_00000000_10000000u,
Bit06 = 0b_00000000_00000000_00000000_01000000u,
Bit05 = 0b_00000000_00000000_00000000_00100000u,
Bit04 = 0b_00000000_00000000_00000000_00010000u,
Bit03 = 0b_00000000_00000000_00000000_00001000u,
Bit02 = 0b_00000000_00000000_00000000_00000100u,
Bit01 = 0b_00000000_00000000_00000000_00000010u,
Bit00 = 0b_00000000_00000000_00000000_00000001u,
All_0 = 0,
All_1 = ~All_0,
Alternating_01 = 0b_01010101_01010101_01010101_01010101,
Alternating_10 = ~Alternating_01,
EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
OddBytesHigh = ~EvenBytesHigh,
}

View File

@@ -1,51 +0,0 @@
using Terminal.Gui.Analyzers.Internal.Attributes;
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// Same as <see cref="BetterEnum"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute.FastIsDefined"/> = <see langword="false" />.
/// </summary>
[GenerateEnumExtensionMethods (FastIsDefined = false)]
[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum BetterEnum_NoFastIsDefined
{
Bit31 = -0b_10000000_00000000_00000000_00000000,
Bit30 = 0b_01000000_00000000_00000000_00000000,
Bit29 = 0b_00100000_00000000_00000000_00000000,
Bit28 = 0b_00010000_00000000_00000000_00000000,
Bit27 = 0b_00001000_00000000_00000000_00000000,
Bit26 = 0b_00000100_00000000_00000000_00000000,
Bit25 = 0b_00000010_00000000_00000000_00000000,
Bit24 = 0b_00000001_00000000_00000000_00000000,
Bit23 = 0b_00000000_10000000_00000000_00000000,
Bit22 = 0b_00000000_01000000_00000000_00000000,
Bit21 = 0b_00000000_00100000_00000000_00000000,
Bit20 = 0b_00000000_00010000_00000000_00000000,
Bit19 = 0b_00000000_00001000_00000000_00000000,
Bit18 = 0b_00000000_00000100_00000000_00000000,
Bit17 = 0b_00000000_00000010_00000000_00000000,
Bit16 = 0b_00000000_00000001_00000000_00000000,
Bit15 = 0b_00000000_00000000_10000000_00000000,
Bit14 = 0b_00000000_00000000_01000000_00000000,
Bit13 = 0b_00000000_00000000_00100000_00000000,
Bit12 = 0b_00000000_00000000_00010000_00000000,
Bit11 = 0b_00000000_00000000_00001000_00000000,
Bit10 = 0b_00000000_00000000_00000100_00000000,
Bit09 = 0b_00000000_00000000_00000010_00000000,
Bit08 = 0b_00000000_00000000_00000001_00000000,
Bit07 = 0b_00000000_00000000_00000000_10000000,
Bit06 = 0b_00000000_00000000_00000000_01000000,
Bit05 = 0b_00000000_00000000_00000000_00100000,
Bit04 = 0b_00000000_00000000_00000000_00010000,
Bit03 = 0b_00000000_00000000_00000000_00001000,
Bit02 = 0b_00000000_00000000_00000000_00000100,
Bit01 = 0b_00000000_00000000_00000000_00000010,
Bit00 = 0b_00000000_00000000_00000000_00000001,
All_0 = 0,
All_1 = ~All_0,
Alternating_01 = 0b_01010101_01010101_01010101_01010101,
Alternating_10 = ~Alternating_01,
EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
OddBytesHigh = ~EvenBytesHigh,
}

View File

@@ -1,52 +0,0 @@
using Terminal.Gui.Analyzers.Internal.Attributes;
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// Same as <see cref="FlagsEnum"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute"/> applied.
/// </summary>
[Flags]
[GenerateEnumExtensionMethods]
[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum BetterFlagsEnum
{
Bit31 = -0b_10000000_00000000_00000000_00000000,
Bit30 = 0b_01000000_00000000_00000000_00000000,
Bit29 = 0b_00100000_00000000_00000000_00000000,
Bit28 = 0b_00010000_00000000_00000000_00000000,
Bit27 = 0b_00001000_00000000_00000000_00000000,
Bit26 = 0b_00000100_00000000_00000000_00000000,
Bit25 = 0b_00000010_00000000_00000000_00000000,
Bit24 = 0b_00000001_00000000_00000000_00000000,
Bit23 = -0b_00000000_10000000_00000000_00000000,
Bit22 = 0b_00000000_01000000_00000000_00000000,
Bit21 = 0b_00000000_00100000_00000000_00000000,
Bit20 = 0b_00000000_00010000_00000000_00000000,
Bit19 = 0b_00000000_00001000_00000000_00000000,
Bit18 = 0b_00000000_00000100_00000000_00000000,
Bit17 = 0b_00000000_00000010_00000000_00000000,
Bit16 = 0b_00000000_00000001_00000000_00000000,
Bit15 = -0b_00000000_00000000_10000000_00000000,
Bit14 = 0b_00000000_00000000_01000000_00000000,
Bit13 = 0b_00000000_00000000_00100000_00000000,
Bit12 = 0b_00000000_00000000_00010000_00000000,
Bit11 = 0b_00000000_00000000_00001000_00000000,
Bit10 = 0b_00000000_00000000_00000100_00000000,
Bit09 = 0b_00000000_00000000_00000010_00000000,
Bit08 = 0b_00000000_00000000_00000001_00000000,
Bit07 = -0b_00000000_00000000_00000000_10000000,
Bit06 = 0b_00000000_00000000_00000000_01000000,
Bit05 = 0b_00000000_00000000_00000000_00100000,
Bit04 = 0b_00000000_00000000_00000000_00010000,
Bit03 = 0b_00000000_00000000_00000000_00001000,
Bit02 = 0b_00000000_00000000_00000000_00000100,
Bit01 = 0b_00000000_00000000_00000000_00000010,
Bit00 = 0b_00000000_00000000_00000000_00000001,
All_0 = 0,
All_1 = ~All_0,
Alternating_01 = 0b_01010101_01010101_01010101_01010101,
Alternating_10 = ~Alternating_01,
EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
OddBytesHigh = ~EvenBytesHigh,
}

View File

@@ -1,53 +0,0 @@
using Terminal.Gui.Analyzers.Internal.Attributes;
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// <summary>
/// Same as <see cref="FlagsEnum_ExplicitInt"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute"/> applied.
/// </summary>
[Flags]
[GenerateEnumExtensionMethods]
[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum BetterFlagsEnum_ExplicitInt : int
{
Bit31 = -0b_10000000_00000000_00000000_00000000,
Bit30 = 0b_01000000_00000000_00000000_00000000,
Bit29 = 0b_00100000_00000000_00000000_00000000,
Bit28 = 0b_00010000_00000000_00000000_00000000,
Bit27 = 0b_00001000_00000000_00000000_00000000,
Bit26 = 0b_00000100_00000000_00000000_00000000,
Bit25 = 0b_00000010_00000000_00000000_00000000,
Bit24 = 0b_00000001_00000000_00000000_00000000,
Bit23 = -0b_00000000_10000000_00000000_00000000,
Bit22 = 0b_00000000_01000000_00000000_00000000,
Bit21 = 0b_00000000_00100000_00000000_00000000,
Bit20 = 0b_00000000_00010000_00000000_00000000,
Bit19 = 0b_00000000_00001000_00000000_00000000,
Bit18 = 0b_00000000_00000100_00000000_00000000,
Bit17 = 0b_00000000_00000010_00000000_00000000,
Bit16 = 0b_00000000_00000001_00000000_00000000,
Bit15 = -0b_00000000_00000000_10000000_00000000,
Bit14 = 0b_00000000_00000000_01000000_00000000,
Bit13 = 0b_00000000_00000000_00100000_00000000,
Bit12 = 0b_00000000_00000000_00010000_00000000,
Bit11 = 0b_00000000_00000000_00001000_00000000,
Bit10 = 0b_00000000_00000000_00000100_00000000,
Bit09 = 0b_00000000_00000000_00000010_00000000,
Bit08 = 0b_00000000_00000000_00000001_00000000,
Bit07 = -0b_00000000_00000000_00000000_10000000,
Bit06 = 0b_00000000_00000000_00000000_01000000,
Bit05 = 0b_00000000_00000000_00000000_00100000,
Bit04 = 0b_00000000_00000000_00000000_00010000,
Bit03 = 0b_00000000_00000000_00000000_00001000,
Bit02 = 0b_00000000_00000000_00000000_00000100,
Bit01 = 0b_00000000_00000000_00000000_00000010,
Bit00 = 0b_00000000_00000000_00000000_00000001,
All_0 = 0,
All_1 = ~All_0,
Alternating_01 = 0b_01010101_01010101_01010101_01010101,
Alternating_10 = ~Alternating_01,
EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
OddBytesHigh = ~EvenBytesHigh,
}

View File

@@ -1,52 +0,0 @@
using Terminal.Gui.Analyzers.Internal.Attributes;
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// Same as <see cref="FlagsEnum_ExplicitUInt"/>, but with <see cref="GenerateEnumExtensionMethodsAttribute"/> applied.
/// </summary>
[Flags]
[GenerateEnumExtensionMethods]
[SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum BetterFlagsEnum_ExplicitUInt : uint
{
Bit31 = 0b_10000000_00000000_00000000_00000000u,
Bit30 = 0b_01000000_00000000_00000000_00000000u,
Bit29 = 0b_00100000_00000000_00000000_00000000u,
Bit28 = 0b_00010000_00000000_00000000_00000000u,
Bit27 = 0b_00001000_00000000_00000000_00000000u,
Bit26 = 0b_00000100_00000000_00000000_00000000u,
Bit25 = 0b_00000010_00000000_00000000_00000000u,
Bit24 = 0b_00000001_00000000_00000000_00000000u,
Bit23 = 0b_00000000_10000000_00000000_00000000u,
Bit22 = 0b_00000000_01000000_00000000_00000000u,
Bit21 = 0b_00000000_00100000_00000000_00000000u,
Bit20 = 0b_00000000_00010000_00000000_00000000u,
Bit19 = 0b_00000000_00001000_00000000_00000000u,
Bit18 = 0b_00000000_00000100_00000000_00000000u,
Bit17 = 0b_00000000_00000010_00000000_00000000u,
Bit16 = 0b_00000000_00000001_00000000_00000000u,
Bit15 = 0b_00000000_00000000_10000000_00000000u,
Bit14 = 0b_00000000_00000000_01000000_00000000u,
Bit13 = 0b_00000000_00000000_00100000_00000000u,
Bit12 = 0b_00000000_00000000_00010000_00000000u,
Bit11 = 0b_00000000_00000000_00001000_00000000u,
Bit10 = 0b_00000000_00000000_00000100_00000000u,
Bit09 = 0b_00000000_00000000_00000010_00000000u,
Bit08 = 0b_00000000_00000000_00000001_00000000u,
Bit07 = 0b_00000000_00000000_00000000_10000000u,
Bit06 = 0b_00000000_00000000_00000000_01000000u,
Bit05 = 0b_00000000_00000000_00000000_00100000u,
Bit04 = 0b_00000000_00000000_00000000_00010000u,
Bit03 = 0b_00000000_00000000_00000000_00001000u,
Bit02 = 0b_00000000_00000000_00000000_00000100u,
Bit01 = 0b_00000000_00000000_00000000_00000010u,
Bit00 = 0b_00000000_00000000_00000000_00000001u,
All_0 = 0,
All_1 = ~All_0,
Alternating_01 = 0b_01010101_01010101_01010101_01010101,
Alternating_10 = ~Alternating_01,
EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
OddBytesHigh = ~EvenBytesHigh,
}

View File

@@ -1,48 +0,0 @@
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// Basic enum without explicitly-defined backing type and no attributes on the enum or any of its members.
/// </summary>
[SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum BasicEnum
{
Bit31 = -0b_10000000_00000000_00000000_00000000,
Bit30 = 0b_01000000_00000000_00000000_00000000,
Bit29 = 0b_00100000_00000000_00000000_00000000,
Bit28 = 0b_00010000_00000000_00000000_00000000,
Bit27 = 0b_00001000_00000000_00000000_00000000,
Bit26 = 0b_00000100_00000000_00000000_00000000,
Bit25 = 0b_00000010_00000000_00000000_00000000,
Bit24 = 0b_00000001_00000000_00000000_00000000,
Bit23 = 0b_00000000_10000000_00000000_00000000,
Bit22 = 0b_00000000_01000000_00000000_00000000,
Bit21 = 0b_00000000_00100000_00000000_00000000,
Bit20 = 0b_00000000_00010000_00000000_00000000,
Bit19 = 0b_00000000_00001000_00000000_00000000,
Bit18 = 0b_00000000_00000100_00000000_00000000,
Bit17 = 0b_00000000_00000010_00000000_00000000,
Bit16 = 0b_00000000_00000001_00000000_00000000,
Bit15 = 0b_00000000_00000000_10000000_00000000,
Bit14 = 0b_00000000_00000000_01000000_00000000,
Bit13 = 0b_00000000_00000000_00100000_00000000,
Bit12 = 0b_00000000_00000000_00010000_00000000,
Bit11 = 0b_00000000_00000000_00001000_00000000,
Bit10 = 0b_00000000_00000000_00000100_00000000,
Bit09 = 0b_00000000_00000000_00000010_00000000,
Bit08 = 0b_00000000_00000000_00000001_00000000,
Bit07 = 0b_00000000_00000000_00000000_10000000,
Bit06 = 0b_00000000_00000000_00000000_01000000,
Bit05 = 0b_00000000_00000000_00000000_00100000,
Bit04 = 0b_00000000_00000000_00000000_00010000,
Bit03 = 0b_00000000_00000000_00000000_00001000,
Bit02 = 0b_00000000_00000000_00000000_00000100,
Bit01 = 0b_00000000_00000000_00000000_00000010,
Bit00 = 0b_00000000_00000000_00000000_00000001,
All_0 = 0,
All_1 = -1,
Alternating_01 = 0b_01010101_01010101_01010101_01010101,
Alternating_10 = unchecked((int)0b_10101010_10101010_10101010_10101010),
OddBytesHigh = unchecked((int)0b_11111111_00000000_11111111_00000000),
EvenBytesHigh = 0b_00000000_11111111_00000000_11111111,
}

View File

@@ -1,50 +0,0 @@
using Terminal.Gui.Analyzers.Internal.Attributes;
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// Basic enum with explicitly-defined backing type of int and no attributes on the enum or any of its members.
/// </summary>
[SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum BasicEnum_ExplicitInt : int
{
Bit31 = -0b_10000000_00000000_00000000_00000000,
Bit30 = 0b_01000000_00000000_00000000_00000000,
Bit29 = 0b_00100000_00000000_00000000_00000000,
Bit28 = 0b_00010000_00000000_00000000_00000000,
Bit27 = 0b_00001000_00000000_00000000_00000000,
Bit26 = 0b_00000100_00000000_00000000_00000000,
Bit25 = 0b_00000010_00000000_00000000_00000000,
Bit24 = 0b_00000001_00000000_00000000_00000000,
Bit23 = 0b_00000000_10000000_00000000_00000000,
Bit22 = 0b_00000000_01000000_00000000_00000000,
Bit21 = 0b_00000000_00100000_00000000_00000000,
Bit20 = 0b_00000000_00010000_00000000_00000000,
Bit19 = 0b_00000000_00001000_00000000_00000000,
Bit18 = 0b_00000000_00000100_00000000_00000000,
Bit17 = 0b_00000000_00000010_00000000_00000000,
Bit16 = 0b_00000000_00000001_00000000_00000000,
Bit15 = 0b_00000000_00000000_10000000_00000000,
Bit14 = 0b_00000000_00000000_01000000_00000000,
Bit13 = 0b_00000000_00000000_00100000_00000000,
Bit12 = 0b_00000000_00000000_00010000_00000000,
Bit11 = 0b_00000000_00000000_00001000_00000000,
Bit10 = 0b_00000000_00000000_00000100_00000000,
Bit09 = 0b_00000000_00000000_00000010_00000000,
Bit08 = 0b_00000000_00000000_00000001_00000000,
Bit07 = 0b_00000000_00000000_00000000_10000000,
Bit06 = 0b_00000000_00000000_00000000_01000000,
Bit05 = 0b_00000000_00000000_00000000_00100000,
Bit04 = 0b_00000000_00000000_00000000_00010000,
Bit03 = 0b_00000000_00000000_00000000_00001000,
Bit02 = 0b_00000000_00000000_00000000_00000100,
Bit01 = 0b_00000000_00000000_00000000_00000010,
Bit00 = 0b_00000000_00000000_00000000_00000001,
All_0 = 0,
All_1 = -1,
Alternating_01 = 0b_01010101_01010101_01010101_01010101,
Alternating_10 = unchecked((int)0b_10101010_10101010_10101010_10101010),
OddBytesHigh = unchecked((int)0b_11111111_00000000_11111111_00000000),
EvenBytesHigh = unchecked((int)0b_00000000_11111111_00000000_11111111),
}

View File

@@ -1,48 +0,0 @@
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// Basic enum with explicitly-defined backing type of uint and no attributes on the enum or any of its members.
/// </summary>
[SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum BasicEnum_ExplicitUInt : uint
{
Bit31 = 0b_10000000_00000000_00000000_00000000u,
Bit30 = 0b_01000000_00000000_00000000_00000000u,
Bit29 = 0b_00100000_00000000_00000000_00000000u,
Bit28 = 0b_00010000_00000000_00000000_00000000u,
Bit27 = 0b_00001000_00000000_00000000_00000000u,
Bit26 = 0b_00000100_00000000_00000000_00000000u,
Bit25 = 0b_00000010_00000000_00000000_00000000u,
Bit24 = 0b_00000001_00000000_00000000_00000000u,
Bit23 = 0b_00000000_10000000_00000000_00000000u,
Bit22 = 0b_00000000_01000000_00000000_00000000u,
Bit21 = 0b_00000000_00100000_00000000_00000000u,
Bit20 = 0b_00000000_00010000_00000000_00000000u,
Bit19 = 0b_00000000_00001000_00000000_00000000u,
Bit18 = 0b_00000000_00000100_00000000_00000000u,
Bit17 = 0b_00000000_00000010_00000000_00000000u,
Bit16 = 0b_00000000_00000001_00000000_00000000u,
Bit15 = 0b_00000000_00000000_10000000_00000000u,
Bit14 = 0b_00000000_00000000_01000000_00000000u,
Bit13 = 0b_00000000_00000000_00100000_00000000u,
Bit12 = 0b_00000000_00000000_00010000_00000000u,
Bit11 = 0b_00000000_00000000_00001000_00000000u,
Bit10 = 0b_00000000_00000000_00000100_00000000u,
Bit09 = 0b_00000000_00000000_00000010_00000000u,
Bit08 = 0b_00000000_00000000_00000001_00000000u,
Bit07 = 0b_00000000_00000000_00000000_10000000u,
Bit06 = 0b_00000000_00000000_00000000_01000000u,
Bit05 = 0b_00000000_00000000_00000000_00100000u,
Bit04 = 0b_00000000_00000000_00000000_00010000u,
Bit03 = 0b_00000000_00000000_00000000_00001000u,
Bit02 = 0b_00000000_00000000_00000000_00000100u,
Bit01 = 0b_00000000_00000000_00000000_00000010u,
Bit00 = 0b_00000000_00000000_00000000_00000001u,
All_0 = 0b_00000000_00000000_00000000_00000000u,
All_1 = 0b_11111111_11111111_11111111_11111111u,
Alternating_01 = 0b_01010101_01010101_01010101_01010101u,
Alternating_10 = 0b_10101010_10101010_10101010_10101010u,
OddBytesHigh = 0b_11111111_00000000_11111111_00000000u,
EvenBytesHigh = 0b_00000000_11111111_00000000_11111111u,
}

View File

@@ -1,45 +0,0 @@
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// Flags enum without explicitly-defined backing type and only a <see cref="FlagsAttribute"/> on the enum declaration No other attributes on the enum or its members..
/// </summary>
[Flags]
[SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum FlagsEnum
{
Bit31 = -0b_10000000_00000000_00000000_00000000,
Bit30 = 0b_01000000_00000000_00000000_00000000,
Bit29 = 0b_00100000_00000000_00000000_00000000,
Bit28 = 0b_00010000_00000000_00000000_00000000,
Bit27 = 0b_00001000_00000000_00000000_00000000,
Bit26 = 0b_00000100_00000000_00000000_00000000,
Bit25 = 0b_00000010_00000000_00000000_00000000,
Bit24 = 0b_00000001_00000000_00000000_00000000,
Bit23 = -0b_00000000_10000000_00000000_00000000,
Bit22 = 0b_00000000_01000000_00000000_00000000,
Bit21 = 0b_00000000_00100000_00000000_00000000,
Bit20 = 0b_00000000_00010000_00000000_00000000,
Bit19 = 0b_00000000_00001000_00000000_00000000,
Bit18 = 0b_00000000_00000100_00000000_00000000,
Bit17 = 0b_00000000_00000010_00000000_00000000,
Bit16 = 0b_00000000_00000001_00000000_00000000,
Bit15 = -0b_00000000_00000000_10000000_00000000,
Bit14 = 0b_00000000_00000000_01000000_00000000,
Bit13 = 0b_00000000_00000000_00100000_00000000,
Bit12 = 0b_00000000_00000000_00010000_00000000,
Bit11 = 0b_00000000_00000000_00001000_00000000,
Bit10 = 0b_00000000_00000000_00000100_00000000,
Bit09 = 0b_00000000_00000000_00000010_00000000,
Bit08 = 0b_00000000_00000000_00000001_00000000,
Bit07 = -0b_00000000_00000000_00000000_10000000,
Bit06 = 0b_00000000_00000000_00000000_01000000,
Bit05 = 0b_00000000_00000000_00000000_00100000,
Bit04 = 0b_00000000_00000000_00000000_00010000,
Bit03 = 0b_00000000_00000000_00000000_00001000,
Bit02 = 0b_00000000_00000000_00000000_00000100,
Bit01 = 0b_00000000_00000000_00000000_00000010,
Bit00 = 0b_00000000_00000000_00000000_00000001,
All_0 = 0,
All_1 = -1
}

View File

@@ -1,45 +0,0 @@
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// Flags enum with explicitly-defined backing type of int and only a <see cref="FlagsAttribute"/> on the enum declaration No other attributes on the enum or its members..
/// </summary>
[Flags]
[SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum FlagsEnum_ExplicitInt : int
{
Bit31 = -0b_10000000_00000000_00000000_00000000,
Bit30 = 0b_01000000_00000000_00000000_00000000,
Bit29 = 0b_00100000_00000000_00000000_00000000,
Bit28 = 0b_00010000_00000000_00000000_00000000,
Bit27 = 0b_00001000_00000000_00000000_00000000,
Bit26 = 0b_00000100_00000000_00000000_00000000,
Bit25 = 0b_00000010_00000000_00000000_00000000,
Bit24 = 0b_00000001_00000000_00000000_00000000,
Bit23 = -0b_00000000_10000000_00000000_00000000,
Bit22 = 0b_00000000_01000000_00000000_00000000,
Bit21 = 0b_00000000_00100000_00000000_00000000,
Bit20 = 0b_00000000_00010000_00000000_00000000,
Bit19 = 0b_00000000_00001000_00000000_00000000,
Bit18 = 0b_00000000_00000100_00000000_00000000,
Bit17 = 0b_00000000_00000010_00000000_00000000,
Bit16 = 0b_00000000_00000001_00000000_00000000,
Bit15 = -0b_00000000_00000000_10000000_00000000,
Bit14 = 0b_00000000_00000000_01000000_00000000,
Bit13 = 0b_00000000_00000000_00100000_00000000,
Bit12 = 0b_00000000_00000000_00010000_00000000,
Bit11 = 0b_00000000_00000000_00001000_00000000,
Bit10 = 0b_00000000_00000000_00000100_00000000,
Bit09 = 0b_00000000_00000000_00000010_00000000,
Bit08 = 0b_00000000_00000000_00000001_00000000,
Bit07 = -0b_00000000_00000000_00000000_10000000,
Bit06 = 0b_00000000_00000000_00000000_01000000,
Bit05 = 0b_00000000_00000000_00000000_00100000,
Bit04 = 0b_00000000_00000000_00000000_00010000,
Bit03 = 0b_00000000_00000000_00000000_00001000,
Bit02 = 0b_00000000_00000000_00000000_00000100,
Bit01 = 0b_00000000_00000000_00000000_00000010,
Bit00 = 0b_00000000_00000000_00000000_00000001,
All_0 = 0,
All_1 = -1
}

View File

@@ -1,45 +0,0 @@
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions.EnumDefinitions;
/// <summary>
/// Flags enum with explicitly-defined backing type of uint and only a <see cref="FlagsAttribute"/> on the enum declaration No other attributes on the enum or its members..
/// </summary>
[Flags]
[SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Naming is intentional.")]
[SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Justification = "Order is intentional.")]
public enum FlagsEnum_ExplicitUInt : uint
{
Bit31 = 0b_10000000_00000000_00000000_00000000u,
Bit30 = 0b_01000000_00000000_00000000_00000000u,
Bit29 = 0b_00100000_00000000_00000000_00000000u,
Bit28 = 0b_00010000_00000000_00000000_00000000u,
Bit27 = 0b_00001000_00000000_00000000_00000000u,
Bit26 = 0b_00000100_00000000_00000000_00000000u,
Bit25 = 0b_00000010_00000000_00000000_00000000u,
Bit24 = 0b_00000001_00000000_00000000_00000000u,
Bit23 = 0b_00000000_10000000_00000000_00000000u,
Bit22 = 0b_00000000_01000000_00000000_00000000u,
Bit21 = 0b_00000000_00100000_00000000_00000000u,
Bit20 = 0b_00000000_00010000_00000000_00000000u,
Bit19 = 0b_00000000_00001000_00000000_00000000u,
Bit18 = 0b_00000000_00000100_00000000_00000000u,
Bit17 = 0b_00000000_00000010_00000000_00000000u,
Bit16 = 0b_00000000_00000001_00000000_00000000u,
Bit15 = 0b_00000000_00000000_10000000_00000000u,
Bit14 = 0b_00000000_00000000_01000000_00000000u,
Bit13 = 0b_00000000_00000000_00100000_00000000u,
Bit12 = 0b_00000000_00000000_00010000_00000000u,
Bit11 = 0b_00000000_00000000_00001000_00000000u,
Bit10 = 0b_00000000_00000000_00000100_00000000u,
Bit09 = 0b_00000000_00000000_00000010_00000000u,
Bit08 = 0b_00000000_00000000_00000001_00000000u,
Bit07 = 0b_00000000_00000000_00000000_10000000u,
Bit06 = 0b_00000000_00000000_00000000_01000000u,
Bit05 = 0b_00000000_00000000_00000000_00100000u,
Bit04 = 0b_00000000_00000000_00000000_00010000u,
Bit03 = 0b_00000000_00000000_00000000_00001000u,
Bit02 = 0b_00000000_00000000_00000000_00000100u,
Bit01 = 0b_00000000_00000000_00000000_00000010u,
Bit00 = 0b_00000000_00000000_00000000_00000001u,
All_0 = 0b_00000000_00000000_00000000_00000000u,
All_1 = 0b_11111111_11111111_11111111_11111111u
}

View File

@@ -1,306 +0,0 @@
using System.Collections.Concurrent;
using System.Collections.ObjectModel;
using System.Reflection;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
using Terminal.Gui.Analyzers.Internal.Attributes;
using Terminal.Gui.Analyzers.Internal.Generators.EnumExtensions;
// ReSharper disable InconsistentNaming
namespace Terminal.Gui.Analyzers.Internal.Tests.Generators.EnumExtensions;
[TestFixture]
[Category ("Source Generators")]
[TestOf (typeof (EnumExtensionMethodsIncrementalGenerator))]
[Parallelizable (ParallelScope.Children)]
[SuppressMessage ("ReSharper", "ExceptionNotDocumented")]
public class EnumExtensionMethodsIncrementalGeneratorTests
{
private static bool _isInitialized;
/// <summary>All enum types declared in the test assembly.</summary>
private static readonly ObservableCollection<Type> _allEnumTypes = [];
/// <summary>
/// All enum types without a <see cref="GenerateEnumExtensionMethodsAttribute"/>, <see cref="_allEnumTypes"/>
/// </summary>
private static readonly HashSet<Type> _boringEnumTypes = [];
/// <summary>All extension classes generated for enums with our attribute.</summary>
private static readonly ObservableCollection<Type> _enumExtensionClasses = [];
private static readonly ConcurrentDictionary<Type, EnumData> _extendedEnumTypeMappings = [];
private static IEnumerable<Type> ExtendedEnumTypes => _extendedEnumTypeMappings.Keys;
private static readonly ReaderWriterLockSlim _initializationLock = new ();
private static IEnumerable<AssemblyExtendedEnumTypeAttribute> GetAssemblyExtendedEnumTypeAttributes () =>
Assembly.GetExecutingAssembly ()
.GetCustomAttributes<AssemblyExtendedEnumTypeAttribute> ();
private static IEnumerable<TestCaseData> Get_AssemblyExtendedEnumTypeAttribute_EnumHasGeneratorAttribute_Cases ()
{
return GetAssemblyExtendedEnumTypeAttributes ()
.Select (
static attr => new TestCaseData (attr)
{
TestName = $"{nameof (AssemblyExtendedEnumTypeAttribute_EnumHasGeneratorAttribute)}({attr.EnumType.Name},{attr.ExtensionClass.Name})",
HasExpectedResult = true,
ExpectedResult = true
});
}
[Test]
[Category ("Attributes")]
[TestCaseSource (nameof (Get_AssemblyExtendedEnumTypeAttribute_EnumHasGeneratorAttribute_Cases))]
public bool AssemblyExtendedEnumTypeAttribute_EnumHasGeneratorAttribute (AssemblyExtendedEnumTypeAttribute attr)
{
Assume.That (attr, Is.Not.Null);
Assume.That (attr.EnumType, Is.Not.Null);
Assume.That (attr.EnumType.IsEnum);
return attr.EnumType.IsDefined (typeof (GenerateEnumExtensionMethodsAttribute));
}
[Test]
[Category("Attributes")]
public void AssemblyExtendedEnumTypeAttribute_ExtensionClassHasExpectedReverseMappingAttribute ([ValueSource(nameof(GetAssemblyExtendedEnumTypeAttributes))]AssemblyExtendedEnumTypeAttribute attr)
{
Assume.That (attr, Is.Not.Null);
Assume.That (attr.ExtensionClass, Is.Not.Null);
Assume.That (attr.ExtensionClass.IsClass);
Assume.That (attr.ExtensionClass.IsSealed);
Assert.That (attr.ExtensionClass.IsDefined (typeof (ExtensionsForEnumTypeAttribute<>)));
}
[Test]
[Category("Attributes")]
public void ExtendedEnum_AssemblyHasMatchingAttribute ([ValueSource(nameof(GetExtendedEnum_EnumData))]EnumData enumData)
{
Assume.That (enumData, Is.Not.Null);
Assume.That (enumData.EnumType, Is.Not.Null);
Assume.That (enumData.EnumType.IsEnum);
Assert.That (enumData.EnumType, Has.Attribute<GenerateEnumExtensionMethodsAttribute> ());
}
[Test]
public void BoringEnum_DoesNotHaveExtensions ([ValueSource (nameof (_boringEnumTypes))] Type enumType)
{
Assume.That (enumType.IsEnum);
Assert.That (enumType, Has.No.Attribute<GenerateEnumExtensionMethodsAttribute> ());
}
[Test]
public void ExtendedEnum_FastIsDefinedFalse_DoesNotHaveFastIsDefined ([ValueSource (nameof (GetExtendedEnumTypes_FastIsDefinedFalse))] EnumData enumData)
{
Assume.That (enumData.EnumType.IsEnum);
Assume.That (enumData.EnumType, Has.Attribute<GenerateEnumExtensionMethodsAttribute> ());
Assume.That (enumData.GeneratorAttribute, Is.Not.Null);
Assume.That (enumData.GeneratorAttribute, Is.EqualTo (enumData.EnumType.GetCustomAttribute<GenerateEnumExtensionMethodsAttribute> ()));
Assume.That (enumData.GeneratorAttribute, Has.Property ("FastIsDefined").False);
Assume.That (enumData.ExtensionClass, Is.Not.Null);
Assert.That (enumData.ExtensionClass!.GetMethod ("FastIsDefined"), Is.Null);
}
[Test]
public void ExtendedEnum_StaticExtensionClassExists ([ValueSource (nameof (ExtendedEnumTypes))] Type enumType)
{
Assume.That (enumType.IsEnum);
Assume.That (enumType, Has.Attribute<GenerateEnumExtensionMethodsAttribute> ());
Assume.That (enumType, Has.Attribute<GenerateEnumExtensionMethodsAttribute> ());
}
[Test]
public void ExtendedEnum_FastIsDefinedTrue_HasFastIsDefined ([ValueSource (nameof (GetExtendedEnumTypes_FastIsDefinedTrue))] EnumData enumData)
{
Assume.That (enumData.EnumType, Is.Not.Null);
Assume.That (enumData.EnumType.IsEnum);
Assume.That (enumData.EnumType, Has.Attribute<GenerateEnumExtensionMethodsAttribute> ());
Assume.That (enumData.ExtensionClass, Is.Not.Null);
TypeWrapper extensionClassTypeInfo = new(enumData.ExtensionClass!);
Assume.That (extensionClassTypeInfo.IsStaticClass);
Assume.That (enumData.GeneratorAttribute, Is.Not.Null);
Assume.That (enumData.GeneratorAttribute, Is.EqualTo (enumData.EnumType.GetCustomAttribute<GenerateEnumExtensionMethodsAttribute> ()));
Assume.That (enumData.GeneratorAttribute, Has.Property ("FastIsDefined").True);
MethodInfo? fastIsDefinedMethod = enumData.ExtensionClass!.GetMethod ("FastIsDefined");
Assert.That (fastIsDefinedMethod, Is.Not.Null);
Assert.That (fastIsDefinedMethod, Has.Attribute<ExtensionAttribute> ());
extensionClassTypeInfo.GetMethodsWithAttribute<ExtensionAttribute> (false);
}
private static IEnumerable<EnumData> GetExtendedEnum_EnumData ()
{
_initializationLock.EnterUpgradeableReadLock ();
try
{
if (!_isInitialized)
{
Initialize ();
}
return _extendedEnumTypeMappings.Values;
}
finally
{
_initializationLock.ExitUpgradeableReadLock ();
}
}
private static IEnumerable<EnumData> GetExtendedEnumTypes_FastIsDefinedFalse ()
{
_initializationLock.EnterUpgradeableReadLock ();
try
{
if (!_isInitialized)
{
Initialize ();
}
return _extendedEnumTypeMappings.Values.Where (static t => t.GeneratorAttribute?.FastIsDefined is false);
}
finally
{
_initializationLock.ExitUpgradeableReadLock ();
}
}
private static IEnumerable<EnumData> GetExtendedEnumTypes_FastIsDefinedTrue ()
{
_initializationLock.EnterUpgradeableReadLock ();
try
{
if (!_isInitialized)
{
Initialize ();
}
return _extendedEnumTypeMappings.Values.Where (static t => t.GeneratorAttribute?.FastIsDefined is true);
}
finally
{
_initializationLock.ExitUpgradeableReadLock ();
}
}
private static void Initialize ()
{
if (!_initializationLock.IsUpgradeableReadLockHeld || !_initializationLock.TryEnterWriteLock (5000))
{
return;
}
try
{
if (_isInitialized)
{
return;
}
_allEnumTypes.CollectionChanged += AllEnumTypes_CollectionChanged;
_enumExtensionClasses.CollectionChanged += EnumExtensionClasses_OnCollectionChanged;
Type [] allAssemblyTypes = Assembly
.GetExecutingAssembly ()
.GetTypes ();
foreach (Type type in allAssemblyTypes.Where (IsDefinedEnum))
{
_allEnumTypes.Add (type);
}
foreach (Type type in allAssemblyTypes.Where (HasExtensionForEnumTypeAttribute))
{
_enumExtensionClasses.Add (type);
}
_isInitialized = true;
}
finally
{
_initializationLock.ExitWriteLock ();
}
return;
static bool IsDefinedEnum (Type t) { return t is { IsEnum: true, IsGenericType: false, IsConstructedGenericType: false, IsTypeDefinition: true }; }
static void AllEnumTypes_CollectionChanged (object? sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action is not NotifyCollectionChangedAction.Add and not NotifyCollectionChangedAction.Replace || e.NewItems is null)
{
return;
}
foreach (Type enumType in e.NewItems.OfType<Type> ())
{
if (enumType.GetCustomAttribute<GenerateEnumExtensionMethodsAttribute> () is not { } generatorAttribute)
{
_boringEnumTypes.Add (enumType);
continue;
}
_extendedEnumTypeMappings.AddOrUpdate (
enumType,
CreateNewEnumData,
UpdateGeneratorAttributeProperty,
generatorAttribute);
}
}
static EnumData CreateNewEnumData (Type tEnum, GenerateEnumExtensionMethodsAttribute attr) { return new (tEnum, attr); }
static EnumData UpdateGeneratorAttributeProperty (Type tEnum, EnumData data, GenerateEnumExtensionMethodsAttribute attr)
{
data.GeneratorAttribute ??= attr;
return data;
}
static void EnumExtensionClasses_OnCollectionChanged (object? sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action != NotifyCollectionChangedAction.Add)
{
return;
}
foreach (Type extensionClassType in e.NewItems!.OfType<Type> ())
{
if (extensionClassType.GetCustomAttribute (typeof (ExtensionsForEnumTypeAttribute<>), false) is not IExtensionsForEnumTypeAttributes
{
EnumType.IsEnum: true
} extensionForAttribute)
{
continue;
}
_extendedEnumTypeMappings [extensionForAttribute.EnumType].ExtensionClass ??= extensionClassType;
}
}
}
private static bool HasExtensionForEnumTypeAttribute (Type t) => t.IsClass && t.IsDefined (typeof (ExtensionsForEnumTypeAttribute<>));
public sealed record EnumData (
Type EnumType,
GenerateEnumExtensionMethodsAttribute? GeneratorAttribute = null,
Type? ExtensionClass = null,
IExtensionsForEnumTypeAttributes? ExtensionForEnumTypeAttribute = null)
{
public Type? ExtensionClass { get; set; } = ExtensionClass;
public IExtensionsForEnumTypeAttributes? ExtensionForEnumTypeAttribute { get; set; } = ExtensionForEnumTypeAttribute;
public GenerateEnumExtensionMethodsAttribute? GeneratorAttribute { get; set; } = GeneratorAttribute;
}
}

View File

@@ -1,3 +0,0 @@
[assembly: SuppressMessage ("Naming", "CA1707:Identifiers should not contain underscores", Scope = "module", Justification = "Naming is intentional.")]
[assembly: SuppressMessage ("Roslynator", "RCS1154:Sort enum members", Scope = "module", Justification = "Order is intentional.")]
[assembly: SuppressMessage ("Naming", "CA1711:Identifiers should not have incorrect suffix", Scope = "module", Justification = "Naming is intentional.")]

View File

@@ -1,111 +0,0 @@
using System.CodeDom.Compiler;
using System.Text;
namespace Terminal.Gui.Analyzers.Internal.Tests;
[TestFixture]
[Category ("Extension Methods")]
[TestOf (typeof (IndentedTextWriterExtensions))]
[Parallelizable (ParallelScope.Children)]
public class IndentedTextWriterExtensionsTests
{
[Test]
public void Pop_Decrements ()
{
StringBuilder sb = new (0);
using var sw = new StringWriter (sb);
using var writer = new IndentedTextWriter (sw);
writer.Indent = 5;
Assume.That (writer.Indent, Is.EqualTo (5));
writer.Pop ();
Assert.That (writer.Indent, Is.EqualTo (4));
}
[Test]
public void Pop_WithClosing_WritesAndPops ([Values ("}", ")", "]")] string scopeClosing)
{
StringBuilder sb = new (256);
using var sw = new StringWriter (sb);
using var writer = new IndentedTextWriter (sw, " ");
writer.Indent = 5;
writer.Flush ();
Assume.That (writer.Indent, Is.EqualTo (5));
Assume.That (sb.Length, Is.Zero);
// Need to write something first, or IndentedTextWriter won't emit the indentation for the first call.
// So we'll write an empty line.
writer.WriteLine ();
for (ushort indentCount = 5; indentCount > 0;)
{
writer.Pop (scopeClosing);
Assert.That (writer.Indent, Is.EqualTo (--indentCount));
}
writer.Flush ();
var result = sb.ToString ();
Assert.That (
result,
Is.EqualTo (
$"""
{scopeClosing}
{scopeClosing}
{scopeClosing}
{scopeClosing}
{scopeClosing}
"""));
}
[Test]
public void Push_Increments ()
{
StringBuilder sb = new (32);
using var sw = new StringWriter (sb);
using var writer = new IndentedTextWriter (sw, " ");
for (int indentCount = 0; indentCount < 5; indentCount++)
{
writer.Push ();
Assert.That (writer.Indent, Is.EqualTo (indentCount + 1));
}
}
[Test]
public void Push_WithOpening_WritesAndPushes ([Values ('{', '(', '[')] char scopeOpening)
{
StringBuilder sb = new (256);
using var sw = new StringWriter (sb);
using var writer = new IndentedTextWriter (sw, " ");
for (ushort indentCount = 0; indentCount < 5;)
{
writer.Push ("Opening UninterestingEnum", scopeOpening);
Assert.That (writer.Indent, Is.EqualTo (++indentCount));
}
writer.Flush ();
var result = sb.ToString ();
Assert.That (
result,
Is.EqualTo (
$"""
Opening UninterestingEnum
{scopeOpening}
Opening UninterestingEnum
{scopeOpening}
Opening UninterestingEnum
{scopeOpening}
Opening UninterestingEnum
{scopeOpening}
Opening UninterestingEnum
{scopeOpening}
"""));
}
}

View File

@@ -1,52 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>12</LangVersion>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>portable</DebugType>
<DefineConstants>$(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL;CODE_ANALYSIS</DefineConstants>
<ImplicitUsings>enable</ImplicitUsings>
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="NUnit" Version="4.1.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.2.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Terminal.Gui.Analyzers.Internal\Terminal.Gui.Analyzers.Internal.csproj">
<PrivateAssets>all</PrivateAssets>
<OutputItemType>Analyzer</OutputItemType>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Using Include="NUnit.Framework" />
<Using Include="Terminal.Gui" />
<Using Include="Terminal.Gui.Analyzers" />
<Using Include="Terminal.Gui.Analyzers.Internal" />
<Using Include="System.Diagnostics.CodeAnalysis" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="JetBrains.Annotations" Version="2024.2.0" />
</ItemGroup>
</Project>

View File

@@ -1,3 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generators_005Cenumextensions_005Cenumdefinitions_005Cwithgenerator/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generators_005Cenumextensions_005Cenumdefinitions_005Cwithoutgenerator/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -1,20 +0,0 @@
using Microsoft.CodeAnalysis;
namespace Terminal.Gui.Analyzers.Internal;
internal static class AccessibilityExtensions
{
internal static string ToCSharpString (this Accessibility value)
{
return value switch
{
Accessibility.Public => "public",
Accessibility.Internal => "internal",
Accessibility.Private => "private",
Accessibility.Protected => "protected",
Accessibility.ProtectedAndInternal => "private protected",
Accessibility.ProtectedOrInternal => "protected internal",
_ => string.Empty
};
}
}

View File

@@ -1,8 +0,0 @@
## Release 1.0
### New Rules
Rule ID | Category | Severity | Notes
--------|----------|----------|--------------------
TG0001 | Usage | Error | TG0001_GlobalNamespaceNotSupported
TG0002 | Usage | Error | TG0002_UnderlyingTypeNotSupported

View File

@@ -1,4 +0,0 @@
### New Rules
Rule ID | Category | Severity | Notes
--------|----------|----------|--------------------

View File

@@ -1,117 +0,0 @@
#define JETBRAINS_ANNOTATIONS
using System.Collections.Immutable;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Terminal.Gui.Analyzers.Internal.Attributes;
using Terminal.Gui.Analyzers.Internal.Generators.EnumExtensions;
namespace Terminal.Gui.Analyzers.Internal.Analyzers;
/// <summary>
/// Design-time analyzer that checks for proper use of <see cref="GenerateEnumExtensionMethodsAttribute"/>.
/// </summary>
[DiagnosticAnalyzer (LanguageNames.CSharp)]
[UsedImplicitly]
internal sealed class GenerateEnumExtensionMethodsAttributeAnalyzer : DiagnosticAnalyzer
{
// ReSharper disable once InconsistentNaming
private static readonly DiagnosticDescriptor TG0001_GlobalNamespaceNotSupported = new (
// ReSharper restore InconsistentNaming
"TG0001",
$"{nameof (GenerateEnumExtensionMethodsAttribute)} not supported on global enums",
"{0} is in the global namespace, which is not supported by the source generator ({1}) used by {2}. Move the enum to a namespace or remove the attribute.",
"Usage",
DiagnosticSeverity.Error,
true,
null,
null,
WellKnownDiagnosticTags.NotConfigurable,
WellKnownDiagnosticTags.Compiler);
// ReSharper disable once InconsistentNaming
private static readonly DiagnosticDescriptor TG0002_UnderlyingTypeNotSupported = new (
"TG0002",
$"{nameof (GenerateEnumExtensionMethodsAttribute)} not supported for this enum type",
"{0} has an underlying type of {1}, which is not supported by the source generator ({2}) used by {3}. Only enums backed by int or uint are supported.",
"Usage",
DiagnosticSeverity.Error,
true,
null,
null,
WellKnownDiagnosticTags.NotConfigurable,
WellKnownDiagnosticTags.Compiler);
/// <inheritdoc/>
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
[
TG0001_GlobalNamespaceNotSupported,
TG0002_UnderlyingTypeNotSupported
];
/// <inheritdoc/>
public override void Initialize (AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis (GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution ();
context.RegisterSyntaxNodeAction (CheckAttributeLocations, SyntaxKind.EnumDeclaration);
return;
static void CheckAttributeLocations (SyntaxNodeAnalysisContext analysisContext)
{
ISymbol? symbol = analysisContext.SemanticModel.GetDeclaredSymbol (analysisContext.Node) as INamedTypeSymbol;
if (symbol is not INamedTypeSymbol { EnumUnderlyingType: { } } enumSymbol)
{
// Somehow not even an enum declaration.
// Skip it.
return;
}
// Check attributes for those we care about and react accordingly.
foreach (AttributeData attributeData in enumSymbol.GetAttributes ())
{
if (attributeData.AttributeClass?.Name != nameof (GenerateEnumExtensionMethodsAttribute))
{
// Just skip - not an interesting attribute.
continue;
}
// Check enum underlying type for supported types (int and uint, currently)
// Report TG0002 if unsupported underlying type.
if (enumSymbol.EnumUnderlyingType is not { SpecialType: SpecialType.System_Int32 or SpecialType.System_UInt32 })
{
analysisContext.ReportDiagnostic (
Diagnostic.Create (
TG0002_UnderlyingTypeNotSupported,
enumSymbol.Locations.FirstOrDefault (),
enumSymbol.Name,
enumSymbol.EnumUnderlyingType.Name,
nameof (EnumExtensionMethodsIncrementalGenerator),
nameof (GenerateEnumExtensionMethodsAttribute)
)
);
}
// Check enum namespace (only non-global supported, currently)
// Report TG0001 if in the global namespace.
if (enumSymbol.ContainingSymbol is not INamespaceSymbol { IsGlobalNamespace: false })
{
analysisContext.ReportDiagnostic (
Diagnostic.Create (
TG0001_GlobalNamespaceNotSupported,
enumSymbol.Locations.FirstOrDefault (),
enumSymbol.Name,
nameof (EnumExtensionMethodsIncrementalGenerator),
nameof (GenerateEnumExtensionMethodsAttribute)
)
);
}
}
}
}
}

View File

@@ -1,3 +0,0 @@
N:System.Runtime.CompilerServices
N:System.Diagnostics.CodeAnalysis
N:System.Numerics

View File

@@ -1,27 +0,0 @@
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable once RedundantNullableDirective
#nullable enable
namespace Terminal.Gui.Analyzers.Internal.Attributes;
/// <summary>Assembly attribute declaring a known pairing of an <see langword="enum" /> type to an extension class.</summary>
/// <remarks>This attribute should only be written by internal source generators for Terminal.Gui. No other usage of any kind is supported.</remarks>
[System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class AssemblyExtendedEnumTypeAttribute : System.Attribute
{
/// <summary>Creates a new instance of <see cref="AssemblyExtendedEnumTypeAttribute" /> from the provided parameters.</summary>
/// <param name="enumType">The <see cref="System.Type" /> of an <see langword="enum" /> decorated with a <see cref="GenerateEnumExtensionMethodsAttribute" />.</param>
/// <param name="extensionClass">The <see cref="System.Type" /> of the <see langword="class" /> decorated with an <see cref="ExtensionsForEnumTypeAttribute{TEnum}" /> referring to the same type as <paramref name="enumType" />.</param>
public AssemblyExtendedEnumTypeAttribute (System.Type enumType, System.Type extensionClass)
{
EnumType = enumType;
ExtensionClass = extensionClass;
}
///<summary>An <see langword="enum" /> type that has been extended by Terminal.Gui source generators.</summary>
public System.Type EnumType { get; init; }
///<summary>A class containing extension methods for <see cref="EnumType"/>.</summary>
public System.Type ExtensionClass { get; init; }
/// <inheritdoc />
public override string ToString () => $"{EnumType.Name},{ExtensionClass.Name}";
}

View File

@@ -1,37 +0,0 @@
// ReSharper disable RedundantNameQualifier
// ReSharper disable RedundantNullableDirective
// ReSharper disable UnusedType.Global
#pragma warning disable IDE0001, IDE0240
#nullable enable
namespace Terminal.Gui.Analyzers.Internal.Attributes;
/// <summary>
/// Attribute written by the source generator for <see langword="enum" /> extension classes, for easier analysis and reflection.
/// </summary>
/// <remarks>
/// Properties are just convenient shortcuts to properties of <typeparamref name="TEnum"/>.
/// </remarks>
[System.AttributeUsage (System.AttributeTargets.Class | System.AttributeTargets.Interface)]
internal sealed class ExtensionsForEnumTypeAttribute<TEnum>: System.Attribute, IExtensionsForEnumTypeAttributes where TEnum : struct, System.Enum
{
/// <summary>
/// The namespace-qualified name of <typeparamref name="TEnum"/>.
/// </summary>
public string EnumFullName => EnumType.FullName!;
/// <summary>
/// The unqualified name of <typeparamref name="TEnum"/>.
/// </summary>
public string EnumName => EnumType.Name;
/// <summary>
/// The namespace containing <typeparamref name="TEnum"/>.
/// </summary>
public string EnumNamespace => EnumType.Namespace!;
/// <summary>
/// The <see cref="System.Type"/> given by <see langword="typeof"/>(<typeparamref name="TEnum"/>).
/// </summary>
public System.Type EnumType => typeof (TEnum);
}

View File

@@ -1,110 +0,0 @@
// ReSharper disable RedundantNullableDirective
// ReSharper disable RedundantUsingDirective
// ReSharper disable ClassNeverInstantiated.Global
#nullable enable
using System;
using Attribute = System.Attribute;
using AttributeUsageAttribute = System.AttributeUsageAttribute;
using AttributeTargets = System.AttributeTargets;
namespace Terminal.Gui.Analyzers.Internal.Attributes;
/// <summary>
/// Used to enable source generation of a common set of extension methods for enum types.
/// </summary>
[AttributeUsage (AttributeTargets.Enum)]
internal sealed class GenerateEnumExtensionMethodsAttribute : Attribute
{
/// <summary>
/// The name of the generated static class.
/// </summary>
/// <remarks>
/// If unspecified, null, empty, or only whitespace, defaults to the name of the enum plus "Extensions".<br/>
/// No other validation is performed, so illegal values will simply result in compiler errors.
/// <para>
/// Explicitly specifying a default value is unnecessary and will result in unnecessary processing.
/// </para>
/// </remarks>
public string? ClassName { get; set; }
/// <summary>
/// The namespace in which to place the generated static class containing the extension methods.
/// </summary>
/// <remarks>
/// If unspecified, null, empty, or only whitespace, defaults to the namespace of the enum.<br/>
/// No other validation is performed, so illegal values will simply result in compiler errors.
/// <para>
/// Explicitly specifying a default value is unnecessary and will result in unnecessary processing.
/// </para>
/// </remarks>
public string? ClassNamespace { get; set; }
/// <summary>
/// Whether to generate a fast, zero-allocation, non-boxing, and reflection-free alternative to the built-in
/// <see cref="Enum.HasFlag"/> method.
/// </summary>
/// <remarks>
/// <para>
/// Default: false
/// </para>
/// <para>
/// If the enum is not decorated with <see cref="FlagsAttribute"/>, this option has no effect.
/// </para>
/// <para>
/// If multiple members have the same value, the first member with that value will be used and subsequent members
/// with the same value will be skipped.
/// </para>
/// <para>
/// Overloads taking the enum type itself as well as the underlying type of the enum will be generated, enabling
/// avoidance of implicit or explicit cast overhead.
/// </para>
/// <para>
/// Explicitly specifying a default value is unnecessary and will result in unnecessary processing.
/// </para>
/// </remarks>
public bool FastHasFlags { get; set; }
/// <summary>
/// Whether to generate a fast, zero-allocation, and reflection-free alternative to the built-in
/// <see cref="Enum.IsDefined"/> method,
/// using a switch expression as a hard-coded reverse mapping of numeric values to explicitly-named members.
/// </summary>
/// <remarks>
/// <para>
/// Default: true
/// </para>
/// <para>
/// If multiple members have the same value, the first member with that value will be used and subsequent members
/// with the same value will be skipped.
/// </para>
/// <para>
/// As with <see cref="Enum.IsDefined"/> the source generator only considers explicitly-named members.<br/>
/// Generation of values which represent valid bitwise combinations of members of enums decorated with
/// <see cref="FlagsAttribute"/> is not affected by this property.
/// </para>
/// </remarks>
public bool FastIsDefined { get; init; } = true;
/// <summary>
/// Gets a <see langword="bool"/> value indicating if this <see cref="GenerateEnumExtensionMethodsAttribute"/> instance
/// contains default values only. See <see href="#remarks">remarks</see> of this method or documentation on properties of this type for details.
/// </summary>
/// <returns>
/// A <see langword="bool"/> value indicating if all property values are default for this
/// <see cref="GenerateEnumExtensionMethodsAttribute"/> instance.
/// </returns>
/// <remarks>
/// Default values that will result in a <see langword="true"/> return value are:<br/>
/// <see cref="FastIsDefined"/> &amp;&amp; !<see cref="FastHasFlags"/> &amp;&amp; <see cref="ClassName"/>
/// <see langword="is"/> <see langword="null"/> &amp;&amp; <see cref="ClassNamespace"/> <see langword="is"/>
/// <see langword="null"/>
/// </remarks>
public override bool IsDefaultAttribute ()
{
return FastIsDefined
&& !FastHasFlags
&& ClassName is null
&& ClassNamespace is null;
}
}

View File

@@ -1,14 +0,0 @@
// ReSharper disable All
using System;
namespace Terminal.Gui.Analyzers.Internal.Attributes;
/// <summary>
/// Interface to simplify general enumeration of constructed generic types for
/// <see cref="ExtensionsForEnumTypeAttribute{TEnum}"/>
/// </summary>
internal interface IExtensionsForEnumTypeAttributes
{
Type EnumType { get; }
}

View File

@@ -1,11 +0,0 @@
// ReSharper disable once CheckNamespace
namespace System.Numerics;
/// <summary>
/// Included for compatibility with .net7+, but has no members.
/// Thus it cannot be explicitly used in generator code.
/// Use it for static analysis only.
/// </summary>
/// <typeparam name="T">The left operand type.</typeparam>
/// <typeparam name="T1">The right operand type.</typeparam>
/// <typeparam name="T2">The return type.</typeparam>
internal interface IEqualityOperators<T, T1, T2>;

View File

@@ -1,6 +0,0 @@
namespace System.Runtime.CompilerServices;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field, Inherited = false)]
public sealed class IntrinsicAttribute : Attribute
{
}

View File

@@ -1,43 +0,0 @@
// ReSharper disable once CheckNamespace
namespace Terminal.Gui.Analyzers.Internal.Compatibility;
/// <summary>
/// Extension methods for <see langword="int"/> and <see langword="uint"/> types.
/// </summary>
/// <remarks>
/// This is mostly just for backward compatibility with netstandard2.0.
/// </remarks>
public static class NumericExtensions
{
/// <summary>
/// Gets the population count (number of bits set to 1) of this 32-bit value.
/// </summary>
/// <param name="value">The value to get the population count of.</param>
/// <remarks>
/// The algorithm is the well-known SWAR (SIMD Within A Register) method for population count.<br/>
/// Included for hardware- and runtime- agnostic support for the equivalent of the x86 popcnt instruction, since
/// System.Numerics.Intrinsics isn't available in netstandard2.0.<br/>
/// It performs the operation simultaneously on 4 bytes at a time, rather than the naive method of testing all 32 bits
/// individually.<br/>
/// Most compilers can recognize this and turn it into a single platform-specific instruction, when available.
/// </remarks>
/// <returns>
/// An unsigned 32-bit integer value containing the population count of <paramref name="value"/>.
/// </returns>
[MethodImpl (MethodImplOptions.AggressiveInlining)]
public static uint GetPopCount (this uint value)
{
unchecked
{
value -= (value >> 1) & 0x55555555;
value = (value & 0x33333333) + ((value >> 2) & 0x33333333);
value = (value + (value >> 4)) & 0x0F0F0F0F;
return (value * 0x01010101) >> 24;
}
}
/// <inheritdoc cref="GetPopCount(uint)"/>
[MethodImpl (MethodImplOptions.AggressiveInlining)]
public static uint GetPopCount (this int value) { return GetPopCount (Unsafe.As<int, uint> (ref value)); }
}

View File

@@ -1,204 +0,0 @@
// ReSharper disable MemberCanBePrivate.Global
using System;
using System.CodeDom.Compiler;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Terminal.Gui.Analyzers.Internal.Attributes;
namespace Terminal.Gui.Analyzers.Internal.Constants;
/// <summary>String constants for frequently-used boilerplate.</summary>
/// <remarks>These are for performance, instead of using Roslyn to build it all during execution of analyzers.</remarks>
internal static class Strings
{
internal const string AnalyzersAttributesNamespace = $"{InternalAnalyzersNamespace}.Attributes";
internal const string AssemblyExtendedEnumTypeAttributeFullName = $"{AnalyzersAttributesNamespace}.{nameof (AssemblyExtendedEnumTypeAttribute)}";
internal const string DefaultTypeNameSuffix = "Extensions";
internal const string FallbackClassNamespace = $"{TerminalGuiRootNamespace}";
internal const string InternalAnalyzersNamespace = $"{AnalyzersRootNamespace}.Internal";
internal const string TerminalGuiRootNamespace = "Terminal.Gui";
private const string AnalyzersRootNamespace = $"{TerminalGuiRootNamespace}.Analyzers";
private const string NetStandard20CompatibilityNamespace = $"{InternalAnalyzersNamespace}.Compatibility";
/// <summary>
/// Names of dotnet namespaces and types. Included as compile-time constants to avoid unnecessary work for the Roslyn
/// source generators.
/// </summary>
/// <remarks>Implemented as nested static types because XmlDoc doesn't work on namespaces.</remarks>
internal static class DotnetNames
{
/// <summary>Fully-qualified attribute type names. Specific applications (uses) are in <see cref="Applications"/>.</summary>
internal static class Attributes
{
/// <inheritdoc cref="CompilerGeneratedAttribute"/>
internal const string CompilerGenerated = $"{Namespaces.System_Runtime_CompilerServices}.{nameof (CompilerGeneratedAttribute)}";
/// <inheritdoc cref="DebuggerNonUserCodeAttribute"/>
internal const string DebuggerNonUserCode = $"{Namespaces.System_Diagnostics}.{nameof (DebuggerNonUserCodeAttribute)}";
/// <inheritdoc cref="ExcludeFromCodeCoverageAttribute"/>
internal const string ExcludeFromCodeCoverage = $"{Namespaces.System_Diagnostics_CodeAnalysis}.{nameof (ExcludeFromCodeCoverageAttribute)}";
internal const string Flags = $"{Namespaces.SystemNs}.{nameof (FlagsAttribute)}";
internal const string GeneratedCode = $"{Namespaces.System_CodeDom_Compiler}.{nameof (GeneratedCodeAttribute)}";
/// <inheritdoc cref="MethodImplOptions.AggressiveInlining"/>
/// <remarks>Use of this attribute should be carefully evaluated.</remarks>
internal const string MethodImpl = $"{Namespaces.System_Runtime_CompilerServices}.{nameof (MethodImplAttribute)}";
/// <summary>Attributes formatted for use in code, including square brackets.</summary>
internal static class Applications
{
// ReSharper disable MemberHidesStaticFromOuterClass
internal const string Flags = $"[{Attributes.Flags}]";
/// <inheritdoc cref="System.CodeDom.Compiler.GeneratedCodeAttribute"/>
internal const string GeneratedCode = $"""[{Attributes.GeneratedCode}("{InternalAnalyzersNamespace}","1.0")]""";
/// <inheritdoc cref="MethodImplOptions.AggressiveInlining"/>
/// <remarks>Use of this attribute should be carefully evaluated.</remarks>
internal const string AggressiveInlining = $"[{MethodImpl}({Types.MethodImplOptions}.{nameof (MethodImplOptions.AggressiveInlining)})]";
/// <inheritdoc cref="DebuggerNonUserCodeAttribute"/>
internal const string DebuggerNonUserCode = $"[{Attributes.DebuggerNonUserCode}]";
/// <inheritdoc cref="CompilerGeneratedAttribute"/>
internal const string CompilerGenerated = $"[{Attributes.CompilerGenerated}]";
/// <inheritdoc cref="ExcludeFromCodeCoverageAttribute"/>
internal const string ExcludeFromCodeCoverage = $"[{Attributes.ExcludeFromCodeCoverage}]";
// ReSharper restore MemberHidesStaticFromOuterClass
}
}
/// <summary>Names of dotnet namespaces.</summary>
internal static class Namespaces
{
internal const string SystemNs = nameof (System);
// ReSharper disable InconsistentNaming
internal const string System_CodeDom = $"{SystemNs}.{nameof (System.CodeDom)}";
internal const string System_CodeDom_Compiler = $"{System_CodeDom}.{nameof (System.CodeDom.Compiler)}";
internal const string System_ComponentModel = $"{SystemNs}.{nameof (System.ComponentModel)}";
internal const string System_Diagnostics = $"{SystemNs}.{nameof (System.Diagnostics)}";
internal const string System_Diagnostics_CodeAnalysis = $"{System_Diagnostics}.{nameof (System.Diagnostics.CodeAnalysis)}";
internal const string System_Numerics = $"{SystemNs}.{nameof (System.Numerics)}";
internal const string System_Runtime = $"{SystemNs}.{nameof (System.Runtime)}";
internal const string System_Runtime_CompilerServices = $"{System_Runtime}.{nameof (System.Runtime.CompilerServices)}";
// ReSharper restore InconsistentNaming
}
internal static class Types
{
internal const string Attribute = $"{Namespaces.SystemNs}.{nameof (System.Attribute)}";
internal const string AttributeTargets = $"{Namespaces.SystemNs}.{nameof (System.AttributeTargets)}";
internal const string AttributeUsageAttribute = $"{Namespaces.SystemNs}.{nameof (System.AttributeUsageAttribute)}";
internal const string MethodImplOptions =
$"{Namespaces.System_Runtime_CompilerServices}.{nameof (System.Runtime.CompilerServices.MethodImplOptions)}";
}
}
internal static class Templates
{
internal const string AutoGeneratedCommentBlock = $"""
//------------------------------------------------------------------------------
// <auto-generated>
// This file and the code it contains was generated by a source generator in
// the {InternalAnalyzersNamespace} library.
//
// Modifications to this file are not supported and will be lost when
// source generation is triggered, either implicitly or explicitly.
// </auto-generated>
//------------------------------------------------------------------------------
""";
/// <summary>
/// A set of explicit type aliases to work around Terminal.Gui having name collisions with types like
/// <see cref="System.Attribute"/>.
/// </summary>
internal const string DotnetExplicitTypeAliasUsingDirectives = $"""
using Attribute = {DotnetNames.Types.Attribute};
using AttributeUsageAttribute = {DotnetNames.Types.AttributeUsageAttribute};
using GeneratedCode = {DotnetNames.Attributes.GeneratedCode};
""";
/// <summary>Using directives for common namespaces in generated code.</summary>
internal const string DotnetNamespaceUsingDirectives = $"""
using {DotnetNames.Namespaces.SystemNs};
using {DotnetNames.Namespaces.System_CodeDom};
using {DotnetNames.Namespaces.System_CodeDom_Compiler};
using {DotnetNames.Namespaces.System_ComponentModel};
using {DotnetNames.Namespaces.System_Numerics};
using {DotnetNames.Namespaces.System_Runtime};
using {DotnetNames.Namespaces.System_Runtime_CompilerServices};
""";
/// <summary>
/// A set of empty namespaces that MAY be referenced in generated code, especially in using statements,
/// which are always included to avoid additional complexity due to conditional compilation.
/// </summary>
internal const string DummyNamespaceDeclarations = $$"""
// These are dummy declarations to avoid complexity with conditional compilation.
#pragma warning disable IDE0079 // Remove unnecessary suppression
#pragma warning disable RCS1259 // Remove empty syntax
namespace {{TerminalGuiRootNamespace}} { }
namespace {{AnalyzersRootNamespace}} { }
namespace {{InternalAnalyzersNamespace}} { }
namespace {{NetStandard20CompatibilityNamespace}} { }
namespace {{AnalyzersAttributesNamespace}} { }
#pragma warning restore RCS1259 // Remove empty syntax
#pragma warning restore IDE0079 // Remove unnecessary suppression
""";
internal const string StandardHeader = $"""
{AutoGeneratedCommentBlock}
// ReSharper disable RedundantUsingDirective
// ReSharper disable once RedundantNullableDirective
{NullableContextDirective}
{StandardUsingDirectivesText}
""";
/// <summary>
/// Standard set of using directives for generated extension method class files.
/// Not all are always needed, but all are included so we don't have to worry about it.
/// </summary>
internal const string StandardUsingDirectivesText = $"""
{DotnetNamespaceUsingDirectives}
{DotnetExplicitTypeAliasUsingDirectives}
using {TerminalGuiRootNamespace};
using {AnalyzersRootNamespace};
using {InternalAnalyzersNamespace};
using {AnalyzersAttributesNamespace};
using {NetStandard20CompatibilityNamespace};
""";
internal const string AttributesForGeneratedInterfaces = $"""
{DotnetNames.Attributes.Applications.GeneratedCode}
{DotnetNames.Attributes.Applications.CompilerGenerated}
""";
internal const string AttributesForGeneratedTypes = $"""
{DotnetNames.Attributes.Applications.GeneratedCode}
{DotnetNames.Attributes.Applications.CompilerGenerated}
{DotnetNames.Attributes.Applications.DebuggerNonUserCode}
{DotnetNames.Attributes.Applications.ExcludeFromCodeCoverage}
""";
/// <summary>
/// Preprocessor directive to enable nullability context for generated code.<br/>
/// This should always be emitted, as it applies only to generated code.<br/>
/// As such, generated code MUST be properly annotated.
/// </summary>
internal const string NullableContextDirective = "#nullable enable";
}
}

View File

@@ -1,235 +0,0 @@
using System;
using System.CodeDom.Compiler;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text;
using Microsoft.CodeAnalysis.Text;
using Terminal.Gui.Analyzers.Internal.Constants;
namespace Terminal.Gui.Analyzers.Internal.Generators.EnumExtensions;
/// <summary>
/// The class responsible for turning an <see cref="EnumExtensionMethodsGenerationInfo"/>
/// into actual C# code.
/// </summary>
/// <remarks>Try to use this type as infrequently as possible.</remarks>
/// <param name="metadata">
/// A reference to an <see cref="IGeneratedTypeMetadata{TSelf}"/> which will be used
/// to generate the extension class code. The object will not be validated,
/// so it is critical that it be correct and remain unchanged while in use
/// by an instance of this class. Behavior if those rules are not followed
/// is undefined.
/// </param>
[SuppressMessage ("CodeQuality", "IDE0079", Justification = "Suppressions here are intentional and the warnings they disable are just noise.")]
internal sealed class CodeWriter (in EnumExtensionMethodsGenerationInfo metadata) : IStandardCSharpCodeGenerator<EnumExtensionMethodsGenerationInfo>
{
// Using the null suppression operator here because this will always be
// initialized to non-null before a reference to it is returned.
private SourceText _sourceText = null!;
/// <inheritdoc/>
public EnumExtensionMethodsGenerationInfo Metadata
{
[MethodImpl (MethodImplOptions.AggressiveInlining)]
[return: NotNull]
get;
[param: DisallowNull]
set;
} = metadata;
/// <inheritdoc/>
public ref readonly SourceText GenerateSourceText (Encoding? encoding = null)
{
encoding ??= Encoding.UTF8;
_sourceText = SourceText.From (GetFullSourceText (), encoding);
return ref _sourceText;
}
/// <summary>
/// Gets the using directive for the namespace containing the enum,
/// if different from the extension class namespace, or an empty string, if they are the same.
/// </summary>
private string EnumNamespaceUsingDirective => Metadata.TargetTypeNamespace != Metadata.GeneratedTypeNamespace
// ReSharper disable once HeapView.ObjectAllocation
? $"using {Metadata.TargetTypeNamespace};"
: string.Empty;
private string EnumTypeKeyword => Metadata.EnumBackingTypeCode switch
{
TypeCode.Int32 => "int",
TypeCode.UInt32 => "uint",
_ => string.Empty
};
/// <summary>Gets the class declaration line.</summary>
private string ExtensionClassDeclarationLine => $"public static partial class {Metadata.GeneratedTypeName}";
// ReSharper disable once HeapView.ObjectAllocation
/// <summary>Gets the XmlDoc for the extension class declaration.</summary>
private string ExtensionClassDeclarationXmlDoc =>
$"/// <summary>Extension methods for the <see cref=\"{Metadata.TargetTypeFullName}\"/> <see langword=\"enum\" /> type.</summary>";
// ReSharper disable once HeapView.ObjectAllocation
/// <summary>Gets the extension class file-scoped namespace directive.</summary>
private string ExtensionClassNamespaceDirective => $"namespace {Metadata.GeneratedTypeNamespace};";
/// <summary>
/// An attribute to decorate the extension class with for easy mapping back to the target enum type, for reflection and
/// analysis.
/// </summary>
private string ExtensionsForTypeAttributeLine => $"[ExtensionsForEnumType<{Metadata.TargetTypeFullName}>]";
/// <summary>
/// Creates the code for the FastHasFlags method.
/// </summary>
/// <remarks>
/// Since the generator already only writes code for enums backed by <see langword="int"/> and <see langword="uint"/>,
/// this method is safe, as we'll always be using a DWORD.
/// </remarks>
/// <param name="w">An instance of an <see cref="IndentedTextWriter"/> to write to.</param>
private void GetFastHasFlagsMethods (IndentedTextWriter w)
{
// The version taking the same enum type as the check value.
w.WriteLine (
$"/// <summary>Determines if the specified flags are set in the current value of this <see cref=\"{Metadata.TargetTypeFullName}\" />.</summary>");
w.WriteLine ("/// <remarks>NO VALIDATION IS PERFORMED!</remarks>");
w.WriteLine (
$"/// <returns>True, if all flags present in <paramref name=\"checkFlags\" /> are also present in the current value of the <see cref=\"{Metadata.TargetTypeFullName}\" />.<br />Otherwise false.</returns>");
w.WriteLine (Strings.DotnetNames.Attributes.Applications.AggressiveInlining);
w.Push (
$"{Metadata.Accessibility.ToCSharpString ()} static bool FastHasFlags (this {Metadata.TargetTypeFullName} e, {Metadata.TargetTypeFullName} checkFlags)");
w.WriteLine ($"ref uint enumCurrentValueRef = ref Unsafe.As<{Metadata.TargetTypeFullName},uint> (ref e);");
w.WriteLine ($"ref uint checkFlagsValueRef = ref Unsafe.As<{Metadata.TargetTypeFullName},uint> (ref checkFlags);");
w.WriteLine ("return (enumCurrentValueRef & checkFlagsValueRef) == checkFlagsValueRef;");
w.Pop ();
// The version taking the underlying type of the enum as the check value.
w.WriteLine (
$"/// <summary>Determines if the specified mask bits are set in the current value of this <see cref=\"{Metadata.TargetTypeFullName}\" />.</summary>");
w.WriteLine (
$"/// <param name=\"e\">The <see cref=\"{Metadata.TargetTypeFullName}\" /> value to check against the <paramref name=\"mask\" /> value.</param>");
w.WriteLine ("/// <param name=\"mask\">A mask to apply to the current value.</param>");
w.WriteLine (
$"/// <returns>True, if all bits set to 1 in the mask are also set to 1 in the current value of the <see cref=\"{Metadata.TargetTypeFullName}\" />.<br />Otherwise false.</returns>");
w.WriteLine ("/// <remarks>NO VALIDATION IS PERFORMED!</remarks>");
w.WriteLine (Strings.DotnetNames.Attributes.Applications.AggressiveInlining);
w.Push (
$"{Metadata.Accessibility.ToCSharpString ()} static bool FastHasFlags (this {Metadata.TargetTypeFullName} e, {EnumTypeKeyword} mask)");
w.WriteLine ($"ref {EnumTypeKeyword} enumCurrentValueRef = ref Unsafe.As<{Metadata.TargetTypeFullName},{EnumTypeKeyword}> (ref e);");
w.WriteLine ("return (enumCurrentValueRef & mask) == mask;");
w.Pop ();
}
/// <summary>
/// Creates the code for the FastIsDefined method.
/// </summary>
[SuppressMessage ("ReSharper", "SwitchStatementHandlesSomeKnownEnumValuesWithDefault", Justification = "Only need to handle int and uint.")]
[SuppressMessage ("ReSharper", "SwitchStatementMissingSomeEnumCasesNoDefault", Justification = "Only need to handle int and uint.")]
private void GetFastIsDefinedMethod (IndentedTextWriter w)
{
w.WriteLine (
$"/// <summary>Determines if the specified <see langword=\"{EnumTypeKeyword}\" /> value is explicitly defined as a named value of the <see cref=\"{Metadata.TargetTypeFullName}\" /> <see langword=\"enum\" /> type.</summary>");
w.WriteLine (
"/// <remarks>Only explicitly named values return true, as with IsDefined. Combined valid flag values of flags enums which are not explicitly named will return false.</remarks>");
w.Push (
$"{Metadata.Accessibility.ToCSharpString ()} static bool FastIsDefined (this {Metadata.TargetTypeFullName} e, {EnumTypeKeyword} value)");
w.Push ("return value switch");
switch (Metadata.EnumBackingTypeCode)
{
case TypeCode.Int32:
foreach (int definedValue in Metadata._intMembers)
{
w.WriteLine ($"{definedValue:D} => true,");
}
break;
case TypeCode.UInt32:
foreach (uint definedValue in Metadata._uIntMembers)
{
w.WriteLine ($"{definedValue:D} => true,");
}
break;
}
w.WriteLine ("_ => false");
w.Pop ("};");
w.Pop ();
}
private string GetFullSourceText ()
{
StringBuilder sb = new (
$"""
{Strings.Templates.StandardHeader}
[assembly: {Strings.AssemblyExtendedEnumTypeAttributeFullName} (typeof({Metadata.TargetTypeFullName}), typeof({Metadata.GeneratedTypeFullName}))]
{EnumNamespaceUsingDirective}
{ExtensionClassNamespaceDirective}
{ExtensionClassDeclarationXmlDoc}
{Strings.Templates.AttributesForGeneratedTypes}
{ExtensionsForTypeAttributeLine}
{ExtensionClassDeclarationLine}
""",
4096);
using IndentedTextWriter w = new (new StringWriter (sb));
w.Push ();
GetNamedValuesToInt32Method (w);
GetNamedValuesToUInt32Method (w);
if (Metadata.GenerateFastIsDefined)
{
GetFastIsDefinedMethod (w);
}
if (Metadata.GenerateFastHasFlags)
{
GetFastHasFlagsMethods (w);
}
w.Pop ();
w.Flush ();
return sb.ToString ();
}
[MethodImpl (MethodImplOptions.AggressiveInlining)]
private void GetNamedValuesToInt32Method (IndentedTextWriter w)
{
w.WriteLine (
$"/// <summary>Directly converts this <see cref=\"{Metadata.TargetTypeFullName}\" /> value to an <see langword=\"int\" /> value with the same binary representation.</summary>");
w.WriteLine ("/// <remarks>NO VALIDATION IS PERFORMED!</remarks>");
w.WriteLine (Strings.DotnetNames.Attributes.Applications.AggressiveInlining);
w.Push ($"{Metadata.Accessibility.ToCSharpString ()} static int AsInt32 (this {Metadata.TargetTypeFullName} e)");
w.WriteLine ($"return Unsafe.As<{Metadata.TargetTypeFullName},int> (ref e);");
w.Pop ();
}
[MethodImpl (MethodImplOptions.AggressiveInlining)]
private void GetNamedValuesToUInt32Method (IndentedTextWriter w)
{
w.WriteLine (
$"/// <summary>Directly converts this <see cref=\"{Metadata.TargetTypeFullName}\" /> value to a <see langword=\"uint\" /> value with the same binary representation.</summary>");
w.WriteLine ("/// <remarks>NO VALIDATION IS PERFORMED!</remarks>");
w.WriteLine (Strings.DotnetNames.Attributes.Applications.AggressiveInlining);
w.Push ($"{Metadata.Accessibility.ToCSharpString ()} static uint AsUInt32 (this {Metadata.TargetTypeFullName} e)");
w.WriteLine ($"return Unsafe.As<{Metadata.TargetTypeFullName},uint> (ref e);");
w.Pop ();
}
}

View File

@@ -1,443 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using Terminal.Gui.Analyzers.Internal.Attributes;
using Terminal.Gui.Analyzers.Internal.Constants;
namespace Terminal.Gui.Analyzers.Internal.Generators.EnumExtensions;
/// <summary>
/// Type containing the information necessary to generate code according to the declared attribute values,
/// as well as the actual code to create the corresponding source code text, to be used in the
/// source generator pipeline.
/// </summary>
/// <remarks>
/// Minimal validation is performed by this type.<br/>
/// Errors in analyzed source code will result in generation failure or broken output.<br/>
/// This type is not intended for use outside of Terminal.Gui library development.
/// </remarks>
internal sealed record EnumExtensionMethodsGenerationInfo : IGeneratedTypeMetadata<EnumExtensionMethodsGenerationInfo>,
IEqualityOperators<EnumExtensionMethodsGenerationInfo, EnumExtensionMethodsGenerationInfo, bool>
{
private const int ExplicitFastHasFlagsMask = 0b_0100;
private const int ExplicitFastIsDefinedMask = 0b_1000;
private const int ExplicitNameMask = 0b_0010;
private const int ExplicitNamespaceMask = 0b_0001;
private const string GeneratorAttributeFullyQualifiedName = $"{GeneratorAttributeNamespace}.{GeneratorAttributeName}";
private const string GeneratorAttributeName = nameof (GenerateEnumExtensionMethodsAttribute);
private const string GeneratorAttributeNamespace = Strings.AnalyzersAttributesNamespace;
/// <summary>
/// Type containing the information necessary to generate code according to the declared attribute values,
/// as well as the actual code to create the corresponding source code text, to be used in the
/// source generator pipeline.
/// </summary>
/// <param name="enumNamespace">The fully-qualified namespace of the enum type, without assembly name.</param>
/// <param name="enumTypeName">
/// The name of the enum type, as would be given by <see langword="nameof"/> on the enum's type
/// declaration.
/// </param>
/// <param name="typeNamespace">
/// The fully-qualified namespace in which to place the generated code, without assembly name. If omitted or explicitly
/// null, uses the value provided in <paramref name="enumNamespace"/>.
/// </param>
/// <param name="typeName">
/// The name of the generated class. If omitted or explicitly null, appends "Extensions" to the value of
/// <paramref name="enumTypeName"/>.
/// </param>
/// <param name="enumBackingTypeCode">The backing type of the enum. Defaults to <see cref="int"/>.</param>
/// <param name="generateFastHasFlags">
/// Whether to generate a fast HasFlag alternative. (Default: true) Ignored if the enum does not also have
/// <see cref="FlagsAttribute"/>.
/// </param>
/// <param name="generateFastIsDefined">Whether to generate a fast IsDefined alternative. (Default: true)</param>
/// <remarks>
/// Minimal validation is performed by this type.<br/>
/// Errors in analyzed source code will result in generation failure or broken output.<br/>
/// This type is not intended for use outside of Terminal.Gui library development.
/// </remarks>
public EnumExtensionMethodsGenerationInfo (
string enumNamespace,
string enumTypeName,
string? typeNamespace = null,
string? typeName = null,
TypeCode enumBackingTypeCode = TypeCode.Int32,
bool generateFastHasFlags = true,
bool generateFastIsDefined = true
) : this (enumNamespace, enumTypeName, enumBackingTypeCode)
{
GeneratedTypeNamespace = typeNamespace ?? enumNamespace;
GeneratedTypeName = typeName ?? string.Concat (enumTypeName, Strings.DefaultTypeNameSuffix);
GenerateFastHasFlags = generateFastHasFlags;
GenerateFastIsDefined = generateFastIsDefined;
}
public EnumExtensionMethodsGenerationInfo (string enumNamespace, string enumTypeName, TypeCode enumBackingType)
{
// Interning these since they're rather unlikely to change.
string enumInternedNamespace = string.Intern (enumNamespace);
string enumInternedName = string.Intern (enumTypeName);
TargetTypeNamespace = enumInternedNamespace;
TargetTypeName = enumInternedName;
EnumBackingTypeCode = enumBackingType;
}
[AccessedThroughProperty (nameof (EnumBackingTypeCode))]
private readonly TypeCode _enumBackingTypeCode;
[AccessedThroughProperty (nameof (GeneratedTypeName))]
private string? _generatedTypeName;
[AccessedThroughProperty (nameof (GeneratedTypeNamespace))]
private string? _generatedTypeNamespace;
private BitVector32 _discoveredProperties = new (0);
/// <summary>The name of the extension class.</summary>
public string? GeneratedTypeName
{
get => _generatedTypeName ?? string.Concat (TargetTypeName, Strings.DefaultTypeNameSuffix);
set => _generatedTypeName = value ?? string.Concat (TargetTypeName, Strings.DefaultTypeNameSuffix);
}
/// <summary>The namespace for the extension class.</summary>
/// <remarks>
/// Value is not validated by the set accessor.<br/>
/// Get accessor will never return null and is thus marked [NotNull] for static analysis, even though the property is
/// declared as a nullable <see langword="string?"/>.<br/>If the backing field for this property is null, the get
/// accessor will return <see cref="TargetTypeNamespace"/> instead.
/// </remarks>
public string? GeneratedTypeNamespace
{
get => _generatedTypeNamespace ?? TargetTypeNamespace;
set => _generatedTypeNamespace = value ?? TargetTypeNamespace;
}
/// <inheritdoc/>
public string TargetTypeFullName => string.Concat (TargetTypeNamespace, ".", TargetTypeName);
/// <inheritdoc/>
public Accessibility Accessibility
{
get;
[UsedImplicitly]
internal set;
} = Accessibility.Public;
/// <inheritdoc/>
public TypeKind TypeKind => TypeKind.Class;
/// <inheritdoc/>
public bool IsRecord => false;
/// <inheritdoc/>
public bool IsClass => true;
/// <inheritdoc/>
public bool IsStruct => false;
/// <inheritdoc/>
public bool IsByRefLike => false;
/// <inheritdoc/>
public bool IsSealed => false;
/// <inheritdoc/>
public bool IsAbstract => false;
/// <inheritdoc/>
public bool IsEnum => false;
/// <inheritdoc/>
public bool IsStatic => true;
/// <inheritdoc/>
public bool IncludeInterface => false;
public string GeneratedTypeFullName => $"{GeneratedTypeNamespace}.{GeneratedTypeName}";
/// <summary>Whether to generate the extension class as partial (Default: true)</summary>
public bool IsPartial => true;
/// <summary>The fully-qualified namespace of the source enum type.</summary>
public string TargetTypeNamespace
{
get;
[UsedImplicitly]
set;
}
/// <summary>The UNQUALIFIED name of the source enum type.</summary>
public string TargetTypeName
{
get;
[UsedImplicitly]
set;
}
/// <summary>
/// The backing type for the enum.
/// </summary>
/// <remarks>For simplicity and formality, only System.Int32 and System.UInt32 are supported at this time.</remarks>
public TypeCode EnumBackingTypeCode
{
get => _enumBackingTypeCode;
init
{
if (value is not TypeCode.Int32 and not TypeCode.UInt32)
{
throw new NotSupportedException ("Only System.Int32 and System.UInt32 are supported at this time.");
}
_enumBackingTypeCode = value;
}
}
/// <summary>
/// Whether a fast alternative to the built-in Enum.HasFlag method will be generated (Default: false)
/// </summary>
public bool GenerateFastHasFlags { [UsedImplicitly] get; set; }
/// <summary>Whether a switch-based IsDefined replacement will be generated (Default: true)</summary>
public bool GenerateFastIsDefined { [UsedImplicitly]get; set; } = true;
internal ImmutableHashSet<int>? _intMembers;
internal ImmutableHashSet<uint>? _uIntMembers;
/// <summary>
/// Fully-qualified name of the extension class
/// </summary>
internal string FullyQualifiedClassName => $"{GeneratedTypeNamespace}.{GeneratedTypeName}";
/// <summary>
/// Whether a Flags was found on the enum type.
/// </summary>
internal bool HasFlagsAttribute {[UsedImplicitly] get; set; }
private static readonly SymbolDisplayFormat FullyQualifiedSymbolDisplayFormatWithoutGlobal =
SymbolDisplayFormat.FullyQualifiedFormat
.WithGlobalNamespaceStyle (
SymbolDisplayGlobalNamespaceStyle.Omitted);
internal bool TryConfigure (INamedTypeSymbol enumSymbol, CancellationToken cancellationToken)
{
using var cts = CancellationTokenSource.CreateLinkedTokenSource (cancellationToken);
cts.Token.ThrowIfCancellationRequested ();
ImmutableArray<AttributeData> attributes = enumSymbol.GetAttributes ();
// This is theoretically impossible, but guarding just in case and canceling if it does happen.
if (attributes.Length == 0)
{
cts.Cancel (true);
return false;
}
// Check all attributes provided for anything interesting.
// Attributes can be in any order, so just check them all and adjust at the end if necessary.
// Note that we do not perform as strict validation on actual usage of the attribute, at this stage,
// because the analyzer should have already thrown errors for invalid uses like global namespace
// or unsupported enum underlying types.
foreach (AttributeData attr in attributes)
{
cts.Token.ThrowIfCancellationRequested ();
string? attributeFullyQualifiedName = attr.AttributeClass?.ToDisplayString (FullyQualifiedSymbolDisplayFormatWithoutGlobal);
// Skip if null or not possibly an attribute we care about
if (attributeFullyQualifiedName is null or not { Length: >= 5 })
{
continue;
}
switch (attributeFullyQualifiedName)
{
// For Flags enums
case Strings.DotnetNames.Attributes.Flags:
{
HasFlagsAttribute = true;
}
continue;
// For the attribute that started this whole thing
case GeneratorAttributeFullyQualifiedName:
{
// If we can't successfully complete this method,
// something is wrong enough that we may as well just stop now.
if (!TryConfigure (attr, cts.Token))
{
if (cts.Token.CanBeCanceled)
{
cts.Cancel ();
}
return false;
}
}
continue;
}
}
// Now get the members, if we know we'll need them.
if (GenerateFastIsDefined || GenerateFastHasFlags)
{
if (EnumBackingTypeCode == TypeCode.Int32)
{
PopulateIntMembersHashSet (enumSymbol);
}
else if (EnumBackingTypeCode == TypeCode.UInt32)
{
PopulateUIntMembersHashSet (enumSymbol);
}
}
return true;
}
private void PopulateIntMembersHashSet (INamedTypeSymbol enumSymbol)
{
ImmutableArray<ISymbol> enumMembers = enumSymbol.GetMembers ();
IEnumerable<IFieldSymbol> fieldSymbols = enumMembers.OfType<IFieldSymbol> ();
_intMembers = fieldSymbols.Select (static m => m.HasConstantValue ? (int)m.ConstantValue : 0).ToImmutableHashSet ();
}
private void PopulateUIntMembersHashSet (INamedTypeSymbol enumSymbol)
{
_uIntMembers = enumSymbol.GetMembers ().OfType<IFieldSymbol> ().Select (static m => (uint)m.ConstantValue).ToImmutableHashSet ();
}
private bool HasExplicitFastHasFlags
{
[UsedImplicitly]get => _discoveredProperties [ExplicitFastHasFlagsMask];
set => _discoveredProperties [ExplicitFastHasFlagsMask] = value;
}
private bool HasExplicitFastIsDefined
{
[UsedImplicitly]get => _discoveredProperties [ExplicitFastIsDefinedMask];
set => _discoveredProperties [ExplicitFastIsDefinedMask] = value;
}
private bool HasExplicitTypeName
{
get => _discoveredProperties [ExplicitNameMask];
set => _discoveredProperties [ExplicitNameMask] = value;
}
private bool HasExplicitTypeNamespace
{
get => _discoveredProperties [ExplicitNamespaceMask];
set => _discoveredProperties [ExplicitNamespaceMask] = value;
}
[MemberNotNullWhen (true, nameof (_generatedTypeName), nameof (_generatedTypeNamespace))]
private bool TryConfigure (AttributeData attr, CancellationToken cancellationToken)
{
using var cts = CancellationTokenSource.CreateLinkedTokenSource (cancellationToken);
cts.Token.ThrowIfCancellationRequested ();
if (attr is not { NamedArguments.Length: > 0 })
{
// Just a naked attribute, so configure with appropriate defaults.
GeneratedTypeNamespace = TargetTypeNamespace;
GeneratedTypeName = string.Concat (TargetTypeName, Strings.DefaultTypeNameSuffix);
return true;
}
cts.Token.ThrowIfCancellationRequested ();
foreach (KeyValuePair<string, TypedConstant> kvp in attr.NamedArguments)
{
string? propName = kvp.Key;
TypedConstant propValue = kvp.Value;
cts.Token.ThrowIfCancellationRequested ();
// For every property name and value pair, set associated metadata
// property, if understood.
switch (propName, propValue)
{
// Null or empty string doesn't make sense, so skip if it happens.
case (null, _):
case ("", _):
continue;
// ClassName is specified, not explicitly null, and at least 1 character long.
case (AttributeProperties.TypeNamePropertyName, { IsNull: false, Value: string { Length: > 1 } classNameProvidedValue }):
if (string.IsNullOrWhiteSpace (classNameProvidedValue))
{
return false;
}
GeneratedTypeName = classNameProvidedValue;
HasExplicitTypeName = true;
continue;
// Class namespace is specified, not explicitly null, and at least 1 character long.
case (AttributeProperties.TypeNamespacePropertyName, { IsNull: false, Value: string { Length: > 1 } classNamespaceProvidedValue }):
if (string.IsNullOrWhiteSpace (classNamespaceProvidedValue))
{
return false;
}
GeneratedTypeNamespace = classNamespaceProvidedValue;
HasExplicitTypeNamespace = true;
continue;
// FastHasFlags is specified
case (AttributeProperties.FastHasFlagsPropertyName, { IsNull: false } fastHasFlagsConstant):
GenerateFastHasFlags = fastHasFlagsConstant.Value is true;
HasExplicitFastHasFlags = true;
continue;
// FastIsDefined is specified
case (AttributeProperties.FastIsDefinedPropertyName, { IsNull: false } fastIsDefinedConstant):
GenerateFastIsDefined = fastIsDefinedConstant.Value is true;
HasExplicitFastIsDefined = true;
continue;
}
}
// The rest is simple enough it's not really worth worrying about cancellation, so don't bother from here on...
// Configure anything that wasn't specified that doesn't have an implicitly safe default
if (!HasExplicitTypeName || _generatedTypeName is null)
{
_generatedTypeName = string.Concat (TargetTypeName, Strings.DefaultTypeNameSuffix);
}
if (!HasExplicitTypeNamespace || _generatedTypeNamespace is null)
{
_generatedTypeNamespace = TargetTypeNamespace;
}
if (!HasFlagsAttribute)
{
GenerateFastHasFlags = false;
}
return true;
}
private static class AttributeProperties
{
internal const string FastHasFlagsPropertyName = nameof (GenerateEnumExtensionMethodsAttribute.FastHasFlags);
internal const string FastIsDefinedPropertyName = nameof (GenerateEnumExtensionMethodsAttribute.FastIsDefined);
internal const string TypeNamePropertyName = nameof (GenerateEnumExtensionMethodsAttribute.ClassName);
internal const string TypeNamespacePropertyName = nameof (GenerateEnumExtensionMethodsAttribute.ClassNamespace);
}
}

View File

@@ -1,452 +0,0 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Threading;
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;
/// <summary>
/// Incremental code generator for enums decorated with <see cref="GenerateEnumExtensionMethodsAttribute"/>.
/// </summary>
[SuppressMessage ("CodeQuality", "IDE0079", Justification = "Suppressions here are intentional and the warnings they disable are just noise.")]
[Generator (LanguageNames.CSharp)]
public sealed class EnumExtensionMethodsIncrementalGenerator : IIncrementalGenerator
{
private const string ExtensionsForEnumTypeAttributeFullyQualifiedName = $"{Strings.AnalyzersAttributesNamespace}.{ExtensionsForEnumTypeAttributeName}";
private const string ExtensionsForEnumTypeAttributeName = "ExtensionsForEnumTypeAttribute";
private const string GeneratorAttributeFullyQualifiedName = $"{Strings.AnalyzersAttributesNamespace}.{GeneratorAttributeName}";
private const string GeneratorAttributeName = nameof (GenerateEnumExtensionMethodsAttribute);
/// <summary>Fully-qualified symbol name format without the "global::" prefix.</summary>
private static readonly SymbolDisplayFormat _fullyQualifiedSymbolDisplayFormatWithoutGlobal =
SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle (SymbolDisplayGlobalNamespaceStyle.Omitted);
/// <inheritdoc/>
/// <remarks>
/// <para>
/// Basically, this method is called once by the compiler, and is responsible for wiring up
/// everything important about how source generation works.
/// </para>
/// <para>
/// See in-line comments for specifics of what's going on.
/// </para>
/// <para>
/// Note that <paramref name="context"/> is everything in the compilation,
/// except for code generated by this generator or generators which have not yet executed.<br/>
/// The methods registered to perform generation get called on-demand by the host (the IDE,
/// compiler, etc), sometimes as often as every single keystroke.
/// </para>
/// </remarks>
public void Initialize (IncrementalGeneratorInitializationContext context)
{
// Write out namespaces that may be used later. Harmless to declare them now and will avoid
// additional processing and potential omissions later on.
context.RegisterPostInitializationOutput (GenerateDummyNamespaces);
// This executes the delegate given to it immediately after Roslyn gets all set up.
//
// As written, this will result in the GenerateEnumExtensionMethodsAttribute code
// being added to the environment, so that it can be used without having to actually
// be declared explicitly in the target project.
// This is important, as it guarantees the type will exist and also guarantees it is
// defined exactly as the generator expects it to be defined.
context.RegisterPostInitializationOutput (GenerateAttributeSources);
// Next up, we define our pipeline.
// To do so, we create one or more IncrementalValuesProvider<T> objects, each of which
// defines on stage of analysis or generation as needed.
//
// Critically, these must be as fast and efficient as reasonably possible because,
// once the pipeline is registered, this stuff can get called A LOT.
//
// Note that declaring these doesn't really do much of anything unless they are given to the
// RegisterSourceOutput method at the end of this method.
//
// The delegates are not actually evaluated right here. That is triggered by changes being
// made to the source code.
// This provider grabs attributes that pass our filter and then creates lightweight
// metadata objects to be used in the final code generation step.
// It also preemptively removes any nulls from the collection before handing things off
// to the code generation logic.
IncrementalValuesProvider<EnumExtensionMethodsGenerationInfo?> enumGenerationInfos =
context
.SyntaxProvider
// This method is a highly-optimized (and highly-recommended) filter on the incoming
// code elements that only bothers to present code that is annotated with the specified
// attribute, by its fully-qualified name, as a string, which is the first parameter.
//
// Two delegates are passed to it, in the second and third parameters.
//
// The second parameter is a filter predicate taking each SyntaxNode that passes the
// name filter above, and then refines that result.
//
// It is critical that the filter predicate be as simple and fast as possible, as it
// will be called a ton, triggered by keystrokes or anything else that modifies code
// in or even related to (in either direction) the pre-filtered code.
// It should collect metadata only and not actually generate any code.
// It must return a boolean indicating whether the supplied SyntaxNode should be
// given to the transform delegate at all.
//
// The third parameter is the "transform" delegate.
// That one only runs when code is changed that passed both the attribute name filter
// and the filter predicate in the second parameter.
// It will be called for everything that passes both of those, so it can still happen
// a lot, but should at least be pretty close.
// In our case, it should be 100% accurate, since we're using OUR attribute, which can
// only be applied to enum types in the first place.
//
// That delegate is responsible for creating some sort of lightweight data structure
// which can later be used to generate the actual source code for output.
//
// THIS DELEGATE DOES NOT GENERATE CODE!
// However, it does need to return instances of the metadata class in use that are either
// null or complete enough to generate meaningful code from, later on.
//
// We then filter out any that were null with the .Where call at the end, so that we don't
// know or care about them when it's time to generate code.
//
// While the syntax of that .Where call is the same as LINQ, that is actually a
// highly-optimized implementation specifically for this use.
.ForAttributeWithMetadataName (
GeneratorAttributeFullyQualifiedName,
IsPotentiallyInterestingDeclaration,
GatherMetadataForCodeGeneration
)
.WithTrackingName ("CollectEnumMetadata")
.Where (static eInfo => eInfo is { });
// Finally, we wire up any IncrementalValuesProvider<T> instances above to the appropriate
// delegate that takes the SourceProductionContext that is current at run-time and an instance of
// our metadata type and takes appropriate action.
// Typically that means generating code from that metadata and adding it to the compilation via
// the received context object.
//
// As with everything else , the delegate will be invoked once for each item that passed
// all of the filters above, so we get to write that method from the perspective of a single
// enum type declaration.
context.RegisterSourceOutput (enumGenerationInfos, GenerateSourceFromGenerationInfo);
}
private static EnumExtensionMethodsGenerationInfo? GatherMetadataForCodeGeneration (
GeneratorAttributeSyntaxContext context,
CancellationToken cancellationToken
)
{
var cts = CancellationTokenSource.CreateLinkedTokenSource (cancellationToken);
cancellationToken.ThrowIfCancellationRequested ();
// If it's not an enum symbol, we don't care.
// EnumUnderlyingType is null for non-enums, so this validates it's an enum declaration.
if (context.TargetSymbol is not INamedTypeSymbol { EnumUnderlyingType: { } } namedSymbol)
{
return null;
}
INamespaceSymbol? enumNamespaceSymbol = namedSymbol.ContainingNamespace;
if (enumNamespaceSymbol is null or { IsGlobalNamespace: true })
{
// Explicitly choosing not to support enums in the global namespace.
// The corresponding analyzer will report this.
return null;
}
string enumName = namedSymbol.Name;
string enumNamespace = enumNamespaceSymbol.ToDisplayString (_fullyQualifiedSymbolDisplayFormatWithoutGlobal);
TypeCode enumTypeCode = namedSymbol.EnumUnderlyingType.Name switch
{
"UInt32" => TypeCode.UInt32,
"Int32" => TypeCode.Int32,
_ => TypeCode.Empty
};
EnumExtensionMethodsGenerationInfo info = new (
enumNamespace,
enumName,
enumTypeCode
);
if (!info.TryConfigure (namedSymbol, cts.Token))
{
cts.Cancel ();
cts.Token.ThrowIfCancellationRequested ();
}
return info;
}
private static void GenerateAttributeSources (IncrementalGeneratorPostInitializationContext postInitializationContext)
{
postInitializationContext
.AddSource (
$"{nameof (IExtensionsForEnumTypeAttributes)}.g.cs",
SourceText.From (
$$"""
// ReSharper disable All
{{Strings.Templates.AutoGeneratedCommentBlock}}
using System;
namespace {{Strings.AnalyzersAttributesNamespace}};
/// <summary>
/// Interface to simplify general enumeration of constructed generic types for
/// <see cref="ExtensionsForEnumTypeAttribute{TEnum}"/>
/// </summary>
{{Strings.Templates.AttributesForGeneratedInterfaces}}
public interface IExtensionsForEnumTypeAttributes
{
System.Type EnumType { get; }
}
""",
Encoding.UTF8));
postInitializationContext
.AddSource (
$"{nameof (AssemblyExtendedEnumTypeAttribute)}.g.cs",
SourceText.From (
$$"""
// ReSharper disable All
#nullable enable
{{Strings.Templates.AutoGeneratedCommentBlock}}
namespace {{Strings.AnalyzersAttributesNamespace}};
/// <summary>Assembly attribute declaring a known pairing of an <see langword="enum" /> type to an extension class.</summary>
/// <remarks>This attribute should only be written by internal source generators for Terminal.Gui. No other usage of any kind is supported.</remarks>
{{Strings.Templates.AttributesForGeneratedTypes}}
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class {{nameof(AssemblyExtendedEnumTypeAttribute)}} : System.Attribute
{
/// <summary>Creates a new instance of <see cref="AssemblyExtendedEnumTypeAttribute" /> from the provided parameters.</summary>
/// <param name="enumType">The <see cref="System.Type" /> of an <see langword="enum" /> decorated with a <see cref="GenerateEnumExtensionMethodsAttribute" />.</param>
/// <param name="extensionClass">The <see cref="System.Type" /> of the <see langword="class" /> decorated with an <see cref="ExtensionsForEnumTypeAttribute{TEnum}" /> referring to the same type as <paramref name="enumType" />.</param>
public AssemblyExtendedEnumTypeAttribute (System.Type enumType, System.Type extensionClass)
{
EnumType = enumType;
ExtensionClass = extensionClass;
}
/// <summary>An <see langword="enum" /> type that has been extended by Terminal.Gui source generators.</summary>
public System.Type EnumType { get; init; }
/// <summary>A class containing extension methods for <see cref="EnumType"/>.</summary>
public System.Type ExtensionClass { get; init; }
/// <inheritdoc />
public override string ToString () => $"{EnumType.Name},{ExtensionClass.Name}";
}
""",
Encoding.UTF8));
postInitializationContext
.AddSource (
$"{GeneratorAttributeFullyQualifiedName}.g.cs",
SourceText.From (
$$"""
{{Strings.Templates.StandardHeader}}
namespace {{Strings.AnalyzersAttributesNamespace}};
/// <summary>
/// Used to enable source generation of a common set of extension methods for enum types.
/// </summary>
{{Strings.Templates.AttributesForGeneratedTypes}}
[{{Strings.DotnetNames.Types.AttributeUsageAttribute}} ({{Strings.DotnetNames.Types.AttributeTargets}}.Enum)]
public sealed class {{GeneratorAttributeName}} : {{Strings.DotnetNames.Types.Attribute}}
{
/// <summary>
/// The name of the generated static class.
/// </summary>
/// <remarks>
/// If unspecified, null, empty, or only whitespace, defaults to the name of the enum plus "Extensions".<br/>
/// No other validation is performed, so illegal values will simply result in compiler errors.
/// <para>
/// Explicitly specifying a default value is unnecessary and will result in unnecessary processing.
/// </para>
/// </remarks>
public string? ClassName { get; set; }
/// <summary>
/// The namespace in which to place the generated static class containing the extension methods.
/// </summary>
/// <remarks>
/// If unspecified, null, empty, or only whitespace, defaults to the namespace of the enum.<br/>
/// No other validation is performed, so illegal values will simply result in compiler errors.
/// <para>
/// Explicitly specifying a default value is unnecessary and will result in unnecessary processing.
/// </para>
/// </remarks>
public string? ClassNamespace { get; set; }
/// <summary>
/// Whether to generate a fast, zero-allocation, non-boxing, and reflection-free alternative to the built-in
/// <see cref="Enum.HasFlag"/> method.
/// </summary>
/// <remarks>
/// <para>
/// Default: false
/// </para>
/// <para>
/// If the enum is not decorated with <see cref="Flags"/>, this option has no effect.
/// </para>
/// <para>
/// If multiple members have the same value, the first member with that value will be used and subsequent members
/// with the same value will be skipped.
/// </para>
/// <para>
/// Overloads taking the enum type itself as well as the underlying type of the enum will be generated, enabling
/// avoidance of implicit or explicit cast overhead.
/// </para>
/// <para>
/// Explicitly specifying a default value is unnecessary and will result in unnecessary processing.
/// </para>
/// </remarks>
public bool FastHasFlags { get; set; }
/// <summary>
/// Whether to generate a fast, zero-allocation, and reflection-free alternative to the built-in
/// <see cref="Enum.IsDefined"/> method,
/// using a switch expression as a hard-coded reverse mapping of numeric values to explicitly-named members.
/// </summary>
/// <remarks>
/// <para>
/// Default: true
/// </para>
/// <para>
/// If multiple members have the same value, the first member with that value will be used and subsequent members
/// with the same value will be skipped.
/// </para>
/// <para>
/// As with <see cref="Enum.IsDefined"/> the source generator only considers explicitly-named members.<br/>
/// Generation of values which represent valid bitwise combinations of members of enums decorated with
/// <see cref="Flags"/> is not affected by this property.
/// </para>
/// </remarks>
public bool FastIsDefined { get; init; } = true;
/// <summary>
/// Gets a <see langword="bool"/> value indicating if this <see cref="GenerateEnumExtensionMethodsAttribute"/> instance
/// contains default values only. See <see href="#remarks">remarks</see> of this method or documentation on properties of this type for details.
/// </summary>
/// <returns>
/// A <see langword="bool"/> value indicating if all property values are default for this
/// <see cref="GenerateEnumExtensionMethodsAttribute"/> instance.
/// </returns>
/// <remarks>
/// Default values that will result in a <see langword="true"/> return value are:<br/>
/// <see cref="FastIsDefined"/> &amp;&amp; !<see cref="FastHasFlags"/> &amp;&amp; <see cref="ClassName"/>
/// <see langword="is"/> <see langword="null"/> &amp;&amp; <see cref="ClassNamespace"/> <see langword="is"/>
/// <see langword="null"/>
/// </remarks>
public override bool IsDefaultAttribute ()
{
return FastIsDefined
&& !FastHasFlags
&& ClassName is null
&& ClassNamespace is null;
}
}
""",
Encoding.UTF8));
postInitializationContext
.AddSource (
$"{ExtensionsForEnumTypeAttributeFullyQualifiedName}.g.cs",
SourceText.From (
$$"""
// ReSharper disable RedundantNameQualifier
// ReSharper disable RedundantNullableDirective
// ReSharper disable UnusedType.Global
{{Strings.Templates.AutoGeneratedCommentBlock}}
#nullable enable
namespace {{Strings.AnalyzersAttributesNamespace}};
/// <summary>
/// Attribute written by the source generator for enum extension classes, for easier analysis and reflection.
/// </summary>
/// <remarks>
/// Properties are just convenient shortcuts to properties of <typeparamref name="TEnum"/>.
/// </remarks>
{{Strings.Templates.AttributesForGeneratedTypes}}
[System.AttributeUsageAttribute (System.AttributeTargets.Class | System.AttributeTargets.Interface)]
public sealed class {{ExtensionsForEnumTypeAttributeName}}<TEnum>: System.Attribute, IExtensionsForEnumTypeAttributes where TEnum : struct, Enum
{
/// <summary>
/// The namespace-qualified name of <typeparamref name="TEnum"/>.
/// </summary>
public string EnumFullName => EnumType.FullName!;
/// <summary>
/// The unqualified name of <typeparamref name="TEnum"/>.
/// </summary>
public string EnumName => EnumType.Name;
/// <summary>
/// The namespace containing <typeparamref name="TEnum"/>.
/// </summary>
public string EnumNamespace => EnumType.Namespace!;
/// <summary>
/// The <see cref="Type"/> given by <see langword="typeof"/>(<typeparamref name="TEnum"/>).
/// </summary>
public Type EnumType => typeof (TEnum);
}
""",
Encoding.UTF8));
}
[SuppressMessage ("Roslynator", "RCS1267", Justification = "Intentionally used so that Spans are used.")]
private static void GenerateDummyNamespaces (IncrementalGeneratorPostInitializationContext postInitializeContext)
{
postInitializeContext.AddSource (
string.Concat (Strings.InternalAnalyzersNamespace, "Namespaces.g.cs"),
SourceText.From (Strings.Templates.DummyNamespaceDeclarations, Encoding.UTF8));
}
private static void GenerateSourceFromGenerationInfo (SourceProductionContext context, EnumExtensionMethodsGenerationInfo? enumInfo)
{
// Just in case we still made it this far with a null...
if (enumInfo is not { })
{
return;
}
CodeWriter writer = new (enumInfo);
context.AddSource ($"{enumInfo.FullyQualifiedClassName}.g.cs", writer.GenerateSourceText ());
}
/// <summary>
/// Returns true if <paramref name="syntaxNode"/> is an EnumDeclarationSyntax
/// whose parent is a NamespaceDeclarationSyntax, FileScopedNamespaceDeclarationSyntax, or a
/// (Class|Struct)DeclarationSyntax.<br/>
/// Additional filtering is performed in later stages.
/// </summary>
private static bool IsPotentiallyInterestingDeclaration (SyntaxNode syntaxNode, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested ();
return syntaxNode is
{
RawKind: 8858, //(int)SyntaxKind.EnumDeclaration,
Parent.RawKind: 8845 //(int)SyntaxKind.FileScopedNamespaceDeclaration
or 8842 //(int)SyntaxKind.NamespaceDeclaration
or 8855 //(int)SyntaxKind.ClassDeclaration
or 8856 //(int)SyntaxKind.StructDeclaration
or 9068 //(int)SyntaxKind.RecordStructDeclaration
or 9063 //(int)SyntaxKind.RecordDeclaration
};
}
}

View File

@@ -1,3 +0,0 @@
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage ("Naming", "CA1708:Names should differ by more than case", Scope = "module", Justification = "That's coming from an external generator.")]

View File

@@ -1,38 +0,0 @@
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
namespace Terminal.Gui.Analyzers.Internal;
/// <summary>
/// Interface for all generators to use for their metadata classes.
/// </summary>
/// <typeparam name="TSelf">The type implementing this interface.</typeparam>
internal interface IGeneratedTypeMetadata<out TSelf> where TSelf : IGeneratedTypeMetadata<TSelf>
{
[UsedImplicitly]
string GeneratedTypeNamespace { get; }
[UsedImplicitly]
string? GeneratedTypeName { get; }
[UsedImplicitly]
string GeneratedTypeFullName { get; }
[UsedImplicitly]
string TargetTypeNamespace { get; }
[UsedImplicitly]
string TargetTypeName { get; }
string TargetTypeFullName { get; }
[UsedImplicitly]
Accessibility Accessibility { get; }
TypeKind TypeKind { get; }
bool IsRecord { get; }
bool IsClass { get; }
bool IsStruct { get; }
[UsedImplicitly]
bool IsPartial { get; }
bool IsByRefLike { get; }
bool IsSealed { get; }
bool IsAbstract { get; }
bool IsEnum { get; }
bool IsStatic { get; }
[UsedImplicitly]
bool IncludeInterface { get; }
}

View File

@@ -1,28 +0,0 @@
using System.Text;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis.Text;
namespace Terminal.Gui.Analyzers.Internal;
internal interface IStandardCSharpCodeGenerator<T> where T : IGeneratedTypeMetadata<T>
{
/// <summary>
/// Generates and returns the full source text corresponding to <see cref="Metadata"/>,
/// in the requested <paramref name="encoding"/> or <see cref="Encoding.UTF8"/> if not provided.
/// </summary>
/// <param name="encoding">
/// The <see cref="Encoding"/> of the generated source text or <see cref="Encoding.UTF8"/> if not
/// provided.
/// </param>
/// <returns></returns>
[UsedImplicitly]
[SkipLocalsInit]
ref readonly SourceText GenerateSourceText (Encoding? encoding = null);
/// <summary>
/// A type implementing <see cref="IGeneratedTypeMetadata{T}"/> which
/// will be used for source generation.
/// </summary>
[UsedImplicitly]
T Metadata { get; set; }
}

View File

@@ -1,71 +0,0 @@
using System.CodeDom.Compiler;
namespace Terminal.Gui.Analyzers.Internal;
/// <summary>
/// Just a simple set of extension methods to increment and decrement the indentation
/// level of an <see cref="IndentedTextWriter"/> via push and pop terms, and to avoid having
/// explicit values all over the place.
/// </summary>
public static class IndentedTextWriterExtensions
{
/// <summary>
/// Decrements <see cref="IndentedTextWriter.Indent"/> by 1, but only if it is greater than 0.
/// </summary>
/// <returns>
/// The resulting indentation level of the <see cref="IndentedTextWriter"/>.
/// </returns>
[MethodImpl (MethodImplOptions.AggressiveInlining)]
public static int Pop (this IndentedTextWriter w, string endScopeDelimiter = "}")
{
if (w.Indent > 0)
{
w.Indent--;
w.WriteLine (endScopeDelimiter);
}
return w.Indent;
}
/// <summary>
/// Decrements <see cref="IndentedTextWriter.Indent"/> by 1 and then writes a closing curly brace.
/// </summary>
[MethodImpl (MethodImplOptions.AggressiveInlining)]
public static void PopCurly (this IndentedTextWriter w, bool withSemicolon = false)
{
w.Indent--;
if (withSemicolon)
{
w.WriteLine ("};");
}
else
{
w.WriteLine ('}');
}
}
/// <summary>
/// Increments <see cref="IndentedTextWriter.Indent"/> by 1, with optional parameters to customize the scope push.
/// </summary>
/// <param name="w">An instance of an <see cref="IndentedTextWriter"/>.</param>
/// <param name="declaration">
/// The first line to be written before indenting and before the optional <paramref name="scopeDelimiter"/> line or
/// null if not needed.
/// </param>
/// <param name="scopeDelimiter">
/// An opening delimiter to write. Written before the indentation and after <paramref name="declaration"/> (if provided). Default is an opening curly brace.
/// </param>
/// <remarks>Calling with no parameters will write an opening curly brace and a line break at the current indentation and then increment.</remarks>
[MethodImpl (MethodImplOptions.AggressiveInlining)]
public static void Push (this IndentedTextWriter w, string? declaration = null, char scopeDelimiter = '{')
{
if (declaration is { Length: > 0 })
{
w.WriteLine (declaration);
}
w.WriteLine (scopeDelimiter);
w.Indent++;
}
}

View File

@@ -1,8 +0,0 @@
{
"profiles": {
"InternalAnalyzers Debug": {
"commandName": "DebugRoslynComponent",
"targetProject": "..\\Terminal.Gui.Analyzers.Internal.Debugging\\Terminal.Gui.Analyzers.Internal.Debugging.csproj"
}
}
}

View File

@@ -1,67 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!--
Do not remove netstandard2.0 from the TargetFramework.
Visual Studio requires that Analyzers/Generators target netstandard2.0 to work properly.
Also do not change this to TargetFrameworks without fully understanding the behavior change that implies.
-->
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<OutputType>Library</OutputType>
<LangVersion>12</LangVersion>
<RootNamespace>Terminal.Gui.Analyzers.Internal</RootNamespace>
<ImplicitUsings>disable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<CodeAnalysisIgnoreGeneratedCode>true</CodeAnalysisIgnoreGeneratedCode>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<IsRoslynComponent>true</IsRoslynComponent>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
</PropertyGroup>
<ItemGroup>
<ApiCompatExcludeAttributesFile Include="ApiCompatExcludedAttributes.txt" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Compatibility/*.cs" />
</ItemGroup>
<PropertyGroup>
<!-- Disabling some useless warnings caused by the netstandard2.0 target -->
<NoWarn>$(NoWarn);nullable;CA1067</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Include="Compatibility/IEqualityOperators.cs" />
<Compile Include="Compatibility/NumericExtensions.cs" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="AnalyzerReleases.Unshipped.md" />
<AdditionalFiles Include="AnalyzerReleases.Shipped.md" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Meziantou.Polyfill" Version="1.0.39" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" PrivateAssets="all" />
<PackageReference Include="Roslynator.Analyzers" Version="4.12.4" PrivateAssets="all" />
<PackageReference Include="Roslynator.CodeAnalysis.Analyzers" Version="4.12.4" PrivateAssets="all" />
<PackageReference Include="Roslynator.CSharp" Version="4.12.4" PrivateAssets="all" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" PrivateAssets="all" />
<PackageReference Include="System.Runtime.Extensions" Version="4.3.1" PrivateAssets="all" />
<PackageReference Include="System.Runtime.Numerics" Version="4.3.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="JetBrains.Annotations" Version="2024.2.0" />
</ItemGroup>
</Project>

View File

@@ -1,4 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp120</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/UsageCheckingInspectionLevel/@EntryValue">InternalsOnly</s:String>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=compatibility/@EntryIndexedValue">False</s:Boolean></wpf:ResourceDictionary>