Skip to content

Commit 18ded67

Browse files
committed
new lint legacy_integral_constants
1 parent 62972ae commit 18ded67

16 files changed

+301
-43
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4887,6 +4887,7 @@ Released 2018-09-13
48874887
[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
48884888
[`large_stack_frames`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames
48894889
[`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value
4890+
[`legacy_integral_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#legacy_integral_constants
48904891
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
48914892
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
48924893
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return

clippy_lints/src/casts/cast_possible_truncation.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
4141
})
4242
},
4343
BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right)
44-
.unwrap_or(u64::max_value())
44+
.unwrap_or(u64::MAX)
4545
.min(apply_reductions(cx, nbits, left, signed)),
4646
BinOpKind::Shr => apply_reductions(cx, nbits, left, signed)
4747
.saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))),
@@ -56,7 +56,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
5656
} else {
5757
None
5858
};
59-
apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
59+
apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::MAX))
6060
},
6161
ExprKind::MethodCall(method, _, [lo, hi], _) => {
6262
if method.ident.as_str() == "clamp" {

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
230230
crate::large_include_file::LARGE_INCLUDE_FILE_INFO,
231231
crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO,
232232
crate::large_stack_frames::LARGE_STACK_FRAMES_INFO,
233+
crate::legacy_integral_constants::LEGACY_INTEGRAL_CONSTANTS_INFO,
233234
crate::len_zero::COMPARISON_TO_EMPTY_INFO,
234235
crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO,
235236
crate::len_zero::LEN_ZERO_INFO,

clippy_lints/src/implicit_saturating_add.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -82,18 +82,18 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
8282

8383
fn get_int_max(ty: Ty<'_>) -> Option<u128> {
8484
match ty.peel_refs().kind() {
85-
Int(IntTy::I8) => i8::max_value().try_into().ok(),
86-
Int(IntTy::I16) => i16::max_value().try_into().ok(),
87-
Int(IntTy::I32) => i32::max_value().try_into().ok(),
88-
Int(IntTy::I64) => i64::max_value().try_into().ok(),
89-
Int(IntTy::I128) => i128::max_value().try_into().ok(),
90-
Int(IntTy::Isize) => isize::max_value().try_into().ok(),
91-
Uint(UintTy::U8) => u8::max_value().try_into().ok(),
92-
Uint(UintTy::U16) => u16::max_value().try_into().ok(),
93-
Uint(UintTy::U32) => u32::max_value().try_into().ok(),
94-
Uint(UintTy::U64) => u64::max_value().try_into().ok(),
95-
Uint(UintTy::U128) => Some(u128::max_value()),
96-
Uint(UintTy::Usize) => usize::max_value().try_into().ok(),
85+
Int(IntTy::I8) => i8::MAX.try_into().ok(),
86+
Int(IntTy::I16) => i16::MAX.try_into().ok(),
87+
Int(IntTy::I32) => i32::MAX.try_into().ok(),
88+
Int(IntTy::I64) => i64::MAX.try_into().ok(),
89+
Int(IntTy::I128) => i128::MAX.try_into().ok(),
90+
Int(IntTy::Isize) => isize::MAX.try_into().ok(),
91+
Uint(UintTy::U8) => u8::MAX.try_into().ok(),
92+
Uint(UintTy::U16) => u16::MAX.try_into().ok(),
93+
Uint(UintTy::U32) => u32::MAX.try_into().ok(),
94+
Uint(UintTy::U64) => u64::MAX.try_into().ok(),
95+
Uint(UintTy::U128) => Some(u128::MAX),
96+
Uint(UintTy::Usize) => usize::MAX.try_into().ok(),
9797
_ => None,
9898
}
9999
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
use clippy_utils::{
2+
diagnostics::span_lint_and_then,
3+
get_parent_expr, is_from_proc_macro, last_path_segment,
4+
msrvs::{self, Msrv},
5+
std_or_core,
6+
};
7+
use rustc_errors::Applicability;
8+
use rustc_hir::{def::Res, def_id::DefId};
9+
use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TyKind};
10+
use rustc_lint::{LateContext, LateLintPass, LintContext};
11+
use rustc_middle::lint::in_external_macro;
12+
use rustc_session::{declare_tool_lint, impl_lint_pass};
13+
use rustc_span::{sym, Symbol};
14+
15+
declare_clippy_lint! {
16+
/// ### What it does
17+
/// Checks for usage of `<integer>::max_value()`, `std::<integer>::MAX`,
18+
/// `std::<float>::EPSILON`, etc.
19+
///
20+
/// ### Why is this bad?
21+
/// All of these have been superceded by the associated constants on their respective types,
22+
/// such as `i128::MAX`. These legacy constants may be deprecated in a future version of rust.
23+
///
24+
/// ### Example
25+
/// ```rust
26+
/// let eps = std::f32::EPSILON;
27+
/// ```
28+
/// Use instead:
29+
/// ```rust
30+
/// let eps = f32::EPSILON;
31+
/// ```
32+
#[clippy::version = "1.72.0"]
33+
pub LEGACY_INTEGRAL_CONSTANTS,
34+
style,
35+
"checks for usage of legacy std integral constants"
36+
}
37+
pub struct LegacyIntegralConstants {
38+
msrv: Msrv,
39+
}
40+
41+
impl LegacyIntegralConstants {
42+
#[must_use]
43+
pub fn new(msrv: Msrv) -> Self {
44+
Self { msrv }
45+
}
46+
}
47+
48+
impl_lint_pass!(LegacyIntegralConstants => [LEGACY_INTEGRAL_CONSTANTS]);
49+
50+
impl<'tcx> LateLintPass<'tcx> for LegacyIntegralConstants {
51+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
52+
if !self.msrv.meets(msrvs::STD_INTEGRAL_CONSTANTS) || in_external_macro(cx.sess(), expr.span) {
53+
return;
54+
}
55+
let ExprKind::Path(qpath) = expr.kind else {
56+
return;
57+
};
58+
59+
// `std::<integer>::<CONST>` check
60+
let (span, sugg, is_method, needs_reexported_primitive) = if let QPath::Resolved(_, path) = qpath
61+
&& let Some(def_id) = path.res.opt_def_id()
62+
&& let Some(name) = path.segments.iter().last().map(|segment| segment.ident.name)
63+
&& let Some(module_name) = is_path_in_integral_module(cx, def_id)
64+
{
65+
(
66+
expr.span,
67+
format!("{module_name}::{name}"),
68+
false,
69+
path.segments.get(0).is_some_and(|segment| segment.ident.name == module_name)
70+
)
71+
// `<integer>::xxx_value` check
72+
} else if let QPath::TypeRelative(ty, _) = qpath
73+
&& let TyKind::Path(ty_qpath) = ty.kind
74+
&& let Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_)) = cx.qpath_res(&ty_qpath, ty.hir_id)
75+
&& let last_segment = last_path_segment(&qpath)
76+
&& let name = last_segment.ident.name.as_str()
77+
&& (name == "max_value" || name == "min_value")
78+
// Also remove the `()`
79+
&& let Some(par_expr) = get_parent_expr(cx, expr)
80+
&& let ExprKind::Call(_, _) = par_expr.kind
81+
{
82+
(
83+
qpath.last_segment_span().with_hi(par_expr.span.hi()),
84+
name[..=2].to_ascii_uppercase(),
85+
true,
86+
false,
87+
)
88+
} else {
89+
return;
90+
};
91+
92+
if !is_from_proc_macro(cx, expr) {
93+
let msg = if is_method {
94+
"usage of a legacy integral constant method"
95+
} else {
96+
"usage of a legacy integral constant"
97+
};
98+
99+
span_lint_and_then(cx, LEGACY_INTEGRAL_CONSTANTS, span, msg, |diag| {
100+
// Add `std::primitive` if necessary
101+
let new_sugg = if needs_reexported_primitive
102+
&& let Some(std_or_core) = std_or_core(cx)
103+
{
104+
format!("{std_or_core}::primitive::{sugg}")
105+
} else {
106+
sugg.clone()
107+
};
108+
diag.span_suggestion(span, "try", new_sugg, Applicability::MachineApplicable);
109+
// If we added `std::primitive`, also suggest without it
110+
if needs_reexported_primitive && let Some((module_name, _)) = sugg.split_once("::") {
111+
diag.note(format!(
112+
"if you remove the `use` statement that introduces `{module_name}`, using the above is \
113+
unnecessary",
114+
));
115+
}
116+
});
117+
}
118+
}
119+
120+
extract_msrv_attr!(LateContext);
121+
}
122+
123+
fn is_path_in_integral_module(cx: &LateContext<'_>, def_id: DefId) -> Option<Symbol> {
124+
if let [
125+
sym::core,
126+
module @ (sym::u8
127+
| sym::i8
128+
| sym::u16
129+
| sym::i16
130+
| sym::u32
131+
| sym::i32
132+
| sym::u64
133+
| sym::i64
134+
| sym::u128
135+
| sym::i128
136+
| sym::usize
137+
| sym::isize
138+
| sym::f32
139+
| sym::f64),
140+
_,
141+
] = &*cx.get_def_path(def_id)
142+
{
143+
return Some(*module);
144+
}
145+
146+
None
147+
}

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ mod large_futures;
170170
mod large_include_file;
171171
mod large_stack_arrays;
172172
mod large_stack_frames;
173+
mod legacy_integral_constants;
173174
mod len_zero;
174175
mod let_if_seq;
175176
mod let_underscore;
@@ -1063,6 +1064,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10631064
def_id_to_usage: rustc_data_structures::fx::FxHashMap::default(),
10641065
})
10651066
});
1067+
store.register_late_pass(move |_| Box::new(legacy_integral_constants::LegacyIntegralConstants::new(msrv())));
10661068
// add lints here, do not remove this comment, it's used in `new_lint`
10671069
}
10681070

clippy_utils/src/msrvs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ msrv_aliases! {
3131
1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN }
3232
1,46,0 { CONST_IF_MATCH }
3333
1,45,0 { STR_STRIP_PREFIX }
34-
1,43,0 { LOG2_10, LOG10_2 }
34+
1,43,0 { LOG2_10, LOG10_2, STD_INTEGRAL_CONSTANTS }
3535
1,42,0 { MATCHES_MACRO, SLICE_PATTERNS, PTR_SLICE_RAW_PARTS }
3636
1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE }
3737
1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF }

tests/ui/checked_conversions.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#![allow(
44
clippy::cast_lossless,
5+
clippy::legacy_integral_constants,
56
unused,
67
// Int::max_value will be deprecated in the future
78
deprecated,

tests/ui/checked_conversions.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#![allow(
44
clippy::cast_lossless,
5+
clippy::legacy_integral_constants,
56
unused,
67
// Int::max_value will be deprecated in the future
78
deprecated,

tests/ui/checked_conversions.stderr

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,103 @@
11
error: checked cast can be simplified
2-
--> $DIR/checked_conversions.rs:16:13
2+
--> $DIR/checked_conversions.rs:17:13
33
|
44
LL | let _ = value <= (u32::max_value() as i64) && value >= 0;
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
66
|
77
= note: `-D clippy::checked-conversions` implied by `-D warnings`
88

99
error: checked cast can be simplified
10-
--> $DIR/checked_conversions.rs:17:13
10+
--> $DIR/checked_conversions.rs:18:13
1111
|
1212
LL | let _ = value <= (u32::MAX as i64) && value >= 0;
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
1414

1515
error: checked cast can be simplified
16-
--> $DIR/checked_conversions.rs:21:13
16+
--> $DIR/checked_conversions.rs:22:13
1717
|
1818
LL | let _ = value <= i64::from(u16::max_value()) && value >= 0;
1919
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
2020

2121
error: checked cast can be simplified
22-
--> $DIR/checked_conversions.rs:22:13
22+
--> $DIR/checked_conversions.rs:23:13
2323
|
2424
LL | let _ = value <= i64::from(u16::MAX) && value >= 0;
2525
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
2626

2727
error: checked cast can be simplified
28-
--> $DIR/checked_conversions.rs:26:13
28+
--> $DIR/checked_conversions.rs:27:13
2929
|
3030
LL | let _ = value <= (u8::max_value() as isize) && value >= 0;
3131
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
3232

3333
error: checked cast can be simplified
34-
--> $DIR/checked_conversions.rs:27:13
34+
--> $DIR/checked_conversions.rs:28:13
3535
|
3636
LL | let _ = value <= (u8::MAX as isize) && value >= 0;
3737
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
3838

3939
error: checked cast can be simplified
40-
--> $DIR/checked_conversions.rs:33:13
40+
--> $DIR/checked_conversions.rs:34:13
4141
|
4242
LL | let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64);
4343
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
4444

4545
error: checked cast can be simplified
46-
--> $DIR/checked_conversions.rs:34:13
46+
--> $DIR/checked_conversions.rs:35:13
4747
|
4848
LL | let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64);
4949
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
5050

5151
error: checked cast can be simplified
52-
--> $DIR/checked_conversions.rs:38:13
52+
--> $DIR/checked_conversions.rs:39:13
5353
|
5454
LL | let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value());
5555
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
5656

5757
error: checked cast can be simplified
58-
--> $DIR/checked_conversions.rs:39:13
58+
--> $DIR/checked_conversions.rs:40:13
5959
|
6060
LL | let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN);
6161
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
6262

6363
error: checked cast can be simplified
64-
--> $DIR/checked_conversions.rs:45:13
64+
--> $DIR/checked_conversions.rs:46:13
6565
|
6666
LL | let _ = value <= i32::max_value() as u32;
6767
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
6868

6969
error: checked cast can be simplified
70-
--> $DIR/checked_conversions.rs:46:13
70+
--> $DIR/checked_conversions.rs:47:13
7171
|
7272
LL | let _ = value <= i32::MAX as u32;
7373
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
7474

7575
error: checked cast can be simplified
76-
--> $DIR/checked_conversions.rs:50:13
76+
--> $DIR/checked_conversions.rs:51:13
7777
|
7878
LL | let _ = value <= isize::max_value() as usize && value as i32 == 5;
7979
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
8080

8181
error: checked cast can be simplified
82-
--> $DIR/checked_conversions.rs:51:13
82+
--> $DIR/checked_conversions.rs:52:13
8383
|
8484
LL | let _ = value <= isize::MAX as usize && value as i32 == 5;
8585
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
8686

8787
error: checked cast can be simplified
88-
--> $DIR/checked_conversions.rs:55:13
88+
--> $DIR/checked_conversions.rs:56:13
8989
|
9090
LL | let _ = value <= u16::max_value() as u32 && value as i32 == 5;
9191
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
9292

9393
error: checked cast can be simplified
94-
--> $DIR/checked_conversions.rs:56:13
94+
--> $DIR/checked_conversions.rs:57:13
9595
|
9696
LL | let _ = value <= u16::MAX as u32 && value as i32 == 5;
9797
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
9898

9999
error: checked cast can be simplified
100-
--> $DIR/checked_conversions.rs:89:13
100+
--> $DIR/checked_conversions.rs:90:13
101101
|
102102
LL | let _ = value <= (u32::MAX as i64) && value >= 0;
103103
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`

0 commit comments

Comments
 (0)