Skip to content

fix: resolve delegate-overload resolution for Moq1203 and Moq1206#919

Merged
rjmurillo merged 2 commits intomainfrom
fix/delegate-overload-resolution
Feb 21, 2026
Merged

fix: resolve delegate-overload resolution for Moq1203 and Moq1206#919
rjmurillo merged 2 commits intomainfrom
fix/delegate-overload-resolution

Conversation

@rjmurillo
Copy link
Copy Markdown
Owner

@rjmurillo rjmurillo commented Feb 21, 2026

Summary

Closes #910
Closes #911

Test plan

  • dotnet build passes with zero errors and zero warnings
  • All 288 Moq1203 tests pass (including 8 new delegate-overload cases)
  • All 92 Moq1206 tests pass (including 4 new delegate-overload cases)
  • Full suite of 2,497 tests passes with no regressions

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Moq analyzers now correctly identify return value specifications in complex method setup chains, with improved handling of chained method invocations and fallback matching.
    • Fixed detection of async delegate lambdas within Returns calls for more accurate recognition of valid Moq method calls.
  • Tests

    • Added test coverage for delegate-based ReturnsAsync scenarios in complex setups.

rjmurillo and others added 2 commits February 20, 2026 17:59
GetSymbolInfo on MemberAccessExpressionSyntax lacks argument context,
so Roslyn cannot resolve delegate-based overloads like
ReturnsAsync((MyValue val) => val). Query the parent
InvocationExpressionSyntax instead, and add a name-based fallback
for cases where IsInstanceOf still cannot match the constructed
generic method against known Moq symbols.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
IsReturnsMethodCallWithAsyncLambda queried GetSymbolInfo on the
MemberAccessExpressionSyntax, missing argument context. Switch to
querying the InvocationExpressionSyntax and add CandidateSymbols
fallback (previously missing entirely), so delegate-typed async
lambdas like Returns(async (string x) => x) are detected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 21, 2026

📝 Walkthrough

Walkthrough

The PR fixes two related analyzer false positives by improving symbol resolution when Moq's delegate-based overloads (e.g., ReturnsAsync((T val) => val)) are used. Changes modify how symbols are queried from invocation expressions and add a name-based fallback method for ambiguous overload scenarios.

Changes

Cohort / File(s) Summary
Symbol Resolution Logic
src/Analyzers/MethodSetupShouldSpecifyReturnValueAnalyzer.cs, src/Analyzers/ReturnsAsyncShouldBeUsedForAsyncMethodsAnalyzer.cs
Both analyzers now query the parent InvocationExpressionSyntax instead of just the MemberAccessExpressionSyntax to provide proper argument context for overload resolution. MethodSetupShouldSpecifyReturnValueAnalyzer adds a new helper method IsKnownReturnValueMethodName that performs name-based fallback matching when Roslyn symbol resolution fails, enabling detection of delegate-based ReturnsAsync calls.
Test Data and Cases
tests/Moq.Analyzers.Test/MethodSetupShouldSpecifyReturnValueAnalyzerTests.cs, tests/Moq.Analyzers.Test/ReturnsAsyncShouldBeUsedForAsyncMethodsAnalyzerTests.cs
Test cases for delegate-based ReturnsAsync moved from negative to positive test data in MethodSetupShouldSpecifyReturnValueAnalyzerTests. ReturnsAsyncShouldBeUsedForAsyncMethodsAnalyzerTests adds a new test data provider DelegateOverloadTestData and test case ShouldFlagAsyncDelegateLambdaInReturns to verify delegate lambda detection via candidate symbol resolution.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PR #910: Both address the same root cause—GetSymbolInfo on MemberAccessExpressionSyntax fails for delegate overloads—by querying parent InvocationExpressionSyntax instead.
  • PR #911: Directly related fix for the sister analyzer ReturnsAsyncShouldBeUsedForAsyncMethodsAnalyzer applying the same symbol-resolution pattern as this PR.
  • PR #907: Previous attempt at fixing the same Moq1203 false positive; this PR supersedes that approach with improved symbol-resolution strategy and name-based fallback.

Suggested labels

bug, analyzers, releasable

Suggested reviewers

  • MattKotsenas
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: fixing delegate-overload resolution for two specific Moq analyzer rules (Moq1203 and Moq1206).
Linked Issues check ✅ Passed The code changes directly address both linked issues: #910 and #911 by implementing delegate-overload resolution fixes for Moq1203 and Moq1206 analyzers.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the two identified issues: modifications to the two analyzers and corresponding test updates with no unrelated changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/delegate-overload-resolution

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @rjmurillo, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the accuracy of the Moq.Analyzers by addressing specific issues related to how Returns and ReturnsAsync methods are interpreted, especially when dealing with delegate-based overloads and async lambdas. The changes improve the analyzers' ability to correctly resolve method symbols, thereby eliminating previous false positives and false negatives and ensuring more reliable code analysis.

Highlights

  • Moq1203 False Positive Resolution: The analyzer for Moq1203 (MethodSetupShouldSpecifyReturnValueAnalyzer) previously produced false positives for delegate-based ReturnsAsync overloads. This has been resolved by querying the InvocationExpressionSyntax for more accurate symbol information and implementing a name-based fallback for cases where Roslyn's IsInstanceOf cannot match constructed generic methods.
  • Moq1206 False Negative Resolution: The analyzer for Moq1206 (ReturnsAsyncShouldBeUsedForAsyncMethodsAnalyzer) failed to detect Returns calls with async lambdas that should have been ReturnsAsync. The fix involves querying the InvocationExpressionSyntax instead of just the MemberAccessExpressionSyntax and utilizing CandidateSymbols to correctly identify these delegate-typed async lambdas.
  • Improved Test Coverage: New test cases have been added for both Moq1203 (8 cases) and Moq1206 (4 cases) to specifically cover delegate-overload scenarios, ensuring the fixes are robust and prevent regressions.
Changelog
  • src/Analyzers/MethodSetupShouldSpecifyReturnValueAnalyzer.cs
    • Updated HasReturnValueSpecification to retrieve SymbolInfo from InvocationExpressionSyntax and added a name-based fallback using IsKnownReturnValueMethodName.
    • Added a new private static method IsKnownReturnValueMethodName to check if a method name corresponds to a known Moq return value specification method.
  • src/Analyzers/ReturnsAsyncShouldBeUsedForAsyncMethodsAnalyzer.cs
    • Modified IsReturnsMethodCallWithAsyncLambda to query SymbolInfo on the InvocationExpressionSyntax and to consider CandidateSymbols for delegate overloads.
  • tests/Moq.Analyzers.Test/MethodSetupShouldSpecifyReturnValueAnalyzerTests.cs
    • Added new test cases to CustomReturnTypeTestData for delegate-based ReturnsAsync calls that are now correctly recognized.
    • Removed previously marked false positive test cases from CustomReturnTypeMissingReturnValueTestData.
  • tests/Moq.Analyzers.Test/ReturnsAsyncShouldBeUsedForAsyncMethodsAnalyzerTests.cs
    • Introduced DelegateOverloadTestData to provide test cases for async delegate lambdas used with Returns.
    • Added a new test method ShouldFlagAsyncDelegateLambdaInReturns to verify the correct flagging of these scenarios.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@deepsource-io
Copy link
Copy Markdown

deepsource-io bot commented Feb 21, 2026

DeepSource Code Review

DeepSource reviewed changes in the commit range c8adddb...0b38a62 on this pull request. Below is the summary for the review, and you can see the individual issues we found as review comments.

For detailed review results, please see the PR on DeepSource ↗

PR Report Card

Security × 0 issues Overall PR Quality   

Focus Area: Hygiene

Guidance
Fix the high-severity naming convention issue for a `Task` return type in tests/Moq.Analyzers.Test.
Reliability × 0 issues
Complexity × 0 issues
Hygiene × 1 issue

Code Review Summary

Analyzer Status Summary Details
C# 1 new issue detected. Review ↗
How are these analyzer statuses calculated?

Administrators can configure which issue categories are reported and cause analysis to be marked as failed when detected. This helps prevent bad and insecure code from being introduced in the codebase. If you're an administrator, you can modify this in the repository's settings.

@coderabbitai coderabbitai bot requested a review from MattKotsenas February 21, 2026 02:11
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively resolves two issues with delegate overload resolution in Moq analyzers. For Moq1203, it correctly gets symbol information from the invocation expression to provide argument context to Roslyn and adds a name-based fallback. For Moq1206, it also queries the invocation and adds a fallback to candidate symbols. The changes are logical, well-commented, and supported by new tests that confirm the fixes for both the false positive and false negative cases. I have one minor suggestion to improve code conciseness.

@codacy-production
Copy link
Copy Markdown

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
-0.15% (target: -1.00%) 75.00% (target: 95.00%)
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (894313b) 2056 1831 89.06%
Head commit (0b38a62) 2073 (+17) 1843 (+12) 88.90% (-0.15%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#919) 24 18 75.00%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

@coderabbitai coderabbitai bot added analyzers Change that impacts an analyzer behavior bug releasable labels Feb 21, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Analyzers/MethodSetupShouldSpecifyReturnValueAnalyzer.cs`:
- Around line 167-180: Update the repository documentation to reflect the
analyzer behavior change introduced around return-value detection: document that
the analyzer now checks both HasReturnValueSymbol(symbolInfo, knownSymbols) and
falls back to
IsKnownReturnValueMethodName(memberAccess.Name.Identifier.ValueText,
knownSymbols) when resolving symbols via semanticModel for
invocation/memberAccess expressions, and add a note in docs/rules/ and README.md
describing the name-based fallback rationale and examples (mention invocation,
memberAccess, semanticModel, HasReturnValueSymbol and
IsKnownReturnValueMethodName) so readers understand the exact matching order and
when the fallback is used.

In
`@tests/Moq.Analyzers.Test/MethodSetupShouldSpecifyReturnValueAnalyzerTests.cs`:
- Around line 367-376: The two delegate-based ReturnsAsync "no diagnostics" test
cases that use ReturnsAsync((MyValue val) => val) (the entries with "var
databaseMock = new Mock<IDatabase>(MockBehavior.Strict)...ReturnsAsync((MyValue
val) => val);" and "new Mock<IDatabase>().Setup(...).ReturnsAsync((MyValue val)
=> val);") should be executed via AllAnalyzersVerifier.VerifyAllAnalyzersAsync()
instead of the analyzer-specific verifier; update the test that currently
asserts no diagnostics for these cases to call
AllAnalyzersVerifier.VerifyAllAnalyzersAsync(...) with the combined test input
(including the "public record MyValue;" and "Task<MyValue> SaveAsync(MyValue
value);" snippets) so they run through all analyzers per the test guidelines.

@rjmurillo rjmurillo merged commit 0bef80b into main Feb 21, 2026
36 of 38 checks passed
@rjmurillo rjmurillo deleted the fix/delegate-overload-resolution branch February 21, 2026 03:31
rjmurillo added a commit that referenced this pull request Feb 21, 2026
## Summary

- **Moq1203 false positive (#910):** `GetSymbolInfo` on
`MemberAccessExpressionSyntax` lacks argument context, so Roslyn cannot
resolve delegate-based overloads like `.ReturnsAsync((MyValue val) =>
val)`. Now queries the parent `InvocationExpressionSyntax` and adds a
name-based fallback for cases where `IsInstanceOf` cannot match
constructed generic methods.
- **Moq1206 false negative (#911):**
`IsReturnsMethodCallWithAsyncLambda` queried `GetSymbolInfo` on the
member access instead of the invocation, and had no `CandidateSymbols`
fallback. Now queries the invocation and falls back to candidate
symbols, so delegate-typed async lambdas like `Returns(async (string x)
=> x)` are detected.

Closes #910
Closes #911

## Test plan

- [x] `dotnet build` passes with zero errors and zero warnings
- [x] All 288 Moq1203 tests pass (including 8 new delegate-overload
cases)
- [x] All 92 Moq1206 tests pass (including 4 new delegate-overload
cases)
- [x] Full suite of 2,497 tests passes with no regressions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Bug Fixes**
* Moq analyzers now correctly identify return value specifications in
complex method setup chains, with improved handling of chained method
invocations and fallback matching.
* Fixed detection of async delegate lambdas within Returns calls for
more accurate recognition of valid Moq method calls.

* **Tests**
* Added test coverage for delegate-based ReturnsAsync scenarios in
complex setups.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

analyzers Change that impacts an analyzer behavior bug releasable

Projects

None yet

1 participant