GFramework/GFramework.Generator/generator/enums/EnumExtensionsGenerator.cs
GwWuYou ce8dca3631 fix(generator): 修复代码生成器属性路径和匹配逻辑
- 修正了枚举扩展生成器中属性的完整名称路径
- 修正了日志生成器中属性的完整名称路径
- 改进了属性匹配逻辑,添加了空值检查
- 增强了属性类名匹配,支持简短名称匹配
2025-12-23 23:03:31 +08:00

121 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.Generator.generator.enums;
[Generator]
public class EnumExtensionsGenerator : IIncrementalGenerator
{
private const string AttributeFullName = "GFramework.Generator.Attributes.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();
}
}