Fix cross-assembly source generation accessibility - #11014
Fix cross-assembly source generation accessibility#11014Amaury Levé (Evangelink) wants to merge 1 commit into
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0f79d9b9-3240-40e6-bc8e-ed8bfc4cfb2e
🧵 Parallel-safety audit — PR #11014Nothing audited here touches process-global state, shared filesystem paths, or
Audited Re-run with
|
🧪 Expert test review — PR #11014
This advisory comment was generated automatically. Grades are heuristic
|
There was a problem hiding this comment.
Note
🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.
✅ 22/22 dimensions clean — no findings.
Review notes:
- Algorithmic Correctness: Moving the dedup check (
seenMethodKeys.Add) before the accessibility check is correct — derived-first iteration means the derived declaration wins fornew-shadowed members. ThehasUnsupportedTestMethodflag is still set on the first (derived) occurrence when applicable. For properties, the flag is set unconditionally before dedup/accessibility, so no regression there either. - The core fix (
IsAccessibleFromConsumernow takingconsumingAssembly) correctly addresses the bug whereInternalandProtectedOrInternalmembers from external assemblies were incorrectly treated as accessible. The delegation toSymbolReferenceabilityHelper.IsMemberAccessibleFromis consistent with howDynamicDataSourceBuilderandAttributeMaterializationHelperalready handle this. HasGettableValuenow uses the same assembly-aware check viaIsMemberAccessibleFrom(getter.DeclaredAccessibility, getter.ContainingType, consumingAssembly), replacing the hardcoded accessibility enum check — consistent and correct.- Dictionary→HashSet refactor reduces memory by not storing values that were never read back, while preserving the same dedup semantics.
- Test coverage: The new
Generator_ExcludesInaccessibleMembersFromBaseTypeInAnotherAssemblytest exercises the cross-assembly scenario with multi-level inheritance,new-shadowing,protected internalinaccessibility, and inaccessible getters — good coverage of the fix.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Two critical hiding defects remain, and cross-assembly internal coverage is incomplete.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Balanced
Findings: 2
New issues introduced by this change (3)
| Severity | Finding |
|---|---|
src/Analyzers/MSTest.SourceGeneration/Generators/TestClassModelBuilder.cs — These kind-specific sets still miss cross-kind hiding. C# member lookup hides base members by name… |
|
src/Analyzers/MSTest.SourceGeneration/Generators/TestClassModelBuilder.cs — BuildMethodSignatureKey distinguishes static and instance methods, but staticness is not part of… |
|
src/Analyzers/MSTest.SourceGeneration/Generators/TestMemberValidationHelper.cs — The assembly-sensitive predicate now covers both Internal and ProtectedOrInternal, but the… |
What changed in this PR
Updates source generation to account for cross-assembly accessibility and inherited-member hiding.
Changes:
- Adds assembly-aware accessibility checks.
- Revises inherited-member filtering.
- Adds two-assembly regression coverage.
| File | Review |
|---|---|
test/UnitTests/MSTest.SourceGeneration.UnitTests/MSTestReflectionMetadataGeneratorTests.cs |
Adds cross-assembly tests, but lacks direct internal member coverage. |
src/Analyzers/MSTest.SourceGeneration/Generators/TestMemberValidationHelper.cs |
Adds assembly-sensitive checks. Moderate: add cross-assembly internal method, property, and getter regressions. |
src/Analyzers/MSTest.SourceGeneration/Generators/TestClassModelBuilder.cs |
Critical: method hiding incorrectly distinguishes staticness and does not account for cross-kind hiding, potentially generating uncompilable code. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| var seenMethodKeys = new HashSet<string>(StringComparer.Ordinal); | ||
| var seenPropertyNames = new HashSet<string>(StringComparer.Ordinal); |
| string key = TestMemberValidationHelper.BuildMethodSignatureKey(method); | ||
| if (!seenMethodKeys.Add(key)) |
| internal static bool IsAccessibleFromConsumer(ISymbol symbol, IAssemblySymbol consumingAssembly) | ||
| => SymbolReferenceabilityHelper.IsMemberAccessibleFrom( | ||
| symbol.DeclaredAccessibility, | ||
| symbol.ContainingAssembly, | ||
| consumingAssembly); |


Summary
Testing
build.cmd -test -projects test\UnitTests\MSTest.SourceGeneration.UnitTests\MSTest.SourceGeneration.UnitTests.csproj -bl