From 75dfb0a94298d09b2b7c681820aa1db71791a4d1 Mon Sep 17 00:00:00 2001
From: GwWuYou <95328647+GeWuYou@users.noreply.github.com>
Date: Sun, 28 Dec 2025 17:13:07 +0800
Subject: [PATCH] =?UTF-8?q?refactor(generators):=20=E9=87=8D=E6=9E=84?=
=?UTF-8?q?=E6=9E=9A=E4=B8=BE=E6=89=A9=E5=B1=95=E7=94=9F=E6=88=90=E5=99=A8?=
=?UTF-8?q?=E5=9F=BA=E7=B1=BB=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 将 EnumExtensionsGenerator 的基类从 MetadataAttributeClassGeneratorBase 改为 AttributeEnumGeneratorBase
- 修改 AttributeMetadataName 为静态私有字段
- 重写 ResolveAttribute 方法用于解析属性数据
- 更新 ValidateSymbol 方法参数类型为 EnumDeclarationSyntax
- 调整命名空间生成逻辑,简化条件判断
- 重构 AttributeEnumGeneratorBase 基类实现
- 添加 ResolveAttribute 抽象方法用于属性解析
- 改进 Initialize 方法中的语法提供程序逻辑
- 添加 GetHintName 虚方法用于生成文件名提示
---
....cs => GenerateEnumExtensionsAttribute.cs} | 0
.../generator/AttributeEnumGeneratorBase.cs | 103 +++++++++++++-----
.../enums/EnumExtensionsGenerator.cs | 65 +++++------
3 files changed, 100 insertions(+), 68 deletions(-)
rename GFramework.SourceGenerators.Abstractions/enums/{EnumExtensionsAttribute.cs => GenerateEnumExtensionsAttribute.cs} (100%)
diff --git a/GFramework.SourceGenerators.Abstractions/enums/EnumExtensionsAttribute.cs b/GFramework.SourceGenerators.Abstractions/enums/GenerateEnumExtensionsAttribute.cs
similarity index 100%
rename from GFramework.SourceGenerators.Abstractions/enums/EnumExtensionsAttribute.cs
rename to GFramework.SourceGenerators.Abstractions/enums/GenerateEnumExtensionsAttribute.cs
diff --git a/GFramework.SourceGenerators.Common/generator/AttributeEnumGeneratorBase.cs b/GFramework.SourceGenerators.Common/generator/AttributeEnumGeneratorBase.cs
index ec36fed..d12233a 100644
--- a/GFramework.SourceGenerators.Common/generator/AttributeEnumGeneratorBase.cs
+++ b/GFramework.SourceGenerators.Common/generator/AttributeEnumGeneratorBase.cs
@@ -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;
///
-/// 基于特性的枚举生成器基类
+/// 属性枚举生成器基类,用于基于特定属性的枚举进行源代码生成
///
-/// 特性类型,必须继承自Attribute
-public abstract class AttributeEnumGeneratorBase : IIncrementalGenerator
- where TAttribute : Attribute
+public abstract class AttributeEnumGeneratorBase : IIncrementalGenerator
{
///
- /// 获取特性的短名称(不包含后缀)
+ /// 获取属性的短名称(不包含后缀)
///
protected abstract string AttributeShortNameWithoutSuffix { get; }
@@ -25,35 +20,83 @@ public abstract class AttributeEnumGeneratorBase : IIncrementalGener
/// 增量生成器初始化上下文
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));
});
}
+ ///
+ /// 解析指定符号上的属性数据
+ ///
+ /// 编译对象
+ /// 命名类型符号
+ /// 属性数据对象,如果未找到则返回null
+ protected abstract AttributeData? ResolveAttribute(
+ Compilation compilation,
+ INamedTypeSymbol symbol);
+
+ ///
+ /// 验证符号是否符合生成要求
+ ///
+ /// 源生产上下文
+ /// 编译对象
+ /// 枚举声明语法节点
+ /// 命名类型符号
+ /// 属性数据
+ /// 验证是否通过
+ protected abstract bool ValidateSymbol(
+ SourceProductionContext context,
+ Compilation compilation,
+ EnumDeclarationSyntax syntax,
+ INamedTypeSymbol symbol,
+ AttributeData attr);
+
///
/// 生成源代码
///
- /// 枚举符号
- /// 特性数据
+ /// 命名类型符号
+ /// 属性数据
/// 生成的源代码字符串
- protected abstract string Generate(INamedTypeSymbol enumSymbol, AttributeData attr);
+ protected abstract string Generate(
+ INamedTypeSymbol symbol,
+ AttributeData attr);
+
+ ///
+ /// 获取生成文件的提示名称
+ ///
+ /// 命名类型符号
+ /// 生成文件的提示名称
+ protected virtual string GetHintName(INamedTypeSymbol symbol)
+ => $"{symbol.Name}.g.cs";
}
\ No newline at end of file
diff --git a/GFramework.SourceGenerators/enums/EnumExtensionsGenerator.cs b/GFramework.SourceGenerators/enums/EnumExtensionsGenerator.cs
index 62fa564..3d39590 100644
--- a/GFramework.SourceGenerators/enums/EnumExtensionsGenerator.cs
+++ b/GFramework.SourceGenerators/enums/EnumExtensionsGenerator.cs
@@ -12,9 +12,9 @@ namespace GFramework.SourceGenerators.enums;
/// 枚举扩展方法生成器,用于自动生成枚举相关的扩展方法
///
[Generator]
-public sealed class EnumExtensionsGenerator : MetadataAttributeClassGeneratorBase
+public sealed class EnumExtensionsGenerator : AttributeEnumGeneratorBase
{
- protected override string AttributeMetadataName =>
+ private static string AttributeMetadataName =>
$"{PathContests.SourceGeneratorsAbstractionsPath}.enums.GenerateEnumExtensionsAttribute";
///
@@ -22,34 +22,30 @@ public sealed class EnumExtensionsGenerator : MetadataAttributeClassGeneratorBas
///
protected override string AttributeShortNameWithoutSuffix => "GenerateEnumExtensions";
- ///
- /// 验证符号是否为有效的枚举类型
- ///
- /// 源生产上下文
- /// 编译对象
- /// 类声明语法节点
- /// 命名类型符号
- /// 属性数据
- /// 验证是否通过
- 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;
}
///
@@ -75,16 +71,9 @@ public sealed class EnumExtensionsGenerator : MetadataAttributeClassGeneratorBas
sb.AppendLine("// ");
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(" {");