mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-25 13:33:28 +08:00
refactor(generators): 重构源代码生成器基类架构
- 将 AttributeClassGeneratorBase 抽象基类拆分为 MetadataAttributeClassGeneratorBase 和 TypeAttributeClassGeneratorBase - 为 GodotLoggerGenerator 实现 TypeAttributeClassGeneratorBase 基类 - 为 EnumExtensionsGenerator 实现 MetadataAttributeClassGeneratorBase 基类 - 为 LoggerGenerator 实现 TypeAttributeClassGeneratorBase 基类 - 为 ContextAwareGenerator 实现 MetadataAttributeClassGeneratorBase 基类 - 添加 ContextAwareGenerator 中对 IContextAware 接口实现的验证逻辑 - 简化 AttributeClassGeneratorBase 中的语法提供程序实现 - 移除 AttributeClassGeneratorBase 中的异常处理和错误输出逻辑 - 优化属性解析机制,使用元数据名称或类型进行特性查找
This commit is contained in:
parent
af24a64d3b
commit
414e49c413
@ -1,12 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using GFramework.Godot.SourceGenerators.Abstractions.logging;
|
||||||
using GFramework.SourceGenerators.Common.constants;
|
using GFramework.SourceGenerators.Common.constants;
|
||||||
using GFramework.SourceGenerators.Common.diagnostics;
|
using GFramework.SourceGenerators.Common.generator;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
||||||
using Microsoft.CodeAnalysis.Text;
|
|
||||||
|
|
||||||
namespace GFramework.Godot.SourceGenerators.logging;
|
namespace GFramework.Godot.SourceGenerators.logging;
|
||||||
|
|
||||||
@ -14,95 +12,25 @@ namespace GFramework.Godot.SourceGenerators.logging;
|
|||||||
/// 日志生成器,用于为标记了GodotLogAttribute的类自动生成日志字段
|
/// 日志生成器,用于为标记了GodotLogAttribute的类自动生成日志字段
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Generator]
|
[Generator]
|
||||||
public sealed class GodotLoggerGenerator : IIncrementalGenerator
|
public sealed class GodotLoggerGenerator : TypeAttributeClassGeneratorBase
|
||||||
{
|
{
|
||||||
private const string AttributeMetadataName =
|
protected override Type AttributeType => typeof(GodotLogAttribute);
|
||||||
$"{PathContests.GodotSourceGeneratorsAbstractionsPath}.logging.GodotLogAttribute";
|
|
||||||
|
|
||||||
private const string AttributeShortNameWithoutSuffix = "GodotLog";
|
|
||||||
|
|
||||||
/// <summary>
|
protected override string AttributeShortNameWithoutSuffix => "GodotLog";
|
||||||
/// 初始化源生成器,设置语法提供程序和源输出注册
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">增量生成器初始化上下文</param>
|
|
||||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
|
||||||
{
|
|
||||||
// 创建语法提供程序,用于查找标记了GodotLogAttribute的类声明
|
|
||||||
var targets = context.SyntaxProvider
|
|
||||||
.CreateSyntaxProvider(
|
|
||||||
static (node, _) =>
|
|
||||||
{
|
|
||||||
if (node is not ClassDeclarationSyntax cls) return false;
|
|
||||||
return cls.AttributeLists
|
|
||||||
.SelectMany(a => a.Attributes)
|
|
||||||
.Any(a => a.Name.ToString().Contains(AttributeShortNameWithoutSuffix));
|
|
||||||
},
|
|
||||||
static (ctx, _) =>
|
|
||||||
{
|
|
||||||
var cls = (ClassDeclarationSyntax)ctx.Node;
|
|
||||||
var sym = ctx.SemanticModel.GetDeclaredSymbol(cls);
|
|
||||||
return (ClassDecl: cls, Symbol: sym);
|
|
||||||
})
|
|
||||||
.Where(x => x.Symbol is not null);
|
|
||||||
|
|
||||||
// 注册源输出,为符合条件的类生成日志字段代码
|
|
||||||
context.RegisterSourceOutput(targets, (spc, pair) =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var classDecl = pair.ClassDecl;
|
|
||||||
var classSymbol = pair.Symbol!;
|
|
||||||
|
|
||||||
var attr = GetAttribute(classSymbol);
|
|
||||||
if (attr is null) return;
|
|
||||||
|
|
||||||
if (!classDecl.Modifiers.Any(SyntaxKind.PartialKeyword))
|
|
||||||
{
|
|
||||||
spc.ReportDiagnostic(Diagnostic.Create(
|
|
||||||
CommonDiagnostics.ClassMustBePartial,
|
|
||||||
classDecl.Identifier.GetLocation(),
|
|
||||||
classSymbol.Name));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var source = Generate(classSymbol, attr);
|
|
||||||
spc.AddSource($"{classSymbol.Name}.Logger.g.cs", SourceText.From(source, Encoding.UTF8));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取类符号上的GodotLogAttribute属性数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="classSymbol">类符号</param>
|
|
||||||
/// <returns>GodotLogAttribute属性数据,如果未找到则返回null</returns>
|
|
||||||
private static AttributeData? GetAttribute(INamedTypeSymbol classSymbol)
|
|
||||||
=> classSymbol.GetAttributes().FirstOrDefault(a =>
|
|
||||||
{
|
|
||||||
var cls = a.AttributeClass;
|
|
||||||
return cls != null &&
|
|
||||||
(cls.ToDisplayString() == AttributeMetadataName ||
|
|
||||||
cls.Name.StartsWith(AttributeShortNameWithoutSuffix));
|
|
||||||
});
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 生成日志字段的源代码
|
/// 生成日志字段的源代码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="classSymbol">类符号</param>
|
/// <param name="symbol">类符号</param>
|
||||||
/// <param name="attr">GodotLogAttribute属性数据</param>
|
/// <param name="attr">GodotLogAttribute属性数据</param>
|
||||||
/// <returns>生成的源代码字符串</returns>
|
/// <returns>生成的源代码字符串</returns>
|
||||||
private static string Generate(INamedTypeSymbol classSymbol, AttributeData attr)
|
protected override string Generate(INamedTypeSymbol symbol, AttributeData attr)
|
||||||
{
|
{
|
||||||
var ns = classSymbol.ContainingNamespace.IsGlobalNamespace
|
var ns = symbol.ContainingNamespace.IsGlobalNamespace
|
||||||
? null
|
? null
|
||||||
: classSymbol.ContainingNamespace.ToDisplayString();
|
: symbol.ContainingNamespace.ToDisplayString();
|
||||||
var className = classSymbol.Name;
|
var className = symbol.Name;
|
||||||
|
|
||||||
// 解析构造函数参数
|
// 解析构造函数参数
|
||||||
var name = className;
|
var name = className;
|
||||||
@ -144,11 +72,19 @@ public sealed class GodotLoggerGenerator : IIncrementalGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 从属性数据中获取指定名称的命名参数值
|
/// 获取生成文件的提示名称
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="symbol">类型符号</param>
|
||||||
|
/// <returns>生成文件的提示名称</returns>
|
||||||
|
protected override string GetHintName(INamedTypeSymbol symbol)
|
||||||
|
=> $"{symbol.Name}.Logger.g.cs";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取属性的命名参数值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="attr">属性数据</param>
|
/// <param name="attr">属性数据</param>
|
||||||
/// <param name="name">参数名称</param>
|
/// <param name="name">参数名称</param>
|
||||||
/// <returns>参数值,如果未找到则返回null</returns>
|
/// <returns>参数值</returns>
|
||||||
private static object? GetNamedArg(AttributeData attr, string name)
|
private static object? GetNamedArg(AttributeData attr, string name)
|
||||||
=> attr.NamedArguments.FirstOrDefault(kv => kv.Key == name).Value.Value;
|
=> attr.NamedArguments.FirstOrDefault(kv => kv.Key == name).Value.Value;
|
||||||
}
|
}
|
||||||
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System.Linq;
|
||||||
using System.Linq;
|
|
||||||
using GFramework.SourceGenerators.Common.diagnostics;
|
using GFramework.SourceGenerators.Common.diagnostics;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
@ -13,13 +12,7 @@ namespace GFramework.SourceGenerators.Common.generator;
|
|||||||
public abstract class AttributeClassGeneratorBase : IIncrementalGenerator
|
public abstract class AttributeClassGeneratorBase : IIncrementalGenerator
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取属性的元数据名称
|
/// 获取属性的短名称(不包含后缀)
|
||||||
/// </summary>
|
|
||||||
protected abstract Type AttributeType { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute 的短名称(不含 Attribute 后缀)
|
|
||||||
/// 仅用于 Syntax 层宽松匹配
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected abstract string AttributeShortNameWithoutSuffix { get; }
|
protected abstract string AttributeShortNameWithoutSuffix { get; }
|
||||||
|
|
||||||
@ -29,66 +22,70 @@ public abstract class AttributeClassGeneratorBase : IIncrementalGenerator
|
|||||||
/// <param name="context">增量生成器初始化上下文</param>
|
/// <param name="context">增量生成器初始化上下文</param>
|
||||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||||
{
|
{
|
||||||
var targets = context.SyntaxProvider.CreateSyntaxProvider(
|
// 创建语法提供程序,查找带有指定属性的类声明
|
||||||
|
var candidates = context.SyntaxProvider.CreateSyntaxProvider(
|
||||||
(node, _) =>
|
(node, _) =>
|
||||||
node is ClassDeclarationSyntax cls &&
|
node is ClassDeclarationSyntax cls &&
|
||||||
cls.AttributeLists
|
cls.AttributeLists
|
||||||
.SelectMany(a => a.Attributes)
|
.SelectMany(a => a.Attributes)
|
||||||
.Any(a => a.Name.ToString()
|
.Any(a => a.Name.ToString()
|
||||||
.Contains(AttributeShortNameWithoutSuffix)),
|
.Contains(AttributeShortNameWithoutSuffix)),
|
||||||
static (ctx, t) =>
|
(ctx, _) =>
|
||||||
{
|
{
|
||||||
var cls = (ClassDeclarationSyntax)ctx.Node;
|
var cls = (ClassDeclarationSyntax)ctx.Node;
|
||||||
var symbol = ctx.SemanticModel.GetDeclaredSymbol(cls, t);
|
var symbol = ctx.SemanticModel.GetDeclaredSymbol(cls);
|
||||||
return (ClassDecl: cls, Symbol: symbol);
|
return (cls, symbol);
|
||||||
}
|
})
|
||||||
)
|
.Where(x => x.symbol is not null);
|
||||||
.Where(x => x.Symbol is not null);
|
|
||||||
|
|
||||||
context.RegisterSourceOutput(targets, (spc, pair) =>
|
var combined = candidates.Combine(context.CompilationProvider);
|
||||||
|
|
||||||
|
context.RegisterSourceOutput(combined, (spc, pair) =>
|
||||||
{
|
{
|
||||||
try
|
var ((cls, symbol), compilation) = pair;
|
||||||
{
|
Execute(spc, compilation, cls, symbol!);
|
||||||
Execute(spc, pair.ClassDecl, pair.Symbol!);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
EmitError(spc, pair.Symbol, ex);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 执行源代码生成的主要逻辑
|
/// 解析指定符号上的属性数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="compilation">编译对象</param>
|
||||||
|
/// <param name="symbol">命名类型符号</param>
|
||||||
|
/// <returns>属性数据,如果未找到则返回null</returns>
|
||||||
|
protected abstract AttributeData? ResolveAttribute(
|
||||||
|
Compilation compilation,
|
||||||
|
INamedTypeSymbol symbol);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行源代码生成
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">源生产上下文</param>
|
/// <param name="context">源生产上下文</param>
|
||||||
|
/// <param name="compilation">编译对象</param>
|
||||||
/// <param name="classDecl">类声明语法节点</param>
|
/// <param name="classDecl">类声明语法节点</param>
|
||||||
/// <param name="symbol">命名类型符号</param>
|
/// <param name="symbol">命名类型符号</param>
|
||||||
private void Execute(
|
private void Execute(
|
||||||
SourceProductionContext context,
|
SourceProductionContext context,
|
||||||
|
Compilation compilation,
|
||||||
ClassDeclarationSyntax classDecl,
|
ClassDeclarationSyntax classDecl,
|
||||||
INamedTypeSymbol symbol)
|
INamedTypeSymbol symbol)
|
||||||
{
|
{
|
||||||
var attr = GetAttribute(symbol);
|
var attr = ResolveAttribute(compilation, symbol);
|
||||||
if (attr == null) return;
|
if (attr is null)
|
||||||
|
return;
|
||||||
|
|
||||||
// partial 校验
|
|
||||||
if (!classDecl.Modifiers.Any(SyntaxKind.PartialKeyword))
|
if (!classDecl.Modifiers.Any(SyntaxKind.PartialKeyword))
|
||||||
{
|
{
|
||||||
ReportClassMustBePartial(context, classDecl, symbol);
|
ReportClassMustBePartial(context, classDecl, symbol);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 子类校验
|
|
||||||
if (!ValidateSymbol(context, classDecl, symbol, attr))
|
if (!ValidateSymbol(context, classDecl, symbol, attr))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var source = Generate(symbol, attr);
|
context.AddSource(GetHintName(symbol), Generate(symbol, attr));
|
||||||
context.AddSource(GetHintName(symbol), source);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 可覆写点
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 验证符号的有效性
|
/// 验证符号的有效性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -101,10 +98,7 @@ public abstract class AttributeClassGeneratorBase : IIncrementalGenerator
|
|||||||
SourceProductionContext context,
|
SourceProductionContext context,
|
||||||
ClassDeclarationSyntax syntax,
|
ClassDeclarationSyntax syntax,
|
||||||
INamedTypeSymbol symbol,
|
INamedTypeSymbol symbol,
|
||||||
AttributeData attr)
|
AttributeData attr) => true;
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 生成源代码
|
/// 生成源代码
|
||||||
@ -122,27 +116,10 @@ public abstract class AttributeClassGeneratorBase : IIncrementalGenerator
|
|||||||
/// <param name="symbol">命名类型符号</param>
|
/// <param name="symbol">命名类型符号</param>
|
||||||
/// <returns>生成文件的提示名称</returns>
|
/// <returns>生成文件的提示名称</returns>
|
||||||
protected virtual string GetHintName(INamedTypeSymbol symbol)
|
protected virtual string GetHintName(INamedTypeSymbol symbol)
|
||||||
{
|
=> $"{symbol.Name}.g.cs";
|
||||||
return $"{symbol.Name}.g.cs";
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Attribute / Diagnostic
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取指定符号的属性数据
|
/// 报告类必须是部分类的错误
|
||||||
/// </summary>
|
|
||||||
/// <param name="symbol">命名类型符号</param>
|
|
||||||
/// <returns>属性数据,如果未找到则返回null</returns>
|
|
||||||
protected virtual AttributeData? GetAttribute(INamedTypeSymbol symbol)
|
|
||||||
{
|
|
||||||
return symbol.GetAttributes().FirstOrDefault(a =>
|
|
||||||
string.Equals(a.AttributeClass?.ToDisplayString(), AttributeType.FullName, StringComparison.Ordinal));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 报告类必须是partial的诊断信息
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">源生产上下文</param>
|
/// <param name="context">源生产上下文</param>
|
||||||
/// <param name="syntax">类声明语法节点</param>
|
/// <param name="syntax">类声明语法节点</param>
|
||||||
@ -157,23 +134,4 @@ public abstract class AttributeClassGeneratorBase : IIncrementalGenerator
|
|||||||
syntax.Identifier.GetLocation(),
|
syntax.Identifier.GetLocation(),
|
||||||
symbol.Name));
|
symbol.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 发出错误信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">源生产上下文</param>
|
|
||||||
/// <param name="symbol">命名类型符号</param>
|
|
||||||
/// <param name="ex">异常对象</param>
|
|
||||||
protected virtual void EmitError(
|
|
||||||
SourceProductionContext context,
|
|
||||||
INamedTypeSymbol? symbol,
|
|
||||||
Exception ex)
|
|
||||||
{
|
|
||||||
var name = symbol?.Name ?? "Unknown";
|
|
||||||
var text =
|
|
||||||
$"// source generator error: {ex.Message}\n// {ex.StackTrace}";
|
|
||||||
context.AddSource($"{name}.Error.g.cs", text);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace GFramework.SourceGenerators.Common.generator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 元数据属性类生成器基类,用于基于元数据名称解析特性的抽象基类
|
||||||
|
/// </summary>
|
||||||
|
public abstract class MetadataAttributeClassGeneratorBase
|
||||||
|
: AttributeClassGeneratorBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取特性元数据名称的抽象属性
|
||||||
|
/// </summary>
|
||||||
|
protected abstract string AttributeMetadataName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据元数据名称解析指定符号上的特性
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="compilation">编译对象,用于获取类型信息</param>
|
||||||
|
/// <param name="symbol">命名类型符号,用于查找其上的特性</param>
|
||||||
|
/// <returns>如果找到匹配的特性则返回AttributeData对象,否则返回null</returns>
|
||||||
|
protected override AttributeData? ResolveAttribute(
|
||||||
|
Compilation compilation,
|
||||||
|
INamedTypeSymbol symbol)
|
||||||
|
{
|
||||||
|
// 通过元数据名称获取特性符号
|
||||||
|
var attrSymbol =
|
||||||
|
compilation.GetTypeByMetadataName(AttributeMetadataName);
|
||||||
|
|
||||||
|
if (attrSymbol is null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 在符号的所有特性中查找与目标特性符号匹配的第一个特性
|
||||||
|
return symbol.GetAttributes()
|
||||||
|
.FirstOrDefault(a =>
|
||||||
|
SymbolEqualityComparer.Default.Equals(
|
||||||
|
a.AttributeClass,
|
||||||
|
attrSymbol));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace GFramework.SourceGenerators.Common.generator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 基于类型特性的类生成器基类
|
||||||
|
/// </summary>
|
||||||
|
public abstract class TypeAttributeClassGeneratorBase
|
||||||
|
: AttributeClassGeneratorBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取要处理的特性类型
|
||||||
|
/// </summary>
|
||||||
|
protected abstract Type AttributeType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解析指定符号上的特性
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="compilation">编译对象(未使用)</param>
|
||||||
|
/// <param name="symbol">要检查的命名类型符号</param>
|
||||||
|
/// <returns>匹配的特性数据,如果未找到则返回null</returns>
|
||||||
|
protected override AttributeData? ResolveAttribute(
|
||||||
|
Compilation compilation,
|
||||||
|
INamedTypeSymbol symbol)
|
||||||
|
{
|
||||||
|
var fullName = AttributeType.FullName;
|
||||||
|
|
||||||
|
// 查找符号上匹配指定特性的第一个实例
|
||||||
|
return symbol.GetAttributes()
|
||||||
|
.FirstOrDefault(a =>
|
||||||
|
string.Equals(a.AttributeClass?.ToDisplayString(), fullName, StringComparison.Ordinal));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System.Linq;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using GFramework.SourceGenerators.Abstractions.enums;
|
using GFramework.SourceGenerators.Common.constants;
|
||||||
using GFramework.SourceGenerators.Common.diagnostics;
|
using GFramework.SourceGenerators.Common.diagnostics;
|
||||||
using GFramework.SourceGenerators.Common.generator;
|
using GFramework.SourceGenerators.Common.generator;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
@ -13,13 +12,10 @@ namespace GFramework.SourceGenerators.enums;
|
|||||||
/// 枚举扩展方法生成器,用于自动生成枚举相关的扩展方法
|
/// 枚举扩展方法生成器,用于自动生成枚举相关的扩展方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Generator]
|
[Generator]
|
||||||
public sealed class EnumExtensionsGenerator : AttributeClassGeneratorBase
|
public sealed class EnumExtensionsGenerator : MetadataAttributeClassGeneratorBase
|
||||||
{
|
{
|
||||||
/// <summary>
|
protected override string AttributeMetadataName =>
|
||||||
/// 使用强类型 Attribute,替代字符串
|
$"{PathContests.SourceGeneratorsAbstractionsPath}.enums.GenerateEnumExtensionsAttribute";
|
||||||
/// </summary>
|
|
||||||
protected override Type AttributeType =>
|
|
||||||
typeof(GenerateEnumExtensionsAttribute);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 仅用于 Syntax 粗筛选
|
/// 仅用于 Syntax 粗筛选
|
||||||
|
|||||||
@ -13,10 +13,10 @@ namespace GFramework.SourceGenerators.logging;
|
|||||||
/// 日志生成器,用于为标记了LogAttribute的类自动生成日志字段
|
/// 日志生成器,用于为标记了LogAttribute的类自动生成日志字段
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Generator]
|
[Generator]
|
||||||
public sealed class LoggerGenerator : AttributeClassGeneratorBase
|
public sealed class LoggerGenerator : TypeAttributeClassGeneratorBase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 强类型 Attribute
|
/// 获取属性元数据的完整名称,用于标识日志属性的完全限定名
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override Type AttributeType => typeof(LogAttribute);
|
protected override Type AttributeType => typeof(LogAttribute);
|
||||||
|
|
||||||
@ -25,6 +25,7 @@ public sealed class LoggerGenerator : AttributeClassGeneratorBase
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected override string AttributeShortNameWithoutSuffix => "Log";
|
protected override string AttributeShortNameWithoutSuffix => "Log";
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 对类进行额外语义校验(可选)
|
/// 对类进行额外语义校验(可选)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -1,26 +1,31 @@
|
|||||||
using System;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using GFramework.SourceGenerators.Abstractions.rule;
|
using GFramework.Core.Abstractions.rule;
|
||||||
using GFramework.SourceGenerators.Common.constants;
|
using GFramework.SourceGenerators.Common.constants;
|
||||||
using GFramework.SourceGenerators.Common.generator;
|
using GFramework.SourceGenerators.Common.generator;
|
||||||
|
using GFramework.SourceGenerators.diagnostics;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
|
||||||
namespace GFramework.SourceGenerators.rule;
|
namespace GFramework.SourceGenerators.rule;
|
||||||
|
|
||||||
[Generator]
|
[Generator]
|
||||||
public sealed class ContextAwareGenerator : AttributeClassGeneratorBase
|
public sealed class ContextAwareGenerator : MetadataAttributeClassGeneratorBase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用强类型 Attribute,替代字符串
|
/// 获取属性元数据的完整名称,用于标识ContextAwareAttribute的完全限定名
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override Type AttributeType => typeof(ContextAwareAttribute);
|
/// <returns>返回ContextAwareAttribute的完全限定名字符串</returns>
|
||||||
|
protected override string AttributeMetadataName =>
|
||||||
|
$"{PathContests.SourceGeneratorsAbstractionsPath}.rule.ContextAwareAttribute";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 仅用于 Syntax 粗筛选
|
/// 仅用于 Syntax 粗筛选
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <returns>返回属性的简短名称,不包含后缀</returns>
|
||||||
protected override string AttributeShortNameWithoutSuffix => "ContextAware";
|
protected override string AttributeShortNameWithoutSuffix => "ContextAware";
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 额外语义校验:必须实现 IContextAware
|
/// 额外语义校验:必须实现 IContextAware
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -30,7 +35,13 @@ public sealed class ContextAwareGenerator : AttributeClassGeneratorBase
|
|||||||
INamedTypeSymbol symbol,
|
INamedTypeSymbol symbol,
|
||||||
AttributeData attr)
|
AttributeData attr)
|
||||||
{
|
{
|
||||||
return true;
|
if (symbol.AllInterfaces.Any(i =>
|
||||||
|
i.ToDisplayString() == typeof(IContextAware).FullName)) return true;
|
||||||
|
context.ReportDiagnostic(Diagnostic.Create(
|
||||||
|
ContextAwareDiagnostic.ClassMustImplementIContextAware,
|
||||||
|
syntax.Identifier.GetLocation(),
|
||||||
|
symbol.Name));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user