Skip to content

Fix MSTEST0049 false positives inside expression trees (#7585)#7592

Open
Evangelink wants to merge 1 commit intomainfrom
fix/mstest0049-expression-tree-false-positives
Open

Fix MSTEST0049 false positives inside expression trees (#7585)#7592
Evangelink wants to merge 1 commit intomainfrom
fix/mstest0049-expression-tree-false-positives

Conversation

@Evangelink
Copy link
Member

Skip reporting MSTEST0049 diagnostics when the invocation is inside an expression tree (e.g. Moq Setup lambdas), where the code fix cannot be meaningfully applied.

  • Add IsInsideExpressionTree helper that walks up the operation tree to detect lambdas converted to Expression
  • Add SystemLinqExpressionsLambdaExpression to WellKnownTypeNames
  • Add 3 tests covering expression tree suppression and regular lambda non-suppression

Fixes #7585

Copilot AI review requested due to automatic review settings March 23, 2026 16:35
@Evangelink Evangelink enabled auto-merge March 23, 2026 16:35
Copy link
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

Updates the MSTEST0049 analyzer to avoid reporting diagnostics for invocations that occur inside expression trees (e.g., Moq Setup lambdas), where applying the code fix would be inappropriate.

Changes:

  • Add expression-tree detection (IsInsideExpressionTree) to suppress MSTEST0049 diagnostics when the invocation is within an Expression<T> lambda.
  • Extend WellKnownTypeNames with System.Linq.Expressions.LambdaExpression for symbol lookup.
  • Add unit tests covering suppression inside expression trees and ensuring normal lambdas still produce diagnostics/fixes.

Reviewed changes

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

File Description
test/UnitTests/MSTest.Analyzers.UnitTests/FlowTestContextCancellationTokenAnalyzerTests.cs Adds new tests validating expression-tree suppression and non-expression lambda behavior.
src/Analyzers/MSTest.Analyzers/Helpers/WellKnownTypeNames.cs Adds a well-known type name constant for LambdaExpression.
src/Analyzers/MSTest.Analyzers/FlowTestContextCancellationTokenAnalyzer.cs Introduces expression-tree detection and skips MSTEST0049 reporting within expression trees.

Skip reporting MSTEST0049 diagnostics when the invocation is inside an
expression tree (e.g. Moq Setup lambdas), where the code fix cannot be
meaningfully applied.

- Add IsInsideExpressionTree helper that walks up the operation tree to
  detect lambdas converted to Expression<T>
- Add SystemLinqExpressionsLambdaExpression to WellKnownTypeNames
- Add 3 tests covering expression tree suppression and regular lambda
  non-suppression
@Evangelink Evangelink force-pushed the fix/mstest0049-expression-tree-false-positives branch from 3663f68 to 31a2317 Compare March 23, 2026 16:54
IOperation? current = operation.Parent;
while (current is not null)
{
if (current is IAnonymousFunctionOperation)
Copy link
Member

Choose a reason for hiding this comment

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

https://github.com/dotnet/sdk/blob/f25f3107b3554e141cbd09113cccf6c321f45143/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Utilities/Compiler/Extensions/IOperationExtensions.cs#L552-L565

Looks like the implementation in SDK (moved from roslyn-analyzers) walks up to either LocalFunction or AnonymousFunction?

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks 👍

if (current is IAnonymousFunctionOperation)
{
// Check if the parent converts this lambda to an Expression<T>.
if (current.Parent is IConversionOperation conversion &&
Copy link
Member

Choose a reason for hiding this comment

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

Implementation referenced in my earlier comment doesn't check IConversionOperation, it just accesses Type right away.

// Check if the parent converts this lambda to an Expression<T>.
if (current.Parent is IConversionOperation conversion &&
conversion.Type is INamedTypeSymbol namedType &&
namedType.Inherits(lambdaExpressionSymbol))
Copy link
Member

Choose a reason for hiding this comment

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

No personal preference for me. But implementation from sdk uses Expression<T> instead of LambdaExpression, and checks for exact type instead of inheritance. I think today, Expression<T> is the only known type that inherits LambdaExpression.

Comment on lines +166 to +174
if (current is IAnonymousFunctionOperation)
{
// Check if the parent converts this lambda to an Expression<T>.
if (current.Parent is IConversionOperation conversion &&
conversion.Type is INamedTypeSymbol namedType &&
namedType.Inherits(lambdaExpressionSymbol))
{
return true;
}
Copy link
Member

Choose a reason for hiding this comment

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

We should probably stop walking up once we find anonymous function.

Copy link
Member

@Youssef1313 Youssef1313 left a comment

Choose a reason for hiding this comment

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

Approving with few comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MSTEST0049 False positive with expressions of Moq

3 participants