Skip to content

Commit 88ecdd0

Browse files
committed
Extract some util functions
1 parent 90bb7a3 commit 88ecdd0

File tree

3 files changed

+68
-63
lines changed

3 files changed

+68
-63
lines changed

clippy_lints/src/casts/cast_possible_truncation.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use clippy_utils::consts::{constant, Constant};
22
use clippy_utils::diagnostics::span_lint;
33
use clippy_utils::expr_or_init;
4-
use clippy_utils::ty::is_isize_or_usize;
4+
use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
55
use rustc_ast::ast;
66
use rustc_attr::IntType;
77
use rustc_hir::def::{DefKind, Res};
88
use rustc_hir::{BinOpKind, Expr, ExprKind};
99
use rustc_lint::LateContext;
10-
use rustc_middle::ty::{self, FloatTy, Ty, VariantDiscr};
10+
use rustc_middle::ty::{self, FloatTy, Ty};
1111

1212
use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION};
1313

@@ -117,17 +117,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
117117
{
118118
let i = def.variant_index_with_ctor_id(id);
119119
let variant = &def.variants[i];
120-
let nbits: u64 = match variant.discr {
121-
VariantDiscr::Explicit(id) => utils::read_explicit_enum_value(cx.tcx, id).unwrap().nbits(),
122-
VariantDiscr::Relative(x) => {
123-
match def.variants[(i.as_usize() - x as usize).into()].discr {
124-
VariantDiscr::Explicit(id) => {
125-
utils::read_explicit_enum_value(cx.tcx, id).unwrap().add(x).nbits()
126-
}
127-
VariantDiscr::Relative(_) => (32 - x.leading_zeros()).into(),
128-
}
129-
}
130-
};
120+
let nbits = utils::enum_value_nbits(get_discriminant_value(cx.tcx, def, i));
131121
(nbits, Some(variant))
132122
} else {
133123
(utils::enum_ty_to_nbits(def, cx.tcx), None)

clippy_lints/src/casts/utils.rs

Lines changed: 7 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
use rustc_middle::mir::interpret::{ConstValue, Scalar};
1+
use clippy_utils::ty::{read_explicit_enum_value, EnumValue};
22
use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr};
3-
use rustc_span::def_id::DefId;
4-
use rustc_target::abi::Size;
53

64
/// Returns the size in bits of an integral type.
75
/// 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 {
2725
}
2826
}
2927

30-
pub(super) enum EnumValue {
31-
Unsigned(u128),
32-
Signed(i128),
33-
}
34-
impl EnumValue {
35-
pub(super) fn add(self, n: u32) -> Self {
36-
match self {
37-
Self::Unsigned(x) => Self::Unsigned(x + u128::from(n)),
38-
Self::Signed(x) => Self::Signed(x + i128::from(n)),
39-
}
40-
}
41-
42-
pub(super) fn nbits(self) -> u64 {
43-
match self {
44-
Self::Unsigned(x) => 128 - x.leading_zeros(),
45-
Self::Signed(x) if x < 0 => 128 - (-(x + 1)).leading_zeros() + 1,
46-
Self::Signed(x) => 128 - x.leading_zeros(),
47-
}
48-
.into()
49-
}
50-
}
51-
52-
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
53-
pub(super) fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option<EnumValue> {
54-
if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) {
55-
match tcx.type_of(id).kind() {
56-
ty::Int(_) => Some(EnumValue::Signed(match value.size().bytes() {
57-
1 => i128::from(value.assert_bits(Size::from_bytes(1)) as u8 as i8),
58-
2 => i128::from(value.assert_bits(Size::from_bytes(2)) as u16 as i16),
59-
4 => i128::from(value.assert_bits(Size::from_bytes(4)) as u32 as i32),
60-
8 => i128::from(value.assert_bits(Size::from_bytes(8)) as u64 as i64),
61-
16 => value.assert_bits(Size::from_bytes(16)) as i128,
62-
_ => return None,
63-
})),
64-
ty::Uint(_) => Some(EnumValue::Unsigned(match value.size().bytes() {
65-
1 => value.assert_bits(Size::from_bytes(1)),
66-
2 => value.assert_bits(Size::from_bytes(2)),
67-
4 => value.assert_bits(Size::from_bytes(4)),
68-
8 => value.assert_bits(Size::from_bytes(8)),
69-
16 => value.assert_bits(Size::from_bytes(16)),
70-
_ => return None,
71-
})),
72-
_ => None,
73-
}
74-
} else {
75-
None
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(),
7633
}
34+
.into()
7735
}
7836

7937
pub(super) fn enum_ty_to_nbits(adt: &AdtDef, tcx: TyCtxt<'_>) -> u64 {

clippy_utils/src/ty.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ use rustc_hir::def_id::DefId;
1010
use rustc_hir::{Expr, TyKind, Unsafety};
1111
use rustc_infer::infer::TyCtxtInferExt;
1212
use rustc_lint::LateContext;
13+
use rustc_middle::mir::interpret::{ConstValue, Scalar};
1314
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
1415
use rustc_middle::ty::{
15-
self, AdtDef, Binder, FnSig, IntTy, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy,
16+
self, AdtDef, Binder, FnSig, IntTy, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy, VariantDiscr,
1617
};
1718
use rustc_span::symbol::Ident;
1819
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
20+
use rustc_target::abi::{Size, VariantIdx};
1921
use rustc_trait_selection::infer::InferCtxtExt;
2022
use rustc_trait_selection::traits::query::normalize::AtExt;
2123
use std::iter;
@@ -515,3 +517,58 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS
515517
}
516518
}
517519
}
520+
521+
#[derive(Clone, Copy)]
522+
pub enum EnumValue {
523+
Unsigned(u128),
524+
Signed(i128),
525+
}
526+
impl core::ops::Add<u32> for EnumValue {
527+
type Output = Self;
528+
fn add(self, n: u32) -> Self::Output {
529+
match self {
530+
Self::Unsigned(x) => Self::Unsigned(x + u128::from(n)),
531+
Self::Signed(x) => Self::Signed(x + i128::from(n)),
532+
}
533+
}
534+
}
535+
536+
/// Attempts to read the given constant as though it were an an enum value.
537+
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
538+
pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option<EnumValue> {
539+
if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) {
540+
match tcx.type_of(id).kind() {
541+
ty::Int(_) => Some(EnumValue::Signed(match value.size().bytes() {
542+
1 => i128::from(value.assert_bits(Size::from_bytes(1)) as u8 as i8),
543+
2 => i128::from(value.assert_bits(Size::from_bytes(2)) as u16 as i16),
544+
4 => i128::from(value.assert_bits(Size::from_bytes(4)) as u32 as i32),
545+
8 => i128::from(value.assert_bits(Size::from_bytes(8)) as u64 as i64),
546+
16 => value.assert_bits(Size::from_bytes(16)) as i128,
547+
_ => return None,
548+
})),
549+
ty::Uint(_) => Some(EnumValue::Unsigned(match value.size().bytes() {
550+
1 => value.assert_bits(Size::from_bytes(1)),
551+
2 => value.assert_bits(Size::from_bytes(2)),
552+
4 => value.assert_bits(Size::from_bytes(4)),
553+
8 => value.assert_bits(Size::from_bytes(8)),
554+
16 => value.assert_bits(Size::from_bytes(16)),
555+
_ => return None,
556+
})),
557+
_ => None,
558+
}
559+
} else {
560+
None
561+
}
562+
}
563+
564+
/// Gets the value of the given variant.
565+
pub fn get_discriminant_value(tcx: TyCtxt<'_>, adt: &'_ AdtDef, i: VariantIdx) -> EnumValue {
566+
let variant = &adt.variants[i];
567+
match variant.discr {
568+
VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap(),
569+
VariantDiscr::Relative(x) => match adt.variants[(i.as_usize() - x as usize).into()].discr {
570+
VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap() + x,
571+
VariantDiscr::Relative(_) => EnumValue::Unsigned(x.into()),
572+
},
573+
}
574+
}

0 commit comments

Comments
 (0)