Extract some util functions
This commit is contained in:
parent
90bb7a3476
commit
88ecdd0804
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -10,12 +10,14 @@
|
||||
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()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user