Skip to content

Commit b05d55e

Browse files
fix(should_implement_trait): only suggest traits that are in the prelude (#15776)
Fixes #6752 changelog: [should_implement_trait]: only suggest traits that are in the prelude
2 parents 5ab16d1 + 2d2d143 commit b05d55e

10 files changed

+872
-315
lines changed

clippy_lints/src/methods/lib.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use clippy_utils::sym;
2+
use clippy_utils::ty::{implements_trait, is_copy};
3+
use rustc_hir::Mutability;
4+
use rustc_lint::LateContext;
5+
use rustc_middle::ty::{self, Ty};
6+
7+
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
8+
pub(super) enum SelfKind {
9+
Value,
10+
Ref,
11+
RefMut,
12+
No, // When we want the first argument type to be different than `Self`
13+
}
14+
15+
impl SelfKind {
16+
pub(super) fn matches<'a>(self, cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
17+
fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
18+
if ty == parent_ty {
19+
true
20+
} else if let Some(boxed_ty) = ty.boxed_ty() {
21+
boxed_ty == parent_ty
22+
} else if let ty::Adt(adt_def, args) = ty.kind()
23+
&& matches!(cx.tcx.get_diagnostic_name(adt_def.did()), Some(sym::Rc | sym::Arc))
24+
{
25+
args.types().next() == Some(parent_ty)
26+
} else {
27+
false
28+
}
29+
}
30+
31+
fn matches_ref<'a>(cx: &LateContext<'a>, mutability: Mutability, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
32+
if let ty::Ref(_, t, m) = *ty.kind() {
33+
return m == mutability && t == parent_ty;
34+
}
35+
36+
let trait_sym = match mutability {
37+
Mutability::Not => sym::AsRef,
38+
Mutability::Mut => sym::AsMut,
39+
};
40+
41+
let Some(trait_def_id) = cx.tcx.get_diagnostic_item(trait_sym) else {
42+
return false;
43+
};
44+
implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
45+
}
46+
47+
fn matches_none<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
48+
!matches_value(cx, parent_ty, ty)
49+
&& !matches_ref(cx, Mutability::Not, parent_ty, ty)
50+
&& !matches_ref(cx, Mutability::Mut, parent_ty, ty)
51+
}
52+
53+
match self {
54+
Self::Value => matches_value(cx, parent_ty, ty),
55+
Self::Ref => matches_ref(cx, Mutability::Not, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty),
56+
Self::RefMut => matches_ref(cx, Mutability::Mut, parent_ty, ty),
57+
Self::No => matches_none(cx, parent_ty, ty),
58+
}
59+
}
60+
61+
#[must_use]
62+
pub(super) fn description(self) -> &'static str {
63+
match self {
64+
Self::Value => "`self` by value",
65+
Self::Ref => "`self` by reference",
66+
Self::RefMut => "`self` by mutable reference",
67+
Self::No => "no `self`",
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)