-
Notifications
You must be signed in to change notification settings - Fork 1.7k
fix legacy_numeric_constants
suggestion when call is wrapped in parens
#15191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
fix legacy_numeric_constants
suggestion when call is wrapped in parens
#15191
Conversation
rustbot has assigned @samueltardieu. Use |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fix gives good results, but in presence of i32::max_value()
, it posts the lint on the i32::max_value
node (not on the call itself), and underlines only i32::max_value
and not i32::max_value()
.
Also, the usage of span_lint_hir_and_then()
is unjustified, as it always posts it on expr
which is where span_lint_and_then()
would post it by default. par_expr
should be used, both for the span and the node to post on.
Rather than looking for the parent in the case of a function call, it is more efficient to look for a function call then to check if a legacy {min,max}_value()
function is used.
Could you try this alternative for check_expr()
and tell me what you think of it?
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
// `std::<integer>::<CONST>` check
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 [.., 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])
{
(
vec![(expr.span, format!("{mod_name}::{name}"))],
"usage of a legacy numeric constant",
)
// `<integer>::xxx_value` check
} 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 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;
};
if !expr.span.in_external_macro(cx.sess().source_map())
&& self.msrv.meets(cx, msrvs::NUMERIC_ASSOCIATED_CONSTANTS)
&& !is_from_proc_macro(cx, expr)
{
span_lint_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.span, msg, |diag| {
diag.multipart_suggestion_verbose(
"use the associated constant instead",
sugg,
Applicability::MaybeIncorrect,
);
});
}
}
Also, could you add those two extra tests?
((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
Thanks for taking a look. I probably won't be able to get back to this until next week, but I should be able to get back to this then |
Fixes #15008
changelog: [
legacy_numeric_constants
]: fix suggestion when call is inside parentheses like(i32::max_value())