]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/casts/utils.rs
Auto merge of #9870 - koka831:unformat-unused-rounding, r=Jarcho
[rust.git] / clippy_lints / src / casts / utils.rs
index 00fd0b3473b4417949097b5ebb34ba8c10144e60..5a4f20f099060c7f911c3cf4e5e10937b59547f4 100644 (file)
@@ -1,4 +1,5 @@
-use rustc_middle::ty::{self, IntTy, Ty, TyCtxt, UintTy};
+use clippy_utils::ty::{read_explicit_enum_value, EnumValue};
+use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr};
 
 /// Returns the size in bits of an integral type.
 /// Will return 0 if the type is not an int or uint variant
@@ -23,3 +24,52 @@ pub(super) fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
         _ => 0,
     }
 }
+
+pub(super) fn enum_value_nbits(value: EnumValue) -> u64 {
+    match value {
+        EnumValue::Unsigned(x) => 128 - x.leading_zeros(),
+        EnumValue::Signed(x) if x < 0 => 128 - (-(x + 1)).leading_zeros() + 1,
+        EnumValue::Signed(x) => 128 - x.leading_zeros(),
+    }
+    .into()
+}
+
+pub(super) fn enum_ty_to_nbits(adt: AdtDef<'_>, tcx: TyCtxt<'_>) -> u64 {
+    let mut explicit = 0i128;
+    let (start, end) = adt
+        .variants()
+        .iter()
+        .fold((0, i128::MIN), |(start, end), variant| match variant.discr {
+            VariantDiscr::Relative(x) => match explicit.checked_add(i128::from(x)) {
+                Some(x) => (start, end.max(x)),
+                None => (i128::MIN, end),
+            },
+            VariantDiscr::Explicit(id) => match read_explicit_enum_value(tcx, id) {
+                Some(EnumValue::Signed(x)) => {
+                    explicit = x;
+                    (start.min(x), end.max(x))
+                },
+                Some(EnumValue::Unsigned(x)) => match i128::try_from(x) {
+                    Ok(x) => {
+                        explicit = x;
+                        (start, end.max(x))
+                    },
+                    Err(_) => (i128::MIN, end),
+                },
+                None => (start, end),
+            },
+        });
+
+    if start > end {
+        // No variants.
+        0
+    } else {
+        let neg_bits = if start < 0 {
+            128 - (-(start + 1)).leading_zeros() + 1
+        } else {
+            0
+        };
+        let pos_bits = if end > 0 { 128 - end.leading_zeros() } else { 0 };
+        neg_bits.max(pos_bits).into()
+    }
+}