diff --git a/GFramework.Godot.SourceGenerators.Tests/Registration/AutoRegisterExportedCollectionsGeneratorTests.cs b/GFramework.Godot.SourceGenerators.Tests/Registration/AutoRegisterExportedCollectionsGeneratorTests.cs index 1c4927a4..612529c3 100644 --- a/GFramework.Godot.SourceGenerators.Tests/Registration/AutoRegisterExportedCollectionsGeneratorTests.cs +++ b/GFramework.Godot.SourceGenerators.Tests/Registration/AutoRegisterExportedCollectionsGeneratorTests.cs @@ -200,6 +200,84 @@ public class AutoRegisterExportedCollectionsGeneratorTests ("TestApp_Bootstrapper.AutoRegisterExportedCollections.g.cs", expected)); } + [Test] + public async Task Generates_Batch_Registration_Method_When_Register_Method_Comes_From_Inherited_Interface() + { + const string source = """ + #nullable enable + using System; + using System.Collections.Generic; + using GFramework.Godot.SourceGenerators.Abstractions; + + namespace GFramework.Godot.SourceGenerators.Abstractions + { + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] + public sealed class AutoRegisterExportedCollectionsAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, Inherited = false, AllowMultiple = false)] + public sealed class RegisterExportedCollectionAttribute : Attribute + { + public RegisterExportedCollectionAttribute(string registryMemberName, string registerMethodName) { } + } + } + + namespace TestApp + { + public interface IKeyValue + { + } + + public interface IRegistry + { + void Registry(IKeyValue mapping); + } + + public interface IAssetRegistry : IRegistry + { + } + + public sealed class IntConfig : IKeyValue + { + } + + [AutoRegisterExportedCollections] + public partial class Bootstrapper + { + private readonly IAssetRegistry? _registry = null; + + [RegisterExportedCollection(nameof(_registry), "Registry")] + public List? Values { get; } = new(); + } + } + """; + + const string expected = """ + // + #nullable enable + + namespace TestApp; + + partial class Bootstrapper + { + private void __RegisterExportedCollections_Generated() + { + if (this.Values is not null && this._registry is not null) + { + foreach (var __generatedItem in this.Values) + { + this._registry.Registry(__generatedItem); + } + } + } + } + + """; + + await GeneratorTest.RunAsync( + source, + ("TestApp_Bootstrapper.AutoRegisterExportedCollections.g.cs", expected)); + } + [Test] public async Task Reports_Diagnostic_When_Collection_Member_Is_Not_Instance_Readable() { diff --git a/GFramework.Godot.SourceGenerators/Registration/AutoRegisterExportedCollectionsGenerator.cs b/GFramework.Godot.SourceGenerators/Registration/AutoRegisterExportedCollectionsGenerator.cs index df0c433b..16effd91 100644 --- a/GFramework.Godot.SourceGenerators/Registration/AutoRegisterExportedCollectionsGenerator.cs +++ b/GFramework.Godot.SourceGenerators/Registration/AutoRegisterExportedCollectionsGenerator.cs @@ -268,8 +268,7 @@ public sealed class AutoRegisterExportedCollectionsGenerator : IIncrementalGener return false; } - var hasCompatibleMethod = registryType.GetMembers(registerMethodName) - .OfType() + var hasCompatibleMethod = EnumerateCandidateMethods(registryType, registerMethodName) .Any(method => !method.IsStatic && method.Parameters.Length == 1 && @@ -319,6 +318,26 @@ public sealed class AutoRegisterExportedCollectionsGenerator : IIncrementalGener return compilation.ClassifyConversion(elementType, parameterType).IsImplicit; } + private static IEnumerable EnumerateCandidateMethods( + INamedTypeSymbol registryType, + string registerMethodName) + { + foreach (var method in registryType.GetMembers(registerMethodName).OfType()) + yield return method; + + for (var baseType = registryType.BaseType; baseType is not null; baseType = baseType.BaseType) + { + foreach (var method in baseType.GetMembers(registerMethodName).OfType()) + yield return method; + } + + foreach (var interfaceType in registryType.AllInterfaces) + { + foreach (var method in interfaceType.GetMembers(registerMethodName).OfType()) + yield return method; + } + } + private static bool TryGetRegistrationAttributeArguments( SourceProductionContext context, ISymbol collectionMember,