diff --git a/docs/rules/Moq1100.md b/docs/rules/Moq1100.md index 51b52041e..efe9c9324 100644 --- a/docs/rules/Moq1100.md +++ b/docs/rules/Moq1100.md @@ -108,32 +108,26 @@ mock.Setup(x => x.TryProcess(out It.Ref.IsAny)) .Returns(true); ``` -## Known Limitations +## Coverage Notes ### Generic Callback Syntax -This analyzer does **not** currently validate type parameter mismatches when using the explicit generic `.Callback()` syntax. For example: +This analyzer validates type parameter mismatches in both lambda parameter inference and 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! +// This WILL trigger Moq1100 - type mismatch detected +mock.Setup(x => x.DoWork("test")) + .Callback(wrongTypeParam => { }); ``` -**Best Practice:** Use lambda parameter inference instead of explicit generic syntax to get full validation: +**Recommended:** Use lambda parameter inference for clarity and readability: ```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 +// Preferred style - clear and validated mock.Setup(x => x.DoWork("test")) - .Callback((string param) => { }); // Type validation works correctly + .Callback((string input) => { }); ``` -**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 2dc220835..4005518e7 100644 --- a/tests/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.cs +++ b/tests/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.cs @@ -218,26 +218,17 @@ public void TestMethod() } /// - /// 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 is an accepted limitation as the explicit generic syntax is rarely used in practice. + /// Verifies that .Callback{T}() with a wrong type parameter produces a diagnostic. + /// The analyzer uses symbol-based resolution of the generic type argument to validate the + /// callback parameter type. It correctly detects the type mismatch between .Callback{int}() + /// and the mocked method parameter type (string). /// - /// - /// - /// 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. - /// - /// /// The Moq version reference assembly group. /// A task representing the asynchronous unit test. [Theory] [InlineData("Net80WithOldMoq")] [InlineData("Net80WithNewMoq")] - public async Task GenericCallbackValidation_CurrentLimitation_IsDocumented(string referenceAssemblyGroup) + public async Task GenericCallbackWithWrongType_ProducesDiagnostic(string referenceAssemblyGroup) { const string source = """ using Moq; @@ -252,15 +243,14 @@ public class TestClass public void TestGenericCallback() { var mock = new Mock(); - // Note: This does NOT trigger a diagnostic (known limitation) - // Best practice: Use .Callback(param => { }) instead of .Callback(param => { }) + // .Callback() mismatches the mocked method parameter type (string). + // The analyzer detects this via symbol-based resolution of the generic type argument. mock.Setup(x => x.DoWork("test")) - .Callback(wrongTypeParam => { }); // Generic syntax not validated + .Callback({|Moq1100:wrongTypeParam|} => { }); } } """; - // This test documents the known limitation - no diagnostic is expected await AnalyzerVerifier.VerifyAnalyzerAsync(source, referenceAssemblyGroup); } }