mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
feat(generator): 添加命名类型符号扩展方法并优化日志生成器
- 新增 INamedTypeSymbolExtensions 扩展类,提供 GetFullClassName 方法获取完整类名 - 在 LoggerGenerator 中引入命名空间扩展,支持嵌套类型完整路径解析 - 重构 LoggerGenerator 的类名和参数解析逻辑,增强代码可读性 - 添加对 record 类型的支持,完善类型判断机制 - 优化泛型参数和约束的处理方式,提升代码生成准确性
This commit is contained in:
parent
3fb281031c
commit
7876647871
@ -0,0 +1,61 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace GFramework.SourceGenerators.Common.extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 提供INamedTypeSymbol类型的扩展方法
|
||||||
|
/// </summary>
|
||||||
|
public static class INamedTypeSymbolExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取命名类型符号的完整类名(包括嵌套类型名称)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="symbol">要获取完整类名的命名类型符号</param>
|
||||||
|
/// <returns>完整的类名,格式为"外层类名.内层类名.当前类名"</returns>
|
||||||
|
public static string GetFullClassName(this INamedTypeSymbol symbol)
|
||||||
|
{
|
||||||
|
var names = new Stack<string>();
|
||||||
|
var current = symbol;
|
||||||
|
|
||||||
|
// 遍历包含类型链,将所有类型名称压入栈中
|
||||||
|
while (current != null)
|
||||||
|
{
|
||||||
|
names.Push(current.Name);
|
||||||
|
current = current.ContainingType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将栈中的名称用点号连接,形成完整的类名
|
||||||
|
return string.Join(".", names);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取命名类型符号的命名空间名称
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="symbol">要获取命名空间的命名类型符号</param>
|
||||||
|
/// <returns>命名空间名称,如果是全局命名空间则返回null</returns>
|
||||||
|
private static string? GetNamespace(this INamedTypeSymbol symbol)
|
||||||
|
{
|
||||||
|
return symbol.ContainingNamespace.IsGlobalNamespace
|
||||||
|
? null
|
||||||
|
: symbol.ContainingNamespace.ToDisplayString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据类型种类解析对应的类型关键字
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="symbol">要解析类型的命名类型符号</param>
|
||||||
|
/// <returns>对应类型的字符串表示,如"class"、"struct"或"record"</returns>
|
||||||
|
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",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using GFramework.SourceGenerators.Abstractions.logging;
|
using GFramework.SourceGenerators.Abstractions.logging;
|
||||||
using GFramework.SourceGenerators.Common.constants;
|
using GFramework.SourceGenerators.Common.constants;
|
||||||
|
using GFramework.SourceGenerators.Common.extensions;
|
||||||
using GFramework.SourceGenerators.Common.generator;
|
using GFramework.SourceGenerators.Common.generator;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
@ -59,30 +60,32 @@ public sealed class LoggerGenerator : TypeAttributeClassGeneratorBase
|
|||||||
? null
|
? null
|
||||||
: symbol.ContainingNamespace.ToDisplayString();
|
: symbol.ContainingNamespace.ToDisplayString();
|
||||||
|
|
||||||
var className = symbol.Name;
|
// 类名和嵌套类完整路径
|
||||||
|
var className = symbol.GetFullClassName();
|
||||||
|
|
||||||
// 解析构造函数参数
|
// 构造函数参数解析
|
||||||
var name = className;
|
var logName = className;
|
||||||
if (attr.ConstructorArguments.Length > 0)
|
if (attr.ConstructorArguments.Length > 0)
|
||||||
{
|
{
|
||||||
var argValue = attr.ConstructorArguments[0].Value;
|
var argValue = attr.ConstructorArguments[0].Value;
|
||||||
name = argValue is string s && !string.IsNullOrWhiteSpace(s)
|
logName = argValue is string s && !string.IsNullOrWhiteSpace(s)
|
||||||
? s
|
? s
|
||||||
: className;
|
: className;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析命名参数
|
// 命名参数解析
|
||||||
var fieldName = GetNamedArg(attr, "FieldName")?.ToString() ?? "_log";
|
var fieldName = GetNamedArg(attr, "FieldName")?.ToString() ?? "_log";
|
||||||
var access = GetNamedArg(attr, "AccessModifier")?.ToString() ?? "private";
|
var access = GetNamedArg(attr, "AccessModifier")?.ToString() ?? "private";
|
||||||
var isStaticObj = GetNamedArg(attr, "IsStatic");
|
var isStaticObj = GetNamedArg(attr, "IsStatic");
|
||||||
var isStatic = isStaticObj is not bool b || b; // 默认 true
|
var isStatic = isStaticObj is not bool b || b; // 默认 true
|
||||||
var staticKeyword = isStatic ? "static " : "";
|
var staticKeyword = isStatic ? "static " : "";
|
||||||
|
|
||||||
// 泛型参数和约束
|
// 泛型参数
|
||||||
var typeParams = symbol.TypeParameters.Length > 0
|
var typeParams = symbol.TypeParameters.Length > 0
|
||||||
? "<" + string.Join(", ", symbol.TypeParameters.Select(tp => tp.Name)) + ">"
|
? "<" + string.Join(", ", symbol.TypeParameters.Select(tp => tp.Name)) + ">"
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
|
// 泛型约束
|
||||||
var constraints = symbol.TypeParameters
|
var constraints = symbol.TypeParameters
|
||||||
.Where(tp => tp.ConstraintTypes.Length > 0 || tp.HasReferenceTypeConstraint || tp.HasValueTypeConstraint ||
|
.Where(tp => tp.ConstraintTypes.Length > 0 || tp.HasReferenceTypeConstraint || tp.HasValueTypeConstraint ||
|
||||||
tp.HasConstructorConstraint)
|
tp.HasConstructorConstraint)
|
||||||
@ -98,6 +101,17 @@ public sealed class LoggerGenerator : TypeAttributeClassGeneratorBase
|
|||||||
return $"where {tp.Name} : {string.Join(", ", parts)}";
|
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();
|
var sb = new StringBuilder();
|
||||||
sb.AppendLine("// <auto-generated />");
|
sb.AppendLine("// <auto-generated />");
|
||||||
sb.AppendLine($"using {PathContests.CoreAbstractionsNamespace}.logging;");
|
sb.AppendLine($"using {PathContests.CoreAbstractionsNamespace}.logging;");
|
||||||
@ -109,16 +123,14 @@ public sealed class LoggerGenerator : TypeAttributeClassGeneratorBase
|
|||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.AppendLine($"partial class {className}{typeParams}");
|
// 生成 partial 类
|
||||||
|
sb.AppendLine($"partial {typeKind} {className}{typeParams}");
|
||||||
foreach (var c in constraints)
|
foreach (var c in constraints)
|
||||||
{
|
|
||||||
sb.AppendLine($" {c}");
|
sb.AppendLine($" {c}");
|
||||||
}
|
|
||||||
|
|
||||||
sb.AppendLine("{");
|
sb.AppendLine("{");
|
||||||
sb.AppendLine(" /// <summary>Auto-generated logger</summary>");
|
sb.AppendLine($" /// <summary>Auto-generated logger</summary>");
|
||||||
sb.AppendLine(
|
sb.AppendLine(
|
||||||
$" {access} {staticKeyword}readonly ILogger {fieldName} = LoggerFactoryResolver.Provider.CreateLogger(\"{name}\");");
|
$" {access} {staticKeyword}readonly ILogger {fieldName} = LoggerFactoryResolver.Provider.CreateLogger(\"{logName}\");");
|
||||||
sb.AppendLine("}");
|
sb.AppendLine("}");
|
||||||
|
|
||||||
return sb.ToString().TrimEnd();
|
return sb.ToString().TrimEnd();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user