1 //! lint on blocks unnecessarily using >= with a + 1 or - 1
3 use clippy_utils
::diagnostics
::span_lint_and_sugg
;
4 use clippy_utils
::source
::snippet_opt
;
5 use rustc_ast
::ast
::{BinOpKind, Expr, ExprKind, LitKind}
;
7 use rustc_errors
::Applicability
;
8 use rustc_lint
::{EarlyContext, EarlyLintPass}
;
9 use rustc_session
::{declare_lint_pass, declare_tool_lint}
;
11 declare_clippy_lint
! {
13 /// Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block
15 /// ### Why is this bad?
16 /// Readability -- better to use `> y` instead of `>= y + 1`.
31 #[clippy::version = "pre 1.29.0"]
34 "instead of using `x >= y + 1`, use `x > y`"
37 declare_lint_pass
!(IntPlusOne
=> [INT_PLUS_ONE
]);
48 #[derive(Copy, Clone)]
55 #[expect(clippy::cast_sign_loss)]
56 fn check_lit(token_lit
: token
::Lit
, target_value
: i128
) -> bool
{
57 if let Ok(LitKind
::Int(value
, ..)) = LitKind
::from_token_lit(token_lit
) {
58 return value
== (target_value
as u128
);
63 fn check_binop(cx
: &EarlyContext
<'_
>, binop
: BinOpKind
, lhs
: &Expr
, rhs
: &Expr
) -> Option
<String
> {
64 match (binop
, &lhs
.kind
, &rhs
.kind
) {
65 // case where `x - 1 >= ...` or `-1 + x >= ...`
66 (BinOpKind
::Ge
, ExprKind
::Binary(lhskind
, lhslhs
, lhsrhs
), _
) => {
67 match (lhskind
.node
, &lhslhs
.kind
, &lhsrhs
.kind
) {
69 (BinOpKind
::Add
, ExprKind
::Lit(lit
), _
) if Self::check_lit(*lit
, -1) => {
70 Self::generate_recommendation(cx
, binop
, lhsrhs
, rhs
, Side
::Lhs
)
73 (BinOpKind
::Sub
, _
, ExprKind
::Lit(lit
)) if Self::check_lit(*lit
, 1) => {
74 Self::generate_recommendation(cx
, binop
, lhslhs
, rhs
, Side
::Lhs
)
79 // case where `... >= y + 1` or `... >= 1 + y`
80 (BinOpKind
::Ge
, _
, ExprKind
::Binary(rhskind
, rhslhs
, rhsrhs
)) if rhskind
.node
== BinOpKind
::Add
=> {
81 match (&rhslhs
.kind
, &rhsrhs
.kind
) {
82 // `y + 1` and `1 + y`
83 (ExprKind
::Lit(lit
), _
) if Self::check_lit(*lit
, 1) => {
84 Self::generate_recommendation(cx
, binop
, rhsrhs
, lhs
, Side
::Rhs
)
86 (_
, ExprKind
::Lit(lit
)) if Self::check_lit(*lit
, 1) => {
87 Self::generate_recommendation(cx
, binop
, rhslhs
, lhs
, Side
::Rhs
)
92 // case where `x + 1 <= ...` or `1 + x <= ...`
93 (BinOpKind
::Le
, ExprKind
::Binary(lhskind
, lhslhs
, lhsrhs
), _
) if lhskind
.node
== BinOpKind
::Add
=> {
94 match (&lhslhs
.kind
, &lhsrhs
.kind
) {
95 // `1 + x` and `x + 1`
96 (ExprKind
::Lit(lit
), _
) if Self::check_lit(*lit
, 1) => {
97 Self::generate_recommendation(cx
, binop
, lhsrhs
, rhs
, Side
::Lhs
)
99 (_
, ExprKind
::Lit(lit
)) if Self::check_lit(*lit
, 1) => {
100 Self::generate_recommendation(cx
, binop
, lhslhs
, rhs
, Side
::Lhs
)
105 // case where `... >= y - 1` or `... >= -1 + y`
106 (BinOpKind
::Le
, _
, ExprKind
::Binary(rhskind
, rhslhs
, rhsrhs
)) => {
107 match (rhskind
.node
, &rhslhs
.kind
, &rhsrhs
.kind
) {
109 (BinOpKind
::Add
, ExprKind
::Lit(lit
), _
) if Self::check_lit(*lit
, -1) => {
110 Self::generate_recommendation(cx
, binop
, rhsrhs
, lhs
, Side
::Rhs
)
113 (BinOpKind
::Sub
, _
, ExprKind
::Lit(lit
)) if Self::check_lit(*lit
, 1) => {
114 Self::generate_recommendation(cx
, binop
, rhslhs
, lhs
, Side
::Rhs
)
123 fn generate_recommendation(
124 cx
: &EarlyContext
<'_
>,
129 ) -> Option
<String
> {
130 let binop_string
= match binop
{
131 BinOpKind
::Ge
=> ">",
132 BinOpKind
::Le
=> "<",
135 if let Some(snippet
) = snippet_opt(cx
, node
.span
) {
136 if let Some(other_side_snippet
) = snippet_opt(cx
, other_side
.span
) {
137 let rec
= match side
{
138 Side
::Lhs
=> Some(format
!("{snippet} {binop_string} {other_side_snippet}")),
139 Side
::Rhs
=> Some(format
!("{other_side_snippet} {binop_string} {snippet}")),
147 fn emit_warning(cx
: &EarlyContext
<'_
>, block
: &Expr
, recommendation
: String
) {
152 "unnecessary `>= y + 1` or `x - 1 >=`",
155 Applicability
::MachineApplicable
, // snippet
160 impl EarlyLintPass
for IntPlusOne
{
161 fn check_expr(&mut self, cx
: &EarlyContext
<'_
>, item
: &Expr
) {
162 if let ExprKind
::Binary(ref kind
, ref lhs
, ref rhs
) = item
.kind
{
163 if let Some(rec
) = Self::check_binop(cx
, kind
.node
, lhs
, rhs
) {
164 Self::emit_warning(cx
, item
, rec
);