| use clippy_utils::sym; | |
| use clippy_utils::ty::{implements_trait, is_copy}; | |
| use rustc_hir::Mutability; | |
| use rustc_lint::LateContext; | |
| use rustc_middle::ty::{self, Ty}; | |
| #[derive(Clone, Copy, PartialEq, Eq, Debug)] | |
| pub(super) enum SelfKind { | |
| Value, | |
| Ref, | |
| RefMut, | |
| No, // When we want the first argument type to be different than `Self` | |
| } | |
| impl SelfKind { | |
| pub(super) fn matches<'a>(self, cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool { | |
| fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool { | |
| if ty == parent_ty { | |
| true | |
| } else if let Some(boxed_ty) = ty.boxed_ty() { | |
| boxed_ty == parent_ty | |
| } else if let ty::Adt(adt_def, args) = ty.kind() | |
| && matches!(cx.tcx.get_diagnostic_name(adt_def.did()), Some(sym::Rc | sym::Arc)) | |
| { | |
| args.iter().next().and_then(ty::GenericArg::as_type) == Some(parent_ty) | |
| } else { | |
| false | |
| } | |
| } | |
| fn matches_ref<'a>(cx: &LateContext<'a>, mutability: Mutability, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool { | |
| if let ty::Ref(_, t, m) = *ty.kind() { | |
| return m == mutability && t == parent_ty; | |
| } | |
| let trait_sym = match mutability { | |
| Mutability::Not => sym::AsRef, | |
| Mutability::Mut => sym::AsMut, | |
| }; | |
| let Some(trait_def_id) = cx.tcx.get_diagnostic_item(trait_sym) else { | |
| return false; | |
| }; | |
| implements_trait(cx, ty, trait_def_id, &[parent_ty.into()]) | |
| } | |
| fn matches_none<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool { | |
| !matches_value(cx, parent_ty, ty) | |
| && !matches_ref(cx, Mutability::Not, parent_ty, ty) | |
| && !matches_ref(cx, Mutability::Mut, parent_ty, ty) | |
| } | |
| match self { | |
| Self::Value => matches_value(cx, parent_ty, ty), | |
| Self::Ref => matches_ref(cx, Mutability::Not, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty), | |
| Self::RefMut => matches_ref(cx, Mutability::Mut, parent_ty, ty), | |
| Self::No => matches_none(cx, parent_ty, ty), | |
| } | |
| } | |
| #[must_use] | |
| pub(super) fn description(self) -> &'static str { | |
| match self { | |
| Self::Value => "`self` by value", | |
| Self::Ref => "`self` by reference", | |
| Self::RefMut => "`self` by mutable reference", | |
| Self::No => "no `self`", | |
| } | |
| } | |
| } |