Skip to content

MSTEST0032: detect Assert.AreEqual(x, x) / Assert.AreNotEqual(x, x) (and AreSame/AreNotSame) with identical operands #9087

@Evangelink

Description

@Evangelink

Summary

We have MSTEST0032 ReviewAlwaysTrueAssertConditionAnalyzer which already catches always-true assertions, and MSTEST0025 PreferAssertFailOverAlwaysFalseConditionsAnalyzer which catches always-false ones, but only when both operands are compile-time constants (e.g. Assert.AreEqual(1, 1)). Neither catches the very common bug pattern where the same expression is passed for both expected and actual:

Assert.AreEqual(x, x);          // always passes -- bug
Assert.AreSame(x, x);           // always passes -- bug
Assert.AreNotEqual(x, x);       // always fails  -- bug
Assert.AreNotSame(x, x);        // always fails  -- bug

This is a real production-quality issue: a case was just spotted in dotnet/sdk, and other Roslyn analyzers (CA1508, RCS1156, S2701) already flag it.

Proposal

Extend the two existing analyzers so that the structural-equivalence check is also applied to operand pairs:

  • MSTEST0032 (always true) -- report AreEqual(a, b) / AreSame(a, b) when a and b reference the same local, parameter, field, or property (with the same receiver chain).
  • MSTEST0025 (always false) -- report AreNotEqual(a, b) / AreNotSame(a, b) under the same condition.

Implementation hint: a small helper on IOperation that walks down conversions/parentheses and then recursively compares the two operations by reference-symbol equality (matching ILocalReferenceOperation, IParameterReferenceOperation, IFieldReferenceOperation, IPropertyReferenceOperation with their instances, and IInstanceReferenceOperation).

Out of scope

  • Side-effecting expressions (GetX() == GetX()) -- skip, since results could differ.
  • The existing diagnostic messages ("always true" / "always false") still fit; no new diagnostic IDs needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/analyzersMSTest.Analyzers Roslyn analyzers and code fixes.
    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions