Skip to content

Commit

Permalink
Updated to incremental source generator
Browse files Browse the repository at this point in the history
  • Loading branch information
VNNCC committed Nov 13, 2024
1 parent 770a291 commit dd45d6d
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 60 deletions.
102 changes: 45 additions & 57 deletions src/EnumsEnhanced/EnumsEnhanced.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Globalization;
using System.Collections.Immutable;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text;
using Microsoft.CodeAnalysis;
Expand All @@ -7,7 +8,7 @@
namespace EnumsEnhanced;

[Generator]
internal class EnumsEnhanced : ISourceGenerator
internal class EnumsEnhanced : IIncrementalGenerator
{
public static readonly DiagnosticDescriptor UnderylingEnumerationTypeNotFound
= new("EE001",

Check warning on line 14 in src/EnumsEnhanced/EnumsEnhanced.cs

View workflow job for this annotation

GitHub Actions / build

Enable analyzer release tracking for the analyzer project containing rule 'EE001' (https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md)

Check warning on line 14 in src/EnumsEnhanced/EnumsEnhanced.cs

View workflow job for this annotation

GitHub Actions / build

Enable analyzer release tracking for the analyzer project containing rule 'EE001' (https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md)

Check warning on line 14 in src/EnumsEnhanced/EnumsEnhanced.cs

View workflow job for this annotation

GitHub Actions / build

Enable analyzer release tracking for the analyzer project containing rule 'EE001' (https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md)

Check warning on line 14 in src/EnumsEnhanced/EnumsEnhanced.cs

View workflow job for this annotation

GitHub Actions / build

Enable analyzer release tracking for the analyzer project containing rule 'EE001' (https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md)
Expand All @@ -17,7 +18,43 @@ public static readonly DiagnosticDescriptor UnderylingEnumerationTypeNotFound
DiagnosticSeverity.Error,
true);

private void GenerateEnumMethods(GeneratorExecutionContext context, EnumDeclarationSyntax enumDeclarationSyntax, INamedTypeSymbol enumSymbol, ISymbol[] memberSymbols, StringBuilder methodSb)
/// <inheritdoc/>
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var enumDeclarationsProvider = context.SyntaxProvider.CreateSyntaxProvider(
static (n, _) => n is EnumDeclarationSyntax,
static (n, _) => ((INamedTypeSymbol)n.SemanticModel.GetDeclaredSymbol(n.Node)!, (EnumDeclarationSyntax)n.Node)
);

context.RegisterSourceOutput(enumDeclarationsProvider.Collect(), static (sourceProductionContext, enumDeclarations) =>
{
foreach (var pair in enumDeclarations)
{
var symbol = pair.Item1;
var eds = pair.Item2;

if (symbol.ContainingType != null)
continue;

var membersSymbols = symbol
.GetMembers()
.Where(x => x is IFieldSymbol)
.Cast<IFieldSymbol>()
.ToImmutableArray();

var sb = new StringBuilder();

GenerateEnumMethods(sourceProductionContext, eds, symbol, membersSymbols, sb);

string classCode = GetClassTemplate(eds, symbol, out string? className)
.Replace("{CLASS_BODY}", sb.ToString());

sourceProductionContext.AddSource($"{className}.g.cs", classCode.Trim());
}
});
}

private static void GenerateEnumMethods(SourceProductionContext sourceProductionContext, EnumDeclarationSyntax enumDeclarationSyntax, INamedTypeSymbol enumSymbol, IList<IFieldSymbol> memberSymbols, StringBuilder methodSb)
{
var methodImplAttributeText = new StringBuilder();
methodImplAttributeText.AppendLine("#if NETCOREAPP3_0_OR_GREATER");
Expand All @@ -32,7 +69,7 @@ private void GenerateEnumMethods(GeneratorExecutionContext context, EnumDeclarat

if (enumUnderlyingType == null)
{
context.ReportDiagnostic(
sourceProductionContext.ReportDiagnostic(
Diagnostic.Create(UnderylingEnumerationTypeNotFound,
enumDeclarationSyntax.Identifier.GetLocation(),
enumDeclarationSyntax.Identifier.ToString()));
Expand Down Expand Up @@ -149,7 +186,7 @@ string GetUnsafeHasFlagReturnStatement()

var switchCasesValue = new StringBuilder();

foreach (var member in memberSymbols.OrderBy(x => x.Name.Length).Cast<IFieldSymbol>())
foreach (var member in memberSymbols.OrderBy(x => x.Name.Length))
{
string memberRef = $"{enumSymbol.Name}.{member.Name}";

Expand Down Expand Up @@ -223,9 +260,9 @@ string GetUnsafeHasFlagReturnStatement()

const string separator = $", ";

for (int i = 0; i < memberSymbols.Length; i++)
for (int i = 0; i < memberSymbols.Count; i++)
{
var member = (IFieldSymbol)memberSymbols[i];
var member = memberSymbols[i];
string memberRef = $"{enumSymbol.Name}.{member.Name}";

if (member.HasConstantValue)
Expand Down Expand Up @@ -450,7 +487,7 @@ string GetUnsafeHasFlagReturnStatement()
}
}

private string GetClassTemplate(EnumDeclarationSyntax eds, ISymbol enumSymbol, out string className)
private static string GetClassTemplate(EnumDeclarationSyntax eds, ISymbol enumSymbol, out string className)
{
className = $"{enumSymbol.Name}Enhanced";

Expand Down Expand Up @@ -488,55 +525,6 @@ static string AccessibilityToAccessModifier(Accessibility accessibility)
};
}
}

/// <inheritdoc/>
public void Execute(GeneratorExecutionContext context)
{
if (context.SyntaxReceiver is not ServiceNotifications receiver || receiver.DeclaredEnums.Count == 0)
return;

for (int i = 0; i < receiver.DeclaredEnums.Count; i++)
{
var eds = receiver.DeclaredEnums[i];

try
{
var semanticModel = context.Compilation.GetSemanticModel(eds.SyntaxTree);

if (semanticModel == null)
continue;

if (semanticModel.GetDeclaredSymbol(eds) is not INamedTypeSymbol symbol)
return;

if (symbol.ContainingType != null)
continue;

var membersSymbols = new ISymbol[eds.Members.Count];

for (int j = 0; j < eds.Members.Count; j++)
membersSymbols[j] = semanticModel.GetDeclaredSymbol(eds.Members[j])!;

var sb = new StringBuilder();

GenerateEnumMethods(context, eds, symbol, membersSymbols, sb);

string classCode = GetClassTemplate(eds, symbol, out string? className)
.Replace("{CLASS_BODY}", sb.ToString());

context.AddSource($"{className}.g.cs", classCode.Trim());
}
catch
{
}
}
}

/// <inheritdoc/>
public void Initialize(GeneratorInitializationContext context)
{
context.RegisterForSyntaxNotifications(() => new ServiceNotifications());
}
}

internal class ServiceNotifications : ISyntaxReceiver
Expand Down
2 changes: 1 addition & 1 deletion src/EnumsEnhanced/EnumsEnhanced.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
4 changes: 2 additions & 2 deletions src/Tests/EnumsEnhancedTest/EnumsEnhancedTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
<PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
Expand Down

0 comments on commit dd45d6d

Please sign in to comment.