using GFramework.SourceGenerators.Common.Diagnostics; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace GFramework.SourceGenerators.Common.Generator; /// /// 属性类生成器基类,用于处理带有特定属性的类并生成相应的源代码 /// public abstract class AttributeClassGeneratorBase : IIncrementalGenerator { /// /// 获取属性的短名称(不包含后缀) /// protected abstract string AttributeShortNameWithoutSuffix { get; } /// /// 初始化增量生成器 /// /// 增量生成器初始化上下文 public void Initialize(IncrementalGeneratorInitializationContext context) { // 创建语法提供程序,查找带有指定属性的类声明 var candidates = context.SyntaxProvider.CreateSyntaxProvider( (node, _) => node is ClassDeclarationSyntax cls && cls.AttributeLists .SelectMany(a => a.Attributes) .Any(a => a.Name.ToString() .Contains(AttributeShortNameWithoutSuffix)), (ctx, _) => { var cls = (ClassDeclarationSyntax)ctx.Node; var symbol = ctx.SemanticModel.GetDeclaredSymbol(cls); return (cls, symbol); }) .Where(x => x.symbol is not null); var combined = candidates.Combine(context.CompilationProvider); context.RegisterSourceOutput(combined, (spc, pair) => { var ((cls, symbol), compilation) = pair; Execute(spc, compilation, cls, symbol!); }); } /// /// 解析指定符号上的属性数据 /// /// 编译对象 /// 命名类型符号 /// 属性数据,如果未找到则返回null protected abstract AttributeData? ResolveAttribute( Compilation compilation, INamedTypeSymbol symbol); /// /// 执行源代码生成 /// /// 源生产上下文 /// 编译对象 /// 类声明语法节点 /// 命名类型符号 private void Execute( SourceProductionContext context, Compilation compilation, ClassDeclarationSyntax classDecl, INamedTypeSymbol symbol) { // ① 进入 Execute CommonDiagnostics.Trace(context, $"[GEN] Enter Execute: {symbol.ToDisplayString()}"); var attr = ResolveAttribute(compilation, symbol); // ② 属性是否解析到 if (attr is null) { CommonDiagnostics.Trace(context, $"[GEN] Attribute NOT resolved on {symbol.ToDisplayString()}"); return; } CommonDiagnostics.Trace(context, $"[GEN] Attribute resolved: {attr.AttributeClass?.ToDisplayString()}"); // ③ partial 校验 if (!classDecl.Modifiers.Any(SyntaxKind.PartialKeyword)) { CommonDiagnostics.Trace(context, $"[GEN] Class is NOT partial: {symbol.Name}"); ReportClassMustBePartial(context, classDecl, symbol); return; } // ④ ValidateSymbol if (!ValidateSymbol(context, compilation, classDecl, symbol, attr)) { CommonDiagnostics.Trace(context, $"[GEN] ValidateSymbol FAILED: {symbol.ToDisplayString()}"); return; } // ⑤ Generate var hintName = GetHintName(symbol); CommonDiagnostics.Trace(context, $"[GEN] Generating source: {hintName}"); context.AddSource(hintName, Generate(context, compilation, symbol, attr)); } /// /// 验证符号的有效性 /// /// 源生产上下文 /// 编译对象 /// 类声明语法节点 /// 命名类型符号 /// 属性数据 /// 验证是否通过 protected virtual bool ValidateSymbol( SourceProductionContext context, Compilation compilation, ClassDeclarationSyntax syntax, INamedTypeSymbol symbol, AttributeData attr) { return true; } /// /// 生成源代码 /// /// 源生产上下文 /// 编译对象 /// 命名类型符号 /// 属性数据 /// 生成的源代码字符串 protected abstract string Generate( SourceProductionContext context, Compilation compilation, INamedTypeSymbol symbol, AttributeData attr); /// /// 获取生成文件的提示名称 /// /// 命名类型符号 /// 生成文件的提示名称 protected virtual string GetHintName(INamedTypeSymbol symbol) { return $"{symbol.Name}.g.cs"; } /// /// 报告类必须是部分类的错误 /// /// 源生产上下文 /// 类声明语法节点 /// 命名类型符号 protected virtual void ReportClassMustBePartial( SourceProductionContext context, ClassDeclarationSyntax syntax, INamedTypeSymbol symbol) { context.ReportDiagnostic(Diagnostic.Create( CommonDiagnostics.ClassMustBePartial, syntax.Identifier.GetLocation(), symbol.Name)); } }