IDEA-386017 [java-inspections] Improvements after review

1. Better documentation
2. Flip arguments in case of strict inequality
3. Better tests


(cherry picked from commit 56c1dab39962fb457ca38a6ac44125b38ef11ea3)

IJ-CR-192581

GitOrigin-RevId: d9c31f14f62a2d6ea28aa00cf67985d9b2ccfb44
This commit is contained in:
Tagir Valeev
2026-02-23 11:36:40 +01:00
committed by intellij-monorepo-bot
parent 725067012d
commit d694fde33a
4 changed files with 45 additions and 24 deletions

View File

@@ -153,8 +153,11 @@ public final class ComparatorMinMaxCanBeUsedInspection extends BaseInspection {
if (!thenIsFirst && !thenIsSecond) return null;
String methodName = RelationType.GE.isSubRelation(relationType) == thenIsFirst ? "max" : "min";
// Need to flip arguments to preserve the semantics precisely if equality is not included into condition,
// as for equal `a` and `b`, `compare(a, b) > 0 ? a : b` returns `b` while `max(a, b)` return `a`.
boolean flip = !relationType.isSubRelation(RelationType.EQ);
return new MinMaxInfo(qualifier, args[0], args[1], methodName);
return new MinMaxInfo(qualifier, args[flip ? 1 : 0], args[flip ? 0 : 1], methodName);
}
private static class ComparatorMinMaxVisitor extends BaseInspectionVisitor {

View File

@@ -1,16 +1,20 @@
<html>
<body>
Reports ternary expressions using <code>Comparator.compare()</code> that can be replaced
with <code>Comparator.max()</code> or <code>Comparator.min()</code> methods available since Java 26.
Reports <code>if</code> statements and ternary expressions with <code>Comparator.compare()</code> calls
that can be replaced with <code>Comparator.max()</code> or <code>Comparator.min()</code> calls.
<p>Example:</p>
<p><b>Example:</b></p>
<pre><code>
Comparator&lt;String&gt; comp = Comparator.naturalOrder();
/*before*/ String result = comp.compare(a, b) > 0 ? a : b;
/*after*/ String result = comp.max(a, b);
String result = comp.compare(a, b) > 0 ? a : b;
</code></pre>
<p>After the quick-fix is applied:</p>
<pre><code>
Comparator&lt;String&gt; comp = Comparator.naturalOrder();
String result = comp.max(a, b);
</code></pre>
<!-- tooltip end -->
<p><small>New in 2026.2</small></p>
<p><small>New in 2026.1</small></p>
</body>
</html>

View File

@@ -4,13 +4,13 @@ import java.util.Comparator;
class ComparatorMinMaxCanBeUsed {
void testGreaterThan(Comparator<String> comp, String a, String b) {
String r1 = comp.max(a, b);
String r2 = comp.min(a, b);
String r1 = comp.max(b, a);
String r2 = comp.min(b, a);
}
void testLessThan(Comparator<String> comp, String a, String b) {
String r1 = comp.min(a, b);
String r2 = comp.max(a, b);
String r1 = comp.min(b, a);
String r2 = comp.max(b, a);
}
void testGreaterThanOrEqual(Comparator<String> comp, String a, String b) {
@@ -25,44 +25,44 @@ class ComparatorMinMaxCanBeUsed {
void testReversedComparison(Comparator<String> comp, String a, String b) {
// 0 < compare(a, b) is equivalent to compare(a, b) > 0
String r1 = comp.max(a, b);
String r1 = comp.max(b, a);
// 0 >= compare(a, b) is equivalent to compare(a, b) <= 0
String r2 = comp.max(a, b);
}
void testParenthesized(Comparator<String> comp, String a, String b) {
String r1 = comp.max(a, b);
String r2 = comp.min(a, b);
String r1 = comp.max(b, a);
String r2 = comp.min(b, a);
}
// If-statement patterns
String testIfReturnGreaterThan(Comparator<String> comp, String a, String b) {
return comp.max(a, b);
return comp.max(b, a);
}
String testIfReturnLessThan(Comparator<String> comp, String a, String b) {
return comp.min(a, b);
return comp.min(b, a);
}
String testIfReturnReversedBranches(Comparator<String> comp, String a, String b) {
return comp.min(a, b);
return comp.min(b, a);
}
String testIfReturnWithBlocks(Comparator<String> comp, String a, String b) {
return comp.max(a, b);
return comp.max(b, a);
}
String testIfImplicitReturn(Comparator<String> comp, String a, String b) {
return comp.max(a, b);
return comp.max(b, a);
}
void testIfAssignment(Comparator<String> comp, String a, String b) {
String r = comp.max(a, b);
String r = comp.max(b, a);
System.out.println(r);
}
void testIfOverwrittenDeclaration(Comparator<String> comp, String a, String b) {
String r = comp.max(a, b);
String r = comp.max(b, a);
System.out.println(r);
}
@@ -72,7 +72,7 @@ class ComparatorMinMaxCanBeUsed {
}
void testIfReversedComparison(Comparator<String> comp, String a, String b) {
String r = comp.max(a, b);
String r = comp.max(b, a);
System.out.println(r);
}
@@ -86,10 +86,15 @@ class ComparatorMinMaxCanBeUsed {
if (comp.compare(a, b) == 0) r = a; else r = b;
System.out.println(r);
}
void testWithPureCall(Comparator<String> comp, String a, String b) {
// Side effects in compare arguments
String r1 = comp.max(b.trim(), a.trim());
}
void testNoWarning(Comparator<String> comp, String a, String b) {
// Side effects in compare arguments
String r1 = comp.max(a.trim(), b.trim());
String r1 = comp.compare(process(a), process(b)) > 0 ? process(a) : process(b);
// Non-matching branches
String r2 = comp.compare(a, b) > 0 ? a : "default";
// Comparison to non-zero
@@ -102,4 +107,6 @@ class ComparatorMinMaxCanBeUsed {
// Branches swapped with unrelated expressions
String r6 = comp.compare(a, b) > 0 ? b : b;
}
native String process(String s);
}

View File

@@ -95,10 +95,15 @@ class ComparatorMinMaxCanBeUsed {
if (comp.compare(a, b) == 0) r = a; else r = b;
System.out.println(r);
}
void testWithPureCall(Comparator<String> comp, String a, String b) {
// Side effects in compare arguments
String r1 = <warning descr="Can be replaced with 'Comparator.max()'">comp.compare(a.trim(), b.trim()) > 0 ? a.trim() : b.trim()</warning>;
}
void testNoWarning(Comparator<String> comp, String a, String b) {
// Side effects in compare arguments
String r1 = <warning descr="Can be replaced with 'Comparator.max()'">comp.compare(a.trim(), b.trim()) > 0 ? a.trim() : b.trim()</warning>;
String r1 = comp.compare(process(a), process(b)) > 0 ? process(a) : process(b);
// Non-matching branches
String r2 = comp.compare(a, b) > 0 ? a : "default";
// Comparison to non-zero
@@ -111,4 +116,6 @@ class ComparatorMinMaxCanBeUsed {
// Branches swapped with unrelated expressions
String r6 = comp.compare(a, b) > 0 ? b : b;
}
native String process(String s);
}