conditionally wrap LHS of int_plus_one error to avoid parser ambiguity

This commit is contained in:
zvkemp
2026-04-13 09:47:39 -04:00
parent ea2b4d224f
commit 69958674d5
4 changed files with 74 additions and 2 deletions
+9 -1
View File
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg;
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp};
use rustc_ast::util::parser::AssocOp;
use rustc_data_structures::packed::Pu128;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
@@ -134,12 +135,19 @@ fn emit_warning(cx: &EarlyContext<'_>, expr: &Expr, new_lhs: &Expr, le_or_ge: Le
|diag| {
let mut app = Applicability::MachineApplicable;
let ctxt = expr.span.ctxt();
let new_lhs = sugg::Sugg::ast(cx, new_lhs, "_", ctxt, &mut app);
let mut new_lhs = sugg::Sugg::ast(cx, new_lhs, "_", ctxt, &mut app);
let new_rhs = sugg::Sugg::ast(cx, new_rhs, "_", ctxt, &mut app);
let new_binop = match le_or_ge {
LeOrGe::Ge => BinOpKind::Gt,
LeOrGe::Le => BinOpKind::Lt,
};
// When the replacement operator is `<`, an `as` cast on the LHS
// must be parenthesized. Otherwise, the parser interprets the `<`
// as the start of generic arguments on the cast type
// (e.g., `x as usize < y` is parsed as `x as usize<y>`).
if matches!(new_lhs, sugg::Sugg::BinOp(AssocOp::Cast, ..)) && new_binop == BinOpKind::Lt {
new_lhs = new_lhs.maybe_paren();
}
let rec = sugg::make_binop(new_binop, &new_lhs, &new_rhs);
diag.span_suggestion(expr.span, "change it to", rec, app);
},
+14
View File
@@ -16,4 +16,18 @@ fn main() {
let _ = x > y; // should be ok
let _ = y < x; // should be ok
// When the suggestion replaces `<=`/`>=` with `<`, an `as` cast on
// the LHS must be parenthesized to avoid parser ambiguity
// (e.g., `x as usize < y` is parsed as `x as usize<y>`).
let z = 0usize;
let _ = (x as usize) < z; //~ int_plus_one
let _ = z > x as usize; //~ int_plus_one
// No parentheses needed when the replacement operator is `>`.
let _ = x as usize > z; //~ int_plus_one
let _ = z < x as usize; //~ int_plus_one
// Nested and parenthesized casts on the LHS.
let _ = ((x as usize) as u8) < 5u8; //~ int_plus_one
let _ = (x as usize) < z; //~ int_plus_one
}
+14
View File
@@ -16,4 +16,18 @@ fn main() {
let _ = x > y; // should be ok
let _ = y < x; // should be ok
// When the suggestion replaces `<=`/`>=` with `<`, an `as` cast on
// the LHS must be parenthesized to avoid parser ambiguity
// (e.g., `x as usize < y` is parsed as `x as usize<y>`).
let z = 0usize;
let _ = x as usize + 1 <= z; //~ int_plus_one
let _ = z >= x as usize + 1; //~ int_plus_one
// No parentheses needed when the replacement operator is `>`.
let _ = x as usize - 1 >= z; //~ int_plus_one
let _ = z <= x as usize - 1; //~ int_plus_one
// Nested and parenthesized casts on the LHS.
let _ = ((x as usize) as u8) + 1 <= 5u8; //~ int_plus_one
let _ = (x as usize) + 1 <= z; //~ int_plus_one
}
+37 -1
View File
@@ -49,5 +49,41 @@ error: unnecessary `>= y + 1` or `x - 1 >=`
LL | let _ = y <= -1 + x;
| ^^^^^^^^^^^ help: change it to: `y < x`
error: aborting due to 8 previous errors
error: unnecessary `>= y + 1` or `x - 1 >=`
--> tests/ui/int_plus_one.rs:24:13
|
LL | let _ = x as usize + 1 <= z;
| ^^^^^^^^^^^^^^^^^^^ help: change it to: `(x as usize) < z`
error: unnecessary `>= y + 1` or `x - 1 >=`
--> tests/ui/int_plus_one.rs:25:13
|
LL | let _ = z >= x as usize + 1;
| ^^^^^^^^^^^^^^^^^^^ help: change it to: `z > x as usize`
error: unnecessary `>= y + 1` or `x - 1 >=`
--> tests/ui/int_plus_one.rs:27:13
|
LL | let _ = x as usize - 1 >= z;
| ^^^^^^^^^^^^^^^^^^^ help: change it to: `x as usize > z`
error: unnecessary `>= y + 1` or `x - 1 >=`
--> tests/ui/int_plus_one.rs:28:13
|
LL | let _ = z <= x as usize - 1;
| ^^^^^^^^^^^^^^^^^^^ help: change it to: `z < x as usize`
error: unnecessary `>= y + 1` or `x - 1 >=`
--> tests/ui/int_plus_one.rs:31:13
|
LL | let _ = ((x as usize) as u8) + 1 <= 5u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: change it to: `((x as usize) as u8) < 5u8`
error: unnecessary `>= y + 1` or `x - 1 >=`
--> tests/ui/int_plus_one.rs:32:13
|
LL | let _ = (x as usize) + 1 <= z;
| ^^^^^^^^^^^^^^^^^^^^^ help: change it to: `(x as usize) < z`
error: aborting due to 14 previous errors