refactor(generators): 重构枚举扩展生成器基类实现

- 将 EnumExtensionsGenerator 的基类从 MetadataAttributeClassGeneratorBase 改为 AttributeEnumGeneratorBase
- 修改 AttributeMetadataName 为静态私有字段
- 重写 ResolveAttribute 方法用于解析属性数据
- 更新 ValidateSymbol 方法参数类型为 EnumDeclarationSyntax
- 调整命名空间生成逻辑,简化条件判断
- 重构 AttributeEnumGeneratorBase 基类实现
- 添加 ResolveAttribute 抽象方法用于属性解析
- 改进 Initialize 方法中的语法提供程序逻辑
- 添加 GetHintName 虚方法用于生成文件名提示
This commit is contained in:
GwWuYou 2025-12-28 17:13:07 +08:00
parent 539d285faa
commit 75dfb0a942
3 changed files with 100 additions and 68 deletions

View File

@ -1,21 +1,16 @@
using System;
using System.Linq;
using System.Text;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
namespace GFramework.SourceGenerators.Common.generator;
/// <summary>
/// 基于特性的枚举生成器基类
/// 属性枚举生成器基类,用于基于特定属性的枚举进行源代码生成
/// </summary>
/// <typeparam name="TAttribute">特性类型必须继承自Attribute</typeparam>
public abstract class AttributeEnumGeneratorBase<TAttribute> : IIncrementalGenerator
where TAttribute : Attribute
public abstract class AttributeEnumGeneratorBase : IIncrementalGenerator
{
/// <summary>
/// 获取性的短名称(不包含后缀)
/// 获取性的短名称(不包含后缀)
/// </summary>
protected abstract string AttributeShortNameWithoutSuffix { get; }
@ -25,35 +20,83 @@ public abstract class AttributeEnumGeneratorBase<TAttribute> : IIncrementalGener
/// <param name="context">增量生成器初始化上下文</param>
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 查找带有指定特性的枚举声明
var enums = context.SyntaxProvider.CreateSyntaxProvider(
(node, _) => node is EnumDeclarationSyntax decl &&
decl.AttributeLists.SelectMany(a => a.Attributes)
.Any(a => a.Name.ToString().Contains(AttributeShortNameWithoutSuffix)),
(ctx, _) =>
{
var decl = (EnumDeclarationSyntax)ctx.Node;
var symbol = ctx.SemanticModel.GetDeclaredSymbol(decl) as INamedTypeSymbol;
return (decl, symbol);
}).Where(x => x.symbol != null);
// 创建语法提供程序,查找带有指定属性的枚举声明
var candidates = context.SyntaxProvider.CreateSyntaxProvider(
(node, _) =>
node is EnumDeclarationSyntax eds &&
eds.AttributeLists
.SelectMany(a => a.Attributes)
.Any(a => a.Name.ToString()
.Contains(AttributeShortNameWithoutSuffix)),
(ctx, _) =>
{
var syntax = (EnumDeclarationSyntax)ctx.Node;
var symbol = ctx.SemanticModel.GetDeclaredSymbol(syntax, cancellationToken: _) as INamedTypeSymbol;
return (syntax, symbol);
})
.Where(x => x.symbol is not null);
// 注册源代码输出
context.RegisterSourceOutput(enums, (spc, pair) =>
var combined = candidates.Combine(context.CompilationProvider);
// 注册源输出,生成最终的源代码
context.RegisterSourceOutput(combined, (spc, pair) =>
{
var attr = pair.symbol!.GetAttributes()
.FirstOrDefault(a => a.AttributeClass?.ToDisplayString() == typeof(TAttribute).FullName);
if (attr == null) return;
var ((syntax, symbol), compilation) = pair;
var src = Generate(pair.symbol!, attr);
spc.AddSource($"{pair.symbol!.Name}.EnumExtensions.g.cs", SourceText.From(src, Encoding.UTF8));
var attr = ResolveAttribute(compilation, symbol!);
if (attr is null)
return;
if (!ValidateSymbol(spc, compilation, syntax, symbol!, attr))
return;
spc.AddSource(
GetHintName(symbol!),
Generate(symbol!, attr));
});
}
/// <summary>
/// 解析指定符号上的属性数据
/// </summary>
/// <param name="compilation">编译对象</param>
/// <param name="symbol">命名类型符号</param>
/// <returns>属性数据对象如果未找到则返回null</returns>
protected abstract AttributeData? ResolveAttribute(
Compilation compilation,
INamedTypeSymbol symbol);
/// <summary>
/// 验证符号是否符合生成要求
/// </summary>
/// <param name="context">源生产上下文</param>
/// <param name="compilation">编译对象</param>
/// <param name="syntax">枚举声明语法节点</param>
/// <param name="symbol">命名类型符号</param>
/// <param name="attr">属性数据</param>
/// <returns>验证是否通过</returns>
protected abstract bool ValidateSymbol(
SourceProductionContext context,
Compilation compilation,
EnumDeclarationSyntax syntax,
INamedTypeSymbol symbol,
AttributeData attr);
/// <summary>
/// 生成源代码
/// </summary>
/// <param name="enumSymbol">枚举符号</param>
/// <param name="attr">特性数据</param>
/// <param name="symbol">命名类型符号</param>
/// <param name="attr">性数据</param>
/// <returns>生成的源代码字符串</returns>
protected abstract string Generate(INamedTypeSymbol enumSymbol, AttributeData attr);
protected abstract string Generate(
INamedTypeSymbol symbol,
AttributeData attr);
/// <summary>
/// 获取生成文件的提示名称
/// </summary>
/// <param name="symbol">命名类型符号</param>
/// <returns>生成文件的提示名称</returns>
protected virtual string GetHintName(INamedTypeSymbol symbol)
=> $"{symbol.Name}.g.cs";
}

View File

@ -12,9 +12,9 @@ namespace GFramework.SourceGenerators.enums;
/// 枚举扩展方法生成器,用于自动生成枚举相关的扩展方法
/// </summary>
[Generator]
public sealed class EnumExtensionsGenerator : MetadataAttributeClassGeneratorBase
public sealed class EnumExtensionsGenerator : AttributeEnumGeneratorBase
{
protected override string AttributeMetadataName =>
private static string AttributeMetadataName =>
$"{PathContests.SourceGeneratorsAbstractionsPath}.enums.GenerateEnumExtensionsAttribute";
/// <summary>
@ -22,34 +22,30 @@ public sealed class EnumExtensionsGenerator : MetadataAttributeClassGeneratorBas
/// </summary>
protected override string AttributeShortNameWithoutSuffix => "GenerateEnumExtensions";
/// <summary>
/// 验证符号是否为有效的枚举类型
/// </summary>
/// <param name="context">源生产上下文</param>
/// <param name="compilation">编译对象</param>
/// <param name="syntax">类声明语法节点</param>
/// <param name="symbol">命名类型符号</param>
/// <param name="attr">属性数据</param>
/// <returns>验证是否通过</returns>
protected override bool ValidateSymbol(
SourceProductionContext context,
Compilation compilation,
ClassDeclarationSyntax syntax,
INamedTypeSymbol symbol,
AttributeData attr)
protected override AttributeData? ResolveAttribute(Compilation compilation, INamedTypeSymbol symbol)
{
if (symbol.TypeKind != TypeKind.Enum)
{
var loc = syntax.Identifier.GetLocation();
context.ReportDiagnostic(Diagnostic.Create(
CommonDiagnostics.ClassMustBePartial, // 可以定义一个新的 Enum 专用 Diagnostic
loc,
symbol.Name
));
return false;
}
var attrSymbol = compilation.GetTypeByMetadataName(AttributeMetadataName);
return true;
if (attrSymbol is null)
return null;
return symbol.GetAttributes()
.FirstOrDefault(a =>
SymbolEqualityComparer.Default.Equals(a.AttributeClass, attrSymbol));
}
protected override bool ValidateSymbol(SourceProductionContext context, Compilation compilation,
EnumDeclarationSyntax syntax,
INamedTypeSymbol symbol, AttributeData attr)
{
if (symbol.TypeKind == TypeKind.Enum) return true;
var loc = syntax.Identifier.GetLocation();
context.ReportDiagnostic(Diagnostic.Create(
CommonDiagnostics.ClassMustBePartial,
loc,
symbol.Name
));
return false;
}
/// <summary>
@ -75,16 +71,9 @@ public sealed class EnumExtensionsGenerator : MetadataAttributeClassGeneratorBas
sb.AppendLine("// <auto-generated />");
sb.AppendLine("using System;");
if (!string.IsNullOrEmpty(ns))
{
sb.AppendLine($"namespace {ns}");
sb.AppendLine("{");
}
else
{
sb.AppendLine("namespace EnumExtensionsGenerated");
sb.AppendLine("{");
}
sb.AppendLine(!string.IsNullOrEmpty(ns) ? $"namespace {ns}" : "namespace EnumExtensionsGenerated");
sb.AppendLine("{");
sb.AppendLine($" public static partial class {enumName}Extensions");
sb.AppendLine(" {");