Skip to content

Commit 0f6932a

Browse files
committed
Auto merge of #9546 - kraktus:default_not_default_trait, r=xFrednet
[`should_implement_trait`] Also lint `default` method close #8550 changelog: FP: [`should_implement_trait`]: Now also works for `default` methods
2 parents 35b7ce5 + 7289835 commit 0f6932a

File tree

2 files changed

+49
-46
lines changed

2 files changed

+49
-46
lines changed

clippy_lints/src/methods/mod.rs

+38-45
Original file line numberDiff line numberDiff line change
@@ -3255,65 +3255,59 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
32553255
let self_ty = cx.tcx.type_of(item.def_id);
32563256

32573257
let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
3258-
if_chain! {
3259-
if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind;
3260-
if let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next();
3261-
3258+
if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind {
32623259
let method_sig = cx.tcx.fn_sig(impl_item.def_id);
32633260
let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
3264-
3265-
let first_arg_ty = method_sig.inputs().iter().next();
3266-
3267-
// check conventions w.r.t. conversion method names and predicates
3268-
if let Some(first_arg_ty) = first_arg_ty;
3269-
3270-
then {
3271-
// if this impl block implements a trait, lint in trait definition instead
3272-
if !implements_trait && cx.access_levels.is_exported(impl_item.def_id) {
3273-
// check missing trait implementations
3274-
for method_config in &TRAIT_METHODS {
3275-
if name == method_config.method_name &&
3276-
sig.decl.inputs.len() == method_config.param_count &&
3277-
method_config.output_type.matches(&sig.decl.output) &&
3278-
method_config.self_kind.matches(cx, self_ty, *first_arg_ty) &&
3279-
fn_header_equals(method_config.fn_header, sig.header) &&
3280-
method_config.lifetime_param_cond(impl_item)
3281-
{
3282-
span_lint_and_help(
3283-
cx,
3284-
SHOULD_IMPLEMENT_TRAIT,
3285-
impl_item.span,
3286-
&format!(
3287-
"method `{}` can be confused for the standard trait method `{}::{}`",
3288-
method_config.method_name,
3289-
method_config.trait_name,
3290-
method_config.method_name
3291-
),
3292-
None,
3293-
&format!(
3294-
"consider implementing the trait `{}` or choosing a less ambiguous method name",
3295-
method_config.trait_name
3296-
)
3297-
);
3298-
}
3261+
let first_arg_ty_opt = method_sig.inputs().iter().next().copied();
3262+
// if this impl block implements a trait, lint in trait definition instead
3263+
if !implements_trait && cx.access_levels.is_exported(impl_item.def_id) {
3264+
// check missing trait implementations
3265+
for method_config in &TRAIT_METHODS {
3266+
if name == method_config.method_name
3267+
&& sig.decl.inputs.len() == method_config.param_count
3268+
&& method_config.output_type.matches(&sig.decl.output)
3269+
// in case there is no first arg, since we already have checked the number of arguments
3270+
// it's should be always true
3271+
&& first_arg_ty_opt.map_or(true, |first_arg_ty| method_config
3272+
.self_kind.matches(cx, self_ty, first_arg_ty)
3273+
)
3274+
&& fn_header_equals(method_config.fn_header, sig.header)
3275+
&& method_config.lifetime_param_cond(impl_item)
3276+
{
3277+
span_lint_and_help(
3278+
cx,
3279+
SHOULD_IMPLEMENT_TRAIT,
3280+
impl_item.span,
3281+
&format!(
3282+
"method `{}` can be confused for the standard trait method `{}::{}`",
3283+
method_config.method_name, method_config.trait_name, method_config.method_name
3284+
),
3285+
None,
3286+
&format!(
3287+
"consider implementing the trait `{}` or choosing a less ambiguous method name",
3288+
method_config.trait_name
3289+
),
3290+
);
32993291
}
33003292
}
3293+
}
33013294

3302-
if sig.decl.implicit_self.has_implicit_self()
3295+
if sig.decl.implicit_self.has_implicit_self()
33033296
&& !(self.avoid_breaking_exported_api
3304-
&& cx.access_levels.is_exported(impl_item.def_id))
3297+
&& cx.access_levels.is_exported(impl_item.def_id))
3298+
&& let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next()
3299+
&& let Some(first_arg_ty) = first_arg_ty_opt
33053300
{
33063301
wrong_self_convention::check(
33073302
cx,
33083303
name,
33093304
self_ty,
3310-
*first_arg_ty,
3305+
first_arg_ty,
33113306
first_arg.pat.span,
33123307
implements_trait,
33133308
false
33143309
);
33153310
}
3316-
}
33173311
}
33183312

33193313
// if this impl block implements a trait, lint in trait definition instead
@@ -3799,7 +3793,6 @@ const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
37993793
ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
38003794
ShouldImplTraitCase::new("std::clone::Clone", "clone", 1, FN_HEADER, SelfKind::Ref, OutType::Any, true),
38013795
ShouldImplTraitCase::new("std::cmp::Ord", "cmp", 2, FN_HEADER, SelfKind::Ref, OutType::Any, true),
3802-
// FIXME: default doesn't work
38033796
ShouldImplTraitCase::new("std::default::Default", "default", 0, FN_HEADER, SelfKind::No, OutType::Any, true),
38043797
ShouldImplTraitCase::new("std::ops::Deref", "deref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
38053798
ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
@@ -3827,7 +3820,7 @@ enum SelfKind {
38273820
Value,
38283821
Ref,
38293822
RefMut,
3830-
No,
3823+
No, // When we want the first argument type to be different than `Self`
38313824
}
38323825

38333826
impl SelfKind {

tests/ui/should_impl_trait/method_list_1.stderr

+11-1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,16 @@ LL | | }
9999
|
100100
= help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name
101101

102+
error: method `default` can be confused for the standard trait method `std::default::Default::default`
103+
--> $DIR/method_list_1.rs:65:5
104+
|
105+
LL | / pub fn default() -> Self {
106+
LL | | unimplemented!()
107+
LL | | }
108+
| |_____^
109+
|
110+
= help: consider implementing the trait `std::default::Default` or choosing a less ambiguous method name
111+
102112
error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref`
103113
--> $DIR/method_list_1.rs:69:5
104114
|
@@ -139,5 +149,5 @@ LL | | }
139149
|
140150
= help: consider implementing the trait `std::ops::Drop` or choosing a less ambiguous method name
141151

142-
error: aborting due to 14 previous errors
152+
error: aborting due to 15 previous errors
143153

0 commit comments

Comments
 (0)