Fix cross-assembly source generation accessibility - #11014
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0f79d9b9-3240-40e6-bc8e-ed8bfc4cfb2e
This comment has been minimized.
This comment has been minimized.
🧪 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.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0f79d9b9-3240-40e6-bc8e-ed8bfc4cfb2e
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
The two model-construction issues can silently omit inherited tests.
Review tier: Balanced
Findings: None
Issues resolved since last review (3)
| Severity | Finding |
|---|---|
src/Analyzers/MSTest.SourceGeneration/Generators/TestMemberValidationHelper.cs — The assembly-sensitive predicate now covers both Internal and ProtectedOrInternal, but the… View resolved comment |
|
src/Analyzers/MSTest.SourceGeneration/Generators/TestClassModelBuilder.cs — BuildMethodSignatureKey distinguishes static and instance methods, but staticness is not part of… View resolved comment |
|
src/Analyzers/MSTest.SourceGeneration/Generators/TestClassModelBuilder.cs — These kind-specific sets still miss cross-kind hiding. C# member lookup hides base members by name… View resolved comment |
Suppressed comments (2)
src/Analyzers/MSTest.SourceGeneration/Generators/TestClassModelBuilder.cs:122
- This hiding check runs before accessor attributes update
hasUnsupportedTestMethod. A base getter/setter carrying[TestMethod]remains visible to the reflection fallback even when a derived method has the property's name; declaring descriptors complete here prevents that fallback and loses the accessor test. Move the existing accessor check ahead of this early exit.
if (methodNamesInDerivedTypes.Contains(property.Name)
|| nonMethodNamesInDerivedTypes.Contains(property.Name))
{
break;
src/Analyzers/MSTest.SourceGeneration/Generators/TestClassModelBuilder.cs:89
- This early exit drops a cross-kind-hidden ancestor test without marking descriptor generation incomplete. Reflection's
Type.GetMethodsstill returns a base method when a nearer field/property merely has the same name, soAreGeneratedDescriptorsCompletecan remaintrueandTypeEnumeratorskips the legacy scan, silently losing that test. Record a skipped[TestMethod]here; the regression should also verify completeness becomes false.
if (nonMethodNamesInDerivedTypes.Contains(method.Name))
{
break;
This comment has been minimized.
This comment has been minimized.
🧪 Expert test review — PR #11014No new or modified test methods were identified in the changed regions of this PR (the pre-step test-file extraction produced no data to review). Re-run with
|
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0f79d9b9-3240-40e6-bc8e-ed8bfc4cfb2e
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Critical member-hiding and signature-normalization cases can still generate uncompilable invocations.
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 (2)
| Severity | Finding |
|---|---|
src/Analyzers/MSTest.SourceGeneration/Generators/TestClassModelBuilder.cs — The deduplication still considers only exact signatures, but generated invokers access members… |
|
src/Analyzers/MSTest.SourceGeneration/Generators/TestMemberValidationHelper.cs — Removing staticness fixes only one signature-equivalence case: this textual key still distinguishes… |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0f79d9b9-3240-40e6-bc8e-ed8bfc4cfb2e
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Differing-signature ancestor methods must be suppressed when hidden by a derived same-name method group.
Review tier: Balanced
Findings: None
Issues resolved since last review (2)
| Severity | Finding |
|---|---|
src/Analyzers/MSTest.SourceGeneration/Generators/TestMemberValidationHelper.cs — Removing staticness fixes only one signature-equivalence case: this textual key still distinguishes… View resolved comment |
|
src/Analyzers/MSTest.SourceGeneration/Generators/TestClassModelBuilder.cs — The deduplication still considers only exact signatures, but generated invokers access members… View resolved comment |
Suppressed comments (1)
src/Analyzers/MSTest.SourceGeneration/Generators/TestClassModelBuilder.cs:92
- Accessible methods declared on a derived level also hide the entire same-name method group from ancestor levels, even when the signatures differ. This condition ignores
methodNamesInDerivedTypes, so the existingDerivedTests.Op(string)/BaseTests.Op(int)shape still emits the base invoker as((DerivedTests)instance).Op(int), which cannot bind to the hidden base method and makes the generated compilation fail. Suppress differing-signature ancestor methods after exact-signature deduplication (while preserving overloads declared in the same type), and update the overload regression to compile the generated output rather than expecting both inherited entries.
if (nonMethodNamesInDerivedTypes.Contains(method.Name)
|| inaccessibleMethodNamesInDerivedTypes.Contains(method.Name))
🧪 Expert test review — PR #11014
Scope note: Only one test file changed in this PR ( This advisory comment was generated automatically. Grades are heuristic and informational — they do not block merging. Re-run with
|
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0f79d9b9-3240-40e6-bc8e-ed8bfc4cfb2e
This comment has been minimized.
This comment has been minimized.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0f79d9b9-3240-40e6-bc8e-ed8bfc4cfb2e
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Compile-diagnostic regression tests are missing for field, event, and nested-type hiding cases.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Balanced
Findings: 1
New issues introduced by this change (1)
| Severity | Finding |
|---|---|
src/Analyzers/MSTest.SourceGeneration/Generators/TestClassModelBuilder.cs — The new field, event, and nested-type hiding branches have no regression coverage; the added… |
Issues resolved since last review (3)
| Severity | Finding |
|---|---|
src/Analyzers/MSTest.SourceGeneration/Generators/TestMemberValidationHelper.cs — The new return-type distinction is not covered by a negative case: removing this condition still… View resolved comment |
|
src/Analyzers/MSTest.SourceGeneration/Generators/TestMemberValidationHelper.cs — dynamic still falls through to SymbolEqualityComparer.Default, which does not equate it with… View resolved comment |
|
src/Analyzers/MSTest.SourceGeneration/Generators/TestMemberValidationHelper.cs — This comparison ignores substitutions on a nested generic type's containing type. For example,… View resolved comment |
🧪 Expert test review — PR #11014No new or modified test methods were identified in the changed regions of this PR (the automated test-file extraction step produced no output to review). Re-run with
|
This comment has been minimized.
This comment has been minimized.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0f79d9b9-3240-40e6-bc8e-ed8bfc4cfb2e
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
One or more issues must be addressed before approval.
Review tier: Balanced
Findings: None
Issues resolved since last review (1)
| Severity | Finding |
|---|---|
src/Analyzers/MSTest.SourceGeneration/Generators/TestClassModelBuilder.cs — The new field, event, and nested-type hiding branches have no regression coverage; the added… View resolved comment |
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
src/Analyzers/MSTest.SourceGeneration/Generators/TestMemberValidationHelper.cs:129
- Method type-parameter names are not part of a CLR signature, so
Run<T>(T)andRun<U>(U)must compare equal. ComparingNamemakes this helper return false for equivalent generic signatures, contrary to its runtime-signature contract and the ordinal-based normalization already used inDependsOnShouldBeValidAnalyzer.cs:827-830. Compare the type-parameter ordinal instead, and add a direct regression with differently named method type parameters.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0f79d9b9-3240-40e6-bc8e-ed8bfc4cfb2e
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Generic method signatures must compare type parameters by kind and ordinal, not by name.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Balanced
Findings: 1
New issues introduced by this change (1)
| Severity | Finding |
|---|---|
src/Analyzers/MSTest.SourceGeneration/Generators/TestMemberValidationHelper.cs — Generic method parameter names are not part of a runtime signature; their ordinal is. Consequently… |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0f79d9b9-3240-40e6-bc8e-ed8bfc4cfb2e
🧵 Parallel-safety audit — PR #11014Parallelization — audited assemblies:
Findings: A (global-state) Both changed test files stay inside the finding taxonomy's blind spot in a good way — neither introduces a new lifecycle mutation, shared path, or
[Info · Low confidence] No Warning/High/Critical findings. Advisory only — heuristic, non-blocking. Re-run with
|
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The reviewed changes have regression coverage and no unresolved approval-blocking issues.
Review tier: Balanced
Findings: None
Issues resolved since last review (1)
| Severity | Finding |
|---|---|
src/Analyzers/MSTest.SourceGeneration/Generators/TestMemberValidationHelper.cs — Generic method parameter names are not part of a runtime signature; their ordinal is. Consequently… View resolved comment |
|
/backport to rel/4.4 |
|
Started backporting to rel/4.4: https://github.com/microsoft/testfx/actions/runs/34945341709 |


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