fix legacy_numeric_constants suggestion when call is wrapped in parens (#15191)

Fixes rust-lang/rust-clippy#15008

changelog: [`legacy_numeric_constants`]: fix suggestion when call is
inside parentheses like `(i32::max_value())`
This commit is contained in:
Samuel Tardieu 2025-07-11 05:28:23 +00:00 committed by GitHub
commit 488f4dd04d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 172 additions and 38 deletions

View file

@ -1,7 +1,8 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_from_proc_macro;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::{get_parent_expr, is_from_proc_macro};
use clippy_utils::source::SpanRangeExt;
use hir::def_id::DefId;
use rustc_errors::Applicability;
use rustc_hir as hir;
@ -102,39 +103,45 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
}
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
let ExprKind::Path(qpath) = &expr.kind else {
return;
};
// `std::<integer>::<CONST>` check
let (span, sugg, msg) = if let QPath::Resolved(None, path) = qpath
let (sugg, msg) = if let ExprKind::Path(qpath) = &expr.kind
&& let QPath::Resolved(None, path) = qpath
&& let Some(def_id) = path.res.opt_def_id()
&& is_numeric_const(cx, def_id)
&& let def_path = cx.get_def_path(def_id)
&& let [.., mod_name, name] = &*def_path
&& let [.., mod_name, name] = &*cx.get_def_path(def_id)
// Skip linting if this usage looks identical to the associated constant,
// since this would only require removing a `use` import (which is already linted).
&& !is_numeric_const_path_canonical(path, [*mod_name, *name])
{
(
expr.span,
format!("{mod_name}::{name}"),
vec![(expr.span, format!("{mod_name}::{name}"))],
"usage of a legacy numeric constant",
)
// `<integer>::xxx_value` check
} else if let QPath::TypeRelative(_, last_segment) = qpath
&& let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id()
&& let Some(par_expr) = get_parent_expr(cx, expr)
&& let ExprKind::Call(_, []) = par_expr.kind
} else if let ExprKind::Call(func, []) = &expr.kind
&& let ExprKind::Path(qpath) = &func.kind
&& let QPath::TypeRelative(ty, last_segment) = qpath
&& let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id()
&& is_integer_method(cx, def_id)
{
let name = last_segment.ident.name.as_str();
(
last_segment.ident.span.with_hi(par_expr.span.hi()),
name[..=2].to_ascii_uppercase(),
"usage of a legacy numeric method",
)
let mut sugg = vec![
// Replace the function name up to the end by the constant name
(
last_segment.ident.span.to(expr.span.shrink_to_hi()),
last_segment.ident.name.as_str()[..=2].to_ascii_uppercase(),
),
];
let before_span = expr.span.shrink_to_lo().until(ty.span);
if !before_span.is_empty() {
// Remove everything before the type name
sugg.push((before_span, String::new()));
}
// Use `::` between the type name and the constant
let between_span = ty.span.shrink_to_hi().until(last_segment.ident.span);
if !between_span.check_source_text(cx, |s| s == "::") {
sugg.push((between_span, String::from("::")));
}
(sugg, "usage of a legacy numeric method")
} else {
return;
};
@ -143,9 +150,8 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
&& self.msrv.meets(cx, msrvs::NUMERIC_ASSOCIATED_CONSTANTS)
&& !is_from_proc_macro(cx, expr)
{
span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| {
diag.span_suggestion_verbose(
span,
span_lint_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.span, msg, |diag| {
diag.multipart_suggestion_verbose(
"use the associated constant instead",
sugg,
Applicability::MaybeIncorrect,

View file

@ -79,9 +79,31 @@ fn main() {
f64::consts::E;
b!();
std::primitive::i32::MAX;
//~^ ERROR: usage of a legacy numeric method
//~| HELP: use the associated constant instead
[(0, "", i128::MAX)];
//~^ ERROR: usage of a legacy numeric constant
//~| HELP: use the associated constant instead
i32::MAX;
//~^ ERROR: usage of a legacy numeric method
//~| HELP: use the associated constant instead
assert_eq!(0, -i32::MAX);
//~^ ERROR: usage of a legacy numeric method
//~| HELP: use the associated constant instead
i128::MAX;
//~^ ERROR: usage of a legacy numeric constant
//~| HELP: use the associated constant instead
u32::MAX;
//~^ ERROR: usage of a legacy numeric method
//~| HELP: use the associated constant instead
i32::MAX;
//~^ ERROR: usage of a legacy numeric method
//~| HELP: use the associated constant instead
type Ω = i32;
Ω::MAX;
//~^ ERROR: usage of a legacy numeric method
//~| HELP: use the associated constant instead
}
#[warn(clippy::legacy_numeric_constants)]

View file

@ -79,9 +79,31 @@ fn main() {
f64::consts::E;
b!();
<std::primitive::i32>::max_value();
//~^ ERROR: usage of a legacy numeric method
//~| HELP: use the associated constant instead
[(0, "", std::i128::MAX)];
//~^ ERROR: usage of a legacy numeric constant
//~| HELP: use the associated constant instead
(i32::max_value());
//~^ ERROR: usage of a legacy numeric method
//~| HELP: use the associated constant instead
assert_eq!(0, -(i32::max_value()));
//~^ ERROR: usage of a legacy numeric method
//~| HELP: use the associated constant instead
(std::i128::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
((i32::max_value)());
//~^ ERROR: usage of a legacy numeric method
//~| HELP: use the associated constant instead
type Ω = i32;
Ω::max_value();
//~^ ERROR: usage of a legacy numeric method
//~| HELP: use the associated constant instead
}
#[warn(clippy::legacy_numeric_constants)]

View file

@ -72,10 +72,10 @@ LL | u32::MAX;
| +++++
error: usage of a legacy numeric method
--> tests/ui/legacy_numeric_constants.rs:50:10
--> tests/ui/legacy_numeric_constants.rs:50:5
|
LL | i32::max_value();
| ^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
@ -84,10 +84,10 @@ LL + i32::MAX;
|
error: usage of a legacy numeric method
--> tests/ui/legacy_numeric_constants.rs:53:9
--> tests/ui/legacy_numeric_constants.rs:53:5
|
LL | u8::max_value();
| ^^^^^^^^^^^
| ^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
@ -96,10 +96,10 @@ LL + u8::MAX;
|
error: usage of a legacy numeric method
--> tests/ui/legacy_numeric_constants.rs:56:9
--> tests/ui/legacy_numeric_constants.rs:56:5
|
LL | u8::min_value();
| ^^^^^^^^^^^
| ^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
@ -120,10 +120,10 @@ LL + u8::MIN;
|
error: usage of a legacy numeric method
--> tests/ui/legacy_numeric_constants.rs:62:27
--> tests/ui/legacy_numeric_constants.rs:62:5
|
LL | ::std::primitive::u8::min_value();
| ^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
@ -132,10 +132,10 @@ LL + ::std::primitive::u8::MIN;
|
error: usage of a legacy numeric method
--> tests/ui/legacy_numeric_constants.rs:65:26
--> tests/ui/legacy_numeric_constants.rs:65:5
|
LL | std::primitive::i32::max_value();
| ^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
@ -171,8 +171,20 @@ LL - let x = std::u64::MAX;
LL + let x = u64::MAX;
|
error: usage of a legacy numeric method
--> tests/ui/legacy_numeric_constants.rs:82:5
|
LL | <std::primitive::i32>::max_value();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
LL - <std::primitive::i32>::max_value();
LL + std::primitive::i32::MAX;
|
error: usage of a legacy numeric constant
--> tests/ui/legacy_numeric_constants.rs:82:14
--> tests/ui/legacy_numeric_constants.rs:85:14
|
LL | [(0, "", std::i128::MAX)];
| ^^^^^^^^^^^^^^
@ -183,8 +195,80 @@ LL - [(0, "", std::i128::MAX)];
LL + [(0, "", i128::MAX)];
|
error: usage of a legacy numeric method
--> tests/ui/legacy_numeric_constants.rs:88:5
|
LL | (i32::max_value());
| ^^^^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
LL - (i32::max_value());
LL + i32::MAX;
|
error: usage of a legacy numeric method
--> tests/ui/legacy_numeric_constants.rs:91:20
|
LL | assert_eq!(0, -(i32::max_value()));
| ^^^^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
LL - assert_eq!(0, -(i32::max_value()));
LL + assert_eq!(0, -i32::MAX);
|
error: usage of a legacy numeric constant
--> tests/ui/legacy_numeric_constants.rs:116:5
--> tests/ui/legacy_numeric_constants.rs:94:5
|
LL | (std::i128::MAX);
| ^^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
LL - (std::i128::MAX);
LL + i128::MAX;
|
error: usage of a legacy numeric method
--> tests/ui/legacy_numeric_constants.rs:97:5
|
LL | (<u32>::max_value());
| ^^^^^^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
LL - (<u32>::max_value());
LL + u32::MAX;
|
error: usage of a legacy numeric method
--> tests/ui/legacy_numeric_constants.rs:100:5
|
LL | ((i32::max_value)());
| ^^^^^^^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
LL - ((i32::max_value)());
LL + i32::MAX;
|
error: usage of a legacy numeric method
--> tests/ui/legacy_numeric_constants.rs:104:5
|
LL | Ω::max_value();
| ^^^^^^^^^^^^^^
|
help: use the associated constant instead
|
LL - Ω::max_value();
LL + Ω::MAX;
|
error: usage of a legacy numeric constant
--> tests/ui/legacy_numeric_constants.rs:138:5
|
LL | std::u32::MAX;
| ^^^^^^^^^^^^^
@ -195,5 +279,5 @@ LL - std::u32::MAX;
LL + u32::MAX;
|
error: aborting due to 16 previous errors
error: aborting due to 23 previous errors