about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/casts/cast_possible_truncation.rs16
-rw-r--r--clippy_lints/src/casts/utils.rs56
-rw-r--r--clippy_utils/src/ty.rs59
3 files changed, 68 insertions, 63 deletions
diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs
index 6c938062c19..9b189ea1ef8 100644
--- a/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -1,13 +1,13 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::expr_or_init;
-use clippy_utils::ty::is_isize_or_usize;
+use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
 use rustc_ast::ast;
 use rustc_attr::IntType;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, FloatTy, Ty, VariantDiscr};
+use rustc_middle::ty::{self, FloatTy, Ty};
 
 use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION};
 
@@ -117,17 +117,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
             {
                 let i = def.variant_index_with_ctor_id(id);
                 let variant = &def.variants[i];
-                let nbits: u64 = match variant.discr {
-                    VariantDiscr::Explicit(id) => utils::read_explicit_enum_value(cx.tcx, id).unwrap().nbits(),
-                    VariantDiscr::Relative(x) => {
-                        match def.variants[(i.as_usize() - x as usize).into()].discr {
-                            VariantDiscr::Explicit(id) => {
-                                utils::read_explicit_enum_value(cx.tcx, id).unwrap().add(x).nbits()
-                            }
-                            VariantDiscr::Relative(_) => (32 - x.leading_zeros()).into(),
-                        }
-                    }
-                };
+                let nbits = utils::enum_value_nbits(get_discriminant_value(cx.tcx, def, i));
                 (nbits, Some(variant))
             } else {
                 (utils::enum_ty_to_nbits(def, cx.tcx), None)
diff --git a/clippy_lints/src/casts/utils.rs b/clippy_lints/src/casts/utils.rs
index fab0c194b37..bbed766c47a 100644
--- a/clippy_lints/src/casts/utils.rs
+++ b/clippy_lints/src/casts/utils.rs
@@ -1,7 +1,5 @@
-use rustc_middle::mir::interpret::{ConstValue, Scalar};
+use clippy_utils::ty::{read_explicit_enum_value, EnumValue};
 use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr};
-use rustc_span::def_id::DefId;
-use rustc_target::abi::Size;
 
 /// Returns the size in bits of an integral type.
 /// Will return 0 if the type is not an int or uint variant
@@ -27,53 +25,13 @@ pub(super) fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
     }
 }
 
-pub(super) enum EnumValue {
-    Unsigned(u128),
-    Signed(i128),
-}
-impl EnumValue {
-    pub(super) fn add(self, n: u32) -> Self {
-        match self {
-            Self::Unsigned(x) => Self::Unsigned(x + u128::from(n)),
-            Self::Signed(x) => Self::Signed(x + i128::from(n)),
-        }
-    }
-
-    pub(super) fn nbits(self) -> u64 {
-        match self {
-            Self::Unsigned(x) => 128 - x.leading_zeros(),
-            Self::Signed(x) if x < 0 => 128 - (-(x + 1)).leading_zeros() + 1,
-            Self::Signed(x) => 128 - x.leading_zeros(),
-        }
-        .into()
-    }
-}
-
-#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
-pub(super) fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option<EnumValue> {
-    if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) {
-        match tcx.type_of(id).kind() {
-            ty::Int(_) => Some(EnumValue::Signed(match value.size().bytes() {
-                1 => i128::from(value.assert_bits(Size::from_bytes(1)) as u8 as i8),
-                2 => i128::from(value.assert_bits(Size::from_bytes(2)) as u16 as i16),
-                4 => i128::from(value.assert_bits(Size::from_bytes(4)) as u32 as i32),
-                8 => i128::from(value.assert_bits(Size::from_bytes(8)) as u64 as i64),
-                16 => value.assert_bits(Size::from_bytes(16)) as i128,
-                _ => return None,
-            })),
-            ty::Uint(_) => Some(EnumValue::Unsigned(match value.size().bytes() {
-                1 => value.assert_bits(Size::from_bytes(1)),
-                2 => value.assert_bits(Size::from_bytes(2)),
-                4 => value.assert_bits(Size::from_bytes(4)),
-                8 => value.assert_bits(Size::from_bytes(8)),
-                16 => value.assert_bits(Size::from_bytes(16)),
-                _ => return None,
-            })),
-            _ => None,
-        }
-    } else {
-        None
+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 {
diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs
index 958e6d1ec46..7d74b69906d 100644
--- a/clippy_utils/src/ty.rs
+++ b/clippy_utils/src/ty.rs
@@ -10,12 +10,14 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, TyKind, Unsafety};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
+use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
 use rustc_middle::ty::{
-    self, AdtDef, Binder, FnSig, IntTy, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy,
+    self, AdtDef, Binder, FnSig, IntTy, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
+use rustc_target::abi::{Size, VariantIdx};
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::query::normalize::AtExt;
 use std::iter;
@@ -515,3 +517,58 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS
         }
     }
 }
+
+#[derive(Clone, Copy)]
+pub enum EnumValue {
+    Unsigned(u128),
+    Signed(i128),
+}
+impl core::ops::Add<u32> for EnumValue {
+    type Output = Self;
+    fn add(self, n: u32) -> Self::Output {
+        match self {
+            Self::Unsigned(x) => Self::Unsigned(x + u128::from(n)),
+            Self::Signed(x) => Self::Signed(x + i128::from(n)),
+        }
+    }
+}
+
+/// Attempts to read the given constant as though it were an an enum value.
+#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
+pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option<EnumValue> {
+    if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) {
+        match tcx.type_of(id).kind() {
+            ty::Int(_) => Some(EnumValue::Signed(match value.size().bytes() {
+                1 => i128::from(value.assert_bits(Size::from_bytes(1)) as u8 as i8),
+                2 => i128::from(value.assert_bits(Size::from_bytes(2)) as u16 as i16),
+                4 => i128::from(value.assert_bits(Size::from_bytes(4)) as u32 as i32),
+                8 => i128::from(value.assert_bits(Size::from_bytes(8)) as u64 as i64),
+                16 => value.assert_bits(Size::from_bytes(16)) as i128,
+                _ => return None,
+            })),
+            ty::Uint(_) => Some(EnumValue::Unsigned(match value.size().bytes() {
+                1 => value.assert_bits(Size::from_bytes(1)),
+                2 => value.assert_bits(Size::from_bytes(2)),
+                4 => value.assert_bits(Size::from_bytes(4)),
+                8 => value.assert_bits(Size::from_bytes(8)),
+                16 => value.assert_bits(Size::from_bytes(16)),
+                _ => return None,
+            })),
+            _ => None,
+        }
+    } else {
+        None
+    }
+}
+
+/// Gets the value of the given variant.
+pub fn get_discriminant_value(tcx: TyCtxt<'_>, adt: &'_ AdtDef, i: VariantIdx) -> EnumValue {
+    let variant = &adt.variants[i];
+    match variant.discr {
+        VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap(),
+        VariantDiscr::Relative(x) => match adt.variants[(i.as_usize() - x as usize).into()].discr {
+            VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap() + x,
+            VariantDiscr::Relative(_) => EnumValue::Unsigned(x.into()),
+        },
+    }
+}