From 9d251ab1f8b4638ce3289ae8f4a42419a295fbc4 Mon Sep 17 00:00:00 2001 From: gewuyou <95328647+GeWuYou@users.noreply.github.com> Date: Thu, 23 Apr 2026 11:48:14 +0800 Subject: [PATCH] =?UTF-8?q?refactor(source-generators-tests):=20=E6=94=B6?= =?UTF-8?q?=E6=95=9B=E8=87=AA=E5=8A=A8=E6=B3=A8=E5=86=8C=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=91=8A=E8=AD=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重构 AutoRegisterModuleGeneratorTests 的内联测试源码与快照常量,降低 MA0051 方法长度并保持生成断言不变 - 更新 analyzer warning reduction 的 tracking 与 trace,记录 RP-032 的验证结果和下一步恢复点 --- .../AutoRegisterModuleGeneratorTests.cs | 633 +++++++++--------- .../analyzer-warning-reduction-tracking.md | 14 +- .../analyzer-warning-reduction-trace.md | 29 + 3 files changed, 358 insertions(+), 318 deletions(-) diff --git a/GFramework.SourceGenerators.Tests/Architectures/AutoRegisterModuleGeneratorTests.cs b/GFramework.SourceGenerators.Tests/Architectures/AutoRegisterModuleGeneratorTests.cs index 5eafa7c2..1ad31c14 100644 --- a/GFramework.SourceGenerators.Tests/Architectures/AutoRegisterModuleGeneratorTests.cs +++ b/GFramework.SourceGenerators.Tests/Architectures/AutoRegisterModuleGeneratorTests.cs @@ -4,109 +4,323 @@ using GFramework.SourceGenerators.Tests.Core; namespace GFramework.SourceGenerators.Tests.Architectures; [TestFixture] +/// +/// 验证 在模块自动注册场景下的生成契约与输出顺序。 +/// public class AutoRegisterModuleGeneratorTests { + private const string AttributeOrderSource = """ + using System; + using GFramework.Core.SourceGenerators.Abstractions.Architectures; + + namespace GFramework.Core.SourceGenerators.Abstractions.Architectures + { + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] + public sealed class AutoRegisterModuleAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] + public sealed class RegisterModelAttribute : Attribute + { + public RegisterModelAttribute(Type modelType) { } + } + + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] + public sealed class RegisterSystemAttribute : Attribute + { + public RegisterSystemAttribute(Type systemType) { } + } + + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] + public sealed class RegisterUtilityAttribute : Attribute + { + public RegisterUtilityAttribute(Type utilityType) { } + } + } + + namespace GFramework.Core.Abstractions.Architectures + { + public interface IArchitecture + { + T RegisterModel(T model) where T : GFramework.Core.Abstractions.Model.IModel; + T RegisterSystem(T system) where T : GFramework.Core.Abstractions.Systems.ISystem; + T RegisterUtility(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility; + } + } + + namespace GFramework.Core.Abstractions.Model + { + public interface IModel { } + } + + namespace GFramework.Core.Abstractions.Systems + { + public interface ISystem { } + } + + namespace GFramework.Core.Abstractions.Utility + { + public interface IUtility { } + } + + namespace TestApp + { + using GFramework.Core.Abstractions.Model; + using GFramework.Core.Abstractions.Systems; + using GFramework.Core.Abstractions.Utility; + using GFramework.Core.SourceGenerators.Abstractions.Architectures; + + public sealed class PlayerModel : IModel { } + public sealed class CombatSystem : ISystem { } + public sealed class AudioUtility : IUtility { } + + [AutoRegisterModule] + [RegisterSystem(typeof(CombatSystem))] + [RegisterModel(typeof(PlayerModel))] + [RegisterUtility(typeof(AudioUtility))] + public partial class GameplayModule + { + } + } + """; + + private const string AttributeOrderExpected = """ + // + #nullable enable + + namespace TestApp; + + partial class GameplayModule + { + public void Install(global::GFramework.Core.Abstractions.Architectures.IArchitecture architecture) + { + architecture.RegisterSystem(new global::TestApp.CombatSystem()); + architecture.RegisterModel(new global::TestApp.PlayerModel()); + architecture.RegisterUtility(new global::TestApp.AudioUtility()); + } + } + + """; + + private const string DeterministicOrderCommonSource = """ + using System; + + namespace GFramework.Core.SourceGenerators.Abstractions.Architectures + { + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] + public sealed class AutoRegisterModuleAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] + public sealed class RegisterModelAttribute : Attribute + { + public RegisterModelAttribute(Type modelType) { } + } + + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] + public sealed class RegisterSystemAttribute : Attribute + { + public RegisterSystemAttribute(Type systemType) { } + } + + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] + public sealed class RegisterUtilityAttribute : Attribute + { + public RegisterUtilityAttribute(Type utilityType) { } + } + } + + namespace GFramework.Core.Abstractions.Architectures + { + public interface IArchitecture + { + T RegisterModel(T model) where T : GFramework.Core.Abstractions.Model.IModel; + T RegisterSystem(T system) where T : GFramework.Core.Abstractions.Systems.ISystem; + T RegisterUtility(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility; + } + } + + namespace GFramework.Core.Abstractions.Model + { + public interface IModel { } + } + + namespace GFramework.Core.Abstractions.Systems + { + public interface ISystem { } + } + + namespace GFramework.Core.Abstractions.Utility + { + public interface IUtility { } + } + + namespace TestApp + { + using GFramework.Core.Abstractions.Model; + using GFramework.Core.Abstractions.Systems; + using GFramework.Core.Abstractions.Utility; + + public sealed class PlayerModel : IModel { } + public sealed class CombatSystem : ISystem { } + public sealed class AudioUtility : IUtility { } + } + """; + + private const string DeterministicOrderPartASource = """ + namespace TestApp + { + using GFramework.Core.SourceGenerators.Abstractions.Architectures; + + // Padding ensures this attribute lives later in the file than the attributes in PartB. + // The generator should still place it first because PartA sorts before PartB. + // padding 01 + // padding 02 + // padding 03 + // padding 04 + // padding 05 + // padding 06 + // padding 07 + // padding 08 + // padding 09 + // padding 10 + [AutoRegisterModule] + [RegisterUtility(typeof(AudioUtility))] + public partial class GameplayModule + { + } + } + """; + + private const string DeterministicOrderPartBSource = """ + namespace TestApp + { + using GFramework.Core.SourceGenerators.Abstractions.Architectures; + + [RegisterSystem(typeof(CombatSystem))] + [RegisterModel(typeof(PlayerModel))] + public partial class GameplayModule + { + } + } + """; + + private const string DeterministicOrderExpected = """ + // + #nullable enable + + namespace TestApp; + + partial class GameplayModule + { + public void Install(global::GFramework.Core.Abstractions.Architectures.IArchitecture architecture) + { + architecture.RegisterUtility(new global::TestApp.AudioUtility()); + architecture.RegisterSystem(new global::TestApp.CombatSystem()); + architecture.RegisterModel(new global::TestApp.PlayerModel()); + } + } + + """; + + private const string TypeConstraintSource = """ + #nullable enable + using System; + using GFramework.Core.SourceGenerators.Abstractions.Architectures; + + namespace GFramework.Core.SourceGenerators.Abstractions.Architectures + { + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] + public sealed class AutoRegisterModuleAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] + public sealed class RegisterModelAttribute : Attribute + { + public RegisterModelAttribute(Type modelType) { } + } + + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] + public sealed class RegisterSystemAttribute : Attribute + { + public RegisterSystemAttribute(Type systemType) { } + } + + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] + public sealed class RegisterUtilityAttribute : Attribute + { + public RegisterUtilityAttribute(Type utilityType) { } + } + } + + namespace GFramework.Core.Abstractions.Architectures + { + public interface IArchitecture + { + T RegisterModel(T model) where T : GFramework.Core.Abstractions.Model.IModel; + T RegisterSystem(T system) where T : GFramework.Core.Abstractions.Systems.ISystem; + T RegisterUtility(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility; + } + } + + namespace GFramework.Core.Abstractions.Model + { + public interface IModel { } + } + + namespace GFramework.Core.Abstractions.Systems + { + public interface ISystem { } + } + + namespace GFramework.Core.Abstractions.Utility + { + public interface IUtility { } + } + + namespace TestApp + { + using GFramework.Core.Abstractions.Model; + using GFramework.Core.SourceGenerators.Abstractions.Architectures; + + public sealed class PlayerModel : IModel { } + + [AutoRegisterModule] + [RegisterModel(typeof(PlayerModel))] + public partial class GameplayModule + where TNullableRef : class? + where TNotNull : notnull + where TUnmanaged : unmanaged + { + } + } + """; + + private const string TypeConstraintExpected = """ + // + #nullable enable + + namespace TestApp; + + partial class GameplayModule + where TNullableRef : class? + where TNotNull : notnull + where TUnmanaged : unmanaged + { + public void Install(global::GFramework.Core.Abstractions.Architectures.IArchitecture architecture) + { + architecture.RegisterModel(new global::TestApp.PlayerModel()); + } + } + + """; + /// /// 验证同一声明上的注册特性会按照源码中的书写顺序生成安装代码。 /// [Test] - public async Task Generates_Module_Install_Method_In_Attribute_Order() + public Task Generates_Module_Install_Method_In_Attribute_Order() { - const string source = """ - using System; - using GFramework.Core.SourceGenerators.Abstractions.Architectures; - - namespace GFramework.Core.SourceGenerators.Abstractions.Architectures - { - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] - public sealed class AutoRegisterModuleAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] - public sealed class RegisterModelAttribute : Attribute - { - public RegisterModelAttribute(Type modelType) { } - } - - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] - public sealed class RegisterSystemAttribute : Attribute - { - public RegisterSystemAttribute(Type systemType) { } - } - - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] - public sealed class RegisterUtilityAttribute : Attribute - { - public RegisterUtilityAttribute(Type utilityType) { } - } - } - - namespace GFramework.Core.Abstractions.Architectures - { - public interface IArchitecture - { - T RegisterModel(T model) where T : GFramework.Core.Abstractions.Model.IModel; - T RegisterSystem(T system) where T : GFramework.Core.Abstractions.Systems.ISystem; - T RegisterUtility(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility; - } - } - - namespace GFramework.Core.Abstractions.Model - { - public interface IModel { } - } - - namespace GFramework.Core.Abstractions.Systems - { - public interface ISystem { } - } - - namespace GFramework.Core.Abstractions.Utility - { - public interface IUtility { } - } - - namespace TestApp - { - using GFramework.Core.Abstractions.Model; - using GFramework.Core.Abstractions.Systems; - using GFramework.Core.Abstractions.Utility; - using GFramework.Core.SourceGenerators.Abstractions.Architectures; - - public sealed class PlayerModel : IModel { } - public sealed class CombatSystem : ISystem { } - public sealed class AudioUtility : IUtility { } - - [AutoRegisterModule] - [RegisterSystem(typeof(CombatSystem))] - [RegisterModel(typeof(PlayerModel))] - [RegisterUtility(typeof(AudioUtility))] - public partial class GameplayModule - { - } - } - """; - - const string expected = """ - // - #nullable enable - - namespace TestApp; - - partial class GameplayModule - { - public void Install(global::GFramework.Core.Abstractions.Architectures.IArchitecture architecture) - { - architecture.RegisterSystem(new global::TestApp.CombatSystem()); - architecture.RegisterModel(new global::TestApp.PlayerModel()); - architecture.RegisterUtility(new global::TestApp.AudioUtility()); - } - } - - """; - - await GeneratorTest.RunAsync( - source, - ("TestApp_GameplayModule.AutoRegisterModule.g.cs", expected)); + return GeneratorTest.RunAsync( + AttributeOrderSource, + ("TestApp_GameplayModule.AutoRegisterModule.g.cs", AttributeOrderExpected)); } /// @@ -115,140 +329,20 @@ public class AutoRegisterModuleGeneratorTests [Test] public async Task Generates_Module_Install_Method_In_Deterministic_Order_Across_Partial_Declarations() { - const string commonSource = """ - using System; - - namespace GFramework.Core.SourceGenerators.Abstractions.Architectures - { - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] - public sealed class AutoRegisterModuleAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] - public sealed class RegisterModelAttribute : Attribute - { - public RegisterModelAttribute(Type modelType) { } - } - - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] - public sealed class RegisterSystemAttribute : Attribute - { - public RegisterSystemAttribute(Type systemType) { } - } - - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] - public sealed class RegisterUtilityAttribute : Attribute - { - public RegisterUtilityAttribute(Type utilityType) { } - } - } - - namespace GFramework.Core.Abstractions.Architectures - { - public interface IArchitecture - { - T RegisterModel(T model) where T : GFramework.Core.Abstractions.Model.IModel; - T RegisterSystem(T system) where T : GFramework.Core.Abstractions.Systems.ISystem; - T RegisterUtility(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility; - } - } - - namespace GFramework.Core.Abstractions.Model - { - public interface IModel { } - } - - namespace GFramework.Core.Abstractions.Systems - { - public interface ISystem { } - } - - namespace GFramework.Core.Abstractions.Utility - { - public interface IUtility { } - } - - namespace TestApp - { - using GFramework.Core.Abstractions.Model; - using GFramework.Core.Abstractions.Systems; - using GFramework.Core.Abstractions.Utility; - - public sealed class PlayerModel : IModel { } - public sealed class CombatSystem : ISystem { } - public sealed class AudioUtility : IUtility { } - } - """; - - const string partASource = """ - namespace TestApp - { - using GFramework.Core.SourceGenerators.Abstractions.Architectures; - - // Padding ensures this attribute lives later in the file than the attributes in PartB. - // The generator should still place it first because PartA sorts before PartB. - // padding 01 - // padding 02 - // padding 03 - // padding 04 - // padding 05 - // padding 06 - // padding 07 - // padding 08 - // padding 09 - // padding 10 - [AutoRegisterModule] - [RegisterUtility(typeof(AudioUtility))] - public partial class GameplayModule - { - } - } - """; - - const string partBSource = """ - namespace TestApp - { - using GFramework.Core.SourceGenerators.Abstractions.Architectures; - - [RegisterSystem(typeof(CombatSystem))] - [RegisterModel(typeof(PlayerModel))] - public partial class GameplayModule - { - } - } - """; - - const string expected = """ - // - #nullable enable - - namespace TestApp; - - partial class GameplayModule - { - public void Install(global::GFramework.Core.Abstractions.Architectures.IArchitecture architecture) - { - architecture.RegisterUtility(new global::TestApp.AudioUtility()); - architecture.RegisterSystem(new global::TestApp.CombatSystem()); - architecture.RegisterModel(new global::TestApp.PlayerModel()); - } - } - - """; - var test = new CSharpSourceGeneratorTest { TestState = { Sources = { - ("Common.cs", commonSource), - ("GameplayModule.PartA.cs", partASource), - ("GameplayModule.PartB.cs", partBSource) + ("Common.cs", DeterministicOrderCommonSource), + ("GameplayModule.PartA.cs", DeterministicOrderPartASource), + ("GameplayModule.PartB.cs", DeterministicOrderPartBSource) }, GeneratedSources = { (typeof(AutoRegisterModuleGenerator), "TestApp_GameplayModule.AutoRegisterModule.g.cs", - NormalizeLineEndings(expected)) + NormalizeLineEndings(DeterministicOrderExpected)) } }, DisabledDiagnostics = { "GF_Common_Trace_001" } @@ -261,102 +355,11 @@ public class AutoRegisterModuleGeneratorTests /// 验证生成器会保留可空引用、notnull 与 unmanaged 约束。 /// [Test] - public async Task Generates_Type_Constraints_For_NullableReference_NotNull_And_Unmanaged() + public Task Generates_Type_Constraints_For_NullableReference_NotNull_And_Unmanaged() { - const string source = """ - #nullable enable - using System; - using GFramework.Core.SourceGenerators.Abstractions.Architectures; - - namespace GFramework.Core.SourceGenerators.Abstractions.Architectures - { - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] - public sealed class AutoRegisterModuleAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] - public sealed class RegisterModelAttribute : Attribute - { - public RegisterModelAttribute(Type modelType) { } - } - - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] - public sealed class RegisterSystemAttribute : Attribute - { - public RegisterSystemAttribute(Type systemType) { } - } - - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] - public sealed class RegisterUtilityAttribute : Attribute - { - public RegisterUtilityAttribute(Type utilityType) { } - } - } - - namespace GFramework.Core.Abstractions.Architectures - { - public interface IArchitecture - { - T RegisterModel(T model) where T : GFramework.Core.Abstractions.Model.IModel; - T RegisterSystem(T system) where T : GFramework.Core.Abstractions.Systems.ISystem; - T RegisterUtility(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility; - } - } - - namespace GFramework.Core.Abstractions.Model - { - public interface IModel { } - } - - namespace GFramework.Core.Abstractions.Systems - { - public interface ISystem { } - } - - namespace GFramework.Core.Abstractions.Utility - { - public interface IUtility { } - } - - namespace TestApp - { - using GFramework.Core.Abstractions.Model; - using GFramework.Core.SourceGenerators.Abstractions.Architectures; - - public sealed class PlayerModel : IModel { } - - [AutoRegisterModule] - [RegisterModel(typeof(PlayerModel))] - public partial class GameplayModule - where TNullableRef : class? - where TNotNull : notnull - where TUnmanaged : unmanaged - { - } - } - """; - - const string expected = """ - // - #nullable enable - - namespace TestApp; - - partial class GameplayModule - where TNullableRef : class? - where TNotNull : notnull - where TUnmanaged : unmanaged - { - public void Install(global::GFramework.Core.Abstractions.Architectures.IArchitecture architecture) - { - architecture.RegisterModel(new global::TestApp.PlayerModel()); - } - } - - """; - - await GeneratorTest.RunAsync( - source, - ("TestApp_GameplayModule.AutoRegisterModule.g.cs", expected)); + return GeneratorTest.RunAsync( + TypeConstraintSource, + ("TestApp_GameplayModule.AutoRegisterModule.g.cs", TypeConstraintExpected)); } /// diff --git a/ai-plan/public/analyzer-warning-reduction/todos/analyzer-warning-reduction-tracking.md b/ai-plan/public/analyzer-warning-reduction/todos/analyzer-warning-reduction-tracking.md index 74e10eb3..0f4721ad 100644 --- a/ai-plan/public/analyzer-warning-reduction/todos/analyzer-warning-reduction-tracking.md +++ b/ai-plan/public/analyzer-warning-reduction/todos/analyzer-warning-reduction-tracking.md @@ -7,8 +7,8 @@ ## 当前恢复点 -- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-031` -- 当前阶段:`Phase 31` +- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-032` +- 当前阶段:`Phase 32` - 当前焦点: - 已完成 `GFramework.Core` 当前 `MA0016` / `MA0002` / `MA0015` / `MA0077` 低风险收口批次 - 已复核 `net10.0` 下的 `MA0158` 基线:`GFramework.Core` / `GFramework.Cqrs` 当前共有 `16` 个 object lock @@ -57,10 +57,14 @@ 场景已收敛为模板化 helper,保留原有快照目录与生成器输入语义不变 - 当前 `GFramework.SourceGenerators.Tests` Release build 基线已从 `49` 条降到 `43` 条;`LoggerGeneratorSnapshotTests.cs` 已不再出现在 `MA0051` 列表中 + - 已完成 `GFramework.SourceGenerators.Tests/Architectures/AutoRegisterModuleGeneratorTests.cs` 的 `MA0051` 收口: + 将内联测试源码与期望快照抽到类级常量、补齐测试类 XML 文档,并将仅作转发的异步测试改为直接返回 `Task` + - 当前 `GFramework.SourceGenerators.Tests` Release build 基线已从 `43` 条降到 `40` 条; + `AutoRegisterModuleGeneratorTests.cs` 已不再出现在 `MA0051` 列表中 - `GFramework.Godot` 的 `Timing.cs` 已同步适配新事件签名,但当前 worktree 的 Godot restore 资产仍受 Windows fallback package folder 干扰,独立 build 需在修复资产后补跑 - 后续继续按 warning 类型和数量批处理,而不是回退到按单文件切片推进 - 下一轮默认继续拆分 `GFramework.SourceGenerators.Tests` 的 `MA0051` 热点,优先处理 - `AutoRegisterModuleGeneratorTests`、`GeneratorSnapshotTest` 或 `ContextGetGeneratorTests` + `GeneratorSnapshotTest` 或 `ContextGetGeneratorTests` - 单次 `boot` 的工作树改动上限控制在约 `100` 个文件以内,避免 recovery context 与 review 面同时失控 - 若任务边界互不冲突,允许使用不同模型的 subagent 并行处理不同 warning 类型或不同目录,但必须遵守显式 ownership @@ -98,6 +102,8 @@ 全部收敛为 `MA0051` - 已完成 `LoggerGeneratorSnapshotTests` 的单文件 `MA0051` 收口;当前 `GFramework.SourceGenerators.Tests` Release build 基线已降到 `43` 条,并通过 focused snapshot tests 保持行为不变 +- 已完成 `AutoRegisterModuleGeneratorTests` 的单文件 `MA0051` 收口;当前 `GFramework.SourceGenerators.Tests` Release build 基线已降到 + `40` 条,并通过 focused generator tests 保持输出契约不变 ## 当前活跃事实 @@ -138,6 +144,8 @@ 通过 schema 类型比较 helper 与显式 `StringComparison.Ordinal` 清空当前项目的 `MA0006` - `RP-020` 继续拆分 `SchemaConfigGenerator.cs` 的 `MA0051` 热点,将当前项目 warnings-only 基线从 `19` 条降到 `9` 条, 并用 focused schema generator tests 验证 50 个用例通过 +- `RP-032` 已完成 `AutoRegisterModuleGeneratorTests` 的 3 个 `MA0051` 收口:通过提取类级常量承载测试源码与快照,保持 + 生成文件名、断言路径与源生成输出不变;`GFramework.SourceGenerators.Tests` warnings-only 基线由 `43` 降至 `40` - `RP-021` 使用 `$gframework-pr-review` 复核当前分支 PR #269 后,修复仍在本地成立的 4 个项:将 `CqrsHandlerRegistryGenerator` 拆分为职责清晰的 partial 文件、为 `ContextAwareGenerator` 生成字段增加稳定前缀并补上 `SetContextProvider` 的运行时 null 校验、为 `Option` 补齐 ``,并新增字段重名场景的生成器快照测试 diff --git a/ai-plan/public/analyzer-warning-reduction/traces/analyzer-warning-reduction-trace.md b/ai-plan/public/analyzer-warning-reduction/traces/analyzer-warning-reduction-trace.md index b5c9fdde..d2b8a5d5 100644 --- a/ai-plan/public/analyzer-warning-reduction/traces/analyzer-warning-reduction-trace.md +++ b/ai-plan/public/analyzer-warning-reduction/traces/analyzer-warning-reduction-trace.md @@ -1,5 +1,34 @@ # Analyzer Warning Reduction 追踪 +## 2026-04-23 — RP-032 + +### 阶段:`AutoRegisterModuleGeneratorTests.cs` `MA0051` 收口(RP-032) + +- 启动复核: + - 按 `gframework-boot` 流程恢复当前 worktree,读取 `AGENTS.md`、`.ai/environment/tools.ai.yaml`、 + `ai-plan/public/README.md` 与 active topic 跟踪文件,确认当前分支 `fix/analyzer-warning-reduction-batch` + 仍映射到 `analyzer-warning-reduction` + - 先用 + `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release -t:Rebuild --no-restore --disable-build-servers -m:1 -p:UseSharedCompilation=false -p:RestoreFallbackFolders="" -nologo -clp:"Summary;WarningsOnly"` + 复核当前 `MA0051` 热点,确认 `AutoRegisterModuleGeneratorTests.cs` 仍有 `3` 个超长方法,适合作为单文件低风险写集 +- 决策: + - 保持 `AutoRegisterModuleGeneratorTests` 的测试输入、生成文件名、快照文本与断言结构不变,只收敛方法长度 + - 采用“提取类级常量承载大段测试源码与期望输出”的方式,避免引入新的共享 helper 或改变场景组装顺序 + - 验证阶段改为串行执行 build/test;避免和同项目并行运行时拿到不完整 `bin/Release` 输出 +- 实施调整: + - 为 `AutoRegisterModuleGeneratorTests` 补齐测试类 XML 文档 + - 将 3 个长测试方法中的源码与期望快照提取为类级 `const string`,保留原有生成文件名与断言目标 + - 将仅转发 `GeneratorTest.RunAsync(...)` 的两个异步测试改为直接返回 `Task` +- 验证结果: + - `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release -t:Rebuild --no-restore --disable-build-servers -m:1 -p:UseSharedCompilation=false -p:RestoreFallbackFolders="" -nologo -clp:"Summary;WarningsOnly"` + - 结果:`40 Warning(s)`,`0 Error(s)`;`AutoRegisterModuleGeneratorTests.cs` 已不再出现在 `MA0051` 列表中 + - `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --no-restore --disable-build-servers --filter FullyQualifiedName~AutoRegisterModuleGeneratorTests -m:1 -p:RestoreFallbackFolders="" -nologo` + - 结果:`3 Passed`,`0 Failed` +- 下一步建议: + - 若继续压缩 `GFramework.SourceGenerators.Tests` 的 `MA0051`,优先处理仅剩单个超长方法的 + `GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTest.cs` + - 若希望单次继续多降几条 warning,则改选 `ContextGetGeneratorTests.cs`,但需要接受更大的单文件写集 + ## 2026-04-23 — RP-031 ### 阶段:`LoggerGeneratorSnapshotTests.cs` `MA0051` 收口(RP-031)