Skip to content

Commit 38b1fd0

Browse files
committed
Auto merge of #7002 - mgacek8:issue6983_wrong_self_convention_inside_trait_impls, r=phansch
wrong_self_convention: fix FP inside trait impl for `to_*` method taking `&self` fixes #6983 changelog: `wrong_self_convention`: fix FP inside trait impl for `to_*` method taking `&self`
2 parents 75d73e9 + 6966c78 commit 38b1fd0

6 files changed

+81
-17
lines changed

clippy_lints/src/methods/mod.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,13 @@ declare_clippy_lint! {
206206
/// |`to_` | not `_mut` |`self` | `Copy` |
207207
/// |`to_` | not `_mut` |`&self` | not `Copy` |
208208
///
209+
/// Note: Clippy doesn't trigger methods with `to_` prefix in:
210+
/// - Traits definition.
211+
/// Clippy can not tell if a type that implements a trait is `Copy` or not.
212+
/// - Traits implementation, when `&self` is taken.
213+
/// The method signature is controlled by the trait and often `&self` is required for all types that implement the trait
214+
/// (see e.g. the `std::string::ToString` trait).
215+
///
209216
/// Please find more info here:
210217
/// https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
211218
///
@@ -1772,7 +1779,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
17721779
let self_ty = cx.tcx.type_of(item.def_id);
17731780

17741781
let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
1775-
17761782
if_chain! {
17771783
if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind;
17781784
if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir().body(id)).next();
@@ -1824,6 +1830,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
18241830
self_ty,
18251831
first_arg_ty,
18261832
first_arg.pat.span,
1833+
implements_trait,
18271834
false
18281835
);
18291836
}
@@ -1893,6 +1900,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
18931900
self_ty,
18941901
first_arg_ty,
18951902
first_arg_span,
1903+
false,
18961904
true
18971905
);
18981906
}

clippy_lints/src/methods/wrong_self_convention.rs

+25-7
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [
2121

2222
// Conversion using `to_` can use borrowed (non-Copy types) or owned (Copy types).
2323
// Source: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
24-
(&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), Convention::ImplementsTrait(false)], &[SelfKind::Ref]),
25-
(&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), Convention::ImplementsTrait(false)], &[SelfKind::Value]),
24+
(&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false),
25+
Convention::IsTraitItem(false)], &[SelfKind::Ref]),
26+
(&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true),
27+
Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Value]),
2628
];
2729

2830
enum Convention {
@@ -32,18 +34,27 @@ enum Convention {
3234
NotEndsWith(&'static str),
3335
IsSelfTypeCopy(bool),
3436
ImplementsTrait(bool),
37+
IsTraitItem(bool),
3538
}
3639

3740
impl Convention {
3841
#[must_use]
39-
fn check<'tcx>(&self, cx: &LateContext<'tcx>, self_ty: &'tcx TyS<'tcx>, other: &str, is_trait_def: bool) -> bool {
42+
fn check<'tcx>(
43+
&self,
44+
cx: &LateContext<'tcx>,
45+
self_ty: &'tcx TyS<'tcx>,
46+
other: &str,
47+
implements_trait: bool,
48+
is_trait_item: bool,
49+
) -> bool {
4050
match *self {
4151
Self::Eq(this) => this == other,
4252
Self::StartsWith(this) => other.starts_with(this) && this != other,
4353
Self::EndsWith(this) => other.ends_with(this) && this != other,
44-
Self::NotEndsWith(this) => !Self::EndsWith(this).check(cx, self_ty, other, is_trait_def),
54+
Self::NotEndsWith(this) => !Self::EndsWith(this).check(cx, self_ty, other, implements_trait, is_trait_item),
4555
Self::IsSelfTypeCopy(is_true) => is_true == is_copy(cx, self_ty),
46-
Self::ImplementsTrait(is_true) => is_true == is_trait_def,
56+
Self::ImplementsTrait(is_true) => is_true == implements_trait,
57+
Self::IsTraitItem(is_true) => is_true == is_trait_item,
4758
}
4859
}
4960
}
@@ -60,19 +71,25 @@ impl fmt::Display for Convention {
6071
},
6172
Self::ImplementsTrait(is_true) => {
6273
let (negation, s_suffix) = if is_true { ("", "s") } else { (" does not", "") };
63-
format!("Method{} implement{} a trait", negation, s_suffix).fmt(f)
74+
format!("method{} implement{} a trait", negation, s_suffix).fmt(f)
75+
},
76+
Self::IsTraitItem(is_true) => {
77+
let suffix = if is_true { " is" } else { " is not" };
78+
format!("method{} a trait item", suffix).fmt(f)
6479
},
6580
}
6681
}
6782
}
6883

84+
#[allow(clippy::too_many_arguments)]
6985
pub(super) fn check<'tcx>(
7086
cx: &LateContext<'tcx>,
7187
item_name: &str,
7288
is_pub: bool,
7389
self_ty: &'tcx TyS<'tcx>,
7490
first_arg_ty: &'tcx TyS<'tcx>,
7591
first_arg_span: Span,
92+
implements_trait: bool,
7693
is_trait_item: bool,
7794
) {
7895
let lint = if is_pub {
@@ -83,7 +100,7 @@ pub(super) fn check<'tcx>(
83100
if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| {
84101
convs
85102
.iter()
86-
.all(|conv| conv.check(cx, self_ty, item_name, is_trait_item))
103+
.all(|conv| conv.check(cx, self_ty, item_name, implements_trait, is_trait_item))
87104
}) {
88105
if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) {
89106
let suggestion = {
@@ -99,6 +116,7 @@ pub(super) fn check<'tcx>(
99116
.filter_map(|conv| {
100117
if (cut_ends_with_conv && matches!(conv, Convention::NotEndsWith(_)))
101118
|| matches!(conv, Convention::ImplementsTrait(_))
119+
|| matches!(conv, Convention::IsTraitItem(_))
102120
{
103121
None
104122
} else {

tests/ui/wrong_self_convention.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -165,15 +165,10 @@ mod issue6307 {
165165
}
166166

167167
mod issue6727 {
168-
trait ToU64 {
169-
fn to_u64(self) -> u64;
170-
fn to_u64_v2(&self) -> u64;
171-
}
172-
173168
#[derive(Clone, Copy)]
174169
struct FooCopy;
175170

176-
impl ToU64 for FooCopy {
171+
impl FooCopy {
177172
fn to_u64(self) -> u64 {
178173
1
179174
}
@@ -185,7 +180,7 @@ mod issue6727 {
185180

186181
struct FooNoCopy;
187182

188-
impl ToU64 for FooNoCopy {
183+
impl FooNoCopy {
189184
// trigger lint
190185
fn to_u64(self) -> u64 {
191186
2

tests/ui/wrong_self_convention.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -176,15 +176,15 @@ LL | fn from_i32(self);
176176
= help: consider choosing a less ambiguous name
177177

178178
error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value
179-
--> $DIR/wrong_self_convention.rs:181:22
179+
--> $DIR/wrong_self_convention.rs:176:22
180180
|
181181
LL | fn to_u64_v2(&self) -> u64 {
182182
| ^^^^^
183183
|
184184
= help: consider choosing a less ambiguous name
185185

186186
error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
187-
--> $DIR/wrong_self_convention.rs:190:19
187+
--> $DIR/wrong_self_convention.rs:185:19
188188
|
189189
LL | fn to_u64(self) -> u64 {
190190
| ^^^^

tests/ui/wrong_self_convention2.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// edition:2018
2+
#![warn(clippy::wrong_self_convention)]
3+
#![warn(clippy::wrong_pub_self_convention)]
4+
#![allow(dead_code)]
5+
6+
fn main() {}
7+
8+
mod issue6983 {
9+
pub struct Thing;
10+
pub trait Trait {
11+
fn to_thing(&self) -> Thing;
12+
}
13+
14+
impl Trait for u8 {
15+
// don't trigger, e.g. `ToString` from `std` requires `&self`
16+
fn to_thing(&self) -> Thing {
17+
Thing
18+
}
19+
}
20+
21+
trait ToU64 {
22+
fn to_u64(self) -> u64;
23+
}
24+
25+
struct FooNoCopy;
26+
// trigger lint
27+
impl ToU64 for FooNoCopy {
28+
fn to_u64(self) -> u64 {
29+
2
30+
}
31+
}
32+
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
2+
--> $DIR/wrong_self_convention2.rs:28:19
3+
|
4+
LL | fn to_u64(self) -> u64 {
5+
| ^^^^
6+
|
7+
= note: `-D clippy::wrong-self-convention` implied by `-D warnings`
8+
= help: consider choosing a less ambiguous name
9+
10+
error: aborting due to previous error
11+

0 commit comments

Comments
 (0)