Skip to content

Commit da08b7f

Browse files
committed
new lint legacy_integral_constants
1 parent 62972ae commit da08b7f

17 files changed

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

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()`
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//@run-rustfix
2+
//@aux-build:proc_macros.rs
3+
#![allow(clippy::no_effect, deprecated, unused)]
4+
#![warn(clippy::legacy_integral_constants)]
5+
6+
#[macro_use]
7+
extern crate proc_macros;
8+
9+
fn main() {
10+
f32::EPSILON;
11+
u8::MIN;
12+
usize::MIN;
13+
u32::MAX;
14+
use std::u32::MAX;
15+
u32::MAX;
16+
u32::MAX;
17+
u8::MAX;
18+
u8::MIN;
19+
::std::primitive::u8::MIN;
20+
::std::u8::MIN;
21+
::std::primitive::u8::MIN;
22+
std::primitive::u32::MAX;
23+
// Don't lint
24+
f32::EPSILON;
25+
u8::MIN;
26+
external! {
27+
::std::primitive::u8::MIN;
28+
::std::u8::MIN;
29+
::std::primitive::u8::min_value();
30+
}
31+
}

0 commit comments

Comments
 (0)