diff --git a/GFramework.Generator/generator/logging/LoggerGenerator.cs b/GFramework.Generator/generator/logging/LoggerGenerator.cs
index b523d10..c60da8b 100644
--- a/GFramework.Generator/generator/logging/LoggerGenerator.cs
+++ b/GFramework.Generator/generator/logging/LoggerGenerator.cs
@@ -1,4 +1,5 @@
-using System.Linq;
+using System;
+using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
@@ -7,81 +8,92 @@ using Microsoft.CodeAnalysis.Text;
namespace GFramework.Generator.generator.logging
{
- ///
- /// 日志生成器,用于为标记了LogAttribute的类自动生成日志字段
- ///
[Generator]
public sealed class LoggerGenerator : IIncrementalGenerator
{
- private const string AttributeMetadataName =
- "GFramework.Generator.Attributes.generator.logging.LogAttribute";
+ // 请确保这里的命名空间和类名与 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)
{
- // 筛选出带有指定属性标记的类
- var targets =
- context.SyntaxProvider.CreateSyntaxProvider(
- static (node, _) =>
+ // 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 =>
{
- if (node is not ClassDeclarationSyntax cls)
- return false;
+ 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);
- // 只要写了 [Log] / [Log(...)] 就命中
- return cls.AttributeLists
- .SelectMany(a => a.Attributes)
- .Any(a =>
- {
- var name = a.Name.ToString();
- return name == "Log"
- || name == "LogAttribute"
- || name.EndsWith(".Log")
- || name.EndsWith(".LogAttribute");
- });
- },
- 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) =>
{
- var classDecl = pair.ClassDecl;
- var classSymbol = pair.Symbol!;
-
- if (!classDecl.Modifiers.Any(SyntaxKind.PartialKeyword))
+ // === 关键修复:添加 try-catch 块 ===
+ try
{
- spc.ReportDiagnostic(
- Diagnostic.Create(
- Diagnostics.MustBePartial,
+ 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))
+ {
+ // 如果 Diagnostics 类有问题,这里可能会崩,先注释掉或确保该类存在
+ spc.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor("GEN001", "Class must be partial", "Class '{0}' must be partial",
+ "Usage", DiagnosticSeverity.Error, true),
classDecl.Identifier.GetLocation(),
classSymbol.Name));
- return;
+
+ 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));
}
-
- var source = Generate(classSymbol, spc);
- spc.AddSource($"{classSymbol.Name}.Logger.g.cs",
- SourceText.From(source, Encoding.UTF8));
});
-
}
+ private static AttributeData GetAttribute(INamedTypeSymbol classSymbol)
+ {
+ return classSymbol.GetAttributes().FirstOrDefault(a =>
+ {
+ var cls = a.AttributeClass;
+ if (cls == null) return false;
- ///
- /// 生成日志字段代码
- ///
- /// 类符号
- /// 源代码生成上下文
- /// 生成的代码字符串
- private static string Generate(INamedTypeSymbol classSymbol, SourceProductionContext spc)
+ // 宽松匹配:全名匹配 OR 名字匹配
+ return cls.ToDisplayString() == AttributeMetadataName ||
+ cls.Name == AttributeShortName;
+ });
+ }
+
+ private static string Generate(INamedTypeSymbol classSymbol, AttributeData attr)
{
var ns = classSymbol.ContainingNamespace.IsGlobalNamespace
? null
@@ -89,63 +101,34 @@ namespace GFramework.Generator.generator.logging
var className = classSymbol.Name;
- var attr = classSymbol.GetAttributes()
- .FirstOrDefault(a =>
+ // === 解析 Category ===
+ string category = className; // 默认值
+
+ // 检查构造函数参数 (第一个参数)
+ if (attr.ConstructorArguments.Length > 0)
+ {
+ var argValue = attr.ConstructorArguments[0].Value;
+ if (argValue is string s && !string.IsNullOrWhiteSpace(s))
{
- var c = a.AttributeClass;
- if (c is null) return false;
-
- return c.ToDisplayString() == AttributeMetadataName
- || c.Name == "LogAttribute";
- });
-
- if (attr is null)
- {
- // 理论上不会发生,但防御式处理
- spc.ReportDiagnostic(
- Diagnostic.Create(
- Diagnostics.LogAttributeInvalid,
- classSymbol.Locations.FirstOrDefault(),
- className,
- "未找到 LogAttribute"
- ));
- return string.Empty;
+ category = s;
+ }
}
- // === 解析 category ===
- string category;
+ // === 解析 Named Arguments (更加安全的获取方式) ===
+ var fieldName = GetNamedArg(attr, "FieldName")?.ToString() ?? "_log";
+ var access =
+ GetNamedArg(attr, "AccessModifier")?.ToString() ??
+ "private"; // 注意:如果你的 AccessModifier 是枚举,这里得到的可能是 int 或枚举名
- if (attr.ConstructorArguments.Length == 0)
- {
- // 默认:类名
- category = className;
- }
- else if (attr.ConstructorArguments[0].Value is string s &&
- !string.IsNullOrWhiteSpace(s))
- {
- category = s;
- }
- else
- {
- spc.ReportDiagnostic(
- Diagnostic.Create(
- Diagnostics.LogAttributeInvalid,
- classSymbol.Locations.FirstOrDefault(),
- className,
- "LogAttribute 的构造参数不是有效的 string"
- ));
- return string.Empty;
- }
-
- var fieldName = GetNamedArg(attr, "FieldName", "_log");
- var access = GetNamedArg(attr, "AccessModifier", "private");
- var isStatic = GetNamedArg(attr, "IsStatic", true);
+ // 处理 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;");
+ sb.AppendLine("using GFramework.Core.logging;"); // 确保这里引用了 ILog 和 Log 类
if (ns is not null)
{
@@ -155,6 +138,7 @@ namespace GFramework.Generator.generator.logging
sb.AppendLine($" public partial class {className}");
sb.AppendLine(" {");
+ sb.AppendLine($" /// Auto-generated logger");
sb.AppendLine(
$" {access} {staticKeyword}readonly ILog {fieldName} = " +
$"Log.CreateLogger(\"{category}\");");
@@ -166,24 +150,15 @@ namespace GFramework.Generator.generator.logging
return sb.ToString();
}
-
- ///
- /// 获取属性参数的值
- ///
- /// 参数类型
- /// 属性数据
- /// 参数名称
- /// 默认值
- /// 参数值或默认值
- private static T GetNamedArg(AttributeData attr, string name, T defaultValue)
+ private static object? GetNamedArg(AttributeData attr, string name)
{
foreach (var kv in attr.NamedArguments)
{
- if (kv.Key == name && kv.Value.Value is T v)
- return v;
+ if (kv.Key == name)
+ return kv.Value.Value;
}
- return defaultValue;
+ return null;
}
}
}
\ No newline at end of file