mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
refactor(generators): 重构枚举扩展生成器基类实现
- 将 EnumExtensionsGenerator 的基类从 MetadataAttributeClassGeneratorBase 改为 AttributeEnumGeneratorBase - 修改 AttributeMetadataName 为静态私有字段 - 重写 ResolveAttribute 方法用于解析属性数据 - 更新 ValidateSymbol 方法参数类型为 EnumDeclarationSyntax - 调整命名空间生成逻辑,简化条件判断 - 重构 AttributeEnumGeneratorBase 基类实现 - 添加 ResolveAttribute 抽象方法用于属性解析 - 改进 Initialize 方法中的语法提供程序逻辑 - 添加 GetHintName 虚方法用于生成文件名提示
This commit is contained in:
parent
539d285faa
commit
75dfb0a942
@ -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";
|
||||
}
|
||||
@ -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(" {");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user