mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-23 03:04:29 +08:00
- 将GFramework.SourceGenerators.Attributes重命名为GFramework.SourceGenerators.Abstractions - 将GFramework.Godot.SourceGenerators.Attributes重命名为GFramework.Godot.SourceGenerators.Abstractions - 更新所有源生成器中对Attribute命名空间的引用 - 修改项目引用从Attributes指向Abstractions - 添加程序集打包配置到生成项目 - 更新解决方案文件中的项目引用路径 - 修正测试文件中的命名空间引用
122 lines
4.6 KiB
C#
122 lines
4.6 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Text;
|
|
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 =
|
|
"GFramework.SourceGenerators.Abstractions.generator.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 ||
|
|
ad.AttributeClass?.ToDisplayString().EndsWith(".GenerateEnumExtensionsAttribute") == true);
|
|
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();
|
|
}
|
|
} |