diff --git a/GFramework.Godot.SourceGenerators.Tests/Registration/AutoRegisterExportedCollectionsGeneratorTests.cs b/GFramework.Godot.SourceGenerators.Tests/Registration/AutoRegisterExportedCollectionsGeneratorTests.cs index 1a9afec6..3a67d3c5 100644 --- a/GFramework.Godot.SourceGenerators.Tests/Registration/AutoRegisterExportedCollectionsGeneratorTests.cs +++ b/GFramework.Godot.SourceGenerators.Tests/Registration/AutoRegisterExportedCollectionsGeneratorTests.cs @@ -327,8 +327,7 @@ public class AutoRegisterExportedCollectionsGeneratorTests { Sources = { source } }, - DisabledDiagnostics = { "GF_Common_Trace_001" }, - TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + DisabledDiagnostics = { "GF_Common_Trace_001" } }; test.ExpectedDiagnostics.Add(new DiagnosticResult("GF_AutoExport_003", DiagnosticSeverity.Error) diff --git a/GFramework.Godot.SourceGenerators/Registration/AutoRegisterExportedCollectionsGenerator.cs b/GFramework.Godot.SourceGenerators/Registration/AutoRegisterExportedCollectionsGenerator.cs index d6fe8db3..12589767 100644 --- a/GFramework.Godot.SourceGenerators/Registration/AutoRegisterExportedCollectionsGenerator.cs +++ b/GFramework.Godot.SourceGenerators/Registration/AutoRegisterExportedCollectionsGenerator.cs @@ -357,15 +357,23 @@ public sealed class AutoRegisterExportedCollectionsGenerator : IIncrementalGener INamedTypeSymbol registryType, string registerMethodName) { + // Start from the declared registry type so directly declared overloads win the cheap checks + // before we expand into inherited declarations. foreach (var method in registryType.GetMembers(registerMethodName).OfType()) yield return method; + // Concrete registry types can inherit callable implementations from base classes. When the + // registry itself is an interface, BaseType is null and this phase intentionally yields nothing. for (var baseType = registryType.BaseType; baseType is not null; baseType = baseType.BaseType) { foreach (var method in baseType.GetMembers(registerMethodName).OfType()) yield return method; } + // Only interface-typed registry members should search interface inheritance. For classes or + // structs this avoids accepting explicit interface implementations that generated code cannot + // call through `this..(...)`. AllInterfaces is already transitive, so the + // same semantic contract may appear multiple times; that is safe because the caller only uses Any(). if (registryType.TypeKind != TypeKind.Interface) yield break;