-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
dbc6018
commit 106e493
Showing
5 changed files
with
178 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
|
||
/// <summary> | ||
/// Generator which generates a property containing an enum's values. | ||
/// </summary> | ||
[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<MemberDeclarationSyntax>( | ||
PropertyDeclaration( | ||
ArrayType( | ||
IdentifierName(enumIdentifier) | ||
) | ||
.WithRankSpecifiers( | ||
SingletonList( | ||
ArrayRankSpecifier( | ||
SingletonSeparatedList<ExpressionSyntax>( | ||
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<ExpressionSyntax>(enumMembers) | ||
) | ||
) | ||
).WithSemicolonToken( | ||
Token(SyntaxKind.SemicolonToken) | ||
) | ||
) | ||
) | ||
).NormalizeWhitespace() | ||
.GetText(Encoding.UTF8); | ||
var hintName = enumDeclaration.GetHintName(@namespace); | ||
|
||
return new GeneratorResult(hintName, sourceText); | ||
} | ||
|
||
private static IEnumerable<SyntaxNodeOrToken> GetEnumMemberAccessExpressions(SyntaxToken enumIdentifier, SeparatedSyntaxList<EnumMemberDeclarationSyntax> enumMembers) | ||
{ | ||
foreach (var enumMember in enumMembers) | ||
{ | ||
yield return MemberAccessExpression( | ||
SyntaxKind.SimpleMemberAccessExpression, | ||
IdentifierName(enumIdentifier), | ||
IdentifierName(enumMember.Identifier) | ||
); | ||
yield return Token(SyntaxKind.CommaToken); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters