fix: 启用 Source Generator 程序集级自动发现 - #410
Conversation
程序集级 [assembly: AspectCoreGenerateProxy] 自动发现此前被 Execute 入口的 attrData is null -> continue 门挡死:自动发现产出的类型不带类型级特性, 全部被丢弃,导致该功能形同虚设(文档与 Execute 注释均宣称支持)。 引入 Candidate(Type, Explicit) 来源标记,将候选数据流拆分为显式标注与 自动发现两条路径;自动发现路径按默认语义创建代理(class -> 类代理, interface -> 无目标 stub 代理)。同时修复本程序集自动发现误用 Compilation.GlobalNamespace(会混入引用程序集 metadata 类型)的问题, 改用 Assembly.GlobalNamespace,并合并 IsEligibleForAutoProxy / GetAssemblyEligibleTypes 消除过滤逻辑漂移。 新增 AssemblyLevelAutoProxyTests 覆盖:本程序集与引用程序集自动发现、 不合格类型(sealed/static/含事件/无可代理成员/struct)跳过、显式标注 与自动发现共存不重复。EngineParity 全套 133 测试通过,无回归。
3c6d62f to
c1a8296
Compare
latte-gh
left a comment
There was a problem hiding this comment.
[BLOCKING] 引用程序集的 assembly-level 自动发现会把 internal 类型也加入候选,导致消费者项目生成不可编译源码。
当前 GetReferencedAssemblyCandidates 在发现引用程序集有 [assembly: AspectCoreGenerateProxy] 后枚举 assemblySymbol.GlobalNamespace,并在 IsEligibleForAutoProxy 中接受 Accessibility.Internal:
src/AspectCore.SourceGenerator/AspectCoreProxyGenerator.cs:65-71:引用程序集 assembly-level attribute 分支把符合条件的类型作为 auto-discovered candidate 加入。src/AspectCore.SourceGenerator/AspectCoreProxyGenerator.cs:123-125:自动发现过滤接受public/internal,注释写的是“Generated proxy code lives in the same assembly”。src/AspectCore.SourceGenerator/AspectCoreProxyGenerator.cs:365-377:随后为这些类型创建 interface/class proxy entry。
这个“同程序集可见”的前提只对当前编译程序集成立;对引用程序集不成立。消费者项目中的 source generator 输出不在被引用程序集内,不能访问对方的 internal class/interface。
我用隔离副本验证了最小复现:引用程序集声明 [assembly: AspectCoreGenerateProxy],并包含 internal class InternalService 和 internal interface IInternalService;主程序集只引用该库并运行 generator。新增临时回归测试后执行:
dotnet test tests/AspectCore.Core.Tests/AspectCore.Core.Tests.csproj --configuration Release -f net9.0 --filter "FullyQualifiedName~InternalReferencedAssemblyAutoProxyRegressionTests"
结果失败,输出包含:
CS0122: 'IInternalService' is inaccessible due to its protection level
CS0122: 'InternalService' is inaccessible due to its protection level
建议把 current assembly 和 referenced assembly 的自动发现可见性规则拆开:当前程序集可以继续允许 public/internal;引用程序集自动发现应至少限制为跨程序集可访问类型(通常只允许 public,除非显式完整支持 InternalsVisibleTo 的生成程序集身份契约)。同时补一个“引用程序集 assembly-level attribute + internal 类型”的回归测试,防止消费者编译场景再次漏掉。
引用程序集的 assembly-level 自动发现此前会接受 internal 类型,而生成的 代理代码编译进消费者程序集,无法访问被引用程序集的 internal 类型,导致 CS0122(消费者项目生成不可编译源码)。 修复:IsEligibleForAutoProxy 统一只接受 public 类型。顺带发现 current assembly 的 internal 类型自动发现同样会产生 CS0060(生成的代理类恒为 public,ProxyEmitter 硬编码,不能继承/实现可访问性更低的类型),因此 两路自动发现一致排除 internal。 新增回归测试: - 引用程序集带 assembly 特性 + internal class/interface -> 被排除,public 仍生成 - 本程序集 internal 类型 -> 被排除,public 仍生成
|
已修复,感谢 review。新增提交 修复方式
一个超出 review 范围的顺带发现实现时实测发现:当前编译程序集的 因此我让两路自动发现一致排除 验证新增 2 个回归测试(共 6 个):
|
latte-gh
left a comment
There was a problem hiding this comment.
Re-reviewed head fd7ff0ddce7ae57fcfe34dce4fbd204c7b1e3cd4.
The previous blocking issue is fixed. Assembly-level auto-discovery now excludes non-public types, so referenced assemblies with [assembly: AspectCoreGenerateProxy] no longer emit proxies for internal class/interface symbols that are inaccessible from the consuming compilation. The new regression tests cover both referenced-assembly internal types and current-assembly internal types, while preserving public type auto-discovery.
Checks reviewed:
AssemblyLevelAutoProxyTestsonnet9.0: 6/6 passed locally in an isolated archive checkout.git diff --check origin/master...origin/pr/410: passed.- GitHub checks for the current head are green, including build-and-test on Ubuntu/Windows, lint, Unit/E2E/NativeAOT test execution, coverage gates, CodeQL, and NativeAOT Verify.
No actionable findings for this revision.
问题
[assembly: AspectCoreGenerateProxy]程序集级自动发现功能实际是失效的。Execute入口对每个候选无条件执行attrData is null → continue(AspectCoreProxyGenerator.cs:184-188),而自动发现产出的类型不带类型级特性,全部被丢弃 → 生成器不产出任何代理。source-generator.md与Execute注释均宣称支持该能力,但从未有测试或使用者触发过(全仓库 grep 不到[assembly: AspectCoreGenerateProxy]的真实调用方)。改动
src/AspectCore.SourceGenerator/AspectCoreProxyGenerator.cs:Candidate(Type, Explicit)来源标记,将候选数据流拆分为显式标注与自动发现两条路径:Compilation.GlobalNamespace,会混入引用程序集的 metadata 类型(实测会扫到System.IUtfChar<TSelf>并生成其代理、撞 hintName 冲突);改用compilation.Assembly.GlobalNamespace(仅源程序集声明的类型)。该问题在 baseline 中即潜伏,只是被 attrData gate 掩盖。IsEligibleForAutoProxy与GetAssemblyEligibleTypes为统一实现,消除两处过滤逻辑漂移(事件跳过、带特性类型跳过的差异)。测试
新增
tests/AspectCore.Core.Tests/EngineParity/AssemblyLevelAutoProxyTests.cs(4 个用例):[assembly: AspectCoreGenerateProxy]自动发现 class/interfaceEngineParity全套 133 个测试通过(net10.0,含两引擎各跑一遍),无回归。行为边界(文档已同步)
程序集级自动发现的接口无可推断的实现类型,默认生成无目标 stub 代理(成员返回
default)。需要带实现的完整接口代理时,仍需显式[AspectCoreGenerateProxy(typeof(Impl))]。