summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
blob: 64ea326b75a0d3335f7407a9f3e17e9176457190 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
use clippy_utils::{meets_msrv, msrvs};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
use rustc_semver::RustcVersion;

use super::CAST_ABS_TO_UNSIGNED;

pub(super) fn check(
    cx: &LateContext<'_>,
    expr: &Expr<'_>,
    cast_expr: &Expr<'_>,
    cast_from: Ty<'_>,
    cast_to: Ty<'_>,
    msrv: Option<RustcVersion>,
) {
    if meets_msrv(msrv, msrvs::UNSIGNED_ABS)
        && let ty::Int(from) = cast_from.kind()
        && let ty::Uint(to) = cast_to.kind()
        && let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind
        && method_path.ident.name.as_str() == "abs"
    {
        let span = if from.bit_width() == to.bit_width() {
            expr.span
        } else {
            // if the result of `.unsigned_abs` would be a different type, keep the cast
            // e.g. `i64 -> usize`, `i16 -> u8`
            cast_expr.span
        };

        span_lint_and_sugg(
            cx,
            CAST_ABS_TO_UNSIGNED,
            span,
            &format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
            "replace with",
            format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")),
            Applicability::MachineApplicable,
        );
    }
}