Skip to content

Commit d74200a

Browse files
refactor(invalid_upcast_comparisons): move to under operators, simplify (#15956)
The last two commits could arguably be split off into a separate PR -- let me know if that's desired. changelog: none
2 parents f144c6c + e71b46f commit d74200a

File tree

4 files changed

+82
-95
lines changed

4 files changed

+82
-95
lines changed

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
228228
crate::inline_fn_without_body::INLINE_FN_WITHOUT_BODY_INFO,
229229
crate::int_plus_one::INT_PLUS_ONE_INFO,
230230
crate::integer_division_remainder_used::INTEGER_DIVISION_REMAINDER_USED_INFO,
231-
crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO,
232231
crate::item_name_repetitions::ENUM_VARIANT_NAMES_INFO,
233232
crate::item_name_repetitions::MODULE_INCEPTION_INFO,
234233
crate::item_name_repetitions::MODULE_NAME_REPETITIONS_INFO,
@@ -591,6 +590,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
591590
crate::operators::IMPOSSIBLE_COMPARISONS_INFO,
592591
crate::operators::INEFFECTIVE_BIT_MASK_INFO,
593592
crate::operators::INTEGER_DIVISION_INFO,
593+
crate::operators::INVALID_UPCAST_COMPARISONS_INFO,
594594
crate::operators::MANUAL_DIV_CEIL_INFO,
595595
crate::operators::MANUAL_IS_MULTIPLE_OF_INFO,
596596
crate::operators::MANUAL_MIDPOINT_INFO,

clippy_lints/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ mod init_numbered_fields;
172172
mod inline_fn_without_body;
173173
mod int_plus_one;
174174
mod integer_division_remainder_used;
175-
mod invalid_upcast_comparisons;
176175
mod item_name_repetitions;
177176
mod items_after_statements;
178177
mod items_after_test_module;
@@ -541,7 +540,6 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
541540
store.register_late_pass(move |_| Box::new(derivable_impls::DerivableImpls::new(conf)));
542541
store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef));
543542
store.register_late_pass(|_| Box::new(empty_enums::EmptyEnums));
544-
store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
545543
store.register_late_pass(|_| Box::<regex::Regex>::default());
546544
store.register_late_pass(move |tcx| Box::new(ifs::CopyAndPaste::new(tcx, conf)));
547545
store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator));
Lines changed: 56 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use rustc_errors::Applicability;
2-
use rustc_hir::{Expr, ExprKind};
3-
use rustc_lint::{LateContext, LateLintPass};
2+
use rustc_hir::{BinOpKind, Expr, ExprKind};
3+
use rustc_lint::LateContext;
44
use rustc_middle::ty::layout::LayoutOf;
55
use rustc_middle::ty::{self, IntTy, UintTy};
6-
use rustc_session::declare_lint_pass;
76
use rustc_span::Span;
87

98
use clippy_utils::comparisons;
@@ -12,29 +11,26 @@ use clippy_utils::consts::{ConstEvalCtxt, FullInt};
1211
use clippy_utils::diagnostics::span_lint;
1312
use clippy_utils::source::snippet_with_context;
1413

15-
declare_clippy_lint! {
16-
/// ### What it does
17-
/// Checks for comparisons where the relation is always either
18-
/// true or false, but where one side has been upcast so that the comparison is
19-
/// necessary. Only integer types are checked.
20-
///
21-
/// ### Why is this bad?
22-
/// An expression like `let x : u8 = ...; (x as u32) > 300`
23-
/// will mistakenly imply that it is possible for `x` to be outside the range of
24-
/// `u8`.
25-
///
26-
/// ### Example
27-
/// ```no_run
28-
/// let x: u8 = 1;
29-
/// (x as u32) > 300;
30-
/// ```
31-
#[clippy::version = "pre 1.29.0"]
32-
pub INVALID_UPCAST_COMPARISONS,
33-
pedantic,
34-
"a comparison involving an upcast which is always true or false"
35-
}
14+
use super::INVALID_UPCAST_COMPARISONS;
15+
16+
pub(super) fn check<'tcx>(
17+
cx: &LateContext<'tcx>,
18+
cmp: BinOpKind,
19+
lhs: &'tcx Expr<'_>,
20+
rhs: &'tcx Expr<'_>,
21+
span: Span,
22+
) {
23+
let normalized = comparisons::normalize_comparison(cmp, lhs, rhs);
24+
let Some((rel, normalized_lhs, normalized_rhs)) = normalized else {
25+
return;
26+
};
3627

37-
declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
28+
let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs);
29+
let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs);
30+
31+
upcast_comparison_bounds_err(cx, span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false);
32+
upcast_comparison_bounds_err(cx, span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true);
33+
}
3834

3935
fn numeric_cast_precast_bounds(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(FullInt, FullInt)> {
4036
if let ExprKind::Cast(cast_exp, _) = expr.kind {
@@ -68,29 +64,6 @@ fn numeric_cast_precast_bounds(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<
6864
}
6965
}
7066

71-
fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
72-
if let ExprKind::Cast(cast_val, _) = expr.kind {
73-
let mut applicability = Applicability::MachineApplicable;
74-
let (cast_val_snip, _) = snippet_with_context(
75-
cx,
76-
cast_val.span,
77-
expr.span.ctxt(),
78-
"the expression",
79-
&mut applicability,
80-
);
81-
span_lint(
82-
cx,
83-
INVALID_UPCAST_COMPARISONS,
84-
span,
85-
format!(
86-
"because of the numeric bounds on `{}` prior to casting, this expression is always {}",
87-
cast_val_snip,
88-
if always { "true" } else { "false" },
89-
),
90-
);
91-
}
92-
}
93-
9467
fn upcast_comparison_bounds_err<'tcx>(
9568
cx: &LateContext<'tcx>,
9669
span: Span,
@@ -103,63 +76,54 @@ fn upcast_comparison_bounds_err<'tcx>(
10376
if let Some((lb, ub)) = lhs_bounds
10477
&& let Some(norm_rhs_val) = ConstEvalCtxt::new(cx).eval_full_int(rhs, span.ctxt())
10578
{
106-
if rel == Rel::Eq || rel == Rel::Ne {
107-
if norm_rhs_val < lb || norm_rhs_val > ub {
108-
err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
109-
}
110-
} else if match rel {
111-
Rel::Lt => {
112-
if invert {
113-
norm_rhs_val < lb
114-
} else {
115-
ub < norm_rhs_val
79+
match rel {
80+
Rel::Eq => {
81+
if norm_rhs_val < lb || ub < norm_rhs_val {
82+
err_upcast_comparison(cx, span, lhs, false);
11683
}
11784
},
118-
Rel::Le => {
119-
if invert {
120-
norm_rhs_val <= lb
121-
} else {
122-
ub <= norm_rhs_val
85+
Rel::Ne => {
86+
if norm_rhs_val < lb || ub < norm_rhs_val {
87+
err_upcast_comparison(cx, span, lhs, true);
12388
}
12489
},
125-
Rel::Eq | Rel::Ne => unreachable!(),
126-
} {
127-
err_upcast_comparison(cx, span, lhs, true);
128-
} else if match rel {
12990
Rel::Lt => {
130-
if invert {
131-
norm_rhs_val >= ub
132-
} else {
133-
lb >= norm_rhs_val
91+
if (invert && norm_rhs_val < lb) || (!invert && ub < norm_rhs_val) {
92+
err_upcast_comparison(cx, span, lhs, true);
93+
} else if (!invert && norm_rhs_val <= lb) || (invert && ub <= norm_rhs_val) {
94+
err_upcast_comparison(cx, span, lhs, false);
13495
}
13596
},
13697
Rel::Le => {
137-
if invert {
138-
norm_rhs_val > ub
139-
} else {
140-
lb > norm_rhs_val
98+
if (invert && norm_rhs_val <= lb) || (!invert && ub <= norm_rhs_val) {
99+
err_upcast_comparison(cx, span, lhs, true);
100+
} else if (!invert && norm_rhs_val < lb) || (invert && ub < norm_rhs_val) {
101+
err_upcast_comparison(cx, span, lhs, false);
141102
}
142103
},
143-
Rel::Eq | Rel::Ne => unreachable!(),
144-
} {
145-
err_upcast_comparison(cx, span, lhs, false);
146104
}
147105
}
148106
}
149107

150-
impl<'tcx> LateLintPass<'tcx> for InvalidUpcastComparisons {
151-
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
152-
if let ExprKind::Binary(ref cmp, lhs, rhs) = expr.kind {
153-
let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs);
154-
let Some((rel, normalized_lhs, normalized_rhs)) = normalized else {
155-
return;
156-
};
157-
158-
let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs);
159-
let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs);
160-
161-
upcast_comparison_bounds_err(cx, expr.span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false);
162-
upcast_comparison_bounds_err(cx, expr.span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true);
163-
}
108+
fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
109+
if let ExprKind::Cast(cast_val, _) = expr.kind {
110+
let mut applicability = Applicability::MachineApplicable;
111+
let (cast_val_snip, _) = snippet_with_context(
112+
cx,
113+
cast_val.span,
114+
expr.span.ctxt(),
115+
"the expression",
116+
&mut applicability,
117+
);
118+
span_lint(
119+
cx,
120+
INVALID_UPCAST_COMPARISONS,
121+
span,
122+
format!(
123+
"because of the numeric bounds on `{}` prior to casting, this expression is always {}",
124+
cast_val_snip,
125+
if always { "true" } else { "false" },
126+
),
127+
);
164128
}
165129
}

clippy_lints/src/operators/mod.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod float_cmp;
1111
mod float_equality_without_abs;
1212
mod identity_op;
1313
mod integer_division;
14+
mod invalid_upcast_comparisons;
1415
mod manual_div_ceil;
1516
mod manual_is_multiple_of;
1617
mod manual_midpoint;
@@ -888,6 +889,28 @@ declare_clippy_lint! {
888889
"manually reimplementing `div_ceil`"
889890
}
890891

892+
declare_clippy_lint! {
893+
/// ### What it does
894+
/// Checks for comparisons where the relation is always either
895+
/// true or false, but where one side has been upcast so that the comparison is
896+
/// necessary. Only integer types are checked.
897+
///
898+
/// ### Why is this bad?
899+
/// An expression like `let x : u8 = ...; (x as u32) > 300`
900+
/// will mistakenly imply that it is possible for `x` to be outside the range of
901+
/// `u8`.
902+
///
903+
/// ### Example
904+
/// ```no_run
905+
/// let x: u8 = 1;
906+
/// (x as u32) > 300;
907+
/// ```
908+
#[clippy::version = "pre 1.29.0"]
909+
pub INVALID_UPCAST_COMPARISONS,
910+
pedantic,
911+
"a comparison involving an upcast which is always true or false"
912+
}
913+
891914
pub struct Operators {
892915
arithmetic_context: numeric_arithmetic::Context,
893916
verbose_bit_mask_threshold: u64,
@@ -935,6 +958,7 @@ impl_lint_pass!(Operators => [
935958
MANUAL_MIDPOINT,
936959
MANUAL_IS_MULTIPLE_OF,
937960
MANUAL_DIV_CEIL,
961+
INVALID_UPCAST_COMPARISONS,
938962
]);
939963

940964
impl<'tcx> LateLintPass<'tcx> for Operators {
@@ -950,6 +974,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
950974
}
951975
erasing_op::check(cx, e, op.node, lhs, rhs);
952976
identity_op::check(cx, e, op.node, lhs, rhs);
977+
invalid_upcast_comparisons::check(cx, op.node, lhs, rhs, e.span);
953978
needless_bitwise_bool::check(cx, e, op.node, lhs, rhs);
954979
manual_midpoint::check(cx, e, op.node, lhs, rhs, self.msrv);
955980
manual_is_multiple_of::check(cx, e, op.node, lhs, rhs, self.msrv);

0 commit comments

Comments
 (0)