using System.Linq; 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) { var attr = ResolveAttribute(compilation, symbol); if (attr is null) return; if (!classDecl.Modifiers.Any(SyntaxKind.PartialKeyword)) { ReportClassMustBePartial(context, classDecl, symbol); return; } if (!ValidateSymbol(context, classDecl, symbol, attr)) return; context.AddSource(GetHintName(symbol), Generate(symbol, attr)); } /// /// 验证符号的有效性 /// /// 源生产上下文 /// 类声明语法节点 /// 命名类型符号 /// 属性数据 /// 验证是否通过 protected virtual bool ValidateSymbol( SourceProductionContext context, ClassDeclarationSyntax syntax, INamedTypeSymbol symbol, AttributeData attr) => true; /// /// 生成源代码 /// /// 命名类型符号 /// 属性数据 /// 生成的源代码字符串 protected abstract string Generate( INamedTypeSymbol symbol, AttributeData attr); /// /// 获取生成文件的提示名称 /// /// 命名类型符号 /// 生成文件的提示名称 protected virtual string GetHintName(INamedTypeSymbol symbol) => $"{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)); } }