fix: forward wrapped access of interface members via the declaring interface - #849
Conversation
…terface Mocking an interface that inherits two sibling interfaces declaring a member with the same name did not compile: the implicit member forwarded to the wrapped instance through the mocked interface, where the access is ambiguous between the siblings (CS0229 for properties and events, CS0121 for methods and indexers). Always cast `MockRegistry.Wraps` to the declaring interface (`ContainingType`) for interface mocks. This subsumes the special case for explicit implementations (hidden members), whose `ExplicitImplementation` is the containing type anyway. Class mocks keep forwarding through the mocked class.
There was a problem hiding this comment.
Pull request overview
This PR fixes a source-generator wrapping edge case for interface mocks where a mocked interface inherits multiple sibling interfaces that declare same-named members. The generated forwarding code now casts MockRegistry.Wraps to the declaring interface (ContainingType) so member access is unambiguous and compiles correctly (avoiding CS0229/CS0121), while class mocks continue forwarding through the mocked class type.
Changes:
- Update interface-member forwarding in the source generator to delegate through each member’s declaring interface when wrapping.
- Add runtime and generator tests covering sibling-interface collisions across properties, indexers, methods, and events.
- Update docs to reflect the clarified wrapping/forwarding behavior for interface members.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| Tests/Mockolate.Tests/TestHelpers/IChocolateGiftSet.cs | Adds sibling-interface hierarchy used to reproduce/verify ambiguous-member wrapping scenarios. |
| Tests/Mockolate.Tests/MockTests.WrappingInterfaceTests.cs | Adds runtime wrapping tests proving correct delegation for sibling-interface members. |
| Tests/Mockolate.SourceGenerators.Tests/MockTests.cs | Adds generator regression tests ensuring generated code delegates via declaring interfaces for sibling collisions. |
| Tests/Mockolate.SourceGenerators.Tests/MockTests.ClassTests.PropertiesTests.cs | Updates expected generated output for wrapping delegation to use declaring interfaces in base-interface members. |
| Tests/Mockolate.SourceGenerators.Tests/MockTests.ClassTests.MethodTests.cs | Updates expected generated output for wrapping delegation to use declaring interfaces in base-interface members. |
| Tests/Mockolate.SourceGenerators.Tests/MockTests.ClassTests.EventsTests.cs | Updates expected generated output for wrapping delegation to use declaring interfaces in base-interface members. |
| Source/Mockolate.SourceGenerators/Sources/Sources.MockClass.cs | Implements the core generator change: cast wraps to ContainingType for interface mocks when forwarding. |
| Docs/pages/01-create-mocks.md | Documents that interface members are forwarded through their declaring interfaces (including new hiding and sibling collisions). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
🚀 Benchmark ResultsDetails
Details
Details
Details
Details
Details
|
|
…e members via the declaring interface (#849) by Valentin Breuß
…e members via the declaring interface (#849) by Valentin Breuß
|
This is addressed in release v3.4.1. |



Mocking an interface that inherits two sibling interfaces declaring a member with the same name did not compile: the implicit member forwarded to the wrapped instance through the mocked interface, where the access is ambiguous between the siblings (CS0229 for properties and events, CS0121 for methods and indexers).
Always cast
MockRegistry.Wrapsto the declaring interface (ContainingType) for interface mocks. This subsumes the special case for explicit implementations (hidden members), whoseExplicitImplementationis the containing type anyway. Class mocks keep forwarding through the mocked class.