Skip to content

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

Conversation

ComputerDruid
Copy link
Contributor

@ComputerDruid ComputerDruid commented Jun 30, 2025

Fixes #15008

changelog: [legacy_numeric_constants]: fix suggestion when call is inside parentheses like (i32::max_value())

@ComputerDruid ComputerDruid marked this pull request as ready for review June 30, 2025 23:51
@rustbot
Copy link
Collaborator

rustbot commented Jun 30, 2025

r? @samueltardieu

rustbot has assigned @samueltardieu.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Jun 30, 2025
Copy link
Member

@samueltardieu samueltardieu left a 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

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Jul 1, 2025
@ComputerDruid
Copy link
Contributor Author

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

Copy link

github-actions bot commented Jul 10, 2025

Lintcheck changes for 9457d64

Lint Added Removed Changed
clippy::legacy_numeric_constants 0 0 24

This comment will be updated if you push new changes

ComputerDruid and others added 5 commits July 10, 2025 11:56
Removes an unnecessary use of `span_lint_hir_and_then()` where
`span_lint_and_then()` would do.
This also moves the lint to be posted on the call.
This removes the need for using source snippets in the replacement.
@ComputerDruid ComputerDruid force-pushed the fix_legacy_numeric_constants_with_parens branch from 40e0db3 to 9457d64 Compare July 10, 2025 19:02
@ComputerDruid
Copy link
Contributor Author

ComputerDruid commented Jul 10, 2025

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().

Underlining the whole call is actually a simplification, so folded that in to the main commit.

Also, could you add those two extra tests?

This is now commit 2.

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.

Switching to span_lint_and_then is now commit 3. (although it doesn't post it on the right node until commit 4)

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?

I like it! I split it into:

  • commit 4: "refactor legacy_numeric_constants to check calls instead of paths", which also results in posting the lint on the call instead of the path
  • commit 5: "refactor legacy_numeric_constants to use multipart suggestion", which gets rid of the need to use the source snippet.

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties and removed S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) labels Jul 10, 2025
@samueltardieu samueltardieu added this pull request to the merge queue Jul 11, 2025
@samueltardieu
Copy link
Member

samueltardieu commented Jul 11, 2025

Thanks. I'm still bugged a little by the fact that we talk about a "legacy numeric method" instead of "legacy numeric associated function", but this is not introduced by this PR, and might even be easier to read despite being technically incorrect.

Merged via the queue into rust-lang:master with commit 488f4dd Jul 11, 2025
11 checks passed
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Jul 11, 2025
@ComputerDruid ComputerDruid deleted the fix_legacy_numeric_constants_with_parens branch July 11, 2025 07:07
github-merge-queue bot pushed a commit that referenced this pull request Jul 26, 2025
changelog: [`ip_constant`]: fix suggestion when call is inside
parentheses like `(Ipv4Addr::new(127, 0, 0, 1))`

Very similar to the fix in
#15191
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

legacy_numeric_constants spans are a bit off, synatx error due to misssing )
3 participants