]> git.lizzy.rs Git - rust.git/blobdiff - src/tools/clippy/clippy_utils/src/ty.rs
Merge commit 'e329249b6a3a98830d860c74c8234a8dd9407436' into clippyup
[rust.git] / src / tools / clippy / clippy_utils / src / ty.rs
index b44899e6bd587235a64fbbb5fc2f4e066ec5759e..0646d1524a767310ee26d879649a16a441d8ee5e 100644 (file)
 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;
@@ -169,7 +171,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
             // because we don't want to lint functions returning empty arrays
             is_must_use_ty(cx, *ty)
         },
-        ty::Tuple(substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
+        ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)),
         ty::Opaque(ref def_id, _) => {
             for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
                 if let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() {
@@ -249,11 +251,11 @@ pub fn is_non_aggregate_primitive_type(ty: Ty<'_>) -> bool {
 /// Returns `true` if the given type is a primitive (a `bool` or `char`, any integer or
 /// floating-point number type, a `str`, or an array, slice, or tuple of those types).
 pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
-    match ty.kind() {
+    match *ty.kind() {
         ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
         ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true,
-        ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(*inner_type),
-        ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type),
+        ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type),
+        ty::Tuple(inner_types) => inner_types.iter().all(is_recursively_primitive_type),
         _ => false,
     }
 }
@@ -393,9 +395,9 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
 
 /// Checks if a given type looks safe to be uninitialized.
 pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    match ty.kind() {
-        ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, *component),
-        ty::Tuple(types) => types.types().all(|ty| is_uninit_value_valid_for_ty(cx, ty)),
+    match *ty.kind() {
+        ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component),
+        ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)),
         ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did),
         _ => false,
     }
@@ -426,8 +428,8 @@ impl<'tcx> ExprFnSig<'tcx> {
     pub fn input(self, i: usize) -> Binder<'tcx, Ty<'tcx>> {
         match self {
             Self::Sig(sig) => sig.input(i),
-            Self::Closure(sig) => sig.input(0).map_bound(|ty| ty.tuple_element_ty(i).unwrap()),
-            Self::Trait(inputs, _) => inputs.map_bound(|ty| ty.tuple_element_ty(i).unwrap()),
+            Self::Closure(sig) => sig.input(0).map_bound(|ty| ty.tuple_fields()[i]),
+            Self::Trait(inputs, _) => inputs.map_bound(|ty| ty.tuple_fields()[i]),
         }
     }
 
@@ -515,3 +517,72 @@ 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()),
+        },
+    }
+}
+
+/// Check if the given type is either `core::ffi::c_void`, `std::os::raw::c_void`, or one of the
+/// platform specific `libc::<platform>::c_void` types in libc.
+pub fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
+    if let ty::Adt(adt, _) = ty.kind()
+        && let &[krate, .., name] = &*cx.get_def_path(adt.did)
+        && let sym::libc | sym::core | sym::std = krate
+        && name.as_str() == "c_void"
+    {
+        true
+    } else {
+        false
+    }
+}