From d0e86933cfb6261be746371cffc5fa806019fa47 Mon Sep 17 00:00:00 2001
From: gewuyou <95328647+GeWuYou@users.noreply.github.com>
Date: Thu, 23 Apr 2026 11:22:59 +0800
Subject: [PATCH] =?UTF-8?q?fix(sourcegenerators-tests):=20=E6=B8=85?=
=?UTF-8?q?=E7=90=86=E4=BD=8E=E9=A3=8E=E9=99=A9=20warning=20=E5=9F=BA?=
=?UTF-8?q?=E7=BA=BF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 修复 GFramework.SourceGenerators.Tests 中低风险的 MA0004 与 MA0048,统一改为直接返回 Task 或在文件 I/O 上显式使用 ConfigureAwait(false)
- 更新 AnalyzerTestDriver 文件名与类型名对齐,避免测试基础设施继续产生文件命名 warning
- 更新 analyzer-warning-reduction 的 active tracking 与 trace,记录 RP-030 的 61 到 49 warnings-only 基线变化和验证结果
---
.../Config/SchemaConfigGeneratorEnumTests.cs | 16 ++++----
.../SchemaConfigGeneratorSnapshotTests.cs | 41 +++++++++++++++----
...{AnalyzerTest.cs => AnalyzerTestDriver.cs} | 4 +-
.../Core/GeneratorSnapshotTest.cs | 4 +-
.../GeneratorSnapshotTestSecurityTests.cs | 8 ++--
.../Core/GeneratorTest.cs | 8 ++--
.../analyzer-warning-reduction-tracking.md | 38 +++++++++++------
.../analyzer-warning-reduction-trace.md | 37 +++++++++++++++++
8 files changed, 115 insertions(+), 41 deletions(-)
rename GFramework.SourceGenerators.Tests/Core/{AnalyzerTest.cs => AnalyzerTestDriver.cs} (93%)
diff --git a/GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorEnumTests.cs b/GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorEnumTests.cs
index 801a343c..7b123753 100644
--- a/GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorEnumTests.cs
+++ b/GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorEnumTests.cs
@@ -13,7 +13,7 @@ public class SchemaConfigGeneratorEnumTests
/// 验证对象 enum 文档输出与快照保持一致。
///
[Test]
- public async Task Snapshot_Should_Preserve_Object_Enum_Documentation()
+ public Task Snapshot_Should_Preserve_Object_Enum_Documentation()
{
const string source = """
namespace TestApp
@@ -51,14 +51,14 @@ public class SchemaConfigGeneratorEnumTests
("monster.schema.json", schema));
Assert.That(result.Results.Single().Diagnostics, Is.Empty);
- await AssertSnapshotAsync(result, "MonsterConfig.ObjectEnum.g.txt");
+ return AssertSnapshotAsync(result, "MonsterConfig.ObjectEnum.g.txt");
}
///
/// 验证数组项 enum 文档回退输出与快照保持一致。
///
[Test]
- public async Task Snapshot_Should_Preserve_Array_Item_Enum_Documentation_Fallback()
+ public Task Snapshot_Should_Preserve_Array_Item_Enum_Documentation_Fallback()
{
const string source = """
namespace TestApp
@@ -88,14 +88,14 @@ public class SchemaConfigGeneratorEnumTests
("monster.schema.json", schema));
Assert.That(result.Results.Single().Diagnostics, Is.Empty);
- await AssertSnapshotAsync(result, "MonsterConfig.ArrayItemEnum.g.txt");
+ return AssertSnapshotAsync(result, "MonsterConfig.ArrayItemEnum.g.txt");
}
///
/// 验证对象数组项 enum 文档回退输出与快照保持一致。
///
[Test]
- public async Task Snapshot_Should_Preserve_Array_Object_Item_Enum_Documentation_Fallback()
+ public Task Snapshot_Should_Preserve_Array_Object_Item_Enum_Documentation_Fallback()
{
const string source = """
namespace TestApp
@@ -136,7 +136,7 @@ public class SchemaConfigGeneratorEnumTests
("monster.schema.json", schema));
Assert.That(result.Results.Single().Diagnostics, Is.Empty);
- await AssertSnapshotAsync(result, "MonsterConfig.ArrayObjectItemEnum.g.txt");
+ return AssertSnapshotAsync(result, "MonsterConfig.ArrayObjectItemEnum.g.txt");
}
///
@@ -176,11 +176,11 @@ public class SchemaConfigGeneratorEnumTests
if (!File.Exists(path))
{
Directory.CreateDirectory(snapshotFolder);
- await File.WriteAllTextAsync(path, actual);
+ await File.WriteAllTextAsync(path, actual).ConfigureAwait(false);
Assert.Fail($"Snapshot not found. Generated new snapshot at:\n{path}");
}
- var expected = await File.ReadAllTextAsync(path);
+ var expected = await File.ReadAllTextAsync(path).ConfigureAwait(false);
Assert.That(
Normalize(expected),
Is.EqualTo(Normalize(actual)),
diff --git a/GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.cs b/GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.cs
index 71c0065c..2d5cce4a 100644
--- a/GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.cs
+++ b/GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.cs
@@ -12,7 +12,7 @@ public class SchemaConfigGeneratorSnapshotTests
/// 验证一个最小 monster schema 能生成配置类型、表包装和注册辅助。
///
[Test]
- public async Task Snapshot_SchemaConfigGenerator()
+ public Task Snapshot_SchemaConfigGenerator()
{
const string source = """
using System;
@@ -183,12 +183,7 @@ public class SchemaConfigGeneratorSnapshotTests
"SchemaConfigGenerator");
snapshotFolder = Path.GetFullPath(snapshotFolder);
- await AssertSnapshotAsync(generatedSources, snapshotFolder, "MonsterConfig.g.cs", "MonsterConfig.g.txt");
- await AssertSnapshotAsync(generatedSources, snapshotFolder, "MonsterTable.g.cs", "MonsterTable.g.txt");
- await AssertSnapshotAsync(generatedSources, snapshotFolder, "MonsterConfigBindings.g.cs",
- "MonsterConfigBindings.g.txt");
- await AssertSnapshotAsync(generatedSources, snapshotFolder, "GeneratedConfigCatalog.g.cs",
- "GeneratedConfigCatalog.g.txt");
+ return AssertAllSnapshotsAsync(generatedSources, snapshotFolder);
}
///
@@ -213,17 +208,45 @@ public class SchemaConfigGeneratorSnapshotTests
if (!File.Exists(path))
{
Directory.CreateDirectory(snapshotFolder);
- await File.WriteAllTextAsync(path, actual);
+ await File.WriteAllTextAsync(path, actual).ConfigureAwait(false);
Assert.Fail($"Snapshot not found. Generated new snapshot at:\n{path}");
}
- var expected = await File.ReadAllTextAsync(path);
+ var expected = await File.ReadAllTextAsync(path).ConfigureAwait(false);
Assert.That(
Normalize(expected),
Is.EqualTo(Normalize(actual)),
$"Snapshot mismatch: {generatedFileName}");
}
+ ///
+ /// 依次验证 schema 生成器产出的全部核心快照文件。
+ ///
+ /// 生成结果字典。
+ /// 快照目录。
+ /// 全部快照断言完成后的异步任务。
+ private static async Task AssertAllSnapshotsAsync(
+ IReadOnlyDictionary generatedSources,
+ string snapshotFolder)
+ {
+ await AssertSnapshotAsync(generatedSources, snapshotFolder, "MonsterConfig.g.cs", "MonsterConfig.g.txt")
+ .ConfigureAwait(false);
+ await AssertSnapshotAsync(generatedSources, snapshotFolder, "MonsterTable.g.cs", "MonsterTable.g.txt")
+ .ConfigureAwait(false);
+ await AssertSnapshotAsync(
+ generatedSources,
+ snapshotFolder,
+ "MonsterConfigBindings.g.cs",
+ "MonsterConfigBindings.g.txt")
+ .ConfigureAwait(false);
+ await AssertSnapshotAsync(
+ generatedSources,
+ snapshotFolder,
+ "GeneratedConfigCatalog.g.cs",
+ "GeneratedConfigCatalog.g.txt")
+ .ConfigureAwait(false);
+ }
+
///
/// 标准化快照文本以避免平台换行差异。
///
diff --git a/GFramework.SourceGenerators.Tests/Core/AnalyzerTest.cs b/GFramework.SourceGenerators.Tests/Core/AnalyzerTestDriver.cs
similarity index 93%
rename from GFramework.SourceGenerators.Tests/Core/AnalyzerTest.cs
rename to GFramework.SourceGenerators.Tests/Core/AnalyzerTestDriver.cs
index 9d9a0b73..b2f962d0 100644
--- a/GFramework.SourceGenerators.Tests/Core/AnalyzerTest.cs
+++ b/GFramework.SourceGenerators.Tests/Core/AnalyzerTestDriver.cs
@@ -15,7 +15,7 @@ public static class AnalyzerTestDriver
/// 测试输入源码。
/// 期望诊断集合。
/// 异步测试任务。
- public static async Task RunAsync(
+ public static Task RunAsync(
string source,
params DiagnosticResult[] diagnostics)
{
@@ -29,6 +29,6 @@ public static class AnalyzerTestDriver
};
test.ExpectedDiagnostics.AddRange(diagnostics);
- await test.RunAsync();
+ return test.RunAsync();
}
}
diff --git a/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTest.cs b/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTest.cs
index fe8b9bff..9587440b 100644
--- a/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTest.cs
+++ b/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTest.cs
@@ -83,13 +83,13 @@ public static class GeneratorSnapshotTest
{
// 第一次运行:生成 snapshot
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
- await File.WriteAllTextAsync(path, content.ToString());
+ await File.WriteAllTextAsync(path, content.ToString()).ConfigureAwait(false);
Assert.Fail(
$"未找到快照文件,已在以下路径生成新快照:\n{path}");
}
- var expected = await File.ReadAllTextAsync(path);
+ var expected = await File.ReadAllTextAsync(path).ConfigureAwait(false);
Assert.That(
Normalize(expected),
diff --git a/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTestSecurityTests.cs b/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTestSecurityTests.cs
index b52fa027..d096a059 100644
--- a/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTestSecurityTests.cs
+++ b/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTestSecurityTests.cs
@@ -20,8 +20,8 @@ public class GeneratorSnapshotTestSecurityTests
var snapshotRoot = CreateSnapshotRoot();
var source = BuildSource();
- Assert.ThrowsAsync(async () =>
- await GeneratorSnapshotTest.RunAsync(
+ Assert.ThrowsAsync(() =>
+ GeneratorSnapshotTest.RunAsync(
source,
snapshotRoot,
_ => Path.Combine(snapshotRoot, "Status.EnumExtensions.g.cs")));
@@ -36,8 +36,8 @@ public class GeneratorSnapshotTestSecurityTests
var snapshotRoot = CreateSnapshotRoot();
var source = BuildSource();
- Assert.ThrowsAsync(async () =>
- await GeneratorSnapshotTest.RunAsync(
+ Assert.ThrowsAsync(() =>
+ GeneratorSnapshotTest.RunAsync(
source,
snapshotRoot,
_ => Path.Combine("..", "escaped", "Status.EnumExtensions.g.cs")));
diff --git a/GFramework.SourceGenerators.Tests/Core/GeneratorTest.cs b/GFramework.SourceGenerators.Tests/Core/GeneratorTest.cs
index bed493e7..e582fbd9 100644
--- a/GFramework.SourceGenerators.Tests/Core/GeneratorTest.cs
+++ b/GFramework.SourceGenerators.Tests/Core/GeneratorTest.cs
@@ -13,11 +13,11 @@ public static class GeneratorTest
/// 输入的源代码
/// 期望生成的源文件集合,包含文件名和内容的元组
/// 异步操作任务
- public static async Task RunAsync(
+ public static Task RunAsync(
string source,
params (string filename, string content)[] generatedSources)
{
- await RunAsync(
+ return RunAsync(
source,
additionalReferences: [],
generatedSources);
@@ -30,7 +30,7 @@ public static class GeneratorTest
/// 附加元数据引用,用于构造多程序集场景。
/// 期望生成的源文件集合,包含文件名和内容的元组。
/// 异步操作任务。
- public static async Task RunAsync(
+ public static Task RunAsync(
string source,
IEnumerable additionalReferences,
params (string filename, string content)[] generatedSources)
@@ -52,7 +52,7 @@ public static class GeneratorTest
foreach (var additionalReference in additionalReferences)
test.TestState.AdditionalReferences.Add(additionalReference);
- await test.RunAsync();
+ return test.RunAsync();
}
///
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 a4dfd97f..bf1ce29b 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-029`
-- 当前阶段:`Phase 29`
+- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-030`
+- 当前阶段:`Phase 30`
- 当前焦点:
- 已完成 `GFramework.Core` 当前 `MA0016` / `MA0002` / `MA0015` / `MA0077` 低风险收口批次
- 已复核 `net10.0` 下的 `MA0158` 基线:`GFramework.Core` / `GFramework.Cqrs` 当前共有 `16` 个 object lock
@@ -50,9 +50,12 @@
- 当前 `GFramework.Core.SourceGenerators` warnings-only 基线已降到 `0` 条
- 当前 `GFramework.Cqrs.SourceGenerators` warnings-only 基线已降到 `0` 条
- 当前 `GFramework.Game.SourceGenerators` warnings-only 基线已从 `46` 条降到 `0` 条
+ - 已完成 `GFramework.SourceGenerators.Tests` 低风险 `MA0004` / `MA0048` 收口:测试辅助器改为直接返回 `Task`,
+ 文件 I/O 显式补齐 `ConfigureAwait(false)`,`AnalyzerTestDriver` 文件名与类型名重新对齐
+ - 当前 `GFramework.SourceGenerators.Tests` warnings-only 基线已从 `61` 条降到 `49` 条,剩余 warning 均为 `MA0051`
- `GFramework.Godot` 的 `Timing.cs` 已同步适配新事件签名,但当前 worktree 的 Godot restore 资产仍受 Windows fallback package folder 干扰,独立 build 需在修复资产后补跑
- 后续继续按 warning 类型和数量批处理,而不是回退到按单文件切片推进
- - 下一轮默认继续拆分 `GFramework.Game.SourceGenerators` 的 `MA0051` 热点,或评估跨 target 的 `MA0158`
+ - 下一轮默认继续拆分 `GFramework.SourceGenerators.Tests` 的 `MA0051` 热点,或评估跨 target 的 `MA0158`
锁替换风险
- 单次 `boot` 的工作树改动上限控制在约 `100` 个文件以内,避免 recovery context 与 review 面同时失控
- 若任务边界互不冲突,允许使用不同模型的 subagent 并行处理不同 warning 类型或不同目录,但必须遵守显式 ownership
@@ -87,6 +90,8 @@
- 已完成当前分支与 `main` 的 `CqrsHandlerRegistryGenerator.cs` 冲突化解:保留当前 partial 结构,并把
`main` 侧新增的模型文档合并到 `CqrsHandlerRegistryGenerator.Models.cs`
- 已完成 `GFramework.Game.SourceGenerators` 中 `SchemaConfigGenerator` 的剩余 `MA0051` 收口;warnings-only 基线已降到 `0` 条
+- 已完成 `GFramework.SourceGenerators.Tests` 的首轮低风险 warning 清理;当前项目已清空 `MA0004` / `MA0048`,剩余 warning
+ 全部收敛为 `MA0051`
## 当前活跃事实
@@ -144,6 +149,9 @@
并把“变更模块必须运行对应 build 且处理 warning”的治理规则写回 `AGENTS.md`
- `RP-029` 已完成 `SchemaConfigGenerator` 剩余 `MA0051` 收口:`GFramework.Game.SourceGenerators` 独立 Release
warnings-only build 已清零,并通过 `SchemaConfigGenerator` focused generator tests 锁定生成输出未回退
+- `RP-030` 已完成 `GFramework.SourceGenerators.Tests` 低风险 `MA0004` / `MA0048` 收口:`AnalyzerTestDriver` 文件名已与
+ 类型名一致,测试辅助器与 schema snapshot 断言路径已改为直接返回 `Task` 或显式使用 `ConfigureAwait(false)`;
+ 当前测试项目 warnings-only 基线从 `61` 条降到 `49` 条,剩余均为 `MA0051`
- 当前工作树分支 `fix/analyzer-warning-reduction-batch` 已在 `ai-plan/public/README.md` 建立 topic 映射
## 当前风险
@@ -156,13 +164,12 @@
- 缓解措施:继续以唯一源位置和 warning 家族为主要决策依据,而不是只看原始 warning 总数
- net10 专属 warning 风险:`MA0158` 建议使用 `System.Threading.Lock`,但项目多 target 时需要确认兼容边界
- 缓解措施:下一轮先按 target framework 与 API 可用性评估,不直接批量替换共享源码中的 `object` lock
-- source generator warning 外溢风险:运行 `GFramework.SourceGenerators.Tests` 会构建相邻 generator/test 项目并显示既有
- `GFramework.Game.SourceGenerators` 与测试项目 warning
- - 缓解措施:继续以被修改 generator 项目的独立 warnings-only build 作为主验收,并用 focused generator test 验证行为
-- source generator test warning 治理风险:`GFramework.SourceGenerators.Tests` 当前仍有既有 `MA0051` / `MA0004` / `MA0048`
- warning,本轮 focused test 已通过,但测试项目整包 warning 尚未进入本轮写集
- - 缓解措施:本轮已在 failed-test follow-up 的定向 `dotnet test` 中再次确认这些 warning 仍为既有基线;后续若继续修改该测试项目,
- 应按新增 `AGENTS.md` 规则先明确 warning 收口范围,再决定是否进入专门清理切片
+- source generator warning 外溢风险:运行 `GFramework.SourceGenerators.Tests` 会构建相邻 generator/test 项目,并在输出中混入
+ 测试项目自身的结构性 warning 基线
+ - 缓解措施:继续以被修改项目的独立 warnings-only build 作为主验收,并用 focused generator test 验证行为
+- source generator test warning 治理风险:`GFramework.SourceGenerators.Tests` 当前仍有 `49` 条既有 `MA0051` warning;
+ 一旦继续进入该写集,就必须把测试项目 warning 一并纳入本轮完成条件
+ - 缓解措施:已先清空低风险 `MA0004` / `MA0048`,后续继续保持“单 warning family、单测试域”的节奏推进 `MA0051`
- ContextAware 基类命名隐藏风险:若生成器只看当前类型声明成员,派生规则会重新占用基类已声明的
`_gFrameworkContextAware*` 字段名,导致生成成员隐藏继承状态并让快照无法锁定后缀分配行为
- 缓解措施:本轮已改为遍历完整 base-type 链收集保留名,并用 inherited collision 快照用例锁定该行为
@@ -325,13 +332,20 @@
- 结果:`54 Passed`,`0 Failed`
- 说明:测试项目构建仍显示既有 `GFramework.SourceGenerators.Tests` `MA0048` / `MA0051` / `MA0004` warning;不属于本轮
`GFramework.Game.SourceGenerators` 写集
+- `RP-030` 的验证结果:
+ - `dotnet restore GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -p:RestoreFallbackFolders="" -nologo`
+ - 结果:通过;刷新 Linux 侧 restore 资产以移除 Windows fallback package folder 干扰
+ - `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release -t:Rebuild --no-restore -p:UseSharedCompilation=false -p:RestoreFallbackFolders="" -nologo -clp:"Summary;WarningsOnly"`
+ - 结果:`49 Warning(s)`,`0 Error(s)`;当前项目已不再出现 `MA0004` / `MA0048`,剩余 warning 全部为 `MA0051`
+ - `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --no-restore --filter "FullyQualifiedName~GeneratorSnapshotTestSecurityTests|FullyQualifiedName~SchemaConfigGeneratorSnapshotTests|FullyQualifiedName~SchemaConfigGeneratorEnumTests" -m:1 -p:RestoreFallbackFolders="" -nologo`
+ - 结果:`6 Passed`,`0 Failed`
- active 跟踪文件只保留当前恢复点、活跃事实、风险与下一步,不再重复保存已完成阶段的长篇历史
## 下一步
1. 若要继续该主题,先读 active tracking,再按需展开历史归档中的 warning 热点与验证记录
-2. 下一轮优先评估是否将 `GFramework.SourceGenerators.Tests` 的既有 `MA0051` / `MA0004` / `MA0048` 作为独立 warning
- 清理切片;若进入该写集,需要先明确测试项目 warning 也属于本轮必须处理的模块范围
+2. 下一轮优先继续 `GFramework.SourceGenerators.Tests` 的 `MA0051` 收口,先在单一测试域内选择一个文件或一组同构 snapshot
+ 用例拆分,不再把已清零的 `MA0004` / `MA0048` 混回写集
3. 若改回推进 `MA0158`,先设计 `net8.0` / `net9.0` / `net10.0` 多 target 条件编译方案,不直接批量替换共享源码中的
`object` lock
4. 若后续继续改动 `GFramework.Godot`,先修复该项目的 Linux 侧 restore 资产,再补跑独立 build
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 c789f477..fae414cf 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,42 @@
# Analyzer Warning Reduction 追踪
+## 2026-04-23 — RP-030
+
+### 阶段:`GFramework.SourceGenerators.Tests` 低风险 `MA0004` / `MA0048` 收口(RP-030)
+
+- 启动复核:
+ - 按 `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`
+ - 先对 `GFramework.SourceGenerators.Tests` 执行
+ `dotnet restore GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -p:RestoreFallbackFolders="" -nologo`,
+ 刷新 Linux 侧 restore 资产,规避 Windows fallback package folder 干扰
+ - 用
+ `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release -t:Rebuild --no-restore -p:UseSharedCompilation=false -p:RestoreFallbackFolders="" -nologo -clp:"Summary;WarningsOnly"`
+ 复核当前基线,确认该测试项目共有 `61` 条 warning,其中低风险切片集中在 `MA0004` 与单个 `MA0048`
+- 决策:
+ - 不直接进入大型 snapshot/test 方法的 `MA0051`,先收口纯 test-infrastructure 层的 `MA0004` / `MA0048`
+ - 对“只是转发异步调用”的 helper 直接返回 `Task`,只在真实文件 I/O 上显式补 `ConfigureAwait(false)`,避免无意义的
+ `async/await` 包装
+ - 将 `AnalyzerTestDriver` 所在文件改名为与类型一致,单独清理 `MA0048`,不改类型名与调用方契约
+- 实施调整:
+ - 将 `AnalyzerTestDriver.RunAsync(...)` 与 `GeneratorTest.RunAsync(...)` 改为直接返回下游 `Task`
+ - 为 `GeneratorSnapshotTest`、`SchemaConfigGeneratorSnapshotTests` 与 `SchemaConfigGeneratorEnumTests` 中的异步文件读写
+ 显式补齐 `ConfigureAwait(false)`,并把仅作转发的测试方法改为直接返回 `Task`
+ - 将 `GeneratorSnapshotTestSecurityTests` 的 `Assert.ThrowsAsync(...)` 改为直接返回目标 `Task`,移除无收益的
+ `async` 包装
+ - 将 `GFramework.SourceGenerators.Tests/Core/AnalyzerTest.cs` 重命名为
+ `GFramework.SourceGenerators.Tests/Core/AnalyzerTestDriver.cs`
+- 验证结果:
+ - `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release -t:Rebuild --no-restore -p:UseSharedCompilation=false -p:RestoreFallbackFolders="" -nologo -clp:"Summary;WarningsOnly"`
+ - 结果:`49 Warning(s)`,`0 Error(s)`;当前项目已不再出现 `MA0004` / `MA0048`,剩余 warning 全部为 `MA0051`
+ - `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --no-restore --filter "FullyQualifiedName~GeneratorSnapshotTestSecurityTests|FullyQualifiedName~SchemaConfigGeneratorSnapshotTests|FullyQualifiedName~SchemaConfigGeneratorEnumTests" -m:1 -p:RestoreFallbackFolders="" -nologo`
+ - 结果:`6 Passed`,`0 Failed`
+- 下一步建议:
+ - 若继续 analyzer warning reduction,继续把 `GFramework.SourceGenerators.Tests` 作为独立写集,只处理 `MA0051`
+ - 下一轮优先选择单一测试域的同构长方法,例如 `LoggerGeneratorSnapshotTests`、`AutoRegisterModuleGeneratorTests`
+ 或共享 helper `GeneratorSnapshotTest`
+
## 2026-04-23 — RP-029
### 阶段:`SchemaConfigGenerator.cs` 剩余 `MA0051` 收口(RP-029)