From 77e332fd44bfedd73287fee4f8ee111c8d1deae4 Mon Sep 17 00:00:00 2001
From: gewuyou <95328647+GeWuYou@users.noreply.github.com>
Date: Fri, 24 Apr 2026 12:37:47 +0800
Subject: [PATCH] =?UTF-8?q?fix(analyzer):=20=E6=94=B6=E5=8F=A3=E5=BD=93?=
=?UTF-8?q?=E5=89=8D=E6=89=B9=E6=AC=A1=E8=AD=A6=E5=91=8A=E5=88=87=E7=89=87?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 修复 UnifiedSettingsFile 与 LocalizationMap 的集合暴露形状,减少可变集合泄漏风险
- 优化 CqrsHandlerRegistryGeneratorTests 的大型 fixture 组织方式,降低 MA0051 噪音
- 更新 analyzer warning reduction 的 active todo 与 trace,回写 0 warning solution 基线
---
.../Data/UnifiedSettingsDataRepository.cs | 10 +-
GFramework.Game/Data/UnifiedSettingsFile.cs | 12 +-
.../Setting/Data/LocalizationMap.cs | 3 +
.../Cqrs/CqrsHandlerRegistryGeneratorTests.cs | 1381 +++++++++--------
.../analyzer-warning-reduction-tracking.md | 96 +-
.../analyzer-warning-reduction-trace.md | 74 +-
6 files changed, 756 insertions(+), 820 deletions(-)
diff --git a/GFramework.Game/Data/UnifiedSettingsDataRepository.cs b/GFramework.Game/Data/UnifiedSettingsDataRepository.cs
index 1cd13eb1..7412c948 100644
--- a/GFramework.Game/Data/UnifiedSettingsDataRepository.cs
+++ b/GFramework.Game/Data/UnifiedSettingsDataRepository.cs
@@ -283,15 +283,21 @@ public class UnifiedSettingsDataRepository(
/// 复制当前统一文件快照,确保未提交修改不会污染内存中的已提交状态。
///
/// 要复制的统一文件快照。
- /// 包含独立 section 字典的新快照。
+ /// 包含独立 section 映射副本的新快照。
private static UnifiedSettingsFile CloneFile(UnifiedSettingsFile source)
{
ArgumentNullException.ThrowIfNull(source);
+ // 反序列化后的运行时类型可能只是 IDictionary 实现;若底层仍是 Dictionary,则保留其 comparer,
+ // 否则退回到按当前内容复制,避免因为 API 抽象化而改变持久化前后的键比较语义。
+ var sections = source.Sections is Dictionary dictionary
+ ? new Dictionary(dictionary, dictionary.Comparer)
+ : new Dictionary(source.Sections);
+
return new UnifiedSettingsFile
{
Version = source.Version,
- Sections = new Dictionary(source.Sections, source.Sections.Comparer)
+ Sections = sections
};
}
diff --git a/GFramework.Game/Data/UnifiedSettingsFile.cs b/GFramework.Game/Data/UnifiedSettingsFile.cs
index 694dcc28..89e1425b 100644
--- a/GFramework.Game/Data/UnifiedSettingsFile.cs
+++ b/GFramework.Game/Data/UnifiedSettingsFile.cs
@@ -11,6 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+using System.Collections.Generic;
using GFramework.Core.Abstractions.Versioning;
namespace GFramework.Game.Data;
@@ -22,13 +23,16 @@ namespace GFramework.Game.Data;
internal sealed class UnifiedSettingsFile : IVersioned
{
///
- /// 配置节集合,存储不同类型的配置数据
- /// 键为配置节名称,值为配置对象
+ /// 配置节映射,存储不同类型的配置数据。
///
- public Dictionary Sections { get; set; } = new();
+ ///
+ /// 这里公开为 而不是具体的 ,
+ /// 以避免暴露可替换的具体集合实现,同时继续兼容 Newtonsoft.Json 对字典对象的序列化与反序列化。
+ ///
+ public IDictionary Sections { get; set; } = new Dictionary();
///
/// 配置文件版本号,用于版本控制和兼容性检查
///
public int Version { get; set; }
-}
\ No newline at end of file
+}
diff --git a/GFramework.Godot/Setting/Data/LocalizationMap.cs b/GFramework.Godot/Setting/Data/LocalizationMap.cs
index 369d0fc3..9d5f33bf 100644
--- a/GFramework.Godot/Setting/Data/LocalizationMap.cs
+++ b/GFramework.Godot/Setting/Data/LocalizationMap.cs
@@ -11,6 +11,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+using System;
+using System.Collections.Generic;
+
namespace GFramework.Godot.Setting.Data;
///
diff --git a/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs b/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
index 3930aef9..458eaa18 100644
--- a/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
+++ b/GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs
@@ -684,6 +684,685 @@ public class CqrsHandlerRegistryGeneratorTests
""";
+ // Keep large source fixtures at class scope so MA0051 reduction stays behavior-neutral for generator tests.
+ private const string HiddenPointerResponseCompilationErrorSource = """
+ using System;
+
+ namespace Microsoft.Extensions.DependencyInjection
+ {
+ public interface IServiceCollection { }
+
+ public static class ServiceCollectionServiceExtensions
+ {
+ public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
+ }
+ }
+
+ namespace GFramework.Core.Abstractions.Logging
+ {
+ public interface ILogger
+ {
+ void Debug(string msg);
+ }
+ }
+
+ namespace GFramework.Cqrs.Abstractions.Cqrs
+ {
+ public interface IRequest { }
+ public interface INotification { }
+ public interface IStreamRequest { }
+
+ public interface IRequestHandler where TRequest : IRequest { }
+ public interface INotificationHandler where TNotification : INotification { }
+ public interface IStreamRequestHandler where TRequest : IStreamRequest { }
+ }
+
+ namespace GFramework.Cqrs
+ {
+ public interface ICqrsHandlerRegistry
+ {
+ void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ public sealed class CqrsHandlerRegistryAttribute : Attribute
+ {
+ public CqrsHandlerRegistryAttribute(Type registryType) { }
+ }
+ }
+
+ namespace TestApp
+ {
+ using GFramework.Cqrs.Abstractions.Cqrs;
+
+ public sealed class Container
+ {
+ private unsafe struct HiddenResponse
+ {
+ }
+
+ private unsafe sealed record HiddenRequest() : IRequest;
+
+ public unsafe sealed class HiddenHandler : IRequestHandler
+ {
+ }
+ }
+ }
+ """;
+
+ private const string MixedDirectAndPreciseRegistrationsSource = """
+ using System;
+
+ namespace Microsoft.Extensions.DependencyInjection
+ {
+ public interface IServiceCollection { }
+
+ public static class ServiceCollectionServiceExtensions
+ {
+ public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
+ }
+ }
+
+ namespace GFramework.Core.Abstractions.Logging
+ {
+ public interface ILogger
+ {
+ void Debug(string msg);
+ }
+ }
+
+ namespace GFramework.Cqrs.Abstractions.Cqrs
+ {
+ public interface IRequest { }
+ public interface INotification { }
+ public interface IStreamRequest { }
+
+ public interface IRequestHandler where TRequest : IRequest { }
+ public interface INotificationHandler where TNotification : INotification { }
+ public interface IStreamRequestHandler where TRequest : IStreamRequest { }
+ }
+
+ namespace GFramework.Cqrs
+ {
+ public interface ICqrsHandlerRegistry
+ {
+ void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ public sealed class CqrsHandlerRegistryAttribute : Attribute
+ {
+ public CqrsHandlerRegistryAttribute(Type registryType) { }
+ }
+ }
+
+ namespace TestApp
+ {
+ using GFramework.Cqrs.Abstractions.Cqrs;
+
+ public sealed record VisibleRequest() : IRequest;
+
+ public sealed class Container
+ {
+ private sealed record HiddenResponse();
+
+ private sealed record HiddenRequest() : IRequest;
+
+ public sealed class MixedHandler :
+ IRequestHandler,
+ IRequestHandler
+ {
+ }
+ }
+ }
+ """;
+
+ private const string MixedReflectedImplementationAndPreciseRegistrationsSource = """
+ using System;
+
+ namespace Microsoft.Extensions.DependencyInjection
+ {
+ public interface IServiceCollection { }
+
+ public static class ServiceCollectionServiceExtensions
+ {
+ public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
+ }
+ }
+
+ namespace GFramework.Core.Abstractions.Logging
+ {
+ public interface ILogger
+ {
+ void Debug(string msg);
+ }
+ }
+
+ namespace GFramework.Cqrs.Abstractions.Cqrs
+ {
+ public interface IRequest { }
+ public interface INotification { }
+ public interface IStreamRequest { }
+
+ public interface IRequestHandler where TRequest : IRequest { }
+ public interface INotificationHandler where TNotification : INotification { }
+ public interface IStreamRequestHandler where TRequest : IStreamRequest { }
+ }
+
+ namespace GFramework.Cqrs
+ {
+ public interface ICqrsHandlerRegistry
+ {
+ void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ public sealed class CqrsHandlerRegistryAttribute : Attribute
+ {
+ public CqrsHandlerRegistryAttribute(Type registryType) { }
+ }
+ }
+
+ namespace TestApp
+ {
+ using GFramework.Cqrs.Abstractions.Cqrs;
+
+ public sealed record VisibleRequest() : IRequest;
+
+ public sealed class Container
+ {
+ private sealed record HiddenResponse();
+
+ private sealed record HiddenRequest() : IRequest;
+
+ private sealed class HiddenMixedHandler :
+ IRequestHandler,
+ IRequestHandler
+ {
+ }
+ }
+ }
+ """;
+
+ private const string ExternalProtectedTypeContractsSource = """
+ namespace GFramework.Cqrs.Abstractions.Cqrs
+ {
+ public interface IRequest { }
+ public interface INotification { }
+ public interface IStreamRequest { }
+
+ public interface IRequestHandler where TRequest : IRequest { }
+ public interface INotificationHandler where TNotification : INotification { }
+ public interface IStreamRequestHandler where TRequest : IStreamRequest { }
+ }
+ """;
+
+ private const string ExternalProtectedTypeDependencySource = """
+ using GFramework.Cqrs.Abstractions.Cqrs;
+
+ namespace Dep;
+
+ public sealed record VisibleRequest() : IRequest;
+
+ public abstract class VisibilityScope
+ {
+ protected internal sealed record ProtectedResponse();
+
+ protected internal sealed record ProtectedRequest() : IRequest;
+ }
+
+ public abstract class HandlerBase :
+ VisibilityScope,
+ IRequestHandler,
+ IRequestHandler
+ {
+ }
+ """;
+
+ private const string ExternalProtectedTypeLookupSource = """
+ using System;
+ using Dep;
+
+ namespace Microsoft.Extensions.DependencyInjection
+ {
+ public interface IServiceCollection { }
+
+ public static class ServiceCollectionServiceExtensions
+ {
+ public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
+ }
+ }
+
+ namespace GFramework.Core.Abstractions.Logging
+ {
+ public interface ILogger
+ {
+ void Debug(string msg);
+ }
+ }
+
+ namespace GFramework.Cqrs
+ {
+ public interface ICqrsHandlerRegistry
+ {
+ void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ public sealed class CqrsHandlerRegistryAttribute : Attribute
+ {
+ public CqrsHandlerRegistryAttribute(Type registryType) { }
+ }
+ }
+
+ namespace TestApp
+ {
+ public sealed class DerivedHandler : HandlerBase
+ {
+ }
+ }
+ """;
+
+ private const string LegacyFallbackMarkerHiddenHandlerSource = """
+ using System;
+
+ namespace Microsoft.Extensions.DependencyInjection
+ {
+ public interface IServiceCollection { }
+
+ public static class ServiceCollectionServiceExtensions
+ {
+ public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
+ }
+ }
+
+ namespace GFramework.Core.Abstractions.Logging
+ {
+ public interface ILogger
+ {
+ void Debug(string msg);
+ }
+ }
+
+ namespace GFramework.Cqrs.Abstractions.Cqrs
+ {
+ public interface IRequest { }
+ public interface INotification { }
+ public interface IStreamRequest { }
+
+ public interface IRequestHandler where TRequest : IRequest { }
+ public interface INotificationHandler where TNotification : INotification { }
+ public interface IStreamRequestHandler where TRequest : IStreamRequest { }
+ }
+
+ namespace GFramework.Cqrs
+ {
+ public interface ICqrsHandlerRegistry
+ {
+ void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ public sealed class CqrsHandlerRegistryAttribute : Attribute
+ {
+ public CqrsHandlerRegistryAttribute(Type registryType) { }
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly)]
+ public sealed class CqrsReflectionFallbackAttribute : Attribute
+ {
+ public CqrsReflectionFallbackAttribute() { }
+ }
+ }
+
+ namespace TestApp
+ {
+ using GFramework.Cqrs.Abstractions.Cqrs;
+
+ public sealed record VisibleRequest() : IRequest;
+
+ public sealed class Container
+ {
+ private sealed record HiddenRequest() : IRequest;
+
+ private sealed class HiddenHandler : IRequestHandler { }
+ }
+
+ public sealed class VisibleHandler : IRequestHandler { }
+ }
+ """;
+
+ private const string FallbackMarkerUnavailableHiddenHandlerSource = """
+ using System;
+
+ namespace Microsoft.Extensions.DependencyInjection
+ {
+ public interface IServiceCollection { }
+
+ public static class ServiceCollectionServiceExtensions
+ {
+ public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
+ }
+ }
+
+ namespace GFramework.Core.Abstractions.Logging
+ {
+ public interface ILogger
+ {
+ void Debug(string msg);
+ }
+ }
+
+ namespace GFramework.Cqrs.Abstractions.Cqrs
+ {
+ public interface IRequest { }
+ public interface INotification { }
+ public interface IStreamRequest { }
+
+ public interface IRequestHandler where TRequest : IRequest { }
+ public interface INotificationHandler where TNotification : INotification { }
+ public interface IStreamRequestHandler where TRequest : IStreamRequest { }
+ }
+
+ namespace GFramework.Cqrs
+ {
+ public interface ICqrsHandlerRegistry
+ {
+ void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ public sealed class CqrsHandlerRegistryAttribute : Attribute
+ {
+ public CqrsHandlerRegistryAttribute(Type registryType) { }
+ }
+ }
+
+ namespace TestApp
+ {
+ using GFramework.Cqrs.Abstractions.Cqrs;
+
+ public sealed record VisibleRequest() : IRequest;
+
+ public sealed class Container
+ {
+ private sealed record HiddenRequest() : IRequest;
+
+ private sealed class HiddenHandler : IRequestHandler { }
+ }
+
+ public sealed class VisibleHandler : IRequestHandler { }
+ }
+ """;
+
+ private const string MissingFallbackAttributeDiagnosticSource = """
+ using System;
+
+ namespace Microsoft.Extensions.DependencyInjection
+ {
+ public interface IServiceCollection { }
+
+ public static class ServiceCollectionServiceExtensions
+ {
+ public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
+ }
+ }
+
+ namespace GFramework.Core.Abstractions.Logging
+ {
+ public interface ILogger
+ {
+ void Debug(string msg);
+ }
+ }
+
+ namespace GFramework.Cqrs.Abstractions.Cqrs
+ {
+ public interface IRequest { }
+ public interface INotification { }
+ public interface IStreamRequest { }
+
+ public interface IRequestHandler where TRequest : IRequest { }
+ public interface INotificationHandler where TNotification : INotification { }
+ public interface IStreamRequestHandler where TRequest : IStreamRequest { }
+ }
+
+ namespace GFramework.Cqrs
+ {
+ public interface ICqrsHandlerRegistry
+ {
+ void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ public sealed class CqrsHandlerRegistryAttribute : Attribute
+ {
+ public CqrsHandlerRegistryAttribute(Type registryType) { }
+ }
+ }
+
+ namespace TestApp
+ {
+ using GFramework.Cqrs.Abstractions.Cqrs;
+
+ public sealed class Container
+ {
+ private unsafe struct HiddenResponse
+ {
+ }
+
+ private unsafe sealed record HiddenRequest() : IRequest>;
+
+ public unsafe sealed class HiddenHandler : IRequestHandler>
+ {
+ }
+ }
+ }
+ """;
+
+ private const string UnresolvedErrorTypeRuntimeLookupSource = """
+ using System;
+
+ namespace Microsoft.Extensions.DependencyInjection
+ {
+ public interface IServiceCollection { }
+
+ public static class ServiceCollectionServiceExtensions
+ {
+ public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
+ }
+ }
+
+ namespace GFramework.Core.Abstractions.Logging
+ {
+ public interface ILogger
+ {
+ void Debug(string msg);
+ }
+ }
+
+ namespace GFramework.Cqrs.Abstractions.Cqrs
+ {
+ public interface IRequest { }
+ public interface INotification { }
+ public interface IStreamRequest { }
+
+ public interface IRequestHandler where TRequest : IRequest { }
+ public interface INotificationHandler where TNotification : INotification { }
+ public interface IStreamRequestHandler where TRequest : IStreamRequest { }
+ }
+
+ namespace GFramework.Cqrs
+ {
+ public interface ICqrsHandlerRegistry
+ {
+ void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ public sealed class CqrsHandlerRegistryAttribute : Attribute
+ {
+ public CqrsHandlerRegistryAttribute(Type registryType) { }
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly)]
+ public sealed class CqrsReflectionFallbackAttribute : Attribute
+ {
+ public CqrsReflectionFallbackAttribute(params string[] fallbackHandlerTypeNames) { }
+ }
+ }
+
+ namespace TestApp
+ {
+ using GFramework.Cqrs.Abstractions.Cqrs;
+
+ public sealed record BrokenRequest() : IRequest;
+
+ public sealed class BrokenHandler : IRequestHandler
+ {
+ }
+ }
+ """;
+
+ private const string DynamicResponseNormalizationSource = """
+ using System;
+
+ namespace Microsoft.Extensions.DependencyInjection
+ {
+ public interface IServiceCollection { }
+
+ public static class ServiceCollectionServiceExtensions
+ {
+ public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
+ }
+ }
+
+ namespace GFramework.Core.Abstractions.Logging
+ {
+ public interface ILogger
+ {
+ void Debug(string msg);
+ }
+ }
+
+ namespace GFramework.Cqrs.Abstractions.Cqrs
+ {
+ public interface IRequest { }
+ public interface INotification { }
+ public interface IStreamRequest { }
+
+ public interface IRequestHandler where TRequest : IRequest { }
+ public interface INotificationHandler where TNotification : INotification { }
+ public interface IStreamRequestHandler where TRequest : IStreamRequest { }
+ }
+
+ namespace GFramework.Cqrs
+ {
+ public interface ICqrsHandlerRegistry
+ {
+ void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ public sealed class CqrsHandlerRegistryAttribute : Attribute
+ {
+ public CqrsHandlerRegistryAttribute(Type registryType) { }
+ }
+ }
+
+ namespace TestApp
+ {
+ using GFramework.Cqrs.Abstractions.Cqrs;
+
+ public sealed record DynamicRequest() : IRequest;
+
+ public sealed class DynamicHandler : IRequestHandler
+ {
+ }
+ }
+ """;
+
+ private const string AssemblyLevelFallbackMetadataSource = """
+ using System;
+
+ namespace Microsoft.Extensions.DependencyInjection
+ {
+ public interface IServiceCollection { }
+
+ public static class ServiceCollectionServiceExtensions
+ {
+ public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
+ }
+ }
+
+ namespace GFramework.Core.Abstractions.Logging
+ {
+ public interface ILogger
+ {
+ void Debug(string msg);
+ }
+ }
+
+ namespace GFramework.Cqrs.Abstractions.Cqrs
+ {
+ public interface IRequest { }
+ public interface INotification { }
+ public interface IStreamRequest { }
+
+ public interface IRequestHandler where TRequest : IRequest { }
+ public interface INotificationHandler where TNotification : INotification { }
+ public interface IStreamRequestHandler where TRequest : IStreamRequest { }
+ }
+
+ namespace GFramework.Cqrs
+ {
+ public interface ICqrsHandlerRegistry
+ {
+ void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ public sealed class CqrsHandlerRegistryAttribute : Attribute
+ {
+ public CqrsHandlerRegistryAttribute(Type registryType) { }
+ }
+
+ [AttributeUsage(AttributeTargets.Assembly)]
+ public sealed class CqrsReflectionFallbackAttribute : Attribute
+ {
+ public CqrsReflectionFallbackAttribute(params string[] fallbackHandlerTypeNames) { }
+ }
+ }
+
+ namespace TestApp
+ {
+ using GFramework.Cqrs.Abstractions.Cqrs;
+
+ public sealed class Container
+ {
+ private unsafe struct AlphaResponse
+ {
+ }
+
+ private unsafe struct BetaResponse
+ {
+ }
+
+ private unsafe sealed record AlphaRequest() : IRequest>;
+
+ private unsafe sealed record BetaRequest() : IRequest>;
+
+ public unsafe sealed class BetaHandler : IRequestHandler>
+ {
+ }
+
+ public unsafe sealed class AlphaHandler : IRequestHandler>
+ {
+ }
+ }
+ }
+ """;
+
///
/// 验证生成器会为当前程序集中的 request、notification 和 stream 处理器生成稳定顺序的注册器。
///
@@ -752,73 +1431,8 @@ public class CqrsHandlerRegistryGeneratorTests
[Test]
public void Reports_Compilation_Error_And_Skips_Precise_Registration_For_Hidden_Pointer_Response()
{
- const string source = """
- using System;
-
- namespace Microsoft.Extensions.DependencyInjection
- {
- public interface IServiceCollection { }
-
- public static class ServiceCollectionServiceExtensions
- {
- public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
- }
- }
-
- namespace GFramework.Core.Abstractions.Logging
- {
- public interface ILogger
- {
- void Debug(string msg);
- }
- }
-
- namespace GFramework.Cqrs.Abstractions.Cqrs
- {
- public interface IRequest { }
- public interface INotification { }
- public interface IStreamRequest { }
-
- public interface IRequestHandler where TRequest : IRequest { }
- public interface INotificationHandler where TNotification : INotification { }
- public interface IStreamRequestHandler where TRequest : IStreamRequest { }
- }
-
- namespace GFramework.Cqrs
- {
- public interface ICqrsHandlerRegistry
- {
- void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
- }
-
- [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
- public sealed class CqrsHandlerRegistryAttribute : Attribute
- {
- public CqrsHandlerRegistryAttribute(Type registryType) { }
- }
- }
-
- namespace TestApp
- {
- using GFramework.Cqrs.Abstractions.Cqrs;
-
- public sealed class Container
- {
- private unsafe struct HiddenResponse
- {
- }
-
- private unsafe sealed record HiddenRequest() : IRequest;
-
- public unsafe sealed class HiddenHandler : IRequestHandler
- {
- }
- }
- }
- """;
-
var execution = ExecuteGenerator(
- source,
+ HiddenPointerResponseCompilationErrorSource,
allowUnsafe: true);
var inputCompilationErrors = execution.InputCompilationDiagnostics
.Where(static diagnostic => diagnostic.Severity == DiagnosticSeverity.Error)
@@ -855,75 +1469,8 @@ public class CqrsHandlerRegistryGeneratorTests
[Test]
public async Task Generates_Mixed_Direct_And_Precise_Registrations_For_Same_Implementation()
{
- const string source = """
- using System;
-
- namespace Microsoft.Extensions.DependencyInjection
- {
- public interface IServiceCollection { }
-
- public static class ServiceCollectionServiceExtensions
- {
- public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
- }
- }
-
- namespace GFramework.Core.Abstractions.Logging
- {
- public interface ILogger
- {
- void Debug(string msg);
- }
- }
-
- namespace GFramework.Cqrs.Abstractions.Cqrs
- {
- public interface IRequest { }
- public interface INotification { }
- public interface IStreamRequest { }
-
- public interface IRequestHandler where TRequest : IRequest { }
- public interface INotificationHandler where TNotification : INotification { }
- public interface IStreamRequestHandler where TRequest : IStreamRequest { }
- }
-
- namespace GFramework.Cqrs
- {
- public interface ICqrsHandlerRegistry
- {
- void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
- }
-
- [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
- public sealed class CqrsHandlerRegistryAttribute : Attribute
- {
- public CqrsHandlerRegistryAttribute(Type registryType) { }
- }
- }
-
- namespace TestApp
- {
- using GFramework.Cqrs.Abstractions.Cqrs;
-
- public sealed record VisibleRequest() : IRequest;
-
- public sealed class Container
- {
- private sealed record HiddenResponse();
-
- private sealed record HiddenRequest() : IRequest;
-
- public sealed class MixedHandler :
- IRequestHandler,
- IRequestHandler
- {
- }
- }
- }
- """;
-
await GeneratorTest.RunAsync(
- source,
+ MixedDirectAndPreciseRegistrationsSource,
("CqrsHandlerRegistry.g.cs", MixedDirectAndPreciseRegistrationsExpected));
}
@@ -934,75 +1481,8 @@ public class CqrsHandlerRegistryGeneratorTests
[Test]
public async Task Generates_Mixed_Reflected_Implementation_And_Precise_Registrations_For_Same_Implementation()
{
- const string source = """
- using System;
-
- namespace Microsoft.Extensions.DependencyInjection
- {
- public interface IServiceCollection { }
-
- public static class ServiceCollectionServiceExtensions
- {
- public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
- }
- }
-
- namespace GFramework.Core.Abstractions.Logging
- {
- public interface ILogger
- {
- void Debug(string msg);
- }
- }
-
- namespace GFramework.Cqrs.Abstractions.Cqrs
- {
- public interface IRequest { }
- public interface INotification { }
- public interface IStreamRequest { }
-
- public interface IRequestHandler where TRequest : IRequest { }
- public interface INotificationHandler where TNotification : INotification { }
- public interface IStreamRequestHandler where TRequest : IStreamRequest { }
- }
-
- namespace GFramework.Cqrs
- {
- public interface ICqrsHandlerRegistry
- {
- void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
- }
-
- [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
- public sealed class CqrsHandlerRegistryAttribute : Attribute
- {
- public CqrsHandlerRegistryAttribute(Type registryType) { }
- }
- }
-
- namespace TestApp
- {
- using GFramework.Cqrs.Abstractions.Cqrs;
-
- public sealed record VisibleRequest() : IRequest;
-
- public sealed class Container
- {
- private sealed record HiddenResponse();
-
- private sealed record HiddenRequest() : IRequest;
-
- private sealed class HiddenMixedHandler :
- IRequestHandler,
- IRequestHandler
- {
- }
- }
- }
- """;
-
await GeneratorTest.RunAsync(
- source,
+ MixedReflectedImplementationAndPreciseRegistrationsSource,
("CqrsHandlerRegistry.g.cs", MixedReflectedImplementationAndPreciseRegistrationsExpected));
}
@@ -1013,94 +1493,15 @@ public class CqrsHandlerRegistryGeneratorTests
[Test]
public void Generates_Precise_Assembly_Type_Lookups_For_Inaccessible_External_Protected_Types()
{
- const string contractsSource = """
- namespace GFramework.Cqrs.Abstractions.Cqrs
- {
- public interface IRequest { }
- public interface INotification { }
- public interface IStreamRequest { }
-
- public interface IRequestHandler where TRequest : IRequest { }
- public interface INotificationHandler where TNotification : INotification { }
- public interface IStreamRequestHandler where TRequest : IStreamRequest { }
- }
- """;
-
- const string dependencySource = """
- using GFramework.Cqrs.Abstractions.Cqrs;
-
- namespace Dep;
-
- public sealed record VisibleRequest() : IRequest;
-
- public abstract class VisibilityScope
- {
- protected internal sealed record ProtectedResponse();
-
- protected internal sealed record ProtectedRequest() : IRequest;
- }
-
- public abstract class HandlerBase :
- VisibilityScope,
- IRequestHandler,
- IRequestHandler
- {
- }
- """;
-
- const string source = """
- using System;
- using Dep;
-
- namespace Microsoft.Extensions.DependencyInjection
- {
- public interface IServiceCollection { }
-
- public static class ServiceCollectionServiceExtensions
- {
- public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
- }
- }
-
- namespace GFramework.Core.Abstractions.Logging
- {
- public interface ILogger
- {
- void Debug(string msg);
- }
- }
-
- namespace GFramework.Cqrs
- {
- public interface ICqrsHandlerRegistry
- {
- void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
- }
-
- [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
- public sealed class CqrsHandlerRegistryAttribute : Attribute
- {
- public CqrsHandlerRegistryAttribute(Type registryType) { }
- }
- }
-
- namespace TestApp
- {
- public sealed class DerivedHandler : HandlerBase
- {
- }
- }
- """;
-
var contractsReference = MetadataReferenceTestBuilder.CreateFromSource(
"Contracts",
- contractsSource);
+ ExternalProtectedTypeContractsSource);
var dependencyReference = MetadataReferenceTestBuilder.CreateFromSource(
"Dependency",
- dependencySource,
+ ExternalProtectedTypeDependencySource,
contractsReference);
var generatedSource = RunGenerator(
- source,
+ ExternalProtectedTypeLookupSource,
contractsReference,
dependencyReference);
@@ -1122,77 +1523,8 @@ public class CqrsHandlerRegistryGeneratorTests
[Test]
public async Task Does_Not_Emit_Legacy_Fallback_Marker_When_Generated_Registry_Can_Self_Register_Hidden_Handler()
{
- const string source = """
- using System;
-
- namespace Microsoft.Extensions.DependencyInjection
- {
- public interface IServiceCollection { }
-
- public static class ServiceCollectionServiceExtensions
- {
- public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
- }
- }
-
- namespace GFramework.Core.Abstractions.Logging
- {
- public interface ILogger
- {
- void Debug(string msg);
- }
- }
-
- namespace GFramework.Cqrs.Abstractions.Cqrs
- {
- public interface IRequest { }
- public interface INotification { }
- public interface IStreamRequest { }
-
- public interface IRequestHandler where TRequest : IRequest { }
- public interface INotificationHandler where TNotification : INotification { }
- public interface IStreamRequestHandler where TRequest : IStreamRequest { }
- }
-
- namespace GFramework.Cqrs
- {
- public interface ICqrsHandlerRegistry
- {
- void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
- }
-
- [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
- public sealed class CqrsHandlerRegistryAttribute : Attribute
- {
- public CqrsHandlerRegistryAttribute(Type registryType) { }
- }
-
- [AttributeUsage(AttributeTargets.Assembly)]
- public sealed class CqrsReflectionFallbackAttribute : Attribute
- {
- public CqrsReflectionFallbackAttribute() { }
- }
- }
-
- namespace TestApp
- {
- using GFramework.Cqrs.Abstractions.Cqrs;
-
- public sealed record VisibleRequest() : IRequest;
-
- public sealed class Container
- {
- private sealed record HiddenRequest() : IRequest;
-
- private sealed class HiddenHandler : IRequestHandler { }
- }
-
- public sealed class VisibleHandler : IRequestHandler { }
- }
- """;
-
await GeneratorTest.RunAsync(
- source,
+ LegacyFallbackMarkerHiddenHandlerSource,
("CqrsHandlerRegistry.g.cs", HiddenNestedHandlerSelfRegistrationExpected));
}
@@ -1203,71 +1535,8 @@ public class CqrsHandlerRegistryGeneratorTests
[Test]
public async Task Generates_Registry_For_Hidden_Handler_When_Fallback_Marker_Is_Unavailable()
{
- const string source = """
- using System;
-
- namespace Microsoft.Extensions.DependencyInjection
- {
- public interface IServiceCollection { }
-
- public static class ServiceCollectionServiceExtensions
- {
- public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
- }
- }
-
- namespace GFramework.Core.Abstractions.Logging
- {
- public interface ILogger
- {
- void Debug(string msg);
- }
- }
-
- namespace GFramework.Cqrs.Abstractions.Cqrs
- {
- public interface IRequest { }
- public interface INotification { }
- public interface IStreamRequest { }
-
- public interface IRequestHandler where TRequest : IRequest { }
- public interface INotificationHandler where TNotification : INotification { }
- public interface IStreamRequestHandler where TRequest : IStreamRequest { }
- }
-
- namespace GFramework.Cqrs
- {
- public interface ICqrsHandlerRegistry
- {
- void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
- }
-
- [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
- public sealed class CqrsHandlerRegistryAttribute : Attribute
- {
- public CqrsHandlerRegistryAttribute(Type registryType) { }
- }
- }
-
- namespace TestApp
- {
- using GFramework.Cqrs.Abstractions.Cqrs;
-
- public sealed record VisibleRequest() : IRequest;
-
- public sealed class Container
- {
- private sealed record HiddenRequest() : IRequest;
-
- private sealed class HiddenHandler : IRequestHandler { }
- }
-
- public sealed class VisibleHandler : IRequestHandler { }
- }
- """;
-
await GeneratorTest.RunAsync(
- source,
+ FallbackMarkerUnavailableHiddenHandlerSource,
("CqrsHandlerRegistry.g.cs", HiddenNestedHandlerSelfRegistrationExpected));
}
@@ -1279,73 +1548,8 @@ public class CqrsHandlerRegistryGeneratorTests
public void
Reports_Diagnostic_And_Skips_Registry_When_Fallback_Metadata_Is_Required_But_Runtime_Contract_Lacks_Fallback_Attribute()
{
- const string source = """
- using System;
-
- namespace Microsoft.Extensions.DependencyInjection
- {
- public interface IServiceCollection { }
-
- public static class ServiceCollectionServiceExtensions
- {
- public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
- }
- }
-
- namespace GFramework.Core.Abstractions.Logging
- {
- public interface ILogger
- {
- void Debug(string msg);
- }
- }
-
- namespace GFramework.Cqrs.Abstractions.Cqrs
- {
- public interface IRequest { }
- public interface INotification { }
- public interface IStreamRequest { }
-
- public interface IRequestHandler where TRequest : IRequest { }
- public interface INotificationHandler where TNotification : INotification { }
- public interface IStreamRequestHandler where TRequest : IStreamRequest { }
- }
-
- namespace GFramework.Cqrs
- {
- public interface ICqrsHandlerRegistry
- {
- void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
- }
-
- [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
- public sealed class CqrsHandlerRegistryAttribute : Attribute
- {
- public CqrsHandlerRegistryAttribute(Type registryType) { }
- }
- }
-
- namespace TestApp
- {
- using GFramework.Cqrs.Abstractions.Cqrs;
-
- public sealed class Container
- {
- private unsafe struct HiddenResponse
- {
- }
-
- private unsafe sealed record HiddenRequest() : IRequest>;
-
- public unsafe sealed class HiddenHandler : IRequestHandler>
- {
- }
- }
- }
- """;
-
var execution = ExecuteGenerator(
- source,
+ MissingFallbackAttributeDiagnosticSource,
allowUnsafe: true);
var inputCompilationErrors = execution.InputCompilationDiagnostics
.Where(static diagnostic => diagnostic.Severity == DiagnosticSeverity.Error)
@@ -1382,71 +1586,7 @@ public class CqrsHandlerRegistryGeneratorTests
[Test]
public void Emits_Runtime_Type_Lookup_When_Handler_Contract_Contains_Unresolved_Error_Types()
{
- const string source = """
- using System;
-
- namespace Microsoft.Extensions.DependencyInjection
- {
- public interface IServiceCollection { }
-
- public static class ServiceCollectionServiceExtensions
- {
- public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
- }
- }
-
- namespace GFramework.Core.Abstractions.Logging
- {
- public interface ILogger
- {
- void Debug(string msg);
- }
- }
-
- namespace GFramework.Cqrs.Abstractions.Cqrs
- {
- public interface IRequest { }
- public interface INotification { }
- public interface IStreamRequest { }
-
- public interface IRequestHandler where TRequest : IRequest { }
- public interface INotificationHandler where TNotification : INotification { }
- public interface IStreamRequestHandler where TRequest : IStreamRequest { }
- }
-
- namespace GFramework.Cqrs
- {
- public interface ICqrsHandlerRegistry
- {
- void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
- }
-
- [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
- public sealed class CqrsHandlerRegistryAttribute : Attribute
- {
- public CqrsHandlerRegistryAttribute(Type registryType) { }
- }
-
- [AttributeUsage(AttributeTargets.Assembly)]
- public sealed class CqrsReflectionFallbackAttribute : Attribute
- {
- public CqrsReflectionFallbackAttribute(params string[] fallbackHandlerTypeNames) { }
- }
- }
-
- namespace TestApp
- {
- using GFramework.Cqrs.Abstractions.Cqrs;
-
- public sealed record BrokenRequest() : IRequest;
-
- public sealed class BrokenHandler : IRequestHandler
- {
- }
- }
- """;
-
- var execution = ExecuteGenerator(source);
+ var execution = ExecuteGenerator(UnresolvedErrorTypeRuntimeLookupSource);
var inputCompilationErrors = execution.InputCompilationDiagnostics
.Where(static diagnostic => diagnostic.Severity == DiagnosticSeverity.Error)
.ToArray();
@@ -1483,65 +1623,7 @@ public class CqrsHandlerRegistryGeneratorTests
[Test]
public void Emits_Object_Type_Reference_When_Handler_Response_Uses_Dynamic()
{
- const string source = """
- using System;
-
- namespace Microsoft.Extensions.DependencyInjection
- {
- public interface IServiceCollection { }
-
- public static class ServiceCollectionServiceExtensions
- {
- public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
- }
- }
-
- namespace GFramework.Core.Abstractions.Logging
- {
- public interface ILogger
- {
- void Debug(string msg);
- }
- }
-
- namespace GFramework.Cqrs.Abstractions.Cqrs
- {
- public interface IRequest { }
- public interface INotification { }
- public interface IStreamRequest { }
-
- public interface IRequestHandler where TRequest : IRequest { }
- public interface INotificationHandler where TNotification : INotification { }
- public interface IStreamRequestHandler where TRequest : IStreamRequest { }
- }
-
- namespace GFramework.Cqrs
- {
- public interface ICqrsHandlerRegistry
- {
- void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
- }
-
- [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
- public sealed class CqrsHandlerRegistryAttribute : Attribute
- {
- public CqrsHandlerRegistryAttribute(Type registryType) { }
- }
- }
-
- namespace TestApp
- {
- using GFramework.Cqrs.Abstractions.Cqrs;
-
- public sealed record DynamicRequest() : IRequest;
-
- public sealed class DynamicHandler : IRequestHandler
- {
- }
- }
- """;
-
- var execution = ExecuteGenerator(source);
+ var execution = ExecuteGenerator(DynamicResponseNormalizationSource);
var inputCompilationErrors = execution.InputCompilationDiagnostics
.Where(static diagnostic => diagnostic.Severity == DiagnosticSeverity.Error)
.ToArray();
@@ -1574,89 +1656,8 @@ public class CqrsHandlerRegistryGeneratorTests
public void
Emits_Assembly_Level_Fallback_Metadata_When_Fallback_Is_Required_And_Runtime_Contract_Is_Available()
{
- const string source = """
- using System;
-
- namespace Microsoft.Extensions.DependencyInjection
- {
- public interface IServiceCollection { }
-
- public static class ServiceCollectionServiceExtensions
- {
- public static void AddTransient(IServiceCollection services, Type serviceType, Type implementationType) { }
- }
- }
-
- namespace GFramework.Core.Abstractions.Logging
- {
- public interface ILogger
- {
- void Debug(string msg);
- }
- }
-
- namespace GFramework.Cqrs.Abstractions.Cqrs
- {
- public interface IRequest { }
- public interface INotification { }
- public interface IStreamRequest { }
-
- public interface IRequestHandler where TRequest : IRequest { }
- public interface INotificationHandler where TNotification : INotification { }
- public interface IStreamRequestHandler where TRequest : IStreamRequest { }
- }
-
- namespace GFramework.Cqrs
- {
- public interface ICqrsHandlerRegistry
- {
- void Register(Microsoft.Extensions.DependencyInjection.IServiceCollection services, GFramework.Core.Abstractions.Logging.ILogger logger);
- }
-
- [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
- public sealed class CqrsHandlerRegistryAttribute : Attribute
- {
- public CqrsHandlerRegistryAttribute(Type registryType) { }
- }
-
- [AttributeUsage(AttributeTargets.Assembly)]
- public sealed class CqrsReflectionFallbackAttribute : Attribute
- {
- public CqrsReflectionFallbackAttribute(params string[] fallbackHandlerTypeNames) { }
- }
- }
-
- namespace TestApp
- {
- using GFramework.Cqrs.Abstractions.Cqrs;
-
- public sealed class Container
- {
- private unsafe struct AlphaResponse
- {
- }
-
- private unsafe struct BetaResponse
- {
- }
-
- private unsafe sealed record AlphaRequest() : IRequest>;
-
- private unsafe sealed record BetaRequest() : IRequest>;
-
- public unsafe sealed class BetaHandler : IRequestHandler>
- {
- }
-
- public unsafe sealed class AlphaHandler : IRequestHandler>
- {
- }
- }
- }
- """;
-
var execution = ExecuteGenerator(
- source,
+ AssemblyLevelFallbackMetadataSource,
allowUnsafe: true);
var inputCompilationErrors = execution.InputCompilationDiagnostics
.Where(static diagnostic => diagnostic.Severity == DiagnosticSeverity.Error)
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 707b2f78..5f02b9c4 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
@@ -2,63 +2,40 @@
## 目标
-继续以“优先低风险、保持行为兼容”为原则收敛当前仓库的 Meziantou analyzer warnings,并确保 active recovery 入口保持精简、可恢复。
+继续以“低风险、可审查、可恢复”为原则收敛 analyzer warning,并保持 active recovery 文档只保留当前真值。
## 当前恢复点
-- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-046`
-- 当前阶段:`Phase 46`
+- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-047`
+- 当前阶段:`Phase 47`
- 当前焦点:
- - 已按用户更正后的要求执行前台 `dotnet build GFramework.sln -c Release`,收集当前工作树的 solution 级 warning 基线,并将结果回写 active plan
- - 当前前台 solution Release build 已能稳定完成,结果为 `891 Warning(s)` / `0 Error(s)` / `Time Elapsed 00:00:18.57`
- - 当前 baseline 仍为 `origin/main` (`e692ed3`, `2026-04-24 09:36:17 +0800`);分支仍映射到 `fix/analyzer-warning-reduction-batch` / `GFramework-analyzer`
- - 当前直接观察到的热点 warning 规则集中在 `MA0051`、`MA0158`、`MA0004`,并伴随一部分 `MA0006`、`MA0002`、`MA0009`
- - 当前直接观察到的热点模块集中在 `GFramework.Godot.SourceGenerators`、`GFramework.Godot.SourceGenerators.Tests`、`GFramework.Core`、`GFramework.Game`、`GFramework.Cqrs`、`GFramework.Godot`
- - 非前台形态的同命令当前不稳定:重定向到文件、`script` 分配 TTY、以及若干 logger 组合都曾快速返回 `Build FAILED / 0 Warning(s) / 0 Error(s)` 或 `Restore failed`
-
-## 当前状态摘要
-
-- 已通过 explorer `Rawls` 盘点出本轮最适合并行推进的低风险切片:
- - `GFramework.Game/Data/UnifiedSettingsFile.cs` 的 `MA0016`
- - `GFramework.Godot/Setting/Data/LocalizationMap.cs` 的 `MA0016`
- - `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 的 `MA0051`
-- 已通过 explorer `Arendt` 收敛过旧构建根因:当前离线缓存只有 `Meziantou.Polyfill 1.0.110`,缺少项目请求的 `1.0.116`,导致 restore 失败并使 source-generator 相关 `netstandard2.0` 项目缺失有效引用图
-- worker `Aquinas` 已独立完成 `LocalizationMap` 收口并生成提交 `a0ce04b`(`fix(godot): 收紧本地化映射集合暴露`)
-- worker `Boyle` 已完成 `UnifiedSettingsFile` / `UnifiedSettingsDataRepository` 的最小 API 形状修正,并同步更新 active todo / trace 草稿
-- 主线程本轮重新执行前台 `dotnet build GFramework.sln -c Release`,构建成功并暴露出完整 warning 面,说明当前工作树至少在交互式前台构建路径上已经恢复到可收集 analyzer baseline 的状态
-- 从实时输出可直接确认的热点包括:
- - `GFramework.Godot.SourceGenerators/GodotProjectMetadataGenerator.cs`、`BindNodeSignalGenerator.cs`、`GetNodeGenerator.cs`、`Registration/AutoRegisterExportedCollectionsGenerator.cs`
- - `GFramework.Godot.SourceGenerators.Tests/**` 多个 generator 测试文件
- - `GFramework.Cqrs/Internal/WeakKeyCache.cs`
- - `GFramework.Core/**` 多个锁相关组件,如 `SamplingFilter.cs`、`BindableProperty.cs`、`FileAppender.cs`、`ResourceHandle.cs`
- - `GFramework.Game/Config/YamlConfigSchemaValidator*.cs`、`GFramework.Game/UI/UiRouterBase.cs`、`GFramework.Game/Storage/FileStorage.cs`
-- 同一轮中,多次尝试把相同命令切换到“重定向日志”“TTY 包裹”或“附加 logger 输出到文件”的形态时,构建又会退化成 `Build FAILED / 0 Warning(s) / 0 Error(s)` 或 `Restore failed`
-- 这说明当前环境不只是“能否构建”的问题,还存在“前台构建”和“非前台采集”结果不一致的执行形态漂移
+ - 已重新用经典 logger 形态执行 `dotnet build GFramework.sln -c Release -tl:off -nologo`,当前 solution 基线是 `0 Warning(s)` / `0 Error(s)`
+ - 受影响项目 `GFramework.Game` 与 `GFramework.SourceGenerators.Tests` 的 Release build 也已通过,当前工作树中的 warning-reduction 切片至少在编译层面成立
+ - 当前 baseline 仍为 `origin/main`(`e692ed3`, `2026-04-24 09:36:17 +0800`);batch stop condition 仍为 branch diff 接近 `75` 个文件
+ - 当前已提交 branch diff 仍只有 `3` 个文件、`234` 行,距离 stop condition 很远;工作树另外保留一批未提交切片待整理与提交
## 当前活跃事实
-- 当前主题仍保持 active,因为 analyzer warning reduction 主任务尚未结束,而且本轮新增了可直接消费的 solution warning baseline
-- `CqrsHandlerRegistryGeneratorTests.cs` 当前已不再保留方法内 `const string source = """..."""` 型大型 fixture;后续只需回到真实 warning 热点继续收敛
-- `UnifiedSettingsFile.Sections` 改为 `IDictionary` 后,`CloneFile` 仍会在底层是 `Dictionary` 时保留 comparer,从而避免改变现有 key 比较行为
-- `LocalizationMap` 现在通过私有只读字典与 `IReadOnlyDictionary` 暴露映射,消费者 `GodotLocalizationSettings` 仍只按只读方式使用这些映射
-- 当前 worktree 的推荐构建入口仍是 `bash scripts/dotnet-wsl.sh ...`
-- 当前前台 `dotnet build GFramework.sln -c Release` 的结果是 `891` 条 warning、`0` 条 error,且已确认不是“0 warning 的假成功”
-- 当前 warning 规则的已观察集合包括 `MA0051`、`MA0158`、`MA0004`、`MA0006`、`MA0002`、`MA0009`
-- 当前“非前台采集”路径仍不可信:把输出重定向到文件、追加 file logger 或经 `script` 分配 TTY 时,都未稳定复现前台结果
-- 先前已识别的 `--no-restore` 资产文件漂移、`Meziantou.Polyfill 1.0.116` 缺失、以及 `NU1301` 风险仍保留,但本轮用户要求的 warning 基线以成功的前台 `dotnet build` 结果为准
+- `UnifiedSettingsFile.Sections` 已抽象为 `IDictionary`;`UnifiedSettingsDataRepository.CloneFile` 会在底层仍是 `Dictionary` 时保留 comparer,避免改变既有键比较语义
+- `LocalizationMap` 通过私有 `Dictionary` 字段配合 `IReadOnlyDictionary` 暴露映射,继续避免把可变集合直接暴露给调用方
+- `CqrsHandlerRegistryGeneratorTests.cs` 已把一批大型 fixture 提升到类级常量,当前目标是以更低噪音方式消化 `MA0051`
+- 当前工作树的 tracked 变更集中在:
+ - `GFramework.Game/Data/UnifiedSettingsFile.cs`
+ - `GFramework.Game/Data/UnifiedSettingsDataRepository.cs`
+ - `GFramework.Godot/Setting/Data/LocalizationMap.cs`
+ - `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs`
+ - `docs/zh-CN/contributing.md`
+ - `docs/zh-CN/troubleshooting.md`
+- 当前还存在未跟踪的 `scripts/dotnet-wsl.sh`,用于 WSL Windows-backed worktree 下统一 `dotnet` 环境参数
## 当前风险
-- warning 采集形态漂移风险:同一个 `dotnet build GFramework.sln -c Release` 在前台可成功输出 `891` warnings,但一旦切到日志重定向、TTY 包裹或特定 logger 组合,就可能在约 `1` 秒内快速失败
- - 缓解措施:短期内把“前台普通构建”作为 warning 基线真值来源;若需要自动化统计,再单独排查 stdout/TTY/logger 相关环境差异
-- SDK / workload resolver 环境漂移风险:历史诊断样本里 Linux .NET SDK `10.0.106` 在 solution restore 图阶段报告过 `Microsoft.NET.SDK.WorkloadAutoImportPropsLocator` 缺失
- - 缓解措施:后续若要恢复脚本化或 `--no-restore` 验证,再重新检查当前 WSL `dotnet --info`、workload 解析器状态与仓库推荐构建入口是否一致
-- 资产文件环境漂移风险:历史样本中的根项目 `project.assets.json` 明显来自 Windows restore,上游记录的 fallback package folder 在当前 WSL 会话不存在
- - 缓解措施:需要重新启用 `--no-restore` 验证时,先用与 WSL 兼容的 NuGet / restore 配置重建根项目资产文件
-- 构建环境可达性风险:`Meziantou.Polyfill 1.0.116` 缺失与 `NU1301` 在旧样本中仍是有效线索
- - 缓解措施:后续若再次命中 restore 阻塞,优先核查本地缓存版本与 NuGet 可达性
-- reviewability 风险:当前分支只提交了 `LocalizationMap` 一个 warning 切片,而工作树仍保留 `ai-plan` 等未提交变更
- - 缓解措施:后续 warning reduction 继续按模块或规则切片提交,不把多个热点混成单个大提交
+- `dotnet build` 默认 terminal logger 输出会折叠成进度视图,不适合作为 warning 基线采样入口
+ - 缓解措施:继续使用 `-tl:off` 收集 warning 计数
+- 当前工作树仍有多处未提交修改;如果直接继续扩展批次,会降低 reviewability
+ - 缓解措施:先整理并提交当前切片,再决定是否继续下一轮 warning cleanup
+- `scripts/dotnet-wsl.sh` 与文档更新属于环境治理切片,是否与本轮 warning-reduction 一起提交需要显式判断
+ - 缓解措施:提交前按主题拆分 staging,避免把环境文档与 warning 修正混成一个提交
## 活跃文档
@@ -71,22 +48,15 @@
## 验证说明
-- `dotnet build GFramework.sln -c Release`
- - 结果:成功;`891 Warning(s)`、`0 Error(s)`、`Time Elapsed 00:00:18.57`
- - 补充:当前 warning 流可直接从前台交互式构建观察到;热点规则以 `MA0051`、`MA0158`、`MA0004` 为主
-- `dotnet build GFramework.sln -c Release > /tmp/gframework-build-warnings.log 2>&1`
- - 结果:失败;约 `0.78s` 结束,摘要仅显示 `Build FAILED / 0 Warning(s) / 0 Error(s)`
-- `dotnet build GFramework.sln -c Release '/flp:logfile=/tmp/gframework-build-warnings.log;verbosity=normal'`
- - 结果:成功;但日志文件只保留构建摘要,没有留下可消费的 warning 行
-- `dotnet build GFramework.sln -c Release '/flp1:logfile=/tmp/gframework-build-warnings-only.log;warningsonly'`
- - 结果:成功;但 warning-only 日志文件为空
-- `script -q -c "dotnet build GFramework.sln -c Release" /tmp/gframework-build-full-typescript.log`
- - 结果:失败;TTY 形态下 restore 于约 `0.8s` 退出
-- `git --git-dir=/mnt/f/gewuyou/System/Documents/WorkSpace/GameDev/GFramework/.git/worktrees/GFramework-analyzer --work-tree=/mnt/f/gewuyou/System/Documents/WorkSpace/GameDev/GFramework-WorkTree/GFramework-analyzer branch --show-current`
- - 结果:成功;当前分支为 `fix/analyzer-warning-reduction-batch`
+- `dotnet build GFramework.Game/GFramework.Game.csproj -c Release`
+ - 结果:成功
+- `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release`
+ - 结果:成功
+- `dotnet build GFramework.sln -c Release -tl:off -nologo`
+ - 结果:成功;`0 Warning(s)`、`0 Error(s)`、`Time Elapsed 00:00:12.72`
## 下一步建议
-1. 先以本轮前台 `dotnet build GFramework.sln -c Release` 的 `891` warning baseline 为起点,优先从 `MA0051` / `MA0158` 最密集的模块切分下一批低风险整改
-2. 并行保留环境核查:检查为什么相同命令在重定向日志、TTY 包裹或 logger 组合下会快速失败,避免后续 warning 统计自动化再次失真
-3. 在需要重新启用 `--no-restore` 或脚本化验证时,再回到根 `GFramework.csproj` 资产文件漂移、SDK workload resolver、以及 `Meziantou.Polyfill 1.0.116` / `NU1301` 这几条环境线索
+1. 先把当前工作树中的 warning-reduction 切片与环境文档切片拆分清楚,避免混合提交
+2. 若确认本轮目标只是收口 warning reduction,则优先提交 `Game` / `Godot` / `SourceGenerators.Tests` 相关修改
+3. 若 `scripts/dotnet-wsl.sh` 与中文文档属于独立环境治理工作,则单独跟踪或另起提交
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 eb3a3153..efaa088c 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,71 +1,23 @@
# Analyzer Warning Reduction 追踪
-## 2026-04-24 — RP-046
+## 2026-04-24 — RP-047
-### 阶段:solution warning baseline 采样与 active plan 回写
+### 阶段:solution warning 基线复核与 active plan 去噪
- 触发背景:
- - 用户纠正本轮目标为“执行 `dotnet build` 收集当前项目 warning,并更新当前工作树激活计划”
- - active topic 仍为 `analyzer-warning-reduction`,因此本轮需要先确认 solution 级 warning baseline 是否可直接从当前工作树获取
+ - 用户要求继续按 `$gframework-batch-boot 75` 推进,并明确要求“通过 `dotnet build` 检查警告”
+ - 用户追加要求清理当前计划中的噪音内容,因此本轮除了复核 warning 基线,还要同步压缩 active todo / trace
- 主线程实施:
- - 直接执行前台 `dotnet build GFramework.sln -c Release`
- - 构建成功,得到 `891 Warning(s)` / `0 Error(s)` / `Time Elapsed 00:00:18.57`
- - 从实时输出中确认 warning 热点主要集中在 `GFramework.Godot.SourceGenerators`、`GFramework.Godot.SourceGenerators.Tests`、`GFramework.Core`、`GFramework.Game`、`GFramework.Cqrs`、`GFramework.Godot`
- - 从实时输出中确认规则热点以 `MA0051`、`MA0158`、`MA0004` 为主,并伴随 `MA0006`、`MA0002`、`MA0009`
- - 追加尝试把同一命令改为“重定向到日志文件”“附加 file logger”“`script` 分配 TTY”几种采集方式;这些路径都未稳定复现前台结果,而是出现 `Build FAILED / 0 Warning(s) / 0 Error(s)` 或 `Restore failed`
- - 基于上述差异,本轮把“前台普通构建”视为 warning baseline 真值来源,并把采集形态漂移记录为环境风险
-- 本轮验证结果:
- - `dotnet build GFramework.sln -c Release`
- - 结果:成功;`891 Warning(s)`、`0 Error(s)`
- - `dotnet build GFramework.sln -c Release > /tmp/gframework-build-warnings.log 2>&1`
- - 结果:失败;约 `0.78s` 结束,摘要仅显示 `Build FAILED / 0 Warning(s) / 0 Error(s)`
- - `dotnet build GFramework.sln -c Release '/flp:logfile=/tmp/gframework-build-warnings.log;verbosity=normal'`
- - 结果:成功;但日志文件只保留了构建摘要,没有留下 warning 行
- - `dotnet build GFramework.sln -c Release '/flp1:logfile=/tmp/gframework-build-warnings-only.log;warningsonly'`
- - 结果:成功;但 warning-only 日志文件为空
- - `script -q -c "dotnet build GFramework.sln -c Release" /tmp/gframework-build-full-typescript.log`
- - 结果:失败;TTY 形态下 restore 于约 `0.8s` 退出
+ - 先读取 active topic 文档、基线信息与 branch diff 指标,确认 baseline 仍是 `origin/main`(`e692ed3`)
+ - 复查当前工作树中的 warning-reduction 切片,确认主要未提交修改集中在 `GFramework.Game`、`GFramework.Godot`、`GFramework.SourceGenerators.Tests`
+ - 执行 `dotnet build GFramework.Game/GFramework.Game.csproj -c Release` 与 `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release`,二者均成功
+ - 发现默认 terminal logger 输出不利于读取 warning 数,因此改用 `dotnet build GFramework.sln -c Release -tl:off -nologo`
+ - solution Release build 在经典 logger 形态下成功完成,结果为 `0 Warning(s)` / `0 Error(s)` / `Time Elapsed 00:00:12.72`
+ - 基于该真值,压缩 active todo / trace,移除已经过期的 `891 warnings` 旧基线和过多执行形态细节
- 当前结论:
- - 当前工作树的 solution 级 warning baseline 可以通过普通前台 `dotnet build` 获取,且样本值是 `891` 条 warning、`0` 条 error
- - 当前环境对 stdout/TTY/logger 形态敏感,不能把“把输出落到文件”的结果直接当作同等可信的构建事实
- - 下一轮 warning reduction 应以本轮前台 baseline 为准,而不是继续围绕空日志或快速失败结果做误判
-
-## 2026-04-24 — RP-045
-
-### 阶段:solution no-restore 阻塞面采样与 active plan 回写
-
-- 触发背景:
- - 用户要求显式执行 `dotnet build GFramework.sln -c Release --no-restore`,收集当前项目报错并同步更新当前工作树激活计划
- - active topic 仍为 `analyzer-warning-reduction`,因此本轮的核心工作是把 solution 级失败面与先前的 restore / warning 线索重新归并到同一个恢复点
-- 主线程实施:
- - 先执行 `dotnet build GFramework.sln -c Release --no-restore`,发现命令约 `1` 秒即失败,标准摘要只有 `Build FAILED / 0 Warning(s) / 0 Error(s)`
- - 补跑 `dotnet build GFramework.sln -c Release --no-restore -v:diag`,确认 solution 在根 `GFramework.csproj` 的 inner-build dispatch 阶段退出,没有进入各子项目编译
- - 继续把根项目拆成 `net8.0`、`net9.0`、`net10.0` 三个 `--no-restore` 构建,全部稳定复现同一条 `MSB4018`
- - 读取根项目 `obj/project.assets.json`,确认当前资产文件记录了 Windows restore 元数据与不存在的 fallback package folder
- - 按用户追加要求执行默认 `dotnet build` 与 `dotnet build -v:diag`,确认它不是落在相同失败层,而是更早停在 solution restore 图生成阶段
-- 本轮验证结果:
- - `dotnet build GFramework.sln -c Release --no-restore`
- - 结果:失败;仅有失败摘要,没有暴露真实阻塞点
- - `dotnet build GFramework.sln -c Release --no-restore -v:diag`
- - 结果:失败;失败位置收敛到根 `GFramework.csproj`
- - `dotnet build`
- - 结果:失败;同样约 `1` 秒退出,摘要仍只有 `0 Warning(s) / 0 Error(s)`
- - `dotnet build -v:diag`
- - 结果:失败;停在 `GFramework.sln` 的 `Restore` 路径 `_FilterRestoreGraphProjectInputItems`
- - 补充:具体落点是根 `GFramework.csproj` 的 `_IsProjectRestoreSupported`,日志记录 `MSB4276`,默认 SDK resolver 找不到 `Microsoft.NET.SDK.WorkloadAutoImportPropsLocator`
- - `dotnet build GFramework.csproj -c Release -f net8.0 --no-restore`
- - 结果:失败;`MSB4018`,`ResolvePackageAssets` 因缺失 `D:\Tool\Development Tools\Microsoft Visual Studio\Shared\NuGetPackages` 退出
- - `dotnet build GFramework.csproj -c Release -f net9.0 --no-restore`
- - 结果:失败;与 `net8.0` 相同
- - `dotnet build GFramework.csproj -c Release -f net10.0 --no-restore`
- - 结果:失败;与 `net8.0` 相同
-- 当前结论:
- - 默认 `dotnet build` 与 `dotnet build GFramework.sln -c Release --no-restore` 失败,但二者不是同一层错误;前者先死在 restore 图阶段,后者死在资产解析阶段
- - 当前 solution 级 `--no-restore` 阻塞不是代码编译错误,而是根项目资产文件引用了当前 WSL 不存在的 Windows fallback package folder
- - 当前 restore 路径还额外暴露出 SDK / workload resolver 环境问题,因此仅仅重建资产文件还不足以恢复默认 `dotnet build`
- - 这一层阻塞比先前记录的 `NU1301` 更靠前,因为它会让 `--no-restore` 构建在读取资产阶段直接退出
- - `Meziantou.Polyfill 1.0.116` 缺失 / `NU1301` 仍然是 restore 路径的独立风险;修复资产文件后仍需继续处理
- - active tracking 已升级到 `RP-045`,下一轮恢复应先重建与当前环境一致的根项目资产文件,再回测 solution `--no-restore`
+ - 当前工作树的 solution warning 基线已经降到 `0 Warning(s)`;active plan 中旧的高噪音 warning 基线不再适合作为恢复入口
+ - `-tl:off` 是当前最可靠的 warning 采样入口;默认 terminal logger 更适合看进度,不适合记录计数
+ - 当前批次的主要剩余工作不再是继续找 warning,而是整理并提交现有切片,避免 reviewability 下降
## Archive Context