using System.Collections.Immutable;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
namespace AyCode.Core.Serializers.SourceGenerator;
///
/// Incremental source generator for [AcBinarySerializable] types. Emits an
/// IGeneratedBinaryWriter + IGeneratedBinaryReader implementation for every annotated
/// type, plus a [ModuleInitializer]-based registry hook that wires the generated instances
/// into the runtime serializer at startup.
///
/// Source organization — this generator class is split across multiple partial files
/// for navigational clarity:
///
/// - AcBinarySourceGenerator.cs (this file) — entry point: [Generator] attribute,
/// Initialize + Execute orchestration.
/// - AcBinarySourceGenerator.Models.cs — non-partial model types
/// (SerializableClassInfo, PropInfo, PropertyTypeKind).
/// - AcBinarySourceGenerator.TypeAnalysis.cs — Roslyn-symbol utility passes
/// (kind detection, FNV hashing, name flattening, scan-need recursion).
/// - AcBinarySourceGenerator.Diagnostics.cs — ACBIN001 (cycle warning) + ACBIN002
/// (polymorph misuse error) descriptors and detection methods.
/// - AcBinarySourceGenerator.GetClassInfo.cs — class-info extraction pass (attribute
/// flags + property metadata building).
/// - AcBinarySourceGenerator.GenWriter.cs — writer-side emit (WriteProperties, ScanObject,
/// ScanForDuplicates, per-property emit helpers).
/// - AcBinarySourceGenerator.GenReader.cs — reader-side emit (ReadProperties, ReadObject,
/// per-property read helpers).
/// - AcBinarySourceGenerator.GenInit.cs — ModuleInitializer-based registry hook emit.
///
///
[Generator]
public partial class AcBinarySourceGenerator : IIncrementalGenerator
{
private const string AttributeName = "AyCode.Core.Serializers.Attributes.AcBinarySerializableAttribute";
// Feature gates on the SGen-emitted writer / scan code are driven by `[AcBinarySerializable]`
// attribute flags. Two such gates are wired through SerializableClassInfo:
// • EnablePropertyFilter → omits the per-property `HasPropertyFilter` branch when false.
// • EnablePolymorphDetect → omits the `ObjectWithTypeName + AQN` prefix on `System.Object`-
// declared properties when false (then ACBIN002 guards misuse).
// • EnableInternString → omits StringInterned* case-emit in the reader switch when false.
// All default `true`; opt-out is per type via the attribute ctor parameters.
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var classDeclarations = context.SyntaxProvider
.ForAttributeWithMetadataName(
AttributeName,
predicate: static (node, _) => node is ClassDeclarationSyntax || node is StructDeclarationSyntax,
transform: static (ctx, _) => GetClassInfo(ctx))
.Where(static info => info != null);
context.RegisterSourceOutput(classDeclarations.Collect(),
static (spc, classes) => Execute(classes!, spc));
}
private static void Execute(ImmutableArray classes, SourceProductionContext context)
{
if (classes.IsDefaultOrEmpty) return;
var valid = classes.Where(c => c != null).Cast().ToList();
if (valid.Count == 0) return;
DetectAndReportCycles(valid, context);
DetectAndReportPolymorphicMisuse(valid, context);
foreach (var ci in valid)
{
context.AddSource($"{ci.ClassName}_GeneratedWriter.g.cs", SourceText.From(GenWriter(ci), Encoding.UTF8));
context.AddSource($"{ci.ClassName}_GeneratedReader.g.cs", SourceText.From(GenReader(ci), Encoding.UTF8));
}
context.AddSource("AcBinaryGeneratedWriters_Init.g.cs", SourceText.From(GenInit(valid), Encoding.UTF8));
}
}