From 7876647871e967dad63fe1a3d3ce8827864bc267 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:21:54 +0800 Subject: [PATCH] =?UTF-8?q?feat(generator):=20=E6=B7=BB=E5=8A=A0=E5=91=BD?= =?UTF-8?q?=E5=90=8D=E7=B1=BB=E5=9E=8B=E7=AC=A6=E5=8F=B7=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E5=B9=B6=E4=BC=98=E5=8C=96=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 - 新增 INamedTypeSymbolExtensions 扩展类,提供 GetFullClassName 方法获取完整类名 - 在 LoggerGenerator 中引入命名空间扩展,支持嵌套类型完整路径解析 - 重构 LoggerGenerator 的类名和参数解析逻辑,增强代码可读性 - 添加对 record 类型的支持,完善类型判断机制 - 优化泛型参数和约束的处理方式,提升代码生成准确性 --- .../extensions/INamedTypeSymbolExtensions.cs | 61 +++++++++++++++++++ .../logging/LoggerGenerator.cs | 36 +++++++---- 2 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 GFramework.SourceGenerators.Common/extensions/INamedTypeSymbolExtensions.cs diff --git a/GFramework.SourceGenerators.Common/extensions/INamedTypeSymbolExtensions.cs b/GFramework.SourceGenerators.Common/extensions/INamedTypeSymbolExtensions.cs new file mode 100644 index 0000000..4865ea9 --- /dev/null +++ b/GFramework.SourceGenerators.Common/extensions/INamedTypeSymbolExtensions.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using Microsoft.CodeAnalysis; + +namespace GFramework.SourceGenerators.Common.extensions; + +/// +/// 提供INamedTypeSymbol类型的扩展方法 +/// +public static class INamedTypeSymbolExtensions +{ + /// + /// 获取命名类型符号的完整类名(包括嵌套类型名称) + /// + /// 要获取完整类名的命名类型符号 + /// 完整的类名,格式为"外层类名.内层类名.当前类名" + public static string GetFullClassName(this INamedTypeSymbol symbol) + { + var names = new Stack(); + var current = symbol; + + // 遍历包含类型链,将所有类型名称压入栈中 + while (current != null) + { + names.Push(current.Name); + current = current.ContainingType; + } + + // 将栈中的名称用点号连接,形成完整的类名 + return string.Join(".", names); + } + + /// + /// 获取命名类型符号的命名空间名称 + /// + /// 要获取命名空间的命名类型符号 + /// 命名空间名称,如果是全局命名空间则返回null + private static string? GetNamespace(this INamedTypeSymbol symbol) + { + return symbol.ContainingNamespace.IsGlobalNamespace + ? null + : symbol.ContainingNamespace.ToDisplayString(); + } + + /// + /// 根据类型种类解析对应的类型关键字 + /// + /// 要解析类型的命名类型符号 + /// 对应类型的字符串表示,如"class"、"struct"或"record" + private static string ResolveTypeKind(this INamedTypeSymbol symbol) + { + return symbol.TypeKind switch + { + TypeKind.Class => "class", + TypeKind.Struct => "struct", +#if NET5_0_OR_GREATER || ROSLYN_3_7_OR_GREATER + TypeKind.Record => "record", +#endif + _ => "class", + }; + } +} \ No newline at end of file diff --git a/GFramework.SourceGenerators/logging/LoggerGenerator.cs b/GFramework.SourceGenerators/logging/LoggerGenerator.cs index 3aaa4a8..577ccff 100644 --- a/GFramework.SourceGenerators/logging/LoggerGenerator.cs +++ b/GFramework.SourceGenerators/logging/LoggerGenerator.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using GFramework.SourceGenerators.Abstractions.logging; using GFramework.SourceGenerators.Common.constants; +using GFramework.SourceGenerators.Common.extensions; using GFramework.SourceGenerators.Common.generator; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -59,30 +60,32 @@ public sealed class LoggerGenerator : TypeAttributeClassGeneratorBase ? null : symbol.ContainingNamespace.ToDisplayString(); - var className = symbol.Name; + // 类名和嵌套类完整路径 + var className = symbol.GetFullClassName(); - // 解析构造函数参数 - var name = className; + // 构造函数参数解析 + var logName = className; if (attr.ConstructorArguments.Length > 0) { var argValue = attr.ConstructorArguments[0].Value; - name = argValue is string s && !string.IsNullOrWhiteSpace(s) + logName = argValue is string s && !string.IsNullOrWhiteSpace(s) ? s : className; } - // 解析命名参数 + // 命名参数解析 var fieldName = GetNamedArg(attr, "FieldName")?.ToString() ?? "_log"; var access = GetNamedArg(attr, "AccessModifier")?.ToString() ?? "private"; var isStaticObj = GetNamedArg(attr, "IsStatic"); var isStatic = isStaticObj is not bool b || b; // 默认 true var staticKeyword = isStatic ? "static " : ""; - // 泛型参数和约束 + // 泛型参数 var typeParams = symbol.TypeParameters.Length > 0 ? "<" + string.Join(", ", symbol.TypeParameters.Select(tp => tp.Name)) + ">" : ""; + // 泛型约束 var constraints = symbol.TypeParameters .Where(tp => tp.ConstraintTypes.Length > 0 || tp.HasReferenceTypeConstraint || tp.HasValueTypeConstraint || tp.HasConstructorConstraint) @@ -98,6 +101,17 @@ public sealed class LoggerGenerator : TypeAttributeClassGeneratorBase return $"where {tp.Name} : {string.Join(", ", parts)}"; }); + // 判断类型 + var typeKind = symbol.TypeKind switch + { + TypeKind.Class => "class", + TypeKind.Struct => "struct", +#if NET5_0_OR_GREATER || ROSLYN_3_7_OR_GREATER + TypeKind.Record => "record", +#endif + _ => "class" + }; + var sb = new StringBuilder(); sb.AppendLine("// "); sb.AppendLine($"using {PathContests.CoreAbstractionsNamespace}.logging;"); @@ -109,16 +123,14 @@ public sealed class LoggerGenerator : TypeAttributeClassGeneratorBase sb.AppendLine(); } - sb.AppendLine($"partial class {className}{typeParams}"); + // 生成 partial 类 + sb.AppendLine($"partial {typeKind} {className}{typeParams}"); foreach (var c in constraints) - { sb.AppendLine($" {c}"); - } - sb.AppendLine("{"); - sb.AppendLine(" /// Auto-generated logger"); + sb.AppendLine($" /// Auto-generated logger"); sb.AppendLine( - $" {access} {staticKeyword}readonly ILogger {fieldName} = LoggerFactoryResolver.Provider.CreateLogger(\"{name}\");"); + $" {access} {staticKeyword}readonly ILogger {fieldName} = LoggerFactoryResolver.Provider.CreateLogger(\"{logName}\");"); sb.AppendLine("}"); return sb.ToString().TrimEnd();