fix(pr-review): 修复设置快照比较器契约

- 修复 UnifiedSettingsFile 与 UnifiedSettingsDataRepository 的 comparer 契约,在无法恢复原比较器时显式回退到 StringComparer.Ordinal
- 统一 AutoRegisterExportedCollectionsGeneratorTests 中剩余的 RunAsync 异步等待写法,并补齐 ConfigureAwait(false)
- 更新 analyzer-warning-reduction 跟踪文档,记录 PR follow-up 的验证结果与恢复点
This commit is contained in:
gewuyou 2026-04-24 16:39:25 +08:00
parent 7e45197698
commit 2187f179c3
5 changed files with 60 additions and 19 deletions

View File

@ -288,11 +288,11 @@ public class UnifiedSettingsDataRepository(
{
ArgumentNullException.ThrowIfNull(source);
// 反序列化后的运行时类型可能只是 IDictionary 实现;若底层仍是 Dictionary则保留其 comparer
// 否则退回到按当前内容复制,避免因为 API 抽象化而改变持久化前后的键比较语义
// 反序列化后的运行时类型可能只是 IDictionary 实现;若底层仍是 Dictionary则保留其 comparer
// 若 comparer 已因接口抽象而不可恢复,则显式回退到 Ordinal避免让默认 comparer 语义继续隐式存在
var sections = source.Sections is Dictionary<string, string> dictionary
? new Dictionary<string, string>(dictionary, dictionary.Comparer)
: new Dictionary<string, string>(source.Sections);
: new Dictionary<string, string>(source.Sections, StringComparer.Ordinal);
return new UnifiedSettingsFile
{

View File

@ -11,6 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using GFramework.Core.Abstractions.Versioning;
@ -28,8 +29,11 @@ internal sealed class UnifiedSettingsFile : IVersioned
/// <remarks>
/// 这里公开为 <see cref="IDictionary{TKey,TValue}" /> 而不是具体的 <see cref="Dictionary{TKey,TValue}" />
/// 以避免暴露可替换的具体集合实现,同时继续兼容 Newtonsoft.Json 对字典对象的序列化与反序列化。
/// 默认实例使用 <see cref="StringComparer.Ordinal" />;若调用方提供其他实现,仓库在可以识别底层
/// <see cref="Dictionary{TKey,TValue}" /> comparer 时会保留原语义,否则克隆快照时会显式回退到
/// <see cref="StringComparer.Ordinal" />。
/// </remarks>
public IDictionary<string, string> Sections { get; set; } = new Dictionary<string, string>();
public IDictionary<string, string> Sections { get; set; } = new Dictionary<string, string>(StringComparer.Ordinal);
/// <summary>
/// 配置文件版本号,用于版本控制和兼容性检查

View File

@ -135,7 +135,7 @@ public class AutoRegisterExportedCollectionsGeneratorTests
.WithLocation(0)
.WithArguments("Values"));
await test.RunAsync();
await test.RunAsync().ConfigureAwait(false);
}
[Test]
@ -302,7 +302,7 @@ public class AutoRegisterExportedCollectionsGeneratorTests
.WithLocation(0)
.WithArguments("Register", "_registry", "Values"));
await test.RunAsync();
await test.RunAsync().ConfigureAwait(false);
}
[Test]
@ -500,7 +500,7 @@ public class AutoRegisterExportedCollectionsGeneratorTests
.WithLocation(0)
.WithArguments("_registry", "Values"));
await test.RunAsync();
await test.RunAsync().ConfigureAwait(false);
}
[Test]
@ -555,7 +555,7 @@ public class AutoRegisterExportedCollectionsGeneratorTests
.WithLocation(0)
.WithArguments("Register", "_registry", "Values"));
await test.RunAsync();
await test.RunAsync().ConfigureAwait(false);
}
[Test]
@ -610,7 +610,7 @@ public class AutoRegisterExportedCollectionsGeneratorTests
.WithLocation(0)
.WithArguments("Values"));
await test.RunAsync();
await test.RunAsync().ConfigureAwait(false);
}
[Test]
@ -694,7 +694,7 @@ public class AutoRegisterExportedCollectionsGeneratorTests
""";
}
private static Task VerifyDiagnosticsAsync(
private static async Task VerifyDiagnosticsAsync(
string source,
bool skipGeneratedSourcesCheck = false,
params DiagnosticResult[] expectedDiagnostics)
@ -718,6 +718,6 @@ public class AutoRegisterExportedCollectionsGeneratorTests
test.ExpectedDiagnostics.Add(expectedDiagnostic);
}
return test.RunAsync();
await test.RunAsync().ConfigureAwait(false);
}
}

View File

@ -6,13 +6,13 @@
## 当前恢复点
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-051`
- 当前阶段:`Phase 51`
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-052`
- 当前阶段:`Phase 52`
- 当前焦点:
- `2026-04-24` 本轮已完成 `GFramework.Godot.SourceGenerators.Tests` warning 清理
- 当前主线程切片从生成器实现转到对应测试项目,并已把 `GFramework.Godot.SourceGenerators.Tests``24` 个 warning 降到 `0`
- 当前批次按 `origin/main` merge-base 计算的累计分支 diff 预计为 `23` 个文件,仍低于 `$gframework-batch-boot 75` 的主阈值
- 当前工作树除未跟踪的 `.codex` 目录外,还存在与本批次无关的既有文档 / 跟踪文件修改;提交当前批次时必须只包含本 topic 相关文件
- `2026-04-24` 本轮从当前 PR review 的未解决线程回切到 `GFramework.Game` / `GFramework.Godot.SourceGenerators.Tests`
- `UnifiedSettingsFile.Sections``CloneFile` fallback 已对齐为“可保留原 comparer 时保留,否则显式回退到 `StringComparer.Ordinal`”的文档与实现契约
- `AutoRegisterExportedCollectionsGeneratorTests` 中剩余的 `await test.RunAsync();` 已统一补齐 `.ConfigureAwait(false)`,并同步让 `VerifyDiagnosticsAsync` 内部消费异步等待
- 当前批次仍需避免混入与 analyzer-warning-reduction 无关的既有工作树改动
## 当前活跃事实
@ -23,6 +23,8 @@
- 本轮直接执行仓库根目录 `dotnet build` 成功,并给出 `1184 warning(s)` 的真实输出
- `GFramework.Godot.SourceGenerators.Tests` 已通过测试辅助模板抽取与 `ConfigureAwait(false)` 修正,当前 `Debug` / `Release` 构建均为 `0 Warning(s)`
- 本轮已验证 `dotnet test GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj -c Release --no-build`,结果为 `Passed: 48`
- 本轮已把 PR #283 中仍打开的 `UnifiedSettingsDataRepository.cs` comparer 契约线程落到代码与 XML 注释,避免 fallback 语义继续依赖隐式默认 comparer
- 本轮已确认 `AutoRegisterExportedCollectionsGeneratorTests` 的 5 处裸 `await test.RunAsync();` 不是当前 Release build 告警来源,但仍作为 PR review 一致性项一并修正
## 当前风险
@ -32,6 +34,8 @@
- 缓解措施:若下一轮继续做整仓 warning reduction先定位 `dotnet clean` 的 solution-level 失败原因,或明确继续沿用用户确认的 `1193 warning(s)` clean 基线与本轮 `1184 warning(s)` direct build 观测值
- 当前 worktree 已存在与本批次无关的未提交改动
- 缓解措施:提交当前批次时只暂存 `GFramework.Godot.SourceGenerators.Tests` 与对应 `ai-plan` 文件,避免混入其他 topic 变更
- `GFramework.Game` 当前 `Release` build 仍带有既有 analyzer warning 基线
- 缓解措施:本轮仅验证改动未新增 `UnifiedSettingsDataRepository` / `UnifiedSettingsFile` 相关 warning若继续在该模块做 warning reduction需要另开切片处理现存基线
## 活跃文档
@ -58,8 +62,14 @@
- 结果:成功;`0 Warning(s)``0 Error(s)`
- `dotnet test GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj -c Release --no-build`
- 结果:成功;`Passed: 48``Failed: 0`
- `dotnet build GFramework.Game/GFramework.Game.csproj -c Release`
- 结果:成功;`533 Warning(s)``0 Error(s)`;模块仍存在既有 warning 基线,本轮 follow-up 仅处理 PR review 指向的 comparer 契约与测试异步等待一致性
- `dotnet build GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj -c Release`
- 结果:成功;`0 Warning(s)``0 Error(s)`
- `dotnet test GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj -c Release --no-build`
- 结果:成功;`Passed: 48``Failed: 0`
## 下一步建议
1. 提交当前 `GFramework.Godot.SourceGenerators.Tests` 清理批次,并确认提交只包含本 topic 相关文件
2. 如果继续 warning reduction优先重新评估仓库根目录 `dotnet clean` 的 solution-level 失败,再决定是继续从整仓 `dotnet build` 输出挑热点,还是先修复 clean 基线采集问题
1. 提交当前 comparer 契约与 `ConfigureAwait(false)` PR follow-up并确认只纳入本 topic 相关文件
2. 视 PR review 反馈决定是否继续收敛 `GFramework.Game` 现有 warning 基线,或返回下一轮整仓 warning 热点筛选

View File

@ -1,5 +1,32 @@
# Analyzer Warning Reduction 追踪
# Analyzer Warning Reduction 追踪
## 2026-04-24 — RP-052
### 阶段PR review follow-upcomparer 契约 + `ConfigureAwait(false)` 收尾)
- 触发背景:
- 当前分支 PR #283 的最新 review 中,`greptile-apps[bot]` 仍有一个未解决线程,指出 `UnifiedSettingsDataRepository.CloneFile` fallback 会静默丢失原 comparer
- CodeRabbit 另指出 `AutoRegisterExportedCollectionsGeneratorTests.cs` 中还残留 5 处 `await test.RunAsync();`,与同项目其他测试文件的 `.ConfigureAwait(false)` 风格不一致
- 主线程实施:
- 复核 PR review JSON、`UnifiedSettingsDataRepository.cs``UnifiedSettingsFile.cs``AutoRegisterExportedCollectionsGeneratorTests.cs` 的当前代码,确认只有 comparer 契约线程仍属最新 head 上的实质问题
- 将 `UnifiedSettingsFile.Sections` 的 XML 注释补充为显式 comparer 契约,并把默认字典初始化改为 `StringComparer.Ordinal`
- 将 `CloneFile` fallback 从隐式默认 comparer 改为显式 `StringComparer.Ordinal`,并同步修正文档注释,避免继续暗含“保留原语义”的错误表述
- 把 `AutoRegisterExportedCollectionsGeneratorTests` 中剩余的 5 处 `await test.RunAsync();` 统一为 `.ConfigureAwait(false)`,同时让 `VerifyDiagnosticsAsync` 内部也消费 `ConfigureAwait(false)`
- 验证里程碑:
- `dotnet build GFramework.Game/GFramework.Game.csproj -c Release`
- 结果:成功;`533 Warning(s)``0 Error(s)``GFramework.Game` 仍有既有 warning 基线,本轮 follow-up 仅处理 PR review 指向的 comparer 契约与测试异步等待一致性
- `dotnet build GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj -c Release`
- 结果:成功;`0 Warning(s)``0 Error(s)`
- `dotnet test GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj -c Release --no-build`
- 首次并行复验:失败;`FileNotFoundException`,原因是 `--no-build` 测试在 Release DLL 落盘前启动
- 串行复验:成功;`Passed: 48``Failed: 0`
- 当前结论:
- PR #283 当前仍打开的 comparer review thread 已在本地代码与 XML 注释层面得到对应修复
- `AutoRegisterExportedCollectionsGeneratorTests` 的异步等待风格已与同项目其他测试保持一致
- 当前改动已通过直接受影响测试项目的 Release build 与串行 Release test 复验,可进入提交阶段
## 2026-04-24 — RP-051
### 阶段:`GFramework.Godot.SourceGenerators.Tests` warning 清零