]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/casts/utils.rs
Rollup merge of #102227 - devnexen:solarish_get_path, r=m-ou-se
[rust.git] / src / tools / clippy / clippy_lints / src / casts / utils.rs
1 use clippy_utils::ty::{read_explicit_enum_value, EnumValue};
2 use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr};
3
4 /// Returns the size in bits of an integral type.
5 /// Will return 0 if the type is not an int or uint variant
6 pub(super) fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
7     match typ.kind() {
8         ty::Int(i) => match i {
9             IntTy::Isize => tcx.data_layout.pointer_size.bits(),
10             IntTy::I8 => 8,
11             IntTy::I16 => 16,
12             IntTy::I32 => 32,
13             IntTy::I64 => 64,
14             IntTy::I128 => 128,
15         },
16         ty::Uint(i) => match i {
17             UintTy::Usize => tcx.data_layout.pointer_size.bits(),
18             UintTy::U8 => 8,
19             UintTy::U16 => 16,
20             UintTy::U32 => 32,
21             UintTy::U64 => 64,
22             UintTy::U128 => 128,
23         },
24         _ => 0,
25     }
26 }
27
28 pub(super) fn enum_value_nbits(value: EnumValue) -> u64 {
29     match value {
30         EnumValue::Unsigned(x) => 128 - x.leading_zeros(),
31         EnumValue::Signed(x) if x < 0 => 128 - (-(x + 1)).leading_zeros() + 1,
32         EnumValue::Signed(x) => 128 - x.leading_zeros(),
33     }
34     .into()
35 }
36
37 pub(super) fn enum_ty_to_nbits(adt: AdtDef<'_>, tcx: TyCtxt<'_>) -> u64 {
38     let mut explicit = 0i128;
39     let (start, end) = adt
40         .variants()
41         .iter()
42         .fold((0, i128::MIN), |(start, end), variant| match variant.discr {
43             VariantDiscr::Relative(x) => match explicit.checked_add(i128::from(x)) {
44                 Some(x) => (start, end.max(x)),
45                 None => (i128::MIN, end),
46             },
47             VariantDiscr::Explicit(id) => match read_explicit_enum_value(tcx, id) {
48                 Some(EnumValue::Signed(x)) => {
49                     explicit = x;
50                     (start.min(x), end.max(x))
51                 },
52                 Some(EnumValue::Unsigned(x)) => match i128::try_from(x) {
53                     Ok(x) => {
54                         explicit = x;
55                         (start, end.max(x))
56                     },
57                     Err(_) => (i128::MIN, end),
58                 },
59                 None => (start, end),
60             },
61         });
62
63     if start > end {
64         // No variants.
65         0
66     } else {
67         let neg_bits = if start < 0 {
68             128 - (-(start + 1)).leading_zeros() + 1
69         } else {
70             0
71         };
72         let pos_bits = if end > 0 { 128 - end.leading_zeros() } else { 0 };
73         neg_bits.max(pos_bits).into()
74     }
75 }