using System.Linq; using System.Text; using GFramework.SourceGenerators.Common.constants; using GFramework.SourceGenerators.Common.generator; using GFramework.SourceGenerators.diagnostics; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace GFramework.SourceGenerators.rule; [Generator] public sealed class ContextAwareGenerator : MetadataAttributeClassGeneratorBase { protected override string AttributeMetadataName => $"{PathContests.SourceGeneratorsAbstractionsPath}.rule.ContextAwareAttribute"; protected override string AttributeShortNameWithoutSuffix => "ContextAware"; protected override bool ValidateSymbol( SourceProductionContext context, Compilation compilation, ClassDeclarationSyntax syntax, INamedTypeSymbol symbol, AttributeData attr) { var iContextAware = compilation.GetTypeByMetadataName( $"{PathContests.CoreAbstractionsNamespace}.rule.IContextAware"); if (iContextAware is null) { context.ReportDiagnostic(Diagnostic.Create( ContextAwareDiagnostic.ClassMustImplementIContextAware, syntax.Identifier.GetLocation(), symbol.Name)); return false; } if (!symbol.AllInterfaces.Any(i => SymbolEqualityComparer.Default.Equals(i, iContextAware))) { context.ReportDiagnostic(Diagnostic.Create( ContextAwareDiagnostic.ClassMustImplementIContextAware, syntax.Identifier.GetLocation(), symbol.Name)); 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 iContextAware = compilation.GetTypeByMetadataName( $"{PathContests.CoreAbstractionsNamespace}.rule.IContextAware"); var sb = new StringBuilder(); sb.AppendLine("// "); sb.AppendLine("#nullable enable"); sb.AppendLine(); if (ns is not null) { sb.AppendLine($"namespace {ns};"); sb.AppendLine(); } sb.AppendLine($"partial class {symbol.Name}"); sb.AppendLine("{"); GenerateContextProperty(sb); GenerateInterfaceImplementations(sb, iContextAware!); sb.AppendLine("}"); return sb.ToString().TrimEnd(); } protected override string GetHintName(INamedTypeSymbol symbol) => $"{symbol.Name}.ContextAware.g.cs"; // ========================= // 生成 Context 属性 // ========================= private static void GenerateContextProperty(StringBuilder sb) { sb.AppendLine(" /// "); sb.AppendLine(" /// 自动注入的架构上下文"); sb.AppendLine(" /// "); sb.AppendLine( $" protected {PathContests.CoreAbstractionsNamespace}.architecture.IArchitectureContext Context {{ get; private set; }} = null!;"); sb.AppendLine(); } // ========================= // 自动实现接口方法 // ========================= private static void GenerateInterfaceImplementations( StringBuilder sb, INamedTypeSymbol interfaceSymbol) { var interfaceFullName = interfaceSymbol.ToDisplayString( SymbolDisplayFormat.FullyQualifiedFormat); foreach (var member in interfaceSymbol.GetMembers().OfType()) { if (member.MethodKind != MethodKind.Ordinary) continue; GenerateMethod(sb, interfaceFullName, member); sb.AppendLine(); } } private static void GenerateMethod( StringBuilder sb, string interfaceFullName, IMethodSymbol method) { var returnType = method.ReturnType.ToDisplayString( SymbolDisplayFormat.FullyQualifiedFormat); var parameters = string.Join(", ", method.Parameters.Select(p => $"{p.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} {p.Name}")); sb.AppendLine( $" {returnType} {interfaceFullName}.{method.Name}({parameters})"); sb.AppendLine(" {"); GenerateMethodBody(sb, method); sb.AppendLine(" }"); } // ========================= // 方法语义策略 // ========================= private static void GenerateMethodBody( StringBuilder sb, IMethodSymbol method) { switch (method.Name) { case "SetContext": sb.AppendLine(" Context = context;"); break; case "GetContext": sb.AppendLine(" return Context;"); break; default: GenerateFallbackBody(sb, method); break; } } private static void GenerateFallbackBody( StringBuilder sb, IMethodSymbol method) { if (method.ReturnsVoid) { sb.AppendLine(" // no-op"); } else { sb.AppendLine( $" throw new System.NotImplementedException("); sb.AppendLine( $" \"Method '{method.Name}' is not supported by ContextAwareGenerator.\");"); } } }