diff --git a/Lombok.NET.Test/EnumValuesTest.cs b/Lombok.NET.Test/EnumValuesTest.cs
new file mode 100644
index 0000000..bc2529a
--- /dev/null
+++ b/Lombok.NET.Test/EnumValuesTest.cs
@@ -0,0 +1,22 @@
+using Xunit;
+
+namespace Lombok.NET.Test;
+
+public sealed class EnumValuesTest
+{
+ [Fact]
+ public void Test()
+ {
+ var values = MyEnumValues.Values;
+ Assert.Equal(3, values.Length);
+ Assert.Equal(MyEnum.One, values[0]);
+ Assert.Equal(MyEnum.Two, values[1]);
+ Assert.Equal(MyEnum.Three, values[2]);
+ }
+}
+
+[EnumValues]
+public enum MyEnum
+{
+ One, Two, Three
+}
\ No newline at end of file
diff --git a/Lombok.NET.Test/Lombok.NET.Test.csproj b/Lombok.NET.Test/Lombok.NET.Test.csproj
index 368e2d1..50d0a0d 100644
--- a/Lombok.NET.Test/Lombok.NET.Test.csproj
+++ b/Lombok.NET.Test/Lombok.NET.Test.csproj
@@ -10,10 +10,13 @@
-
-
+
+
-
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/Lombok.NET/Extensions/SyntaxNodeExtensions.cs b/Lombok.NET/Extensions/SyntaxNodeExtensions.cs
index 4061941..a3f4ffd 100644
--- a/Lombok.NET/Extensions/SyntaxNodeExtensions.cs
+++ b/Lombok.NET/Extensions/SyntaxNodeExtensions.cs
@@ -234,7 +234,7 @@ public static bool IsVoid(this TypeSyntax typeSyntax)
///
/// The type to check.
/// True, if the type is declared within another type.
- public static bool IsNestedType(this TypeDeclarationSyntax typeDeclaration)
+ public static bool IsNestedType(this BaseTypeDeclarationSyntax typeDeclaration)
{
return typeDeclaration.Parent is TypeDeclarationSyntax;
}
@@ -311,7 +311,7 @@ public static IEnumerable Where(this IEnumerable members, AccessTypes a
/// The type to get the name for
/// The namespace which will be prepended to the type using underscores.
/// A unique name for the type inside a generator context.
- public static string GetHintName(this TypeDeclarationSyntax type, NameSyntax @namespace)
+ public static string GetHintName(this BaseTypeDeclarationSyntax type, NameSyntax @namespace)
{
return string.Concat(@namespace.ToString().Replace('.', '_'), '_', type.Identifier.Text);
}
diff --git a/Lombok.NET/PropertyGenerators/EnumValuesGenerator.cs b/Lombok.NET/PropertyGenerators/EnumValuesGenerator.cs
new file mode 100644
index 0000000..e1e49ad
--- /dev/null
+++ b/Lombok.NET/PropertyGenerators/EnumValuesGenerator.cs
@@ -0,0 +1,136 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using Lombok.NET.Analyzers;
+using Lombok.NET.Extensions;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
+
+#if DEBUG
+using System.Diagnostics;
+#endif
+
+namespace Lombok.NET.PropertyGenerators;
+
+///
+/// Generator which generates a property containing an enum's values.
+///
+[Generator]
+internal sealed class EnumValuesGenerator : IIncrementalGenerator
+{
+ private static readonly string AttributeName = typeof(EnumValuesAttribute).FullName;
+
+ public void Initialize(IncrementalGeneratorInitializationContext context)
+ {
+#if DEBUG
+ SpinWait.SpinUntil(static () => Debugger.IsAttached);
+#endif
+ var sources = context.SyntaxProvider.ForAttributeWithMetadataName(AttributeName, IsCandidate, Transform);
+ context.AddSources(sources);
+ }
+
+ private static bool IsCandidate(SyntaxNode node, CancellationToken cancellationToken)
+ {
+ return node is EnumDeclarationSyntax;
+ }
+
+ private static GeneratorResult Transform(GeneratorAttributeSyntaxContext context, CancellationToken cancellationToken)
+ {
+ var enumDeclaration = (EnumDeclarationSyntax)context.TargetNode;
+ var @namespace = enumDeclaration.GetNamespace();
+ if (@namespace is null)
+ {
+ var diagnostic = Diagnostic.Create(DiagnosticDescriptors.TypeMustHaveNamespace, enumDeclaration.GetLocation(), enumDeclaration.Identifier.Text);
+
+ return new GeneratorResult(diagnostic);
+ }
+
+ if (enumDeclaration.IsNestedType())
+ {
+ var diagnostic = Diagnostic.Create(DiagnosticDescriptors.TypeMustBeNonNested, enumDeclaration.GetLocation(), enumDeclaration.Identifier.Text);
+
+ return new GeneratorResult(diagnostic);
+ }
+
+ var enumIdentifier = enumDeclaration.Identifier;
+ var valuesClassName = context.Attributes[0].NamedArguments.FirstOrDefault(kv => kv.Key == nameof(EnumValuesAttribute.TypeName)).Value.Value as string
+ ?? enumIdentifier.Text + "Values";
+
+ var enumMembers = GetEnumMemberAccessExpressions(enumIdentifier, enumDeclaration.Members);
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var sourceText = @namespace.CreateNewNamespace(
+ default,
+ ClassDeclaration(valuesClassName)
+ .WithModifiers(
+ TokenList(
+ Token(enumDeclaration.GetAccessibilityModifier()),
+ Token(SyntaxKind.StaticKeyword)
+ )
+ ).WithMembers(
+ SingletonList(
+ PropertyDeclaration(
+ ArrayType(
+ IdentifierName(enumIdentifier)
+ )
+ .WithRankSpecifiers(
+ SingletonList(
+ ArrayRankSpecifier(
+ SingletonSeparatedList(
+ OmittedArraySizeExpression()
+ )
+ )
+ )
+ ),
+ Identifier("Values")
+ ).WithModifiers(
+ TokenList(
+ Token(SyntaxKind.PublicKeyword),
+ Token(SyntaxKind.StaticKeyword))
+ ).WithAccessorList(
+ AccessorList(
+ SingletonList(
+ AccessorDeclaration(
+ SyntaxKind.GetAccessorDeclaration
+ )
+ .WithSemicolonToken(
+ Token(SyntaxKind.SemicolonToken)
+ )
+ )
+ )
+ ).WithInitializer(
+ EqualsValueClause(
+ InitializerExpression(
+ SyntaxKind.ArrayInitializerExpression,
+ SeparatedList(enumMembers)
+ )
+ )
+ ).WithSemicolonToken(
+ Token(SyntaxKind.SemicolonToken)
+ )
+ )
+ )
+ ).NormalizeWhitespace()
+ .GetText(Encoding.UTF8);
+ var hintName = enumDeclaration.GetHintName(@namespace);
+
+ return new GeneratorResult(hintName, sourceText);
+ }
+
+ private static IEnumerable GetEnumMemberAccessExpressions(SyntaxToken enumIdentifier, SeparatedSyntaxList enumMembers)
+ {
+ foreach (var enumMember in enumMembers)
+ {
+ yield return MemberAccessExpression(
+ SyntaxKind.SimpleMemberAccessExpression,
+ IdentifierName(enumIdentifier),
+ IdentifierName(enumMember.Identifier)
+ );
+ yield return Token(SyntaxKind.CommaToken);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Lombok.NET/SourceGeneratorAttributes.cs b/Lombok.NET/SourceGeneratorAttributes.cs
index 9639c65..4a62d60 100644
--- a/Lombok.NET/SourceGeneratorAttributes.cs
+++ b/Lombok.NET/SourceGeneratorAttributes.cs
@@ -175,6 +175,18 @@ public sealed class FreezableAttribute : Attribute
public bool IsUnfreezable { get; set; } = true;
}
+///
+/// Tells Lombok.NET to generate a static class with a property which returns all of the enum's values.
+///
+[AttributeUsage(AttributeTargets.Enum)]
+public sealed class EnumValuesAttribute : Attribute
+{
+ ///
+ /// When specified, allows to override the name of the static class which is generated, in order to avoid name collisions. Defaults to the enum's name + "Values"
+ ///
+ public string TypeName { get; set; } = default!;
+}
+
///
/// The kind of members which Lombok.NET supports.
///