using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; namespace JiShe.CollectBus.IncrementalGenerator { /// /// 复杂类型源生成器 /// [Generator(LanguageNames.CSharp)] public class ComplexTypeSourceAnalyzers : IIncrementalGenerator { private const string AttributeFullName = "JiShe.CollectBus.Analyzers.Shared.SourceAnalyzersAttribute"; public void Initialize(IncrementalGeneratorInitializationContext context) { //Debugger.Launch(); context.RegisterPostInitializationOutput(ctx => { ctx.AddSource("GeneratorInit.g.cs", "// Initialization Marker"); }); // 步骤1:筛选带有 [GenerateAccessors] 的类 var classDeclarations = context.SyntaxProvider .CreateSyntaxProvider( predicate: static (s, _) => IsClassWithAttribute(s), transform: static (ctx, _) => GetClassDeclaration(ctx)) .Where(static c => c is not null); // 步骤2:合并编译信息 var compilationAndClasses = context.CompilationProvider.Combine(classDeclarations.Collect()); context.RegisterSourceOutput(compilationAndClasses, (spc, source) => GenerateCode(source.Left, source.Right!, spc)); } private static bool IsClassWithAttribute(SyntaxNode node) => node is ClassDeclarationSyntax cds && cds.AttributeLists.Count > 0; private static ClassDeclarationSyntax GetClassDeclaration(GeneratorSyntaxContext context) { var classDecl = (ClassDeclarationSyntax)context.Node; var attributeType = context.SemanticModel.Compilation.GetTypeByMetadataName(AttributeFullName); foreach (var attribute in classDecl.AttributeLists.SelectMany(al => al.Attributes)) { var symbol = context.SemanticModel.GetSymbolInfo(attribute).Symbol; if (symbol is IMethodSymbol ctor && SymbolEqualityComparer.Default.Equals(ctor.ContainingType, attributeType)) { return classDecl; } } return null; } /// /// 递归获取所有层级的属性 /// /// /// private static IEnumerable GetAllPropertiesInHierarchy(INamedTypeSymbol classSymbol) { var currentSymbol = classSymbol; while (currentSymbol != null) { foreach (var prop in currentSymbol.GetMembers().OfType()) { yield return prop; } currentSymbol = currentSymbol.BaseType; // 向上遍历基类 } } private static void GenerateCode( Compilation compilation, IEnumerable classes, SourceProductionContext context) { var processedTypes = new HashSet(SymbolEqualityComparer.Default); if (!classes.Any()) { context.ReportDiagnostic(Diagnostic.Create( new DiagnosticDescriptor("GEN002", "No Targets", "No classes with [GenerateAccessors] found", "Debug", DiagnosticSeverity.Warning, true), Location.None)); } foreach (var classDecl in classes.Distinct()) { var model = compilation.GetSemanticModel(classDecl.SyntaxTree); var classSymbol = model.GetDeclaredSymbol(classDecl) as INamedTypeSymbol; if (classSymbol == null || !processedTypes.Add(classSymbol)) { context.ReportDiagnostic(Diagnostic.Create( new DiagnosticDescriptor("GEN003", "Invalid Symbol", $"Class symbol is null for {classDecl.Identifier.Text}", "Error", DiagnosticSeverity.Error, true), Location.None)); continue; } context.ReportDiagnostic(Diagnostic.Create( new DiagnosticDescriptor( "PA001", "Generated Accessors", $"Generating accessors for {classSymbol.Name}", "Performance", DiagnosticSeverity.Info, true), Location.None)); // 新增:输出继承链信息 context.ReportDiagnostic(Diagnostic.Create( new DiagnosticDescriptor("HIERARCHY", "Class Hierarchy", $"Processing class: {classSymbol.Name}, BaseType: {classSymbol.BaseType?.Name}", "Debug", DiagnosticSeverity.Info, true), Location.None)); context.ReportDiagnostic(Diagnostic.Create( new DiagnosticDescriptor("PA002", "Class Found", $"Processing class: {classSymbol.Name}", "Debug", DiagnosticSeverity.Warning, true), Location.None)); var code = BuildAccessorsForType(classSymbol, compilation, processedTypes); System.Diagnostics.Debug.WriteLine($"Generated code for {classSymbol.Name}:\n{code}"); // 调试输出 context.AddSource($"{classSymbol.Name}Extension.g.cs", code); } } private static string BuildAccessorsForType( INamedTypeSymbol classSymbol, Compilation compilation, HashSet processedTypes) { var code = new StringBuilder(); code.AppendLine("#pragma warning disable CS0419 // 禁用警告"); code.AppendLine("// Generated code for " + classSymbol.Name); code.AppendLine("// "); code.AppendLine("#nullable enable"); code.AppendLine($"namespace {classSymbol.ContainingNamespace.ToDisplayString()};"); code.AppendLine(); code.AppendLine($"public static class {classSymbol.Name}Extension{GetGenericParams(classSymbol)}"); code.AppendLine("{"); //foreach (var prop in classSymbol.GetMembers().OfType()) //{ // if (prop.IsIndexer) continue; // GeneratePropertyAccessors(prop, code, compilation, processedTypes); //} foreach (var prop in GetAllPropertiesInHierarchy(classSymbol)) { if (prop.IsIndexer) continue; GeneratePropertyAccessors(prop, code, compilation, processedTypes); } code.AppendLine("}"); return code.ToString(); } //private static string GetGenericParams(INamedTypeSymbol symbol) // => symbol.IsGenericType ? $"<{string.Join(", ", symbol.TypeParameters.Select(t => t.Name))}>" : ""; public static string GetGenericParams(INamedTypeSymbol symbol) { if (!symbol.IsGenericType) return ""; var parameters = symbol.TypeParameters.Select(t => t.Name); return $"<{string.Join(", ", parameters)}>"; } private static void GeneratePropertyAccessors( IPropertySymbol prop, StringBuilder code, Compilation compilation, HashSet processedTypes) { // 关键修复点1:安全类型转换 if (prop.Type is not ITypeSymbol propType) return; code.AppendLine($" // Processing property: {prop.Name}"); // 处理元组类型 if (propType is INamedTypeSymbol { IsTupleType: true } tupleType) { GenerateTupleAccessors(prop, tupleType, code); } else if (propType is INamedTypeSymbol namedType) { GenerateStandardAccessors(prop, namedType, code); ProcessNestedType(namedType, compilation, processedTypes); } } private static void GenerateTupleAccessors(IPropertySymbol prop, INamedTypeSymbol tupleType, StringBuilder code) { var elements = tupleType.TupleElements; var parentType = prop.ContainingType.ToDisplayString(); for (int i = 0; i < elements.Length; i++) { var element = elements[i]; if (element.Type is not ITypeSymbol elementType) continue; var elementName = element.CorrespondingTupleField?.Name ?? $"Item{i + 1}"; code.AppendLine($" public static {elementType.ToDisplayString()} Get{prop.Name}_{elementName}({parentType} obj) => obj.{prop.Name}.{elementName};"); if (prop.SetMethod != null) { var assignments = elements.Select((e, idx) => idx == i ? "value" : $"obj.{prop.Name}.{e.Name}"); code.AppendLine($" public static void Set{prop.Name}_{elementName}({parentType} obj, {elementType.ToDisplayString()} value) => obj.{prop.Name} = ({string.Join(", ", assignments)});"); } } } private static void GenerateStandardAccessors(IPropertySymbol prop, INamedTypeSymbol propType, StringBuilder code) { var parentType = prop.ContainingType.ToDisplayString(); code.AppendLine($" public static {propType.ToDisplayString()} Get{prop.Name}({parentType} obj) => obj.{prop.Name};"); if (prop.SetMethod != null) { code.AppendLine($" public static void Set{prop.Name}({parentType} obj, {propType.ToDisplayString()} value) => obj.{prop.Name} = value;"); } } private static void ProcessNestedType(ITypeSymbol typeSymbol, Compilation compilation, HashSet processedTypes) { if (typeSymbol is not INamedTypeSymbol namedType) return; if (!ShouldProcessNestedType(namedType)) return; if (!processedTypes.Add(namedType)) return; var code = BuildAccessorsForType(namedType, compilation, processedTypes); } private static bool ShouldProcessNestedType(INamedTypeSymbol symbol) { return symbol.DeclaredAccessibility == Accessibility.Public && !symbol.IsTupleType && !symbol.IsAnonymousType && !symbol.IsImplicitlyDeclared && !symbol.Name.StartsWith("<"); } } }