GFramework/GFramework.SourceGenerators/enums/EnumExtensionsGenerator.cs
GwWuYou 929ea6b2d6 refactor(godot): 重构源代码生成器依赖结构
- 将CommonDiagnostics移至GFramework.SourceGenerators.Common模块
- 添加PathContests常量类统一管理路径常量
- 更新GodotLoggerGenerator使用新的路径常量和诊断引用
- 修改项目引用以包含GFramework.SourceGenerators.Common依赖
- 更新NuGet包配置以包含Common模块的DLL和XML文档
- 在解决方案文件中添加GFramework.SourceGenerators.Common项目引用
- 为Common模块创建Analyzer发布跟踪文件
2025-12-28 08:54:52 +08:00

122 lines
4.6 KiB
C#

using System;
using System.Linq;
using System.Text;
using GFramework.SourceGenerators.constants;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
namespace GFramework.SourceGenerators.enums;
[Generator]
public class EnumExtensionsGenerator : IIncrementalGenerator
{
private const string AttributeFullName =
$"{PathContests.RootAbstractionsPath}.enums.GenerateEnumExtensionsAttribute";
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 1. 找到所有 EnumDeclarationSyntax 节点
var enumDecls = context.SyntaxProvider
.CreateSyntaxProvider(
(s, _) => s is EnumDeclarationSyntax,
(ctx, _) =>
(EnumDecl: (EnumDeclarationSyntax)ctx.Node, ctx.SemanticModel))
.Where(t => t.EnumDecl != null);
// 2. 解析为 symbol 并过滤带 Attribute 的 enum
var enumSymbols = enumDecls
.Select((t, _) =>
{
var model = t.SemanticModel;
var enumDecl = t.EnumDecl;
var symbol = model.GetDeclaredSymbol(enumDecl) as INamedTypeSymbol;
return symbol;
})
.Where(symbol => symbol != null)
.Select((symbol, _) =>
{
var hasAttr = symbol!.GetAttributes().Any(ad =>
ad.AttributeClass?.ToDisplayString() == AttributeFullName);
return (Symbol: symbol, HasAttr: hasAttr);
})
.Where(x => x.HasAttr)
.Collect();
// 3. 为每个 enum 生成代码
context.RegisterSourceOutput(enumSymbols, (spc, list) =>
{
foreach (var enumSymbol in list.Select(item => item.Symbol))
try
{
var src = GenerateForEnum(enumSymbol);
var hintName = $"{enumSymbol.Name}.EnumExtensions.g.cs";
spc.AddSource(hintName, SourceText.From(src, Encoding.UTF8));
}
catch (Exception ex)
{
// 发生异常时生成一个注释文件(避免完全静默失败)
var err = $"// EnumExtensionsGenerator failed for {enumSymbol?.Name}: {ex.Message}";
spc.AddSource($"{enumSymbol?.Name}.EnumExtensions.Error.g.cs",
SourceText.From(err, Encoding.UTF8));
}
});
}
private static string GenerateForEnum(INamedTypeSymbol enumSymbol)
{
var ns = enumSymbol.ContainingNamespace.IsGlobalNamespace
? null
: enumSymbol.ContainingNamespace.ToDisplayString();
var enumName = enumSymbol.Name;
var fullEnumName = enumSymbol.ToDisplayString(); // 包含命名空间
var members = enumSymbol.GetMembers().OfType<IFieldSymbol>().Where(f => f.ConstantValue != null).ToArray();
var sb = new StringBuilder();
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($" public static partial class {enumName}Extensions");
sb.AppendLine(" {");
// 1. 单项 IsX 方法
// 替换原第93行开始的 foreach 块
var memberChecks = members.Select(m =>
{
var memberName = m.Name;
var safeMethodName = $"Is{memberName}";
return $@" /// <summary>Auto-generated: 是否为 {memberName}</summary>
public static bool {safeMethodName}(this {fullEnumName} value) => value == {fullEnumName}.{memberName};
";
}).ToArray();
sb.Append(string.Join("", memberChecks));
// 2. IsIn(params ...) 方法
sb.AppendLine(" /// <summary>Auto-generated: 判断是否属于指定集合</summary>");
sb.AppendLine(
$" public static bool IsIn(this {fullEnumName} value, params {fullEnumName}[] values)");
sb.AppendLine(" {");
sb.AppendLine(" if (values == null) return false;");
sb.AppendLine(" foreach (var v in values) if (value == v) return true;");
sb.AppendLine(" return false;");
sb.AppendLine(" }");
sb.AppendLine(" }");
sb.AppendLine("}"); // namespace
return sb.ToString();
}
}