summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
blob: 28ecdea7ea06c3d4e238adf9f54c2342e4d06f30 (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
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::is_isize_or_usize;
use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_middle::ty::Ty;

use super::{utils, CAST_POSSIBLE_WRAP};

pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
    if !(cast_from.is_integral() && cast_to.is_integral()) {
        return;
    }

    let arch_64_suffix = " on targets with 64-bit wide pointers";
    let arch_32_suffix = " on targets with 32-bit wide pointers";
    let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed();
    let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
    let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);

    let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) {
        (true, true) | (false, false) => (to_nbits == from_nbits && cast_unsigned_to_signed, ""),
        (true, false) => (to_nbits <= 32 && cast_unsigned_to_signed, arch_32_suffix),
        (false, true) => (
            cast_unsigned_to_signed,
            if from_nbits == 64 {
                arch_64_suffix
            } else {
                arch_32_suffix
            },
        ),
    };

    if should_lint {
        span_lint(
            cx,
            CAST_POSSIBLE_WRAP,
            expr.span,
            &format!("casting `{cast_from}` to `{cast_to}` may wrap around the value{suffix}",),
        );
    }
}