From 763b460575e00e471c62eec95b5f7633313b8303 Mon Sep 17 00:00:00 2001
From: GwWuYou <95328647+GeWuYou@users.noreply.github.com>
Date: Thu, 25 Dec 2025 21:10:17 +0800
Subject: [PATCH] =?UTF-8?q?refactor(GFramework.Generator):=20=E9=87=8D?=
=?UTF-8?q?=E6=9E=84=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=99=A8=E7=BB=93?=
=?UTF-8?q?=E6=9E=84=E5=B9=B6=E6=B7=BB=E5=8A=A0Godot=E6=97=A5=E5=BF=97?=
=?UTF-8?q?=E7=94=9F=E6=88=90=E5=99=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 移除原有的LoggerGenerator.cs和相关README文档
- 重命名GFramework.Generator为GFramework.SourceGenerators
- 重命名GFramework.Generator.Attributes为GFramework.SourceGenerators.Attributes
- 添加新的Godot日志生成器(GodotLoggerGenerator)及对应属性(GodotLogAttribute)
- 创建GFramework.Godot.SourceGenerators新项目用于Godot特定功能
- 修改日志生成器使用GodotLoggerFactory而非ConsoleLoggerFactory
---
GFramework.Generator/README.md | 4 -
.../generator/logging/LoggerGenerator.cs | 185 --------
.../generator/logging/README.md | 443 ------------------
...k.Godot.SourceGenerators.Attributes.csproj | 9 +
.../logging/GodotLogAttribute.cs | 37 ++
.../AnalyzerReleases.Shipped.md | 0
.../AnalyzerReleases.Unshipped.md | 9 +
.../GFramework.Godot.SourceGenerators.csproj | 19 +
.../logging/Diagnostic.cs | 44 ++
.../logging/GodotLoggerGenerator.cs | 181 +++++++
...amework.SourceGenerators.Attributes.csproj | 0
.../enums/EnumExtensionsAttribute.cs | 2 +-
.../logging/LogAttribute.cs | 24 +-
.../AnalyzerReleases.Shipped.md | 3 +
.../AnalyzerReleases.Unshipped.md | 0
.../GFramework.SourceGenerators.csproj | 10 +-
.../enums/EnumExtensionsGenerator.cs | 5 +-
.../logging/Diagnostic.cs | 16 +-
.../logging/LoggerGenerator.cs | 185 ++++++++
GFramework.csproj | 45 +-
GFramework.sln | 16 +-
21 files changed, 568 insertions(+), 669 deletions(-)
delete mode 100644 GFramework.Generator/README.md
delete mode 100644 GFramework.Generator/generator/logging/LoggerGenerator.cs
delete mode 100644 GFramework.Generator/generator/logging/README.md
create mode 100644 GFramework.Godot.SourceGenerators.Attributes/GFramework.Godot.SourceGenerators.Attributes.csproj
create mode 100644 GFramework.Godot.SourceGenerators.Attributes/logging/GodotLogAttribute.cs
rename {GFramework.Generator => GFramework.Godot.SourceGenerators}/AnalyzerReleases.Shipped.md (100%)
create mode 100644 GFramework.Godot.SourceGenerators/AnalyzerReleases.Unshipped.md
create mode 100644 GFramework.Godot.SourceGenerators/GFramework.Godot.SourceGenerators.csproj
create mode 100644 GFramework.Godot.SourceGenerators/logging/Diagnostic.cs
create mode 100644 GFramework.Godot.SourceGenerators/logging/GodotLoggerGenerator.cs
rename GFramework.Generator.Attributes/GFramework.Generator.Attributes.csproj => GFramework.SourceGenerators.Attributes/GFramework.SourceGenerators.Attributes.csproj (100%)
rename {GFramework.Generator.Attributes/generator => GFramework.SourceGenerators.Attributes}/enums/EnumExtensionsAttribute.cs (92%)
rename {GFramework.Generator.Attributes/generator => GFramework.SourceGenerators.Attributes}/logging/LogAttribute.cs (85%)
create mode 100644 GFramework.SourceGenerators/AnalyzerReleases.Shipped.md
rename {GFramework.Generator => GFramework.SourceGenerators}/AnalyzerReleases.Unshipped.md (100%)
rename GFramework.Generator/GFramework.Generator.csproj => GFramework.SourceGenerators/GFramework.SourceGenerators.csproj (83%)
rename {GFramework.Generator/generator => GFramework.SourceGenerators}/enums/EnumExtensionsGenerator.cs (96%)
rename {GFramework.Generator/generator => GFramework.SourceGenerators}/logging/Diagnostic.cs (79%)
create mode 100644 GFramework.SourceGenerators/logging/LoggerGenerator.cs
diff --git a/GFramework.Generator/README.md b/GFramework.Generator/README.md
deleted file mode 100644
index 08b71e1..0000000
--- a/GFramework.Generator/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-项目额外的简单代码生成器
-目前已有的功能
-
-- 为枚举添加两个扩展方法方便判断枚举值
\ No newline at end of file
diff --git a/GFramework.Generator/generator/logging/LoggerGenerator.cs b/GFramework.Generator/generator/logging/LoggerGenerator.cs
deleted file mode 100644
index 766558f..0000000
--- a/GFramework.Generator/generator/logging/LoggerGenerator.cs
+++ /dev/null
@@ -1,185 +0,0 @@
-#nullable enable
-using System;
-using System.Linq;
-using System.Text;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Text;
-
-namespace GFramework.Generator.generator.logging
-{
- ///
- /// 日志生成器,用于为标记了LogAttribute的类自动生成日志字段
- ///
- [Generator]
- public sealed class LoggerGenerator : IIncrementalGenerator
- {
- // 请确保这里的命名空间和类名与 Attributes 项目中定义的完全一致(注意大小写!)
- private const string AttributeMetadataName = "GFramework.Generator.Attributes.generator.logging.LogAttribute";
- private const string AttributeShortName = "LogAttribute";
- private const string AttributeShortNameWithoutSuffix = "Log";
-
- ///
- /// 初始化生成器,设置语法过滤和代码生成逻辑
- ///
- /// 增量生成器初始化上下文
- public void Initialize(IncrementalGeneratorInitializationContext context)
- {
- // 1. 语法过滤:快速筛选候选类
- 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);
- });
- },
- static (ctx, _) =>
- {
- var classDecl = (ClassDeclarationSyntax)ctx.Node;
- var symbol = ctx.SemanticModel.GetDeclaredSymbol(classDecl);
- return (ClassDecl: classDecl, Symbol: symbol);
- })
- .Where(x => x.Symbol is not null);
-
- // 2. 生成代码
- context.RegisterSourceOutput(targets, (spc, pair) =>
- {
- try
- {
- var classDecl = pair.ClassDecl;
- var classSymbol = pair.Symbol!;
-
- // 再次确认是否真的含有目标 Attribute (语义检查)
- var attr = GetAttribute(classSymbol);
- if (attr == null) return; // 可能是名字相似但不是我们要的 Attribute
-
- // 检查 partial
- if (!classDecl.Modifiers.Any(SyntaxKind.PartialKeyword))
- {
- spc.ReportDiagnostic(Diagnostic.Create(
- Diagnostics.MustBePartial,
- 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));
- }
- catch (Exception ex)
- {
- // === 关键修复:生成错误报告文件 ===
- var errorSource = $"// source generator error: {ex.Message}\n// StackTrace:\n// {ex.StackTrace}";
- // 替换非法字符以防文件名报错
- var safeName = pair.Symbol?.Name ?? "Unknown";
- spc.AddSource($"{safeName}.Logger.Error.g.cs", SourceText.From(errorSource, Encoding.UTF8));
- }
- });
- }
-
- ///
- /// 获取类符号上的LogAttribute特性
- ///
- /// 类符号
- /// LogAttribute特性数据,如果不存在则返回null
- private static AttributeData? GetAttribute(INamedTypeSymbol classSymbol)
- {
- return classSymbol.GetAttributes().FirstOrDefault(a =>
- {
- var cls = a.AttributeClass;
- if (cls == null) return false;
-
- // 宽松匹配:全名匹配 OR 名字匹配
- return cls.ToDisplayString() == AttributeMetadataName ||
- cls.Name == AttributeShortName;
- });
- }
-
- ///
- /// 生成日志字段代码
- ///
- /// 类符号
- /// LogAttribute特性数据
- /// 生成的C#代码字符串
- 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 argValue = attr.ConstructorArguments[0].Value;
-
- name = argValue switch
- {
- // 情况 1: 参数存在,但值为 null (例如 [Log] 且构造函数有默认值 null)
- null => className,
- // 情况 2: 参数存在,且是有效的字符串 (例如 [Log("MyCategory")])
- string s when !string.IsNullOrWhiteSpace(s) => s,
- _ => $"{className}_InvalidArg"
- };
- }
-
- // === 解析 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 staticKeyword = isStatic ? "static " : "";
-
- var sb = new StringBuilder();
- sb.AppendLine("// ");
- sb.AppendLine("using GFramework.Core.logging;"); // 确保这里引用了 ILog 和 Log 类
-
- if (ns is not null)
- {
- sb.AppendLine($"namespace {ns}");
- sb.AppendLine("{");
- }
-
- sb.AppendLine($" public partial class {className}");
- sb.AppendLine(" {");
- sb.AppendLine($" /// Auto-generated logger");
- sb.AppendLine(
- $" {access} {staticKeyword}readonly ILogger {fieldName} = " +
- $"new ConsoleLoggerFactory.GetLogger(\"{name}\");");
- sb.AppendLine(" }");
-
- if (ns is not null)
- sb.AppendLine("}");
-
- return sb.ToString();
- }
-
- ///
- /// 从特性数据中获取命名参数的值
- ///
- /// 特性数据
- /// 参数名称
- /// 参数值,如果不存在则返回null
- private static object? GetNamedArg(AttributeData attr, string name)
- {
- return (from kv in attr.NamedArguments where kv.Key == name select kv.Value.Value).FirstOrDefault();
- }
- }
-}
diff --git a/GFramework.Generator/generator/logging/README.md b/GFramework.Generator/generator/logging/README.md
deleted file mode 100644
index 2ff3880..0000000
--- a/GFramework.Generator/generator/logging/README.md
+++ /dev/null
@@ -1,443 +0,0 @@
-# GFramework 日志代码生成器 (LogAttribute)
-
-## 概述
-
-GFramework 提供了一个强大的日志代码生成器,类似于 Java 的 `@Slf4j` 注解。通过在类上使用 `[Log]` 特性,编译器会自动为该类生成一个日志记录器字段,让您在类的任何地方都能方便地使用日志记录功能。
-
-## 快速开始
-
-### 1. 基本使用
-
-在类上添加 `[Log]` 特性:
-
-```csharp
-using GFramework.Generator.Attributes.generator.logging;
-
-[Log]
-public partial class MyService
-{
- public void DoSomething()
- {
- // 自动生成的 Log 字段可以直接使用
- Log.Info("开始执行操作");
-
- try
- {
- // 业务逻辑
- Log.Debug("执行业务逻辑", new { Operation = "DoSomething" });
- Log.Info("操作执行成功");
- }
- catch (Exception ex)
- {
- Log.Error("操作执行失败", ex);
- }
- }
-}
-```
-
-编译后,生成器会自动为该类添加:
-
-```csharp
-public partial class MyService
-{
- private static ILog Log = Log.CreateLogger("MyService");
-}
-```
-
-### 2. 自定义类别名称
-
-```csharp
-[Log("CustomService")]
-public partial class MyService
-{
- // 生成的 logger 类别为 "CustomService" 而不是 "MyService"
-}
-```
-
-### 3. 自定义字段配置
-
-```csharp
-[Log(FieldName = "Logger", AccessModifier = "protected", IsStatic = false)]
-public partial class MyService
-{
- // 生成: protected ILog Logger = Log.CreateLogger("MyService");
-}
-```
-
-## 特性参数说明
-
-### LogAttribute 构造函数参数
-
-- **category** (string, 可选): 指定日志类别,默认为类名
-
-### 命名参数
-
-- **FieldName** (string, 默认 "Log"): 指定生成的字段名称
-- **AccessModifier** (string, 默认 "private"): 指定字段的访问修饰符
-- **IsStatic** (bool, 默认 true): 指定字段是否为静态的
-
-## 使用示例
-
-### 在系统中的使用
-
-```csharp
-[Log("System")]
-public partial class GameSystem : AbstractSystem
-{
- protected override void OnInit()
- {
- Log.Info("GameSystem 初始化开始");
-
- // 初始化逻辑
- Log.Debug("正在加载游戏数据...");
- Log.Info("GameSystem 初始化完成");
- }
-
- protected override void OnUpdate(float deltaTime)
- {
- Log.Trace("系统更新", new { DeltaTime = deltaTime });
- }
-
- protected override void OnDestroy()
- {
- Log.Info("GameSystem 销毁");
- }
-}
-```
-
-### 在模型中的使用
-
-```csharp
-[Log("Model")]
-public partial class UserModel : AbstractModel
-{
- public string UserName { get; set; }
-
- public void SetUserName(string userName)
- {
- Log.Debug("设置用户名", new { OldValue = UserName, NewValue = userName });
- UserName = userName;
- Log.Info("用户名设置完成", new { UserName = userName });
- }
-}
-```
-
-### 在工具类中的使用
-
-```csharp
-[Log("Utility")]
-public partial class FileUtility
-{
- public void SaveFile(string filePath, string content)
- {
- Log.Debug("开始保存文件", new { FilePath = filePath });
-
- try
- {
- // 文件保存逻辑
- Log.Info("文件保存成功", new { FilePath = filePath });
- }
- catch (Exception ex)
- {
- Log.Error("文件保存失败", ex, new { FilePath = filePath });
- }
- }
-}
-```
-
-### 网络服务中的使用
-
-```csharp
-[Log("Network")]
-public partial class NetworkService
-{
- public async Task GetDataAsync(string url)
- {
- Log.Debug("发起网络请求", new { Url = url, Method = "GET" });
-
- try
- {
- var response = await httpClient.GetStringAsync(url);
- Log.Info("网络请求成功", new { Url = url, ResponseLength = response.Length });
- return response;
- }
- catch (Exception ex)
- {
- Log.Error("网络请求失败", ex, new { Url = url });
- throw;
- }
- }
-}
-```
-
-### 数据库服务中的使用
-
-```csharp
-[Log("Database")]
-public partial class DatabaseService
-{
- public async Task GetUserAsync(int userId)
- {
- Log.Debug("查询用户信息", new { UserId = userId });
-
- try
- {
- var user = await _dbContext.Users.FindAsync(userId);
- if (user != null)
- {
- Log.Info("用户查询成功", new { UserId = userId, UserName = user.Name });
- }
- else
- {
- Log.Warn("用户不存在", new { UserId = userId });
- }
- return user;
- }
- catch (Exception ex)
- {
- Log.Error("用户查询失败", ex, new { UserId = userId });
- throw;
- }
- }
-}
-```
-
-## 高级配置示例
-
-### 使用静态字段
-
-```csharp
-[Log(IsStatic = true)] // 默认配置
-public partial class StaticService
-{
- public static void StaticMethod()
- {
- Log.Info("静态方法调用");
- }
-}
-```
-
-### 使用实例字段
-
-```csharp
-[Log(IsStatic = false)]
-public partial class InstanceService
-{
- private readonly string _instanceId;
-
- public InstanceService(string instanceId)
- {
- _instanceId = instanceId;
- }
-
- public void InstanceMethod()
- {
- Log.Info("实例方法调用", new { InstanceId = _instanceId });
- }
-}
-```
-
-### 使用受保护的字段
-
-```csharp
-[Log(AccessModifier = "protected")]
-public partial class BaseService
-{
- // 子类可以访问 protected 字段
-}
-
-[Log] // 派生类也可以有自己的日志记录器
-public partial class DerivedService : BaseService
-{
- public void DerivedMethod()
- {
- Log.Info("派生类方法");
- // 也可以访问基类的 protected Log 字段
- }
-}
-```
-
-## 最佳实践
-
-### 1. 使用合适的日志类别名称
-
-```csharp
-// 好的做法:使用有意义的类别名称
-[Log("UserService")]
-public partial class UserService { }
-
-// 避免:使用过于通用的类别名称
-[Log("Service")]
-public partial class UserService { }
-```
-
-### 2. 合理设置日志级别
-
-```csharp
-[Log("BusinessLogic")]
-public partial class BusinessService
-{
- public void ProcessOrder(Order order)
- {
- // 使用 Info 记录重要的业务流程
- Log.Info("开始处理订单", new { OrderId = order.Id });
-
- // 使用 Debug 记录调试信息
- Log.Debug("订单验证通过", new { OrderId = order.Id });
-
- // 使用 Warning 记录异常情况
- if (order.Amount > 10000)
- {
- Log.Warn("大额订单", new { OrderId = order.Id, Amount = order.Amount });
- }
-
- // 使用 Error 记录错误
- try
- {
- // 业务逻辑
- }
- catch (Exception ex)
- {
- Log.Error("订单处理失败", ex, new { OrderId = order.Id });
- }
- }
-}
-```
-
-### 3. 记录上下文信息
-
-```csharp
-[Log("UserManagement")]
-public partial class UserManager
-{
- public void UpdateUserProfile(int userId, UserProfile profile)
- {
- Log.Info("更新用户资料", new
- {
- UserId = userId,
- Changes = profile.GetChanges(),
- Timestamp = DateTime.Now
- });
- }
-}
-```
-
-### 4. 在异常处理中使用日志
-
-```csharp
-[Log("DataAccess")]
-public partial class UserRepository
-{
- public async Task GetUserAsync(int userId)
- {
- try
- {
- return await _context.Users.FirstOrDefaultAsync(u => u.Id == userId);
- }
- catch (DbException ex)
- {
- Log.Error("数据库查询失败", ex, new { UserId = userId });
- throw new DataAccessException("无法获取用户信息", ex);
- }
- }
-}
-```
-
-## 框架组件集成
-
-### 在 GFramework 架构中使用
-
-```csharp
-[Log("Architecture")]
-public partial class ExampleArchitecture : AbstractArchitecture
-{
- protected override void Init()
- {
- Log.Info("ExampleArchitecture 初始化开始");
-
- // 注册系统
- RegisterSystem(new GameSystem());
- RegisterSystem(new UISystem());
-
- // 注册模型
- RegisterModel(new UserModel());
- RegisterModel(new GameModel());
-
- // 注册工具
- RegisterUtility(new FileUtility());
-
- Log.Info("ExampleArchitecture 初始化完成");
- }
-}
-```
-
-### 在事件处理中使用
-
-```csharp
-[Log("Event")]
-public partial class UserEventHandler
-{
- [Log("EventHandler")]
- public void OnUserLoginEvent(UserLoginEvent evt)
- {
- Log.Info("用户登录事件", new
- {
- UserId = evt.UserId,
- LoginTime = evt.LoginTime,
- IpAddress = evt.IpAddress
- });
- }
-
- [Log("EventHandler")]
- public void OnUserLogoutEvent(UserLogoutEvent evt)
- {
- Log.Info("用户登出事件", new
- {
- UserId = evt.UserId,
- LogoutTime = evt.LogoutTime,
- SessionDuration = evt.SessionDuration
- });
- }
-}
-```
-
-## 注意事项
-
-1. **部分类**: 使用 `[Log]` 特性的类必须是 `partial` 类,因为生成器会添加字段到同一个类中。
-
-2. **命名空间引用**: 确保项目中引用了 `GFramework.Generator.Attributes` 包。
-
-3. **编译时生成**: 日志字段是在编译时生成的,不会影响运行时性能。
-
-4. **多线程安全**: 生成的 `ILog` 实例是线程安全的,可以在多线程环境中使用。
-
-5. **继承**: 派生类可以有自己的 `[Log]` 特性,也可以访问基类的受保护日志字段。
-
-## 性能考虑
-
-- **编译时生成**: 字段在编译时生成,没有运行时开销
-- **延迟初始化**: 日志记录器按需创建,避免不必要的对象创建
-- **级别检查**: 生成的代码包含级别检查,性能与手动创建的日志记录器相同
-
-## 与现有日志系统的兼容性
-
-生成的代码完全兼容现有的 `GFramework.Core.logging` 系统:
-
-```csharp
-// 现有的方式仍然可以使用
-var manualLogger = Log.CreateLogger("Manual");
-
-// 新生成的字段也可以正常使用
-[Log]
-public partial class MyService
-{
- public void Method()
- {
- // 两种方式都可以使用
- manualLogger.Info("手动创建的日志");
- Log.Info("自动生成的日志");
- }
-}
-```
-
-通过使用 `[Log]` 特性,您可以显著减少样板代码,提高开发效率,同时保持日志记录的一致性和灵活性。
\ No newline at end of file
diff --git a/GFramework.Godot.SourceGenerators.Attributes/GFramework.Godot.SourceGenerators.Attributes.csproj b/GFramework.Godot.SourceGenerators.Attributes/GFramework.Godot.SourceGenerators.Attributes.csproj
new file mode 100644
index 0000000..237d661
--- /dev/null
+++ b/GFramework.Godot.SourceGenerators.Attributes/GFramework.Godot.SourceGenerators.Attributes.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net10.0
+ enable
+ enable
+
+
+
diff --git a/GFramework.Godot.SourceGenerators.Attributes/logging/GodotLogAttribute.cs b/GFramework.Godot.SourceGenerators.Attributes/logging/GodotLogAttribute.cs
new file mode 100644
index 0000000..4508d35
--- /dev/null
+++ b/GFramework.Godot.SourceGenerators.Attributes/logging/GodotLogAttribute.cs
@@ -0,0 +1,37 @@
+#nullable enable
+namespace GFramework.SourceGenerators.Attributes.logging;
+
+///
+/// Godot日志特性,用于在类上标记以自动生成日志字段
+///
+[AttributeUsage(AttributeTargets.Class, Inherited = false)]
+public sealed class GodotLogAttribute : Attribute
+{
+ ///
+ /// 初始化 GodotLogAttribute 类的新实例
+ ///
+ public GodotLogAttribute()
+ {
+ }
+
+ ///
+ /// 初始化 GodotLogAttribute 类的新实例
+ ///
+ /// 日志分类名
+ public GodotLogAttribute(string? name)
+ {
+ Name = name;
+ }
+
+ /// 日志分类名(默认使用类名)
+ public string? Name { get; set; }
+
+ /// 生成字段名
+ public string FieldName { get; set; } = "_log";
+
+ /// 是否生成 static 字段
+ public bool IsStatic { get; set; } = true;
+
+ /// 访问修饰符
+ public string AccessModifier { get; set; } = "private";
+}
\ No newline at end of file
diff --git a/GFramework.Generator/AnalyzerReleases.Shipped.md b/GFramework.Godot.SourceGenerators/AnalyzerReleases.Shipped.md
similarity index 100%
rename from GFramework.Generator/AnalyzerReleases.Shipped.md
rename to GFramework.Godot.SourceGenerators/AnalyzerReleases.Shipped.md
diff --git a/GFramework.Godot.SourceGenerators/AnalyzerReleases.Unshipped.md b/GFramework.Godot.SourceGenerators/AnalyzerReleases.Unshipped.md
new file mode 100644
index 0000000..cb8e1c2
--- /dev/null
+++ b/GFramework.Godot.SourceGenerators/AnalyzerReleases.Unshipped.md
@@ -0,0 +1,9 @@
+; Unshipped analyzer release
+; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md
+
+### New Rules
+
+ Rule ID | Category | Severity | Notes
+------------|--------------------------|----------|------------------------
+ GFLOG001 | GFramework.Godot.Logging | Error | GodotLoggerDiagnostics
+ GFW_LOG001 | GFramework.Godot.Logging | Warning | GodotLoggerDiagnostics
\ No newline at end of file
diff --git a/GFramework.Godot.SourceGenerators/GFramework.Godot.SourceGenerators.csproj b/GFramework.Godot.SourceGenerators/GFramework.Godot.SourceGenerators.csproj
new file mode 100644
index 0000000..350752c
--- /dev/null
+++ b/GFramework.Godot.SourceGenerators/GFramework.Godot.SourceGenerators.csproj
@@ -0,0 +1,19 @@
+
+
+
+ net10.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GFramework.Godot.SourceGenerators/logging/Diagnostic.cs b/GFramework.Godot.SourceGenerators/logging/Diagnostic.cs
new file mode 100644
index 0000000..bf235c0
--- /dev/null
+++ b/GFramework.Godot.SourceGenerators/logging/Diagnostic.cs
@@ -0,0 +1,44 @@
+using Microsoft.CodeAnalysis;
+
+namespace GFramework.Godot.SourceGenerators.logging;
+
+///
+/// 提供诊断描述符的静态类,用于GFramework日志生成器的编译时检查
+///
+internal static class GodotLoggerDiagnostics
+{
+ ///
+ /// 诊断描述符:标识使用[GodotLog]特性的类必须声明为partial
+ ///
+ ///
+ /// ID: GFLOG001
+ /// 严重性: Error
+ /// 分类: GFramework.Godot.Logging
+ ///
+ public static readonly DiagnosticDescriptor MustBePartial =
+ new(
+ id: "GFLOG001",
+ title: "Class must be partial",
+ messageFormat: "Class '{0}' must be declared as partial to use [GodotLog]",
+ category: "GFramework.Godot.Logging",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true
+ );
+
+
+ ///
+ /// 诊断描述符:标识GodotLogAttribute无法在指定类上生成Logger
+ ///
+ ///
+ /// ID: GFW_LOG001
+ /// 严重性: Warning
+ /// 分类: GFramework.Godot.Logging
+ ///
+ public static readonly DiagnosticDescriptor LogAttributeInvalid = new(
+ id: "GFW_LOG001",
+ title: "GodotLogAttribute cannot generate Logger",
+ messageFormat: "GodotLogAttribute on class '{0}' is ineffective: {1}",
+ category: "GFramework.Godot.Logging",
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true);
+}
\ No newline at end of file
diff --git a/GFramework.Godot.SourceGenerators/logging/GodotLoggerGenerator.cs b/GFramework.Godot.SourceGenerators/logging/GodotLoggerGenerator.cs
new file mode 100644
index 0000000..ef84ac4
--- /dev/null
+++ b/GFramework.Godot.SourceGenerators/logging/GodotLoggerGenerator.cs
@@ -0,0 +1,181 @@
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Text;
+
+namespace GFramework.Godot.SourceGenerators.logging;
+
+///
+/// 日志生成器,用于为标记了LogAttribute的类自动生成日志字段
+///
+[Generator]
+public sealed class GodotLoggerGenerator : IIncrementalGenerator
+{
+ private const string AttributeMetadataName = "GFramework.SourceGenerators.Attributes.logging.GodotLogAttribute";
+ private const string AttributeShortName = "GodotLogAttribute";
+ private const string AttributeShortNameWithoutSuffix = "Log";
+
+ ///
+ /// 初始化生成器,设置语法过滤和代码生成逻辑
+ ///
+ /// 增量生成器初始化上下文
+ public void Initialize(IncrementalGeneratorInitializationContext context)
+ {
+ // 1. 语法过滤:快速筛选候选类
+ 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);
+ });
+ },
+ static (ctx, _) =>
+ {
+ var classDecl = (ClassDeclarationSyntax)ctx.Node;
+ var symbol = ctx.SemanticModel.GetDeclaredSymbol(classDecl);
+ return (ClassDecl: classDecl, Symbol: symbol);
+ })
+ .Where(x => x.Symbol is not null);
+
+ // 2. 生成代码
+ context.RegisterSourceOutput(targets, (spc, pair) =>
+ {
+ try
+ {
+ var classDecl = pair.ClassDecl;
+ var classSymbol = pair.Symbol!;
+
+ // 再次确认是否真的含有目标 Attribute (语义检查)
+ var attr = GetAttribute(classSymbol);
+ if (attr == null) return; // 可能是名字相似但不是我们要的 Attribute
+
+ // 检查 partial
+ if (!classDecl.Modifiers.Any(SyntaxKind.PartialKeyword))
+ {
+ spc.ReportDiagnostic(Diagnostic.Create(
+ GodotLoggerDiagnostics.MustBePartial,
+ 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));
+ }
+ catch (Exception ex)
+ {
+ // === 关键修复:生成错误报告文件 ===
+ var errorSource = $"// source generator error: {ex.Message}\n// StackTrace:\n// {ex.StackTrace}";
+ // 替换非法字符以防文件名报错
+ var safeName = pair.Symbol?.Name ?? "Unknown";
+ spc.AddSource($"{safeName}.Logger.Error.g.cs", SourceText.From(errorSource, Encoding.UTF8));
+ }
+ });
+ }
+
+ ///
+ /// 获取类符号上的LogAttribute特性
+ ///
+ /// 类符号
+ /// LogAttribute特性数据,如果不存在则返回null
+ private static AttributeData? GetAttribute(INamedTypeSymbol classSymbol)
+ {
+ return classSymbol.GetAttributes().FirstOrDefault(a =>
+ {
+ var cls = a.AttributeClass;
+ if (cls == null) return false;
+
+ // 宽松匹配:全名匹配 OR 名字匹配
+ return cls.ToDisplayString() == AttributeMetadataName ||
+ cls.Name == AttributeShortName;
+ });
+ }
+
+ ///
+ /// 生成日志字段代码
+ ///
+ /// 类符号
+ /// LogAttribute特性数据
+ /// 生成的C#代码字符串
+ 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 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"
+ };
+ }
+
+ // === 解析 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 staticKeyword = isStatic ? "static " : "";
+
+ var sb = new StringBuilder();
+ sb.AppendLine("// ");
+ sb.AppendLine("using GFramework.Core.logging;"); // 确保这里引用了 ILogger
+ sb.AppendLine("using GFramework.Godot.logging;"); // 确保这里引用了 GodotLoggerFactory
+
+ if (ns is not null)
+ {
+ sb.AppendLine($"namespace {ns}");
+ sb.AppendLine("{");
+ }
+
+ sb.AppendLine($" public partial class {className}");
+ sb.AppendLine(" {");
+ sb.AppendLine(" /// Auto-generated logger");
+ sb.AppendLine(
+ $" {access} {staticKeyword}readonly ILogger {fieldName} = " +
+ $"new GodotLoggerFactory.GetLogger(\"{name}\");");
+ sb.AppendLine(" }");
+
+ if (ns is not null)
+ sb.AppendLine("}");
+
+ return sb.ToString();
+ }
+
+ ///
+ /// 从特性数据中获取命名参数的值
+ ///
+ /// 特性数据
+ /// 参数名称
+ /// 参数值,如果不存在则返回null
+ private static object? GetNamedArg(AttributeData attr, string name)
+ {
+ return (from kv in attr.NamedArguments where kv.Key == name select kv.Value.Value).FirstOrDefault();
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Generator.Attributes/GFramework.Generator.Attributes.csproj b/GFramework.SourceGenerators.Attributes/GFramework.SourceGenerators.Attributes.csproj
similarity index 100%
rename from GFramework.Generator.Attributes/GFramework.Generator.Attributes.csproj
rename to GFramework.SourceGenerators.Attributes/GFramework.SourceGenerators.Attributes.csproj
diff --git a/GFramework.Generator.Attributes/generator/enums/EnumExtensionsAttribute.cs b/GFramework.SourceGenerators.Attributes/enums/EnumExtensionsAttribute.cs
similarity index 92%
rename from GFramework.Generator.Attributes/generator/enums/EnumExtensionsAttribute.cs
rename to GFramework.SourceGenerators.Attributes/enums/EnumExtensionsAttribute.cs
index c3c90a7..8799cfa 100644
--- a/GFramework.Generator.Attributes/generator/enums/EnumExtensionsAttribute.cs
+++ b/GFramework.SourceGenerators.Attributes/enums/EnumExtensionsAttribute.cs
@@ -1,6 +1,6 @@
using System;
-namespace GFramework.Generator.Attributes.generator.enums
+namespace GFramework.SourceGenerators.Attributes.enums
{
///
/// 标注在 enum 上,Source Generator 会为该 enum 生成扩展方法。
diff --git a/GFramework.Generator.Attributes/generator/logging/LogAttribute.cs b/GFramework.SourceGenerators.Attributes/logging/LogAttribute.cs
similarity index 85%
rename from GFramework.Generator.Attributes/generator/logging/LogAttribute.cs
rename to GFramework.SourceGenerators.Attributes/logging/LogAttribute.cs
index d933912..0f2894e 100644
--- a/GFramework.Generator.Attributes/generator/logging/LogAttribute.cs
+++ b/GFramework.SourceGenerators.Attributes/logging/LogAttribute.cs
@@ -1,7 +1,7 @@
#nullable enable
using System;
-namespace GFramework.Generator.Attributes.generator.logging;
+namespace GFramework.SourceGenerators.Attributes.logging;
///
/// 标注在类上,Source Generator 会为该类自动生成一个日志记录器字段。
@@ -9,6 +9,19 @@ namespace GFramework.Generator.Attributes.generator.logging;
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public sealed class LogAttribute : Attribute
{
+ public LogAttribute()
+ {
+ }
+
+ ///
+ /// 初始化 GodotLogAttribute 类的新实例
+ ///
+ /// 日志分类名,默认使用类名
+ public LogAttribute(string? name)
+ {
+ Name = name;
+ }
+
/// 日志分类名(默认使用类名)
public string? Name { get; set; }
@@ -20,13 +33,4 @@ public sealed class LogAttribute : Attribute
/// 访问修饰符
public string AccessModifier { get; set; } = "private";
- public LogAttribute() { }
- ///
- /// 初始化 LogAttribute 类的新实例
- ///
- /// 日志分类名,默认使用类名
- public LogAttribute(string? name)
- {
- Name = name;
- }
}
\ No newline at end of file
diff --git a/GFramework.SourceGenerators/AnalyzerReleases.Shipped.md b/GFramework.SourceGenerators/AnalyzerReleases.Shipped.md
new file mode 100644
index 0000000..60b59dd
--- /dev/null
+++ b/GFramework.SourceGenerators/AnalyzerReleases.Shipped.md
@@ -0,0 +1,3 @@
+; Shipped analyzer releases
+; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md
+
diff --git a/GFramework.Generator/AnalyzerReleases.Unshipped.md b/GFramework.SourceGenerators/AnalyzerReleases.Unshipped.md
similarity index 100%
rename from GFramework.Generator/AnalyzerReleases.Unshipped.md
rename to GFramework.SourceGenerators/AnalyzerReleases.Unshipped.md
diff --git a/GFramework.Generator/GFramework.Generator.csproj b/GFramework.SourceGenerators/GFramework.SourceGenerators.csproj
similarity index 83%
rename from GFramework.Generator/GFramework.Generator.csproj
rename to GFramework.SourceGenerators/GFramework.SourceGenerators.csproj
index f3e46ac..b62eee6 100644
--- a/GFramework.Generator/GFramework.Generator.csproj
+++ b/GFramework.SourceGenerators/GFramework.SourceGenerators.csproj
@@ -1,7 +1,7 @@
- GeWuYou.GFramework.Generator
+ GeWuYou.GFramework.SourceGenerators
netstandard2.0
true
true
@@ -26,7 +26,7 @@
-
@@ -35,12 +35,8 @@
-
-
- true
-
-
diff --git a/GFramework.Generator/generator/enums/EnumExtensionsGenerator.cs b/GFramework.SourceGenerators/enums/EnumExtensionsGenerator.cs
similarity index 96%
rename from GFramework.Generator/generator/enums/EnumExtensionsGenerator.cs
rename to GFramework.SourceGenerators/enums/EnumExtensionsGenerator.cs
index f0bd865..9e31593 100644
--- a/GFramework.Generator/generator/enums/EnumExtensionsGenerator.cs
+++ b/GFramework.SourceGenerators/enums/EnumExtensionsGenerator.cs
@@ -5,12 +5,13 @@ using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
-namespace GFramework.Generator.generator.enums;
+namespace GFramework.SourceGenerators.enums;
[Generator]
public class EnumExtensionsGenerator : IIncrementalGenerator
{
- private const string AttributeFullName = "GFramework.Generator.Attributes.generator.enums.GenerateEnumExtensionsAttribute";
+ private const string AttributeFullName =
+ "GFramework.SourceGenerators.Attributes.generator.enums.GenerateEnumExtensionsAttribute";
public void Initialize(IncrementalGeneratorInitializationContext context)
{
diff --git a/GFramework.Generator/generator/logging/Diagnostic.cs b/GFramework.SourceGenerators/logging/Diagnostic.cs
similarity index 79%
rename from GFramework.Generator/generator/logging/Diagnostic.cs
rename to GFramework.SourceGenerators/logging/Diagnostic.cs
index b52210e..10aea63 100644
--- a/GFramework.Generator/generator/logging/Diagnostic.cs
+++ b/GFramework.SourceGenerators/logging/Diagnostic.cs
@@ -1,13 +1,12 @@
using Microsoft.CodeAnalysis;
-namespace GFramework.Generator.generator.logging;
+namespace GFramework.SourceGenerators.logging;
///
/// 提供诊断描述符的静态类,用于GFramework日志生成器的编译时检查
///
-internal static class Diagnostics
+internal static class LoggerDiagnostics
{
-
///
/// 定义诊断描述符:要求使用[Log]特性的类必须声明为partial
///
@@ -23,17 +22,16 @@ internal static class Diagnostics
DiagnosticSeverity.Error,
isEnabledByDefault: true
);
-
+
///
/// 定义诊断描述符:LogAttribute无法生成Logger的错误情况
///
public static readonly DiagnosticDescriptor LogAttributeInvalid =
new(
id: "GFW_LOG001",
- title: "LogAttribute 无法生成 Logger",
- messageFormat: "类 '{0}' 上的 LogAttribute 无法生效:{1}",
- category: "GFramework.Logging",
+ title: "LogAttribute cannot generate Logger",
+ messageFormat: "LogAttribute on class '{0}' is ineffective: {1}",
+ category: "GFramework.Godot.Logging",
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
-
-}
+}
\ No newline at end of file
diff --git a/GFramework.SourceGenerators/logging/LoggerGenerator.cs b/GFramework.SourceGenerators/logging/LoggerGenerator.cs
new file mode 100644
index 0000000..d71f4c3
--- /dev/null
+++ b/GFramework.SourceGenerators/logging/LoggerGenerator.cs
@@ -0,0 +1,185 @@
+#nullable enable
+
+
+using System;
+using System.Linq;
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Text;
+
+namespace GFramework.SourceGenerators.logging;
+
+///
+/// 日志生成器,用于为标记了LogAttribute的类自动生成日志字段
+///
+[Generator]
+public sealed class LoggerGenerator : IIncrementalGenerator
+{
+ private const string AttributeMetadataName = "GFramework.SourceGenerators.Attributes.logging.GodotLogAttribute";
+ private const string AttributeShortName = "GodotLogAttribute";
+ private const string AttributeShortNameWithoutSuffix = "Log";
+
+ ///
+ /// 初始化生成器,设置语法过滤和代码生成逻辑
+ ///
+ /// 增量生成器初始化上下文
+ public void Initialize(IncrementalGeneratorInitializationContext context)
+ {
+ // 1. 语法过滤:快速筛选候选类
+ 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);
+ });
+ },
+ static (ctx, _) =>
+ {
+ var classDecl = (ClassDeclarationSyntax)ctx.Node;
+ var symbol = ctx.SemanticModel.GetDeclaredSymbol(classDecl);
+ return (ClassDecl: classDecl, Symbol: symbol);
+ })
+ .Where(x => x.Symbol is not null);
+
+ // 2. 生成代码
+ context.RegisterSourceOutput(targets, (spc, pair) =>
+ {
+ try
+ {
+ var classDecl = pair.ClassDecl;
+ var classSymbol = pair.Symbol!;
+
+ // 再次确认是否真的含有目标 Attribute (语义检查)
+ var attr = GetAttribute(classSymbol);
+ if (attr == null) return; // 可能是名字相似但不是我们要的 Attribute
+
+ // 检查 partial
+ if (!classDecl.Modifiers.Any(SyntaxKind.PartialKeyword))
+ {
+ spc.ReportDiagnostic(Diagnostic.Create(
+ LoggerDiagnostics.MustBePartial,
+ 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));
+ }
+ catch (Exception ex)
+ {
+ // === 关键修复:生成错误报告文件 ===
+ var errorSource = $"// source generator error: {ex.Message}\n// StackTrace:\n// {ex.StackTrace}";
+ // 替换非法字符以防文件名报错
+ var safeName = pair.Symbol?.Name ?? "Unknown";
+ spc.AddSource($"{safeName}.Logger.Error.g.cs", SourceText.From(errorSource, Encoding.UTF8));
+ }
+ });
+ }
+
+ ///
+ /// 获取类符号上的LogAttribute特性
+ ///
+ /// 类符号
+ /// LogAttribute特性数据,如果不存在则返回null
+ private static AttributeData? GetAttribute(INamedTypeSymbol classSymbol)
+ {
+ return classSymbol.GetAttributes().FirstOrDefault(a =>
+ {
+ var cls = a.AttributeClass;
+ if (cls == null) return false;
+
+ // 宽松匹配:全名匹配 OR 名字匹配
+ return cls.ToDisplayString() == AttributeMetadataName ||
+ cls.Name == AttributeShortName;
+ });
+ }
+
+ ///
+ /// 生成日志字段代码
+ ///
+ /// 类符号
+ /// LogAttribute特性数据
+ /// 生成的C#代码字符串
+ 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 argValue = attr.ConstructorArguments[0].Value;
+
+ name = argValue switch
+ {
+ // 情况 1: 参数存在,但值为 null (例如 [Log] 且构造函数有默认值 null)
+ null => className,
+ // 情况 2: 参数存在,且是有效的字符串 (例如 [Log("MyCategory")])
+ string s when !string.IsNullOrWhiteSpace(s) => s,
+ _ => $"{className}_InvalidArg"
+ };
+ }
+
+ // === 解析 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 staticKeyword = isStatic ? "static " : "";
+
+ var sb = new StringBuilder();
+ sb.AppendLine("// ");
+ sb.AppendLine("using GFramework.Core.logging;"); // 确保这里引用了 ILog 和 Log 类
+
+ if (ns is not null)
+ {
+ sb.AppendLine($"namespace {ns}");
+ sb.AppendLine("{");
+ }
+
+ sb.AppendLine($" public partial class {className}");
+ sb.AppendLine(" {");
+ sb.AppendLine($" /// Auto-generated logger");
+ sb.AppendLine(
+ $" {access} {staticKeyword}readonly ILogger {fieldName} = " +
+ $"new ConsoleLoggerFactory.GetLogger(\"{name}\");");
+ sb.AppendLine(" }");
+
+ if (ns is not null)
+ sb.AppendLine("}");
+
+ return sb.ToString();
+ }
+
+ ///
+ /// 从特性数据中获取命名参数的值
+ ///
+ /// 特性数据
+ /// 参数名称
+ /// 参数值,如果不存在则返回null
+ private static object? GetNamedArg(AttributeData attr, string name)
+ {
+ return (from kv in attr.NamedArguments where kv.Key == name select kv.Value.Value).FirstOrDefault();
+ }
+}
\ No newline at end of file
diff --git a/GFramework.csproj b/GFramework.csproj
index 17c72b4..a9aa03e 100644
--- a/GFramework.csproj
+++ b/GFramework.csproj
@@ -23,9 +23,27 @@
-
-
+
+ GFramework.SorceGenerators\bin\Debug\netstandard2.0\GFramework.Generator.Attributes.dll
+
+
+ GFramework.SorceGenerators\logging\README.md
+
+
+ GFramework.SorceGenerators\README.md
+
+
+ GFramework.SorceGenerators\AnalyzerReleases.Shipped.md
+
+
+ GFramework.SorceGenerators\AnalyzerReleases.Unshipped.md
+
+
+
+
+
+
@@ -35,15 +53,30 @@
-
-
+
+ GFramework.SorceGenerators\enums\EnumExtensionsGenerator.cs
+
+
+ GFramework.SorceGenerators\logging\Diagnostic.cs
+
+
+ GFramework.SorceGenerators\logging\LoggerGenerator.cs
+
+
+
+
+
+
-
-
+
+
+
+
+
diff --git a/GFramework.sln b/GFramework.sln
index 5af8702..a1f30d9 100644
--- a/GFramework.sln
+++ b/GFramework.sln
@@ -2,9 +2,9 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework ", "GFramework.csproj", "{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.Generator", "GFramework.Generator\GFramework.Generator.csproj", "{E9D51809-0351-4B83-B85B-B5F469AAB3B8}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.SourceGenerators", "GFramework.SourceGenerators\GFramework.SourceGenerators.csproj", "{E9D51809-0351-4B83-B85B-B5F469AAB3B8}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.Generator.Attributes", "GFramework.Generator.Attributes\GFramework.Generator.Attributes.csproj", "{84C5C3C9-5620-4924-BA04-92F813F2B70F}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.SourceGenerators.Attributes", "GFramework.SourceGenerators.Attributes\GFramework.SourceGenerators.Attributes.csproj", "{84C5C3C9-5620-4924-BA04-92F813F2B70F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.Core", "GFramework.Core\GFramework.Core.csproj", "{A6D5854D-79EA-487A-9ED9-396E6A1F8031}"
EndProject
@@ -12,6 +12,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.Godot", "GFramew
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.Game", "GFramework.Game\GFramework.Game.csproj", "{0B00816B-E8B2-4562-8C11-0C06CE761638}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.Godot.SourceGenerators", "GFramework.Godot.SourceGenerators\GFramework.Godot.SourceGenerators.csproj", "{C56FD287-CBC6-4C44-B3DF-103FA3660CA0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.Godot.SourceGenerators.Attributes", "GFramework.Godot.SourceGenerators.Attributes\GFramework.Godot.SourceGenerators.Attributes.csproj", "{3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -42,5 +46,13 @@ Global
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal