Skip to content

docs: investigate and document IsMoqRaisesMethod fallback removal blockers#768

Merged
rjmurillo merged 2 commits intomainfrom
copilot/remove-string-fallback-in-ismoqraisesmethod
Oct 17, 2025
Merged

docs: investigate and document IsMoqRaisesMethod fallback removal blockers#768
rjmurillo merged 2 commits intomainfrom
copilot/remove-string-fallback-in-ismoqraisesmethod

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Oct 11, 2025

Problem

Issue #634 requested removal of the string-based fallback method IsLikelyMoqRaisesMethodByName from IsMoqRaisesMethod, as it was originally added as a temporary safety net in PR #633. The TODO comment indicated this should be removed once symbol-based detection is comprehensive.

Investigation

I attempted to remove the fallback by relying solely on symbol-based detection through IsKnownMoqRaisesMethod. However, this revealed that the symbol-based detection is not yet comprehensive enough to safely remove the fallback.

Test Results

Removing the fallback causes 20 test failures in RaisesEventArgumentsShouldMatchEventSignatureAnalyzerTests across both:

  • Moq 4.8.2 (older version)
  • Moq 4.18.4 (current version)

The failing tests involve detecting Raises calls in chains like:

mockProvider.Setup(x => x.Submit()).Raises(x => x.StringEvent += null, 42)

Attempted Fixes

I attempted to resolve the issue by adding missing Moq interface symbols to MoqKnownSymbols:

  1. Added ISetupGetter<TMock, TProperty> - Interface for property getter setups that have Raises methods
  2. Added ISetupSetter<TMock, TProperty> - Interface for property setter setups that have Raises methods

However, even with these additions, the tests still fail, indicating the root cause is more complex.

Current Symbol Coverage

The symbol-based detection now checks 11 different Moq interface method symbols:

  • ICallback.Raises, ICallback<T>.Raises, ICallback<TMock, TResult>.Raises
  • IReturns.Raises, IReturns<T>.Raises, IReturns<TMock, TResult>.Raises
  • ISetupGetter<TMock, TProperty>.Raises, ISetupSetter<TMock, TProperty>.Raises
  • IRaiseable.Raises, IRaiseableAsync.RaisesAsync

Despite this comprehensive coverage, the symbol resolution for chained method calls like Setup().Raises() is not matching these interface definitions correctly.

Root Cause Analysis

The issue appears to be related to how Roslyn resolves method symbols for chained fluent API calls. When analyzing mock.Setup(...).Raises(...), the method symbol for Raises may not resolve to the specific interface definitions we're checking against via IsInstanceOf, possibly due to:

  1. Complex interface inheritance in Moq's fluent API
  2. Differences in how Moq 4.8.2 vs 4.18.4 structure their interfaces
  3. Symbol resolution limitations in specific code patterns

Changes Made

  1. Added new symbols to MoqKnownSymbols.cs: ISetupGetter and ISetupSetter (useful for future improvements even though they don't fully resolve the current issue)

  2. Enhanced TODO comment with comprehensive investigation documentation:

    • Which symbols are currently checked
    • Why the fallback is still needed
    • What has been attempted
    • Specific next steps for future investigation
  3. Kept the fallback in place to maintain test stability and prevent regressions

Recommended Next Steps

To safely remove the fallback, the following investigation is needed:

  1. Runtime debugging: Set up debugging to inspect actual symbol resolution during test execution to identify which specific Moq interface methods aren't being matched
  2. Version comparison: Deep-dive into Moq 4.8.2 vs 4.18.4 API differences to understand structural changes
  3. Alternative approaches: Consider whether IsInstanceOf is the right approach, or if alternative symbol matching strategies are needed

Testing

✅ All 1,874 tests pass
✅ Code formatted with dotnet format
✅ Build succeeds without warnings
✅ No regressions introduced

Related


Note: This PR documents the investigation findings and improves the codebase by adding useful symbols and comprehensive documentation. However, it does not remove the fallback as originally requested, because doing so would break 20 tests. The issue should remain open until the symbol-based detection can be made comprehensive enough to safely remove the fallback.

Original prompt

This section details on the original issue you should resolve

<issue_title>Remove string-based fallback in IsMoqRaisesMethod once symbol-based detection is comprehensive</issue_title>
<issue_description>## Description

A TODO comment in src/Common/ISymbolExtensions.cs indicates that a string-based fallback method should be removed once symbol-based detection for Moq Raises methods is complete.

Location

  • File: src/Common/ISymbolExtensions.cs
  • Method: IsMoqRaisesMethod
  • Line: ~224

Current Implementation

The method currently uses both:

  1. Primary symbol-based detection via IsKnownMoqRaisesMethod
  2. Fallback string-based detection via IsLikelyMoqRaisesMethodByName

Task

Remove the fallback method IsLikelyMoqRaisesMethodByName once the symbol-based detection is verified to handle all Moq Raises method scenarios comprehensively.

Context

This was flagged during security scanning as a TODO that may indicate incomplete functionality.

References

Requested by: @rjmurillo</issue_description>

<agent_instructions>User Impact & Necessity
Frequency & Real-World Usage:

The Moq Raises and RaisesAsync methods are documented as core event-handling features in Moq's quickstart guide
My research shows active test coverage with dedicated test suites (IsRaisesMethodTests.cs, RaiseEventArgumentsShouldMatchEventSignatureAnalyzerTests.cs, RaisesEventArgumentsShouldMatchEventSignatureAnalyzerTests.cs)
The method is used in 7 locations across the codebase for event-related analyzer detection
Issue #434 specifically tracks Moq quickstart coverage, confirming event patterns (including Raises) are priority features
Current Pain Points:

The string-based fallback (IsLikelyMoqRaisesMethodByName) was intentionally introduced as a "temporary safety net" in PR #633
GitHub Advanced Security flagged this as a TODO indicating "incomplete functionality"
The implementation contradicts established patterns: All other Moq method detection (Setup, Verify, Returns, Callback) use only symbol-based detection via MoqKnownSymbols
The fallback checks namespace.StartsWith("Moq") which could match unintended namespaces (false positives) and miss methods where symbol resolution temporarily fails
Evidence of Issue:

Cursor bot comment on PR #633 identified a namespace detection bug where the logic changed from checking Contains("Moq.Language") to StartsWith("Moq"), introducing both false positives and negatives
Issue #634 (also created from PR #633) specifically requests removal of string-based detection in favor of MoqKnownSymbols pattern
Issue #549 (closed) successfully removed similar string-based fallbacks for consistency
Implementation & Maintenance
Complexity:

Low complexity: The fix involves removing ~15 lines of fallback code (IsLikelyMoqRaisesMethodByName)
Symbol-based detection is already comprehensive: IsKnownMoqRaisesMethod checks 8 different Moq interface method symbols (ICallback, IReturns, IRaiseable variants)
Tests exist and pass with current implementation
Investigation Required:
The key question is: Does the fallback ever actually trigger?

From the code review:

The primary symbol-based path checks: ICallbackRaises, ICallback1Raises, ICallback2Raises, IReturnsRaises, IReturns1Raises, IReturns2Raises, IRaiseableRaises, IRaiseableAsyncRaisesAsync
These cover all documented Moq Raises patterns per the quickstart
If the fallback were needed, tests would fail when it's removed
Recommended Approach:

Remove the fallback method
Run full test suite (including IsRaisesMethodTests, all event-related analyzer tests)
If tests pass → fallback was unnecessary safety theatre
If tests fail → identify which scenarios the symbol-based detection misses and add those symbols to MoqKnownSymbols
Alignment with Project Goals
Strong Alignment:

Code quality: Removing technical debt and inconsistency
Maintainability: One less code path to maintain, reduced complexity
Type safety: Symbol-based detection is more robust than string matching
Performance: Eliminates string operations in hot path
Consistency: Aligns with patterns used in IsMoqSetupMethod, IsMoqReturnsMethod, IsMoqCallbackMethod, etc.
Project Priority:

This is directly related to Issue #434 (Moq quickstart coverage), which has 14/15 sub-issues completed and is marked with "triage" label
The removal supports the broader goal of ensuring all Moq patterns have proper symbol-based detection
The codebase shows active investment in event handling (multiple analyzers: Moq1202, Moq1204, Moq1205)
Trade-offs & Risks
Benefits:

✅ Eliminates false positive risk (matching non-Moq "Raises" methods in any namespace starting with "Moq")
✅ Eliminates false negative risk (missing Moq methods when namespace check fails)
✅ Reduces cognitive load (one clear detection path instead of two)
✅ Aligns with established codebase p...

Fixes #637


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Oct 11, 2025

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


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

…llback

Investigation shows that removing the string-based fallback causes 20 test failures,
indicating symbol-based detection is not yet comprehensive. Added ISetupGetter and
ISetupSetter symbols but tests still fail. The fallback is currently necessary and
requires further investigation to identify missing Moq interface symbols.

Co-authored-by: rjmurillo <6811113+rjmurillo@users.noreply.github.com>
Copilot AI changed the title [WIP] Remove string-based fallback in IsMoqRaisesMethod docs: investigate and document IsMoqRaisesMethod fallback removal blockers Oct 11, 2025
Copilot AI requested a review from rjmurillo October 11, 2025 14:43
Comment thread src/Common/ISymbolExtensions.cs Dismissed
@codacy-production
Copy link
Copy Markdown

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
+0.03% (target: -1.00%) 100.00% (target: 95.00%)
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (3b16ea4) 1999 1772 88.64%
Head commit (8b3909c) 2005 (+6) 1778 (+6) 88.68% (+0.03%)

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 (#768) 7 7 100.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

@rjmurillo rjmurillo marked this pull request as ready for review October 17, 2025 00:38
Copilot AI review requested due to automatic review settings October 17, 2025 00:38
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR documents and investigates why the string-based fallback method in IsMoqRaisesMethod cannot yet be safely removed, addressing issue #634. The investigation revealed that symbol-based detection is incomplete, causing 20 test failures when the fallback is removed.

  • Enhanced documentation with comprehensive investigation findings and root cause analysis
  • Added new Moq interface symbols (ISetupGetter and ISetupSetter) to improve symbol coverage
  • Kept the fallback method in place to maintain test stability

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/Common/WellKnown/MoqKnownSymbols.cs Added ISetupGetter and ISetupSetter interface symbols with their Raises methods
src/Common/ISymbolExtensions.cs Enhanced TODO comment with detailed investigation findings and added new symbol checks

Comment thread src/Common/ISymbolExtensions.cs
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Comment thread src/Common/ISymbolExtensions.cs
@rjmurillo rjmurillo requested a review from Copilot October 17, 2025 01:04
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@rjmurillo rjmurillo merged commit 5172cf3 into main Oct 17, 2025
35 checks passed
@rjmurillo rjmurillo deleted the copilot/remove-string-fallback-in-ismoqraisesmethod branch October 17, 2025 01:04
@rjmurillo rjmurillo added this to the vNext milestone Oct 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove string-based fallback in IsMoqRaisesMethod once symbol-based detection is comprehensive

4 participants