diff --git a/CHANGELOG.md b/CHANGELOG.md index 71671273c57b..de681b488f39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4956,6 +4956,7 @@ Released 2018-09-13 [`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays [`large_stack_frames`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames [`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value +[`legacy_numeric_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#legacy_numeric_constants [`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty [`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero [`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index caaad6d11736..46311d68a882 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -151,6 +151,7 @@ The minimum rust version that the project supports * [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) * [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) * [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold) +* [`legacy_numeric_constants`](https://rust-lang.github.io/rust-clippy/master/index.html#legacy_numeric_constants) ## `cognitive-complexity-threshold` diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 84b99ad5c243..b41be81f3ff1 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -41,7 +41,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b }) }, BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right) - .unwrap_or(u64::max_value()) + .unwrap_or(u64::MAX) .min(apply_reductions(cx, nbits, left, signed)), BinOpKind::Shr => apply_reductions(cx, nbits, left, signed) .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 } else { None }; - apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value())) + apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::MAX)) }, ExprKind::MethodCall(method, _, [lo, hi], _) => { if method.ident.as_str() == "clamp" { diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index db114abfc869..e42255f25bef 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -234,6 +234,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::large_include_file::LARGE_INCLUDE_FILE_INFO, crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO, crate::large_stack_frames::LARGE_STACK_FRAMES_INFO, + crate::legacy_numeric_constants::LEGACY_NUMERIC_CONSTANTS_INFO, crate::len_zero::COMPARISON_TO_EMPTY_INFO, crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO, crate::len_zero::LEN_ZERO_INFO, diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs index ee7973b82ab9..6bd15118b42c 100644 --- a/clippy_lints/src/implicit_saturating_add.rs +++ b/clippy_lints/src/implicit_saturating_add.rs @@ -82,18 +82,18 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { fn get_int_max(ty: Ty<'_>) -> Option { match ty.peel_refs().kind() { - Int(IntTy::I8) => i8::max_value().try_into().ok(), - Int(IntTy::I16) => i16::max_value().try_into().ok(), - Int(IntTy::I32) => i32::max_value().try_into().ok(), - Int(IntTy::I64) => i64::max_value().try_into().ok(), - Int(IntTy::I128) => i128::max_value().try_into().ok(), - Int(IntTy::Isize) => isize::max_value().try_into().ok(), - Uint(UintTy::U8) => u8::max_value().try_into().ok(), - Uint(UintTy::U16) => u16::max_value().try_into().ok(), - Uint(UintTy::U32) => u32::max_value().try_into().ok(), - Uint(UintTy::U64) => u64::max_value().try_into().ok(), - Uint(UintTy::U128) => Some(u128::max_value()), - Uint(UintTy::Usize) => usize::max_value().try_into().ok(), + Int(IntTy::I8) => i8::MAX.try_into().ok(), + Int(IntTy::I16) => i16::MAX.try_into().ok(), + Int(IntTy::I32) => i32::MAX.try_into().ok(), + Int(IntTy::I64) => i64::MAX.try_into().ok(), + Int(IntTy::I128) => i128::MAX.try_into().ok(), + Int(IntTy::Isize) => isize::MAX.try_into().ok(), + Uint(UintTy::U8) => u8::MAX.try_into().ok(), + Uint(UintTy::U16) => u16::MAX.try_into().ok(), + Uint(UintTy::U32) => u32::MAX.try_into().ok(), + Uint(UintTy::U64) => u64::MAX.try_into().ok(), + Uint(UintTy::U128) => Some(u128::MAX), + Uint(UintTy::Usize) => usize::MAX.try_into().ok(), _ => None, } } diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs new file mode 100644 index 000000000000..baae31c82ffc --- /dev/null +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -0,0 +1,223 @@ +use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; +use clippy_utils::msrvs::{Msrv, NUMERIC_ASSOCIATED_CONSTANTS}; +use clippy_utils::source::snippet_opt; +use clippy_utils::{get_parent_expr, is_from_proc_macro, last_path_segment, std_or_core}; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::{Expr, ExprKind, Item, ItemKind, PrimTy, QPath, TyKind, UseKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::hir::nested_filter::OnlyBodies; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::symbol::kw; +use rustc_span::{sym, Symbol}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `::max_value()`, `std::::MAX`, + /// `std::::EPSILON`, etc. + /// + /// ### Why is this bad? + /// All of these have been superceded by the associated constants on their respective types, + /// such as `i128::MAX`. These legacy items may be deprecated in a future version of rust. + /// + /// ### Example + /// ```rust + /// let eps = std::f32::EPSILON; + /// ``` + /// Use instead: + /// ```rust + /// let eps = f32::EPSILON; + /// ``` + #[clippy::version = "1.72.0"] + pub LEGACY_NUMERIC_CONSTANTS, + style, + "checks for usage of legacy std numeric constants and methods" +} +pub struct LegacyNumericConstants { + msrv: Msrv, +} + +impl LegacyNumericConstants { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(LegacyNumericConstants => [LEGACY_NUMERIC_CONSTANTS]); + +impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + let Self { msrv } = self; + + if msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) + && !in_external_macro(cx.sess(), item.span) + && let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind + // These modules are "TBD" deprecated, and the contents are too, so lint on the `use` + // statement directly + && let def_path = cx.get_def_path(path.res[0].def_id()) + && is_path_in_numeric_module(&def_path, true) + { + let plurality = matches!( + kind, + UseKind::Glob | UseKind::Single if matches!(path.res[0], Res::Def(DefKind::Mod, _)), + ); + + span_lint_and_then( + cx, + LEGACY_NUMERIC_CONSTANTS, + path.span, + if plurality { + "importing legacy numeric constants" + } else { + "importing a legacy numeric constant" + }, + |diag| { + if item.ident.name != kw::Underscore { + let msg = if plurality && let [.., module_name] = &*def_path { + format!("use the associated constants on `{module_name}` instead at their usage") + } else if let [.., module_name, name] = &*def_path { + format!("use the associated constant `{module_name}::{name}` instead at its usage") + } else { + return; + }; + + diag.help(msg); + } + }, + ); + } + } + + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { + let Self { msrv } = self; + + cx.tcx.hir().visit_all_item_likes_in_crate(&mut V { cx, msrv }); + } + + extract_msrv_attr!(LateContext); +} + +struct V<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + msrv: &'a Msrv, +} + +impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { + type NestedFilter = OnlyBodies; + + fn nested_visit_map(&mut self) -> Self::Map { + self.cx.tcx.hir() + } + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + walk_expr(self, expr); + let Self { cx, msrv } = *self; + + if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), expr.span) { + return; + } + let ExprKind::Path(qpath) = expr.kind else { + return; + }; + + // `std::::` check + let (span, sugg, msg) = if let QPath::Resolved(None, path) = qpath + && let Some(def_id) = path.res.opt_def_id() + && let path = cx.get_def_path(def_id) + && is_path_in_numeric_module(&path, false) + && let [.., module_name, name] = &*path + && let Some(snippet) = snippet_opt(cx, expr.span) + && let is_float_module = (*module_name == sym::f32 || *module_name == sym::f64) + // Skip linting if this usage looks identical to the associated constant, since this + // would only require removing a `use` import. We don't ignore ones from `f32` or `f64`, however. + && let identical = snippet == format!("{module_name}::{name}") + && (!identical || is_float_module) + { + ( + expr.span, + if identical { + None + } else { + Some(format!("{module_name}::{name}")) + }, + "usage of a legacy numeric constant", + ) + // `::xxx_value` check + } else if let QPath::TypeRelative(ty, _) = qpath + && let TyKind::Path(ty_qpath) = ty.kind + && let Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_)) = cx.qpath_res(&ty_qpath, ty.hir_id) + && let last_segment = last_path_segment(&qpath) + && let name = last_segment.ident.name.as_str() + && (name == "max_value" || name == "min_value") + // Also remove the `()` + && let Some(par_expr) = get_parent_expr(cx, expr) + && let ExprKind::Call(_, _) = par_expr.kind + { + ( + qpath.last_segment_span().with_hi(par_expr.span.hi()), + Some(name[..=2].to_ascii_uppercase()), + "usage of a legacy numeric method", + ) + } else { + return; + }; + + if !is_from_proc_macro(cx, expr) { + span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| { + if let Some(sugg) = sugg { + diag.span_suggestion( + span, + "use the associated constant instead", + sugg, + Applicability::MaybeIncorrect, + ); + } else if let Some(std_or_core) = std_or_core(cx) + && let QPath::Resolved(None, path) = qpath + { + diag.help(format!( + "remove the import that brings `{std_or_core}::{}` into scope", + // Must be `::` if `needs_import_removed` is true yet is + // being linted + path.segments[0].ident.name, + )); + } + }); + } + } +} + +fn is_path_in_numeric_module(path: &[Symbol], ignore_float_modules: bool) -> bool { + if let [ + sym::core, + module @ (sym::u8 + | sym::i8 + | sym::u16 + | sym::i16 + | sym::u32 + | sym::i32 + | sym::u64 + | sym::i64 + | sym::u128 + | sym::i128 + | sym::usize + | sym::isize + | sym::f32 + | sym::f64), + .., + ] = path + && !path.get(2).is_some_and(|&s| s == sym!(consts)) + { + // If `ignore_float_modules` is `true`, return `None` for `_::f32` or `_::f64`, but not + // _::f64::MAX` or similar. + if ignore_float_modules && (*module == sym::f32 || *module == sym::f64) && path.get(2).is_none() { + return false; + } + + return true; + } + + false +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 358004cf460b..3b42dd973792 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -173,6 +173,7 @@ mod large_futures; mod large_include_file; mod large_stack_arrays; mod large_stack_frames; +mod legacy_numeric_constants; mod len_zero; mod let_if_seq; mod let_underscore; @@ -1079,6 +1080,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: needless_raw_string_hashes_allow_one, }) }); + store.register_late_pass(move |_| Box::new(legacy_numeric_constants::LegacyNumericConstants::new(msrv()))); store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns)); store.register_early_pass(|| Box::new(visibility::Visibility)); store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() })); diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 58ae0656db73..142b6392f802 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -294,7 +294,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, LEGACY_NUMERIC_CONSTANTS. /// /// The minimum rust version that the project supports (msrv: Option = None), diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 89f8a65c5ae0..fca4ddeedf10 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -24,7 +24,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::symbol::Ident; +use rustc_span::symbol::{kw, Ident}; use rustc_span::{Span, Symbol}; use rustc_target::spec::abi::Abi; @@ -103,9 +103,13 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) { let start = if ty.is_some() { Pat::Str("<") } else { - path.segments - .first() - .map_or(Pat::Str(""), |seg| Pat::Sym(seg.ident.name)) + path.segments.first().map_or(Pat::Str(""), |seg| { + if seg.ident.name == kw::PathRoot { + Pat::Str("::") + } else { + Pat::Sym(seg.ident.name) + } + }) }; let end = path.segments.last().map_or(Pat::Str(""), |seg| { if seg.args.is_some() { diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 3637476c4087..19c571a53182 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -33,7 +33,7 @@ msrv_aliases! { 1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN } 1,46,0 { CONST_IF_MATCH } 1,45,0 { STR_STRIP_PREFIX } - 1,43,0 { LOG2_10, LOG10_2 } + 1,43,0 { LOG2_10, LOG10_2, NUMERIC_ASSOCIATED_CONSTANTS } 1,42,0 { MATCHES_MACRO, SLICE_PATTERNS, PTR_SLICE_RAW_PARTS } 1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE } 1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF } diff --git a/tests/ui/checked_conversions.fixed b/tests/ui/checked_conversions.fixed index 188e6d975952..0d9c11f568a6 100644 --- a/tests/ui/checked_conversions.fixed +++ b/tests/ui/checked_conversions.fixed @@ -2,6 +2,7 @@ #![allow( clippy::cast_lossless, + clippy::legacy_numeric_constants, unused, // Int::max_value will be deprecated in the future deprecated, diff --git a/tests/ui/checked_conversions.rs b/tests/ui/checked_conversions.rs index 70f0f0975acd..7cd35f2c6936 100644 --- a/tests/ui/checked_conversions.rs +++ b/tests/ui/checked_conversions.rs @@ -2,6 +2,7 @@ #![allow( clippy::cast_lossless, + clippy::legacy_numeric_constants, unused, // Int::max_value will be deprecated in the future deprecated, diff --git a/tests/ui/checked_conversions.stderr b/tests/ui/checked_conversions.stderr index 273ead73bda5..b844891d30f6 100644 --- a/tests/ui/checked_conversions.stderr +++ b/tests/ui/checked_conversions.stderr @@ -1,5 +1,5 @@ error: checked cast can be simplified - --> $DIR/checked_conversions.rs:16:13 + --> $DIR/checked_conversions.rs:17:13 | LL | let _ = value <= (u32::max_value() as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` @@ -7,97 +7,97 @@ LL | let _ = value <= (u32::max_value() as i64) && value >= 0; = note: `-D clippy::checked-conversions` implied by `-D warnings` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:17:13 + --> $DIR/checked_conversions.rs:18:13 | LL | let _ = value <= (u32::MAX as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:21:13 + --> $DIR/checked_conversions.rs:22:13 | LL | let _ = value <= i64::from(u16::max_value()) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:22:13 + --> $DIR/checked_conversions.rs:23:13 | LL | let _ = value <= i64::from(u16::MAX) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:26:13 + --> $DIR/checked_conversions.rs:27:13 | LL | let _ = value <= (u8::max_value() as isize) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:27:13 + --> $DIR/checked_conversions.rs:28:13 | LL | let _ = value <= (u8::MAX as isize) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:33:13 + --> $DIR/checked_conversions.rs:34:13 | LL | let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:34:13 + --> $DIR/checked_conversions.rs:35:13 | LL | let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:38:13 + --> $DIR/checked_conversions.rs:39:13 | LL | let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:39:13 + --> $DIR/checked_conversions.rs:40:13 | LL | let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:45:13 + --> $DIR/checked_conversions.rs:46:13 | LL | let _ = value <= i32::max_value() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:46:13 + --> $DIR/checked_conversions.rs:47:13 | LL | let _ = value <= i32::MAX as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:50:13 + --> $DIR/checked_conversions.rs:51:13 | LL | let _ = value <= isize::max_value() as usize && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:51:13 + --> $DIR/checked_conversions.rs:52:13 | LL | let _ = value <= isize::MAX as usize && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:55:13 + --> $DIR/checked_conversions.rs:56:13 | LL | let _ = value <= u16::max_value() as u32 && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:56:13 + --> $DIR/checked_conversions.rs:57:13 | LL | let _ = value <= u16::MAX as u32 && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> $DIR/checked_conversions.rs:89:13 + --> $DIR/checked_conversions.rs:90:13 | LL | let _ = value <= (u32::MAX as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` diff --git a/tests/ui/legacy_numeric_constants.fixed b/tests/ui/legacy_numeric_constants.fixed new file mode 100644 index 000000000000..46027682a07b --- /dev/null +++ b/tests/ui/legacy_numeric_constants.fixed @@ -0,0 +1,55 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![allow(clippy::no_effect, deprecated, unused)] +#![warn(clippy::legacy_numeric_constants)] +#![feature(lint_reasons)] + +#[macro_use] +extern crate proc_macros; + +use std::u128 as _; +pub mod a { + #![expect(clippy::legacy_numeric_constants)] + pub use std::u128; +} + +fn main() { + f32::EPSILON; + u8::MIN; + usize::MIN; + u32::MAX; + u32::MAX; + #![expect(clippy::legacy_numeric_constants)] + use std::u32::MAX; + u32::MAX; + u32::MAX; + u8::MAX; + u8::MIN; + ::std::primitive::u8::MIN; + ::std::u8::MIN; + ::std::primitive::u8::MIN; + std::primitive::u32::MAX; + u128::MAX; + // Don't lint + use std::f64; + f32::EPSILON; + u8::MIN; + std::f32::consts::E; + f64::consts::E; + external! { + ::std::primitive::u8::MIN; + ::std::u8::MIN; + ::std::primitive::u8::min_value(); + } +} + +#[clippy::msrv = "1.42.0"] +fn msrv_too_low() { + // FIXME: Why does this lint?? + u32::MAX; +} + +#[clippy::msrv = "1.43.0"] +fn msrv_juust_right() { + u32::MAX; +} diff --git a/tests/ui/legacy_numeric_constants.rs b/tests/ui/legacy_numeric_constants.rs new file mode 100644 index 000000000000..432455e4722e --- /dev/null +++ b/tests/ui/legacy_numeric_constants.rs @@ -0,0 +1,109 @@ +//@aux-build:proc_macros.rs:proc-macro +#![allow(clippy::no_effect, deprecated, unused)] +#![warn(clippy::legacy_numeric_constants)] +#![feature(lint_reasons)] + +#[macro_use] +extern crate proc_macros; + +use std::u128 as _; +//~^ ERROR: importing legacy numeric constants +pub mod a { + pub use std::u128; + //~^ ERROR: importing legacy numeric constants + //~| HELP: use the associated constants on `u128` instead at their usage +} + +macro_rules! b { + () => { + mod b { + use std::u32; + fn b() { + let x = std::u64::MAX; + } + } + }; +} + +fn main() { + std::f32::EPSILON; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + std::u8::MIN; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + std::usize::MIN; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + std::u32::MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + core::u32::MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + use std::u32::MAX; + //~^ ERROR: importing a legacy numeric constant + //~| HELP: use the associated constant `u32::MAX` instead at its usage + use std::u8::MIN; + //~^ ERROR: importing a legacy numeric constant + //~| HELP: use the associated constant `u8::MIN` instead at its usage + MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + u32::max_value(); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + u8::max_value(); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + u8::min_value(); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + ::std::u8::MIN; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + ::std::primitive::u8::min_value(); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + std::primitive::u32::max_value(); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + f64::MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: remove the import that brings `std::f64` into scope + self::a::u128::MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + use std::u32; + //~^ ERROR: importing legacy numeric constants + //~| HELP: use the associated constants on `u32` instead at their usage + u32::MAX; + use std::f64; + u128::MAX; + f32::EPSILON; + f64::EPSILON; + ::std::primitive::u8::MIN; + std::f32::consts::E; + f64::consts::E; + u8::MIN; + std::f32::consts::E; + f64::consts::E; + b!(); + //~^ ERROR: importing legacy numeric constants + //~| HELP: use the associated constants on `u32` instead at their usage + external! { + ::std::primitive::u8::MIN; + ::std::u8::MIN; + ::std::primitive::u8::min_value(); + } +} + +#[clippy::msrv = "1.42.0"] +fn msrv_too_low() { + std::u32::MAX; +} + +#[clippy::msrv = "1.43.0"] +fn msrv_juust_right() { + std::u32::MAX; +} diff --git a/tests/ui/legacy_numeric_constants.stderr b/tests/ui/legacy_numeric_constants.stderr new file mode 100644 index 000000000000..daf29adb30f2 --- /dev/null +++ b/tests/ui/legacy_numeric_constants.stderr @@ -0,0 +1,171 @@ +error: importing legacy numeric constants + --> $DIR/legacy_numeric_constants.rs:9:5 + | +LL | use std::u128 as _; + | ^^^^^^^^^ + | + = note: `-D clippy::legacy-numeric-constants` implied by `-D warnings` + +error: importing legacy numeric constants + --> $DIR/legacy_numeric_constants.rs:12:13 + | +LL | pub use std::u128; + | ^^^^^^^^^ + | + = help: use the associated constants on `u128` instead at their usage + +error: importing a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:44:9 + | +LL | use std::u32::MAX; + | ^^^^^^^^^^^^^ + | + = help: use the associated constant `u32::MAX` instead at its usage + +error: importing a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:47:9 + | +LL | use std::u8::MIN; + | ^^^^^^^^^^^^ + | + = help: use the associated constant `u8::MIN` instead at its usage + +error: importing legacy numeric constants + --> $DIR/legacy_numeric_constants.rs:77:9 + | +LL | use std::u32; + | ^^^^^^^^ + | + = help: use the associated constants on `u32` instead at their usage + +error: importing legacy numeric constants + --> $DIR/legacy_numeric_constants.rs:20:17 + | +LL | use std::u32; + | ^^^^^^^^ +... +LL | b!(); + | ---- in this macro invocation + | + = help: use the associated constants on `u32` instead at their usage + = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:29:5 + | +LL | std::f32::EPSILON; + | ^^^^^^^^^^^^^^^^^ help: use the associated constant instead: `f32::EPSILON` + +error: usage of a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:32:5 + | +LL | std::u8::MIN; + | ^^^^^^^^^^^^ help: use the associated constant instead: `u8::MIN` + +error: usage of a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:35:5 + | +LL | std::usize::MIN; + | ^^^^^^^^^^^^^^^ help: use the associated constant instead: `usize::MIN` + +error: usage of a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:38:5 + | +LL | std::u32::MAX; + | ^^^^^^^^^^^^^ help: use the associated constant instead: `u32::MAX` + +error: usage of a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:41:5 + | +LL | core::u32::MAX; + | ^^^^^^^^^^^^^^ help: use the associated constant instead: `u32::MAX` + +error: usage of a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:50:5 + | +LL | MAX; + | ^^^ help: use the associated constant instead: `u32::MAX` + +error: usage of a legacy numeric method + --> $DIR/legacy_numeric_constants.rs:53:10 + | +LL | u32::max_value(); + | ^^^^^^^^^^^ help: use the associated constant instead: `MAX` + +error: usage of a legacy numeric method + --> $DIR/legacy_numeric_constants.rs:56:9 + | +LL | u8::max_value(); + | ^^^^^^^^^^^ help: use the associated constant instead: `MAX` + +error: usage of a legacy numeric method + --> $DIR/legacy_numeric_constants.rs:59:9 + | +LL | u8::min_value(); + | ^^^^^^^^^^^ help: use the associated constant instead: `MIN` + +error: usage of a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:62:5 + | +LL | ::std::u8::MIN; + | ^^^^^^^^^^^^^^ help: use the associated constant instead: `u8::MIN` + +error: usage of a legacy numeric method + --> $DIR/legacy_numeric_constants.rs:65:27 + | +LL | ::std::primitive::u8::min_value(); + | ^^^^^^^^^^^ help: use the associated constant instead: `MIN` + +error: usage of a legacy numeric method + --> $DIR/legacy_numeric_constants.rs:68:26 + | +LL | std::primitive::u32::max_value(); + | ^^^^^^^^^^^ help: use the associated constant instead: `MAX` + +error: usage of a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:71:5 + | +LL | f64::MAX; + | ^^^^^^^^ + | + = help: remove the import that brings `std::f64` into scope + +error: usage of a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:74:5 + | +LL | self::a::u128::MAX; + | ^^^^^^^^^^^^^^^^^^ help: use the associated constant instead: `u128::MAX` + +error: usage of a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:84:5 + | +LL | f64::EPSILON; + | ^^^^^^^^^^^^ + | + = help: remove the import that brings `std::f64` into scope + +error: usage of a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:22:25 + | +LL | let x = std::u64::MAX; + | ^^^^^^^^^^^^^ help: use the associated constant instead: `u64::MAX` +... +LL | b!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:103:5 + | +LL | std::u32::MAX; + | ^^^^^^^^^^^^^ help: use the associated constant instead: `u32::MAX` + +error: usage of a legacy numeric constant + --> $DIR/legacy_numeric_constants.rs:108:5 + | +LL | std::u32::MAX; + | ^^^^^^^^^^^^^ help: use the associated constant instead: `u32::MAX` + +error: aborting due to 24 previous errors + diff --git a/tests/ui/manual_saturating_arithmetic.fixed b/tests/ui/manual_saturating_arithmetic.fixed index 7dd4521fa78e..6f34502d38ba 100644 --- a/tests/ui/manual_saturating_arithmetic.fixed +++ b/tests/ui/manual_saturating_arithmetic.fixed @@ -1,6 +1,6 @@ //@run-rustfix -#![allow(unused_imports)] +#![allow(clippy::legacy_numeric_constants, unused_imports)] use std::{i128, i32, u128, u32}; diff --git a/tests/ui/manual_saturating_arithmetic.rs b/tests/ui/manual_saturating_arithmetic.rs index 463ee0692899..55357e510c90 100644 --- a/tests/ui/manual_saturating_arithmetic.rs +++ b/tests/ui/manual_saturating_arithmetic.rs @@ -1,6 +1,6 @@ //@run-rustfix -#![allow(unused_imports)] +#![allow(clippy::legacy_numeric_constants, unused_imports)] use std::{i128, i32, u128, u32}; diff --git a/tests/ui/suspicious_arithmetic_impl.rs b/tests/ui/suspicious_arithmetic_impl.rs index ae253a0487cb..8f70e4ec6699 100644 --- a/tests/ui/suspicious_arithmetic_impl.rs +++ b/tests/ui/suspicious_arithmetic_impl.rs @@ -1,3 +1,4 @@ +#![allow(clippy::legacy_numeric_constants)] #![warn(clippy::suspicious_arithmetic_impl)] use std::ops::{ Add, AddAssign, BitAnd, BitOr, BitOrAssign, BitXor, Div, DivAssign, Mul, MulAssign, Rem, Shl, Shr, Sub, diff --git a/tests/ui/suspicious_arithmetic_impl.stderr b/tests/ui/suspicious_arithmetic_impl.stderr index ced1305874e5..2b069f1e2e75 100644 --- a/tests/ui/suspicious_arithmetic_impl.stderr +++ b/tests/ui/suspicious_arithmetic_impl.stderr @@ -1,5 +1,5 @@ error: suspicious use of `-` in `Add` impl - --> $DIR/suspicious_arithmetic_impl.rs:13:20 + --> $DIR/suspicious_arithmetic_impl.rs:14:20 | LL | Foo(self.0 - other.0) | ^ @@ -7,7 +7,7 @@ LL | Foo(self.0 - other.0) = note: `-D clippy::suspicious-arithmetic-impl` implied by `-D warnings` error: suspicious use of `-` in `AddAssign` impl - --> $DIR/suspicious_arithmetic_impl.rs:19:23 + --> $DIR/suspicious_arithmetic_impl.rs:20:23 | LL | *self = *self - other; | ^ @@ -15,43 +15,43 @@ LL | *self = *self - other; = note: `-D clippy::suspicious-op-assign-impl` implied by `-D warnings` error: suspicious use of `/` in `MulAssign` impl - --> $DIR/suspicious_arithmetic_impl.rs:32:16 + --> $DIR/suspicious_arithmetic_impl.rs:33:16 | LL | self.0 /= other.0; | ^^ error: suspicious use of `/` in `Rem` impl - --> $DIR/suspicious_arithmetic_impl.rs:70:20 + --> $DIR/suspicious_arithmetic_impl.rs:71:20 | LL | Foo(self.0 / other.0) | ^ error: suspicious use of `|` in `BitAnd` impl - --> $DIR/suspicious_arithmetic_impl.rs:78:20 + --> $DIR/suspicious_arithmetic_impl.rs:79:20 | LL | Foo(self.0 | other.0) | ^ error: suspicious use of `^` in `BitOr` impl - --> $DIR/suspicious_arithmetic_impl.rs:86:20 + --> $DIR/suspicious_arithmetic_impl.rs:87:20 | LL | Foo(self.0 ^ other.0) | ^ error: suspicious use of `&` in `BitXor` impl - --> $DIR/suspicious_arithmetic_impl.rs:94:20 + --> $DIR/suspicious_arithmetic_impl.rs:95:20 | LL | Foo(self.0 & other.0) | ^ error: suspicious use of `>>` in `Shl` impl - --> $DIR/suspicious_arithmetic_impl.rs:102:20 + --> $DIR/suspicious_arithmetic_impl.rs:103:20 | LL | Foo(self.0 >> other.0) | ^^ error: suspicious use of `<<` in `Shr` impl - --> $DIR/suspicious_arithmetic_impl.rs:110:20 + --> $DIR/suspicious_arithmetic_impl.rs:111:20 | LL | Foo(self.0 << other.0) | ^^