diff --git a/GFramework.SourceGenerators.Tests/Analyzers/ContextRegistrationAnalyzerTests.cs b/GFramework.SourceGenerators.Tests/Analyzers/ContextRegistrationAnalyzerTests.cs index 7db229f7..40afbe0f 100644 --- a/GFramework.SourceGenerators.Tests/Analyzers/ContextRegistrationAnalyzerTests.cs +++ b/GFramework.SourceGenerators.Tests/Analyzers/ContextRegistrationAnalyzerTests.cs @@ -365,6 +365,107 @@ public sealed class ContextRegistrationAnalyzerTests "0")); } + [Test] + public async Task Does_Not_Report_When_Inherited_OnInitialize_Calls_Virtual_Helper_Overridden_In_Derived_Architecture() + { + await AnalyzerTestDriver.RunAsync( + Wrap(""" + namespace TestApp + { + using GFramework.Core.Abstractions.Model; + using GFramework.Core.Abstractions.Systems; + using GFramework.Core.Architectures; + using GFramework.SourceGenerators.Abstractions.Rule; + + public interface IInventoryModel : IModel { } + + public sealed class InventoryModel : IInventoryModel { } + + public abstract class ArchitectureBase : Architecture + { + protected override void OnInitialize() + { + RegisterComponents(); + } + + protected virtual void RegisterComponents() + { + } + } + + public sealed class InventoryPanelSystem : ISystem + { + [GetModel] + private IInventoryModel _model = null!; + } + + public sealed class GameArchitecture : ArchitectureBase + { + protected override void RegisterComponents() + { + RegisterModel(new InventoryModel()); + RegisterSystem(new InventoryPanelSystem()); + } + } + } + """)); + } + + [Test] + public async Task Does_Not_Report_When_Inherited_Module_Install_Calls_Virtual_Helper_Overridden_In_Derived_Module() + { + await AnalyzerTestDriver.RunAsync( + Wrap(""" + namespace TestApp + { + using GFramework.Core.Abstractions.Architectures; + using GFramework.Core.Abstractions.Model; + using GFramework.Core.Abstractions.Systems; + using GFramework.Core.Architectures; + using GFramework.SourceGenerators.Abstractions.Rule; + + public interface IInventoryModel : IModel { } + + public sealed class InventoryModel : IInventoryModel { } + + public abstract class ModuleBase : IArchitectureModule + { + public void Install(IArchitecture architecture) + { + RegisterComponents(architecture); + } + + protected virtual void RegisterComponents(IArchitecture architecture) + { + } + } + + public sealed class DerivedInventoryModule : ModuleBase + { + protected override void RegisterComponents(IArchitecture architecture) + { + architecture.RegisterModel(new InventoryModel()); + } + } + + public sealed class InventoryPanelSystem : ISystem + { + [GetModel] + private IInventoryModel _model = null!; + } + + public sealed class GameArchitecture : Architecture + { + protected override void OnInitialize() + { + InstallModule(new DerivedInventoryModule()); + RegisterSystem(new InventoryPanelSystem()); + } + } + } + """)); + } + private static string Wrap(string source) { return $"{TestPreamble}{Environment.NewLine}{Environment.NewLine}{source}"; diff --git a/GFramework.SourceGenerators/Analyzers/ContextRegistrationAnalyzer.cs b/GFramework.SourceGenerators/Analyzers/ContextRegistrationAnalyzer.cs index c691fe65..6b6f2941 100644 --- a/GFramework.SourceGenerators/Analyzers/ContextRegistrationAnalyzer.cs +++ b/GFramework.SourceGenerators/Analyzers/ContextRegistrationAnalyzer.cs @@ -663,10 +663,8 @@ public sealed class ContextRegistrationAnalyzer : DiagnosticAnalyzer if (!SymbolHelpers.IsWithinTypeHierarchy(targetMethod.ContainingType, architectureType)) return false; - // 对已经具备源码的方法保留原始目标,避免把显式的 base 调用重新折回到当前 override。 - helperMethod = targetMethod.DeclaringSyntaxReferences.Length > 0 && !targetMethod.IsAbstract - ? targetMethod - : SymbolHelpers.ResolveHierarchyMethodImplementation(targetMethod, architectureType) ?? targetMethod; + // 优先解析到当前具体架构类型上的 override,只有无法映射时才回退到原始目标方法。 + helperMethod = SymbolHelpers.ResolveHierarchyMethodImplementation(targetMethod, architectureType) ?? targetMethod; return helperMethod.DeclaringSyntaxReferences.Length > 0; } @@ -683,9 +681,8 @@ public sealed class ContextRegistrationAnalyzer : DiagnosticAnalyzer if (!SymbolHelpers.IsWithinTypeHierarchy(targetMethod.ContainingType, moduleType)) return false; - helperMethod = targetMethod.DeclaringSyntaxReferences.Length > 0 && !targetMethod.IsAbstract - ? targetMethod - : SymbolHelpers.ResolveHierarchyMethodImplementation(targetMethod, moduleType) ?? targetMethod; + // 模块安装路径与架构路径一致,也必须优先跟随派生模块上的 override。 + helperMethod = SymbolHelpers.ResolveHierarchyMethodImplementation(targetMethod, moduleType) ?? targetMethod; return helperMethod.DeclaringSyntaxReferences.Length > 0; } }