False negative java:S1862 — commutative operand reversal for !=, <, >, <=, >=

Hi team,

Testing sonar-java with semantics-preserving rewrites, we found that S1862 (“Related `if/else if` statements should not have the same condition”) misses
duplicate conditions when one branch writes the condition in an equivalent form.

This is partly known. SONARJAVA-4111 (thread:
https://community.sonarsource.com/t/java-a-false-negative-about-the-rule-rspec-1862/55025) added normalization for two shapes, `==` operand reversal (`a == b` vs
`b == a`) and redundant parentheses (`a` vs `(a)`), and both fire on the version
below. The same ticket raised a follow-up (Alban Auzeill: *“we could create a
ticket to support `!=` which is also commutative, or even `>`, `>=`, `<`, `<=`
that can be reverted.”*). That follow-up appears never to have been implemented:
operand reversal for `!=`, `>`, `>=`, `<`, `<=` is still a false negative, though it is the same class as the `==` case already handled.

**Product / version:** SonarQube Community Build 26.7.0.124771 (the current latest), sonar-scanner 8.1.0.6389, “Sonar way” profile.

Type: false negative.

Reproducer:

public class S1862Repro {

void foo(int a, int b) {

if (a > b) {

System.out.println(1);

    } else if (b < a) {   // Noncompliant: same condition as \`a > b\`, S1862 should report here

System.out.println(2);

    }

}

}

Expected: a warning on the `else if (b < a)` branch, as it now reports for the `==` reversal.

### Shapes tested on CB 26.7.0.124771

Each row is the same condition in both branches, differing only by an equivalent

rewrite. We are asking only about rows 3-5; the rest records the current

boundary.

| # | rewrite | SONARJAVA-4111 | S1862 today |

|—|---------|----------------|-------------|

| 1 | `a == b` ↔ `b == a` (`==` reversal) | fixed | fires |

| 2 | `a` ↔ `(a)` / `((a))` (redundant parens) | fixed | fires |

| 3 | `a != b` ↔ `b != a` (`!=` reversal) | deferred follow-up | **FN** |

| 4 | `a > b` ↔ `b < a` (`>`/`<` reversal) | deferred follow-up | **FN** |

| 5 | `a >= b` ↔ `b <= a` (`>=`/`<=` reversal) | deferred follow-up | **FN** |

| 6 | `a` ↔ `!(!a)` (double negation) | declined, “complex” | FN |

| 7 | `a != b` ↔ `!(a == b)` (negation into comparison) | declined, “complex” | FN |

Rows 6-7 are the “more complex cases” the ticket declined (“we will not extend the logic to support more complex cases”). We are not requesting them; they mark the boundary.

We also left out `a && b` ↔ `b && a`, since `&&`/`||` short-circuit and reversing the operands is not always behaviour-preserving. Happy to provide more reproducers if useful.

Hi @MarkLee131,

Thank you for taking the time to report this issue.

I confirmed the behavior on our side. java:S1862 already handles swapped operands for ==, but it does not currently do the same for != or for inverse relational pairs such as a > b / b < a and a >= b / b <= a.

This is a real false negative. I’ve created a ticket for it, you can track the fix here: SONARJAVA-6669.

Thank you again for your report.
Erwan