From bc462987afbfe53d1f328e7cdfa1dfac1c59f114 Mon Sep 17 00:00:00 2001
From: GwWuYou <95328647+GeWuYou@users.noreply.github.com>
Date: Sun, 28 Dec 2025 13:39:38 +0800
Subject: [PATCH] =?UTF-8?q?refactor(logging):=20=E9=87=8D=E6=9E=84Godot?=
=?UTF-8?q?=E6=97=A5=E5=BF=97=E7=94=9F=E6=88=90=E5=99=A8=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 将日志生成器注释从LogAttribute更新为GodotLogAttribute
- 移除冗余的常量定义AttributeShortName
- 优化语法提供程序的查询逻辑,简化LINQ表达式
- 更新方法注释,明确源生成器初始化功能
- 简化属性数据获取逻辑,使用更直接的LINQ查询
- 优化代码生成部分的变量命名,提高可读性
- 改进错误处理的代码生成格式,统一命名规范
- 移除不必要的空行和注释,精简代码结构
---
.../logging/GodotLoggerGenerator.cs | 113 +++++++-----------
1 file changed, 40 insertions(+), 73 deletions(-)
diff --git a/GFramework.Godot.SourceGenerators/logging/GodotLoggerGenerator.cs b/GFramework.Godot.SourceGenerators/logging/GodotLoggerGenerator.cs
index e5f8dbd..589cc38 100644
--- a/GFramework.Godot.SourceGenerators/logging/GodotLoggerGenerator.cs
+++ b/GFramework.Godot.SourceGenerators/logging/GodotLoggerGenerator.cs
@@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.Text;
namespace GFramework.Godot.SourceGenerators.logging;
///
-/// 日志生成器,用于为标记了LogAttribute的类自动生成日志字段
+/// 日志生成器,用于为标记了GodotLogAttribute的类自动生成日志字段
///
[Generator]
public sealed class GodotLoggerGenerator : IIncrementalGenerator
@@ -19,37 +19,33 @@ public sealed class GodotLoggerGenerator : IIncrementalGenerator
private const string AttributeMetadataName =
$"{PathContests.RootAbstractionsPath}.logging.GodotLogAttribute";
- private const string AttributeShortName = "GodotLogAttribute";
private const string AttributeShortNameWithoutSuffix = "GodotLog";
///
- /// 初始化生成器,设置语法过滤和代码生成逻辑
+ /// 初始化源生成器,设置语法提供程序和源输出注册
///
/// 增量生成器初始化上下文
public void Initialize(IncrementalGeneratorInitializationContext context)
{
- // 1. 语法过滤:快速筛选候选类
- var targets = context.SyntaxProvider.CreateSyntaxProvider(
+ // 创建语法提供程序,用于查找标记了GodotLogAttribute的类声明
+ var targets = context.SyntaxProvider
+ .CreateSyntaxProvider(
static (node, _) =>
{
if (node is not ClassDeclarationSyntax cls) return false;
- // 只要包含 Log 字眼的 Attribute 就先放行
- return cls.AttributeLists.SelectMany(a => a.Attributes).Any(a =>
- {
- var name = a.Name.ToString();
- // 简单的字符串匹配,防止错过别名情况
- return name.Contains(AttributeShortNameWithoutSuffix);
- });
+ return cls.AttributeLists
+ .SelectMany(a => a.Attributes)
+ .Any(a => a.Name.ToString().Contains(AttributeShortNameWithoutSuffix));
},
static (ctx, _) =>
{
- var classDecl = (ClassDeclarationSyntax)ctx.Node;
- var symbol = ctx.SemanticModel.GetDeclaredSymbol(classDecl);
- return (ClassDecl: classDecl, Symbol: symbol);
+ var cls = (ClassDeclarationSyntax)ctx.Node;
+ var sym = ctx.SemanticModel.GetDeclaredSymbol(cls);
+ return (ClassDecl: cls, Symbol: sym);
})
.Where(x => x.Symbol is not null);
- // 2. 生成代码
+ // 注册源输出,为符合条件的类生成日志字段代码
context.RegisterSourceOutput(targets, (spc, pair) =>
{
try
@@ -57,102 +53,76 @@ public sealed class GodotLoggerGenerator : IIncrementalGenerator
var classDecl = pair.ClassDecl;
var classSymbol = pair.Symbol!;
- // 再次确认是否真的含有目标 Attribute (语义检查)
var attr = GetAttribute(classSymbol);
- if (attr == null) return; // 可能是名字相似但不是我们要的 Attribute
+ if (attr is null) return;
- // 检查 partial
if (!classDecl.Modifiers.Any(SyntaxKind.PartialKeyword))
{
spc.ReportDiagnostic(Diagnostic.Create(
CommonDiagnostics.ClassMustBePartial,
classDecl.Identifier.GetLocation(),
classSymbol.Name));
-
return;
}
var source = Generate(classSymbol, attr);
- var hintName = $"{classSymbol.Name}.Logger.g.cs";
- spc.AddSource(hintName, SourceText.From(source, Encoding.UTF8));
+ spc.AddSource($"{classSymbol.Name}.Logger.g.cs", SourceText.From(source, Encoding.UTF8));
}
catch (Exception ex)
{
- // === 关键修复:生成错误报告文件 ===
- var errorSource = $"// source generator error: {ex.Message}\n// StackTrace:\n// {ex.StackTrace}";
- // 替换非法字符以防文件名报错
var safeName = pair.Symbol?.Name ?? "Unknown";
+ var errorSource = $"// Source generator error: {ex.Message}\n// StackTrace:\n// {ex.StackTrace}";
spc.AddSource($"{safeName}.Logger.Error.g.cs", SourceText.From(errorSource, Encoding.UTF8));
}
});
}
///
- /// 获取类符号上的LogAttribute特性
+ /// 获取类符号上的GodotLogAttribute属性数据
///
/// 类符号
- /// LogAttribute特性数据,如果不存在则返回null
+ /// GodotLogAttribute属性数据,如果未找到则返回null
private static AttributeData? GetAttribute(INamedTypeSymbol classSymbol)
- {
- return classSymbol.GetAttributes().FirstOrDefault(a =>
+ => classSymbol.GetAttributes().FirstOrDefault(a =>
{
var cls = a.AttributeClass;
- if (cls == null) return false;
-
- // 宽松匹配:全名匹配 OR 名字匹配
- return cls.ToDisplayString() == AttributeMetadataName ||
- cls.Name == AttributeShortName;
+ return cls != null &&
+ (cls.ToDisplayString() == AttributeMetadataName ||
+ cls.Name.StartsWith(AttributeShortNameWithoutSuffix));
});
- }
///
- /// 生成日志字段代码
+ /// 生成日志字段的源代码
///
/// 类符号
- /// LogAttribute特性数据
- /// 生成的C#代码字符串
+ /// GodotLogAttribute属性数据
+ /// 生成的源代码字符串
private static string Generate(INamedTypeSymbol classSymbol, AttributeData attr)
{
var ns = classSymbol.ContainingNamespace.IsGlobalNamespace
? null
: classSymbol.ContainingNamespace.ToDisplayString();
-
var className = classSymbol.Name;
- // === 解析 Name ===
- var name = className; // 默认使用类名
-
- // 检查是否有构造函数参数
- if (attr.ConstructorArguments.Length > 0)
+ // 解析构造函数参数
+ var name = className;
+ if (attr.ConstructorArguments.Length > 0 && attr.ConstructorArguments[0].Value is string s &&
+ !string.IsNullOrWhiteSpace(s))
{
- var argValue = attr.ConstructorArguments[0].Value;
-
- name = argValue switch
- {
- // 情况 1: 参数存在,但值为 null (例如 [GodotLog] 且构造函数有默认值 null)
- null => className,
- // 情况 2: 参数存在,且是有效的字符串 (例如 [GodotLog("MyCategory")])
- string s when !string.IsNullOrWhiteSpace(s) => s,
- _ => $"{className}_InvalidArg"
- };
+ name = s;
}
- // === 解析 Named Arguments (更加安全的获取方式) ===
+ // 解析命名参数
var fieldName = GetNamedArg(attr, "FieldName")?.ToString() ?? "_log";
- var access =
- GetNamedArg(attr, "AccessModifier")?.ToString() ??
- "private"; // 注意:如果你的 AccessModifier 是枚举,这里得到的可能是 int 或枚举名
-
- // 处理 bool 类型
- var isStaticObj = GetNamedArg(attr, "IsStatic");
- var isStatic = isStaticObj is not bool b || b; // 默认为 true
-
+ var access = GetNamedArg(attr, "AccessModifier")?.ToString() ?? "private";
+ var isStatic = GetNamedArg(attr, "IsStatic") is not bool b || b;
var staticKeyword = isStatic ? "static " : "";
var sb = new StringBuilder();
sb.AppendLine("// ");
- sb.AppendLine("using GFramework.Core.logging;"); // 确保这里引用了 ILogger
- sb.AppendLine("using GFramework.Godot.logging;"); // 确保这里引用了 GodotLoggerFactory
+ sb.AppendLine("using GFramework.Core.logging;");
+ sb.AppendLine("using GFramework.Godot.logging;");
+ sb.AppendLine();
if (ns is not null)
{
@@ -164,8 +134,7 @@ public sealed class GodotLoggerGenerator : IIncrementalGenerator
sb.AppendLine(" {");
sb.AppendLine(" /// Auto-generated logger");
sb.AppendLine(
- $" {access} {staticKeyword}readonly ILogger {fieldName} = " +
- $"new GodotLoggerFactory().GetLogger(\"{name}\");");
+ $" {access} {staticKeyword}readonly ILogger {fieldName} = new GodotLoggerFactory().GetLogger(\"{name}\");");
sb.AppendLine(" }");
if (ns is not null)
@@ -175,13 +144,11 @@ public sealed class GodotLoggerGenerator : IIncrementalGenerator
}
///
- /// 从特性数据中获取命名参数的值
+ /// 从属性数据中获取指定名称的命名参数值
///
- /// 特性数据
+ /// 属性数据
/// 参数名称
- /// 参数值,如果不存在则返回null
+ /// 参数值,如果未找到则返回null
private static object? GetNamedArg(AttributeData attr, string name)
- {
- return (from kv in attr.NamedArguments where kv.Key == name select kv.Value.Value).FirstOrDefault();
- }
+ => attr.NamedArguments.FirstOrDefault(kv => kv.Key == name).Value.Value;
}
\ No newline at end of file