From 1425c5838a56d8430e4bb404ced4145328567b44 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Oct 2025 14:54:16 +0000 Subject: [PATCH 1/2] Initial plan From b18d2d7f29ad5f1ee3c2dab2df980d37e3395909 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Oct 2025 15:02:47 +0000 Subject: [PATCH 2/2] docs: document generic callback limitation in Moq1100 Co-authored-by: rjmurillo <6811113+rjmurillo@users.noreply.github.com> --- docs/rules/Moq1100.md | 26 +++++++++++++++++++ ...ureShouldMatchMockedMethodAnalyzerTests.cs | 21 +++++++++++---- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/docs/rules/Moq1100.md b/docs/rules/Moq1100.md index f4fc513e6..6ac9483ea 100644 --- a/docs/rules/Moq1100.md +++ b/docs/rules/Moq1100.md @@ -107,6 +107,32 @@ mock.Setup(x => x.TryProcess(out It.Ref.IsAny)) .Returns(true); ``` +## Known Limitations + +### Generic Callback Syntax + +This analyzer does **not** currently validate type parameter mismatches when using the explicit generic `.Callback()` syntax. For example: + +```csharp +// This will NOT trigger a diagnostic (current limitation) +mock.Setup(x => x.DoWork("test")) // DoWork takes a string parameter + .Callback(wrongTypeParam => { }); // Using int instead of string - no warning! +``` + +**Best Practice:** Use lambda parameter inference instead of explicit generic syntax to get full validation: + +```csharp +// ✅ Recommended: Let the compiler infer parameter types +mock.Setup(x => x.DoWork("test")) + .Callback(param => { }); // Type is inferred correctly as string + +// ✅ Also recommended: Explicitly type the lambda parameter +mock.Setup(x => x.DoWork("test")) + .Callback((string param) => { }); // Type validation works correctly +``` + +**Rationale:** The explicit generic `.Callback()` syntax is rarely used in practice. Analysis of open-source Moq usage found zero instances of this pattern. The recommended lambda parameter inference approach provides full type safety and validation coverage. + ## Suppress a warning If you just want to suppress a single violation, add preprocessor directives to diff --git a/tests/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.cs b/tests/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.cs index f77fa314c..e0bd910f6 100644 --- a/tests/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.cs +++ b/tests/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.cs @@ -93,10 +93,20 @@ public void TestMethod() } /// - /// Test to document the current limitation with generic callback validation. + /// Test to document the known limitation with generic callback validation. /// This test documents that .Callback<T>() with wrong type parameters is NOT currently validated. - /// This could be enhanced in a future version. + /// This is an accepted limitation as the explicit generic syntax is rarely used in practice. /// + /// + /// + /// Analysis shows zero real-world usage of the explicit generic .Callback<T>() syntax in open-source projects. + /// The recommended approach is to use lambda parameter inference which provides full type validation: + /// .Callback(param => { }) or .Callback((string param) => { }). + /// + /// + /// See docs/rules/Moq1100.md "Known Limitations" section for best practices. + /// + /// /// A task representing the asynchronous unit test. [Fact] public async Task GenericCallbackValidation_CurrentLimitation_IsDocumented() @@ -114,14 +124,15 @@ public class TestClass public void TestGenericCallback() { var mock = new Mock(); - // Note: This currently does NOT trigger a diagnostic, which could be enhanced in the future + // Note: This does NOT trigger a diagnostic (known limitation) + // Best practice: Use .Callback(param => { }) instead of .Callback(param => { }) mock.Setup(x => x.DoWork("test")) - .Callback(wrongTypeParam => { }); // Should ideally trigger Moq1100 but currently doesn't + .Callback(wrongTypeParam => { }); // Generic syntax not validated } } """; - // This test documents the current limitation - no diagnostic is expected + // This test documents the known limitation - no diagnostic is expected await AnalyzerVerifier.VerifyAnalyzerAsync(source, "Net80WithOldMoq"); } }