using System.Text; using GFramework.SourceGenerators.Common.Constants; using GFramework.SourceGenerators.Common.Generator; using GFramework.SourceGenerators.Diagnostics; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace GFramework.SourceGenerators.Bases; /// /// Priority 特性生成器,为标记了 [Priority] 的类自动生成 IPrioritized 接口实现 /// [Generator] public sealed class PriorityGenerator : MetadataAttributeClassGeneratorBase { /// /// 获取特性的元数据名称 /// protected override string AttributeMetadataName => $"{PathContests.SourceGeneratorsAbstractionsPath}.Bases.PriorityAttribute"; /// /// 获取特性的短名称(不包含后缀) /// protected override string AttributeShortNameWithoutSuffix => "Priority"; /// /// 验证符号是否符合生成条件 /// protected override bool ValidateSymbol( SourceProductionContext context, Compilation compilation, ClassDeclarationSyntax syntax, INamedTypeSymbol symbol, AttributeData attr) { // 1. 必须是 class if (symbol.TypeKind != TypeKind.Class) { context.ReportDiagnostic(Diagnostic.Create( PriorityDiagnostic.OnlyApplyToClass, syntax.Identifier.GetLocation(), symbol.ToDisplayString())); return false; } // 2. 不支持嵌套类 if (symbol.ContainingType != null) { context.ReportDiagnostic(Diagnostic.Create( PriorityDiagnostic.NestedClassNotSupported, syntax.Identifier.GetLocation(), symbol.Name)); return false; } // 3. 必须是 partial if (!syntax.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword))) { context.ReportDiagnostic(Diagnostic.Create( PriorityDiagnostic.MustBePartial, syntax.Identifier.GetLocation(), symbol.Name)); return false; } // 4. 检查是否已手动实现 IPrioritized var iPrioritized = compilation.GetTypeByMetadataName( $"{PathContests.CoreAbstractionsNamespace}.Bases.IPrioritized"); if (iPrioritized != null && symbol.AllInterfaces.Contains(iPrioritized, SymbolEqualityComparer.Default)) { context.ReportDiagnostic(Diagnostic.Create( PriorityDiagnostic.AlreadyImplemented, syntax.Identifier.GetLocation(), symbol.Name)); return false; } // 5. 验证特性参数 if (attr.ConstructorArguments.Length == 0 || attr.ConstructorArguments[0].Value is not int) { context.ReportDiagnostic(Diagnostic.Create( PriorityDiagnostic.InvalidValue, syntax.Identifier.GetLocation())); return false; } return true; } /// /// 生成源代码 /// protected override string Generate( SourceProductionContext context, Compilation compilation, INamedTypeSymbol symbol, AttributeData attr) { var ns = symbol.ContainingNamespace.IsGlobalNamespace ? null : symbol.ContainingNamespace.ToDisplayString(); var priorityValue = (int)attr.ConstructorArguments[0].Value!; var sb = new StringBuilder(); sb.AppendLine("// "); sb.AppendLine("#nullable enable"); sb.AppendLine(); if (ns is not null) { sb.AppendLine($"namespace {ns};"); sb.AppendLine(); } // 生成泛型参数(如果有) var typeParameters = symbol.TypeParameters.Length > 0 ? $"<{string.Join(", ", symbol.TypeParameters.Select(tp => tp.Name))}>" : string.Empty; sb.AppendLine( $"partial class {symbol.Name}{typeParameters} : global::GFramework.Core.Abstractions.Bases.IPrioritized"); sb.AppendLine("{"); sb.AppendLine(" /// "); sb.AppendLine($" /// 获取优先级值: {priorityValue}"); sb.AppendLine(" /// "); sb.AppendLine($" public int Priority => {priorityValue};"); sb.AppendLine("}"); return sb.ToString().TrimEnd(); } /// /// 获取生成文件的提示名称 /// protected override string GetHintName(INamedTypeSymbol symbol) { // 使用完整的元数据名称以避免冲突 var metadataName = symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) .Replace("global::", "") .Replace("<", "_") .Replace(">", "_") .Replace(",", "_") .Replace(" ", "") .Replace(".", "_"); return $"{metadataName}.Priority.g.cs"; } }