No Tautological Math Comparison

ID

csharp.no_tautological_math_comparison

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

CSharp

Tags

arithmetic, reliability, suspicious-comparison

Description

Reports a relational comparison whose result is fixed because the constant it tests against lies outside the range the other operand can represent — a float against double.MaxValue, an int against long.MaxValue, a char against a literal beyond 65535.

Rationale

A comparison that cannot come out both ways is dead logic. The guard it forms never guards anything: the branch behind it is always taken or never taken, and the input validation it appears to perform does not happen. Because both sides read as sensible numeric code, nothing draws attention to it.

The usual origin is a narrowed type. A field that was a double becomes a float, a counter that was a long becomes an int, and the range check left behind keeps naming the old, wider type. The check then silently stops rejecting anything.

Only certainties are reported. The variable must resolve to a declared numeric type, and the constant must be a MaxValue / MinValue member of a strictly wider type, or an integer literal outside the variable range. Nullable declarations are skipped, because a null operand makes any relational comparison false and the outcome is then no longer fixed.

public bool InRange(float value)
{
    return value <= double.MaxValue;      // FLAW — always true; no float exceeds double.MaxValue
}

public bool TooLarge(int count)
{
    return count > long.MaxValue;         // FLAW — always false
}

public bool AboveAsciiRange(char c)
{
    return c < 100000;                    // FLAW — always true; a char stops at 65535
}

public bool InRangeOk(int count)
{
    return count < int.MaxValue;          // OK — int.MaxValue is a value count can reach
}

public bool NarrowerBoundOk(long count)
{
    return count < int.MaxValue;          // OK — a long can exceed int.MaxValue
}

public bool NullableOk(int? count)
{
    return count < long.MaxValue;         // OK — a null operand makes the result false
}

Remediation

Compare against the limit of the operand type rather than a wider one: a float against float.MaxValue, an int against int.MaxValue. If the intent was to check a value against a wider type before narrowing it, do the comparison on the wide value — before the cast or conversion, where the constant is meaningful — or use a checked conversion and handle the overflow. If the check turns out to be genuinely unnecessary, delete it instead of leaving a guard that never fires.