Auto merge of #5725 - montrivo:should-impl-trait, r=flip1995
should_impl_trait - ignore methods with lifetime params Fixes: #5617 changelog: don't lint should_implement_trait when an `Iterator::next` case has explicit parameters
This commit is contained in:
commit
3bd98895f1
@ -1500,6 +1500,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
|
||||
if in_external_macro(cx.sess(), impl_item.span) {
|
||||
return;
|
||||
@ -1525,16 +1526,31 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||
|
||||
then {
|
||||
if cx.access_levels.is_exported(impl_item.hir_id) {
|
||||
// check missing trait implementations
|
||||
for &(method_name, n_args, fn_header, self_kind, out_type, trait_name) in &TRAIT_METHODS {
|
||||
if name == method_name &&
|
||||
sig.decl.inputs.len() == n_args &&
|
||||
out_type.matches(cx, &sig.decl.output) &&
|
||||
self_kind.matches(cx, self_ty, first_arg_ty) &&
|
||||
fn_header_equals(*fn_header, sig.header) {
|
||||
span_lint(cx, SHOULD_IMPLEMENT_TRAIT, impl_item.span, &format!(
|
||||
"defining a method called `{}` on this type; consider implementing \
|
||||
the `{}` trait or choosing a less ambiguous name", name, trait_name));
|
||||
// check missing trait implementations
|
||||
for method_config in &TRAIT_METHODS {
|
||||
if name == method_config.method_name &&
|
||||
sig.decl.inputs.len() == method_config.param_count &&
|
||||
method_config.output_type.matches(cx, &sig.decl.output) &&
|
||||
method_config.self_kind.matches(cx, self_ty, first_arg_ty) &&
|
||||
fn_header_equals(method_config.fn_header, sig.header) &&
|
||||
method_config.lifetime_param_cond(&impl_item)
|
||||
{
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
SHOULD_IMPLEMENT_TRAIT,
|
||||
impl_item.span,
|
||||
&format!(
|
||||
"method `{}` can be confused for the standard trait method `{}::{}`",
|
||||
method_config.method_name,
|
||||
method_config.trait_name,
|
||||
method_config.method_name
|
||||
),
|
||||
None,
|
||||
&format!(
|
||||
"consider implementing the trait `{}` or choosing a less ambiguous method name",
|
||||
method_config.trait_name
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3464,38 +3480,85 @@ const FN_HEADER: hir::FnHeader = hir::FnHeader {
|
||||
abi: rustc_target::spec::abi::Abi::Rust,
|
||||
};
|
||||
|
||||
struct ShouldImplTraitCase {
|
||||
trait_name: &'static str,
|
||||
method_name: &'static str,
|
||||
param_count: usize,
|
||||
fn_header: hir::FnHeader,
|
||||
// implicit self kind expected (none, self, &self, ...)
|
||||
self_kind: SelfKind,
|
||||
// checks against the output type
|
||||
output_type: OutType,
|
||||
// certain methods with explicit lifetimes can't implement the equivalent trait method
|
||||
lint_explicit_lifetime: bool,
|
||||
}
|
||||
impl ShouldImplTraitCase {
|
||||
const fn new(
|
||||
trait_name: &'static str,
|
||||
method_name: &'static str,
|
||||
param_count: usize,
|
||||
fn_header: hir::FnHeader,
|
||||
self_kind: SelfKind,
|
||||
output_type: OutType,
|
||||
lint_explicit_lifetime: bool,
|
||||
) -> ShouldImplTraitCase {
|
||||
ShouldImplTraitCase {
|
||||
trait_name,
|
||||
method_name,
|
||||
param_count,
|
||||
fn_header,
|
||||
self_kind,
|
||||
output_type,
|
||||
lint_explicit_lifetime,
|
||||
}
|
||||
}
|
||||
|
||||
fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool {
|
||||
self.lint_explicit_lifetime
|
||||
|| !impl_item.generics.params.iter().any(|p| {
|
||||
matches!(
|
||||
p.kind,
|
||||
hir::GenericParamKind::Lifetime {
|
||||
kind: hir::LifetimeParamKind::Explicit
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
const TRAIT_METHODS: [(&str, usize, &hir::FnHeader, SelfKind, OutType, &str); 30] = [
|
||||
("add", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Add"),
|
||||
("as_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"),
|
||||
("as_ref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"),
|
||||
("bitand", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitAnd"),
|
||||
("bitor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitOr"),
|
||||
("bitxor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitXor"),
|
||||
("borrow", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"),
|
||||
("borrow_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"),
|
||||
("clone", 1, &FN_HEADER, SelfKind::Ref, OutType::Any, "std::clone::Clone"),
|
||||
("cmp", 2, &FN_HEADER, SelfKind::Ref, OutType::Any, "std::cmp::Ord"),
|
||||
("default", 0, &FN_HEADER, SelfKind::No, OutType::Any, "std::default::Default"),
|
||||
("deref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::ops::Deref"),
|
||||
("deref_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"),
|
||||
("div", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Div"),
|
||||
("drop", 1, &FN_HEADER, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"),
|
||||
("eq", 2, &FN_HEADER, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"),
|
||||
("from_iter", 1, &FN_HEADER, SelfKind::No, OutType::Any, "std::iter::FromIterator"),
|
||||
("from_str", 1, &FN_HEADER, SelfKind::No, OutType::Any, "std::str::FromStr"),
|
||||
("hash", 2, &FN_HEADER, SelfKind::Ref, OutType::Unit, "std::hash::Hash"),
|
||||
("index", 2, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::ops::Index"),
|
||||
("index_mut", 2, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"),
|
||||
("into_iter", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"),
|
||||
("mul", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Mul"),
|
||||
("neg", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Neg"),
|
||||
("next", 1, &FN_HEADER, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"),
|
||||
("not", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Not"),
|
||||
("rem", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Rem"),
|
||||
("shl", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Shl"),
|
||||
("shr", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Shr"),
|
||||
("sub", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Sub"),
|
||||
const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
|
||||
ShouldImplTraitCase::new("std::ops::Add", "add", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::convert::AsMut", "as_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
|
||||
ShouldImplTraitCase::new("std::convert::AsRef", "as_ref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
|
||||
ShouldImplTraitCase::new("std::ops::BitAnd", "bitand", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::ops::BitOr", "bitor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::ops::BitXor", "bitxor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::borrow::Borrow", "borrow", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
|
||||
ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
|
||||
ShouldImplTraitCase::new("std::clone::Clone", "clone", 1, FN_HEADER, SelfKind::Ref, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::cmp::Ord", "cmp", 2, FN_HEADER, SelfKind::Ref, OutType::Any, true),
|
||||
// FIXME: default doesn't work
|
||||
ShouldImplTraitCase::new("std::default::Default", "default", 0, FN_HEADER, SelfKind::No, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::ops::Deref", "deref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
|
||||
ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
|
||||
ShouldImplTraitCase::new("std::ops::Div", "div", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::ops::Drop", "drop", 1, FN_HEADER, SelfKind::RefMut, OutType::Unit, true),
|
||||
ShouldImplTraitCase::new("std::cmp::PartialEq", "eq", 2, FN_HEADER, SelfKind::Ref, OutType::Bool, true),
|
||||
ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter", 1, FN_HEADER, SelfKind::No, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::str::FromStr", "from_str", 1, FN_HEADER, SelfKind::No, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::hash::Hash", "hash", 2, FN_HEADER, SelfKind::Ref, OutType::Unit, true),
|
||||
ShouldImplTraitCase::new("std::ops::Index", "index", 2, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
|
||||
ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut", 2, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
|
||||
ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter", 1, FN_HEADER, SelfKind::Value, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::ops::Mul", "mul", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::ops::Neg", "neg", 1, FN_HEADER, SelfKind::Value, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::iter::Iterator", "next", 1, FN_HEADER, SelfKind::RefMut, OutType::Any, false),
|
||||
ShouldImplTraitCase::new("std::ops::Not", "not", 1, FN_HEADER, SelfKind::Value, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::ops::Rem", "rem", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::ops::Shl", "shl", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::ops::Shr", "shr", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
|
||||
ShouldImplTraitCase::new("std::ops::Sub", "sub", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
@ -10,6 +10,7 @@
|
||||
clippy::non_ascii_literal,
|
||||
clippy::new_without_default,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::print_stdout,
|
||||
clippy::must_use_candidate,
|
||||
clippy::use_self,
|
||||
@ -33,71 +34,6 @@ use std::sync::{self, Arc};
|
||||
|
||||
use option_helpers::IteratorFalsePositives;
|
||||
|
||||
pub struct T;
|
||||
|
||||
impl T {
|
||||
pub fn add(self, other: T) -> T {
|
||||
self
|
||||
}
|
||||
|
||||
// no error, not public interface
|
||||
pub(crate) fn drop(&mut self) {}
|
||||
|
||||
// no error, private function
|
||||
fn neg(self) -> Self {
|
||||
self
|
||||
}
|
||||
|
||||
// no error, private function
|
||||
fn eq(&self, other: T) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
// No error; self is a ref.
|
||||
fn sub(&self, other: T) -> &T {
|
||||
self
|
||||
}
|
||||
|
||||
// No error; different number of arguments.
|
||||
fn div(self) -> T {
|
||||
self
|
||||
}
|
||||
|
||||
// No error; wrong return type.
|
||||
fn rem(self, other: T) {}
|
||||
|
||||
// Fine
|
||||
fn into_u32(self) -> u32 {
|
||||
0
|
||||
}
|
||||
|
||||
fn into_u16(&self) -> u16 {
|
||||
0
|
||||
}
|
||||
|
||||
fn to_something(self) -> u32 {
|
||||
0
|
||||
}
|
||||
|
||||
fn new(self) -> Self {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct T1;
|
||||
|
||||
impl T1 {
|
||||
// Shouldn't trigger lint as it is unsafe.
|
||||
pub unsafe fn add(self, rhs: T1) -> T1 {
|
||||
self
|
||||
}
|
||||
|
||||
// Should not trigger lint since this is an async function.
|
||||
pub async fn next(&mut self) -> Option<T1> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct Lt<'a> {
|
||||
foo: &'a u32,
|
||||
}
|
||||
@ -171,6 +107,8 @@ impl BadNew {
|
||||
}
|
||||
}
|
||||
|
||||
struct T;
|
||||
|
||||
impl Mul<T> for T {
|
||||
type Output = T;
|
||||
// No error, obviously.
|
||||
|
@ -1,15 +1,5 @@
|
||||
error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name
|
||||
--> $DIR/methods.rs:39:5
|
||||
|
|
||||
LL | / pub fn add(self, other: T) -> T {
|
||||
LL | | self
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= note: `-D clippy::should-implement-trait` implied by `-D warnings`
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/methods.rs:169:5
|
||||
--> $DIR/methods.rs:105:5
|
||||
|
|
||||
LL | / fn new() -> i32 {
|
||||
LL | | 0
|
||||
@ -19,7 +9,7 @@ LL | | }
|
||||
= note: `-D clippy::new-ret-no-self` implied by `-D warnings`
|
||||
|
||||
error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
|
||||
--> $DIR/methods.rs:188:13
|
||||
--> $DIR/methods.rs:126:13
|
||||
|
|
||||
LL | let _ = v.iter().filter(|&x| *x < 0).next();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -28,7 +18,7 @@ LL | let _ = v.iter().filter(|&x| *x < 0).next();
|
||||
= note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)`
|
||||
|
||||
error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
|
||||
--> $DIR/methods.rs:191:13
|
||||
--> $DIR/methods.rs:129:13
|
||||
|
|
||||
LL | let _ = v.iter().filter(|&x| {
|
||||
| _____________^
|
||||
@ -38,7 +28,7 @@ LL | | ).next();
|
||||
| |___________________________^
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:208:22
|
||||
--> $DIR/methods.rs:146:22
|
||||
|
|
||||
LL | let _ = v.iter().find(|&x| *x < 0).is_some();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)`
|
||||
@ -46,25 +36,25 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_some();
|
||||
= note: `-D clippy::search-is-some` implied by `-D warnings`
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:209:20
|
||||
--> $DIR/methods.rs:147:20
|
||||
|
|
||||
LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)`
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:210:20
|
||||
--> $DIR/methods.rs:148:20
|
||||
|
|
||||
LL | let _ = (0..1).find(|x| *x == 0).is_some();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)`
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:211:22
|
||||
--> $DIR/methods.rs:149:22
|
||||
|
|
||||
LL | let _ = v.iter().find(|x| **x == 0).is_some();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)`
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:214:13
|
||||
--> $DIR/methods.rs:152:13
|
||||
|
|
||||
LL | let _ = v.iter().find(|&x| {
|
||||
| _____________^
|
||||
@ -74,13 +64,13 @@ LL | | ).is_some();
|
||||
| |______________________________^
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:220:22
|
||||
--> $DIR/methods.rs:158:22
|
||||
|
|
||||
LL | let _ = v.iter().position(|&x| x < 0).is_some();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:223:13
|
||||
--> $DIR/methods.rs:161:13
|
||||
|
|
||||
LL | let _ = v.iter().position(|&x| {
|
||||
| _____________^
|
||||
@ -90,13 +80,13 @@ LL | | ).is_some();
|
||||
| |______________________________^
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:229:22
|
||||
--> $DIR/methods.rs:167:22
|
||||
|
|
||||
LL | let _ = v.iter().rposition(|&x| x < 0).is_some();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:232:13
|
||||
--> $DIR/methods.rs:170:13
|
||||
|
|
||||
LL | let _ = v.iter().rposition(|&x| {
|
||||
| _____________^
|
||||
@ -105,5 +95,5 @@ LL | | }
|
||||
LL | | ).is_some();
|
||||
| |______________________________^
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
83
tests/ui/should_impl_trait/corner_cases.rs
Normal file
83
tests/ui/should_impl_trait/corner_cases.rs
Normal file
@ -0,0 +1,83 @@
|
||||
// edition:2018
|
||||
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
#![allow(
|
||||
clippy::missing_errors_doc,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::must_use_candidate,
|
||||
clippy::unused_self,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::missing_safety_doc,
|
||||
clippy::wrong_self_convention
|
||||
)]
|
||||
|
||||
use std::ops::Mul;
|
||||
use std::rc::{self, Rc};
|
||||
use std::sync::{self, Arc};
|
||||
|
||||
fn main() {}
|
||||
|
||||
pub struct T1;
|
||||
impl T1 {
|
||||
// corner cases: should not lint
|
||||
|
||||
// no error, not public interface
|
||||
pub(crate) fn drop(&mut self) {}
|
||||
|
||||
// no error, private function
|
||||
fn neg(self) -> Self {
|
||||
self
|
||||
}
|
||||
|
||||
// no error, private function
|
||||
fn eq(&self, other: Self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
// No error; self is a ref.
|
||||
fn sub(&self, other: Self) -> &Self {
|
||||
self
|
||||
}
|
||||
|
||||
// No error; different number of arguments.
|
||||
fn div(self) -> Self {
|
||||
self
|
||||
}
|
||||
|
||||
// No error; wrong return type.
|
||||
fn rem(self, other: Self) {}
|
||||
|
||||
// Fine
|
||||
fn into_u32(self) -> u32 {
|
||||
0
|
||||
}
|
||||
|
||||
fn into_u16(&self) -> u16 {
|
||||
0
|
||||
}
|
||||
|
||||
fn to_something(self) -> u32 {
|
||||
0
|
||||
}
|
||||
|
||||
fn new(self) -> Self {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
pub fn next<'b>(&'b mut self) -> Option<&'b mut T1> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct T2;
|
||||
impl T2 {
|
||||
// Shouldn't trigger lint as it is unsafe.
|
||||
pub unsafe fn add(self, rhs: Self) -> Self {
|
||||
self
|
||||
}
|
||||
|
||||
// Should not trigger lint since this is an async function.
|
||||
pub async fn next(&mut self) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
}
|
87
tests/ui/should_impl_trait/method_list_1.rs
Normal file
87
tests/ui/should_impl_trait/method_list_1.rs
Normal file
@ -0,0 +1,87 @@
|
||||
// edition:2018
|
||||
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
#![allow(
|
||||
clippy::missing_errors_doc,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::must_use_candidate,
|
||||
clippy::unused_self,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::missing_safety_doc,
|
||||
clippy::wrong_self_convention
|
||||
)]
|
||||
|
||||
use std::ops::Mul;
|
||||
use std::rc::{self, Rc};
|
||||
use std::sync::{self, Arc};
|
||||
|
||||
fn main() {}
|
||||
pub struct T;
|
||||
|
||||
impl T {
|
||||
// *****************************************
|
||||
// trait method list part 1, should lint all
|
||||
// *****************************************
|
||||
pub fn add(self, other: T) -> T {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn as_mut(&mut self) -> &mut T {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn as_ref(&self) -> &T {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn bitand(self, rhs: T) -> T {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn bitor(self, rhs: Self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn bitxor(self, rhs: Self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn borrow(&self) -> &str {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn borrow_mut(&mut self) -> &mut str {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn clone(&self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn cmp(&self, other: &Self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn default() -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn deref(&self) -> &Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn deref_mut(&mut self) -> &mut Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn div(self, rhs: Self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn drop(&mut self) {
|
||||
unimplemented!()
|
||||
}
|
||||
// **********
|
||||
// part 1 end
|
||||
// **********
|
||||
}
|
143
tests/ui/should_impl_trait/method_list_1.stderr
Normal file
143
tests/ui/should_impl_trait/method_list_1.stderr
Normal file
@ -0,0 +1,143 @@
|
||||
error: method `add` can be confused for the standard trait method `std::ops::Add::add`
|
||||
--> $DIR/method_list_1.rs:25:5
|
||||
|
|
||||
LL | / pub fn add(self, other: T) -> T {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= note: `-D clippy::should-implement-trait` implied by `-D warnings`
|
||||
= help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name
|
||||
|
||||
error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut`
|
||||
--> $DIR/method_list_1.rs:29:5
|
||||
|
|
||||
LL | / pub fn as_mut(&mut self) -> &mut T {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name
|
||||
|
||||
error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref`
|
||||
--> $DIR/method_list_1.rs:33:5
|
||||
|
|
||||
LL | / pub fn as_ref(&self) -> &T {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name
|
||||
|
||||
error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand`
|
||||
--> $DIR/method_list_1.rs:37:5
|
||||
|
|
||||
LL | / pub fn bitand(self, rhs: T) -> T {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name
|
||||
|
||||
error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor`
|
||||
--> $DIR/method_list_1.rs:41:5
|
||||
|
|
||||
LL | / pub fn bitor(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name
|
||||
|
||||
error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor`
|
||||
--> $DIR/method_list_1.rs:45:5
|
||||
|
|
||||
LL | / pub fn bitxor(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name
|
||||
|
||||
error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow`
|
||||
--> $DIR/method_list_1.rs:49:5
|
||||
|
|
||||
LL | / pub fn borrow(&self) -> &str {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name
|
||||
|
||||
error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut`
|
||||
--> $DIR/method_list_1.rs:53:5
|
||||
|
|
||||
LL | / pub fn borrow_mut(&mut self) -> &mut str {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name
|
||||
|
||||
error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone`
|
||||
--> $DIR/method_list_1.rs:57:5
|
||||
|
|
||||
LL | / pub fn clone(&self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name
|
||||
|
||||
error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp`
|
||||
--> $DIR/method_list_1.rs:61:5
|
||||
|
|
||||
LL | / pub fn cmp(&self, other: &Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name
|
||||
|
||||
error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref`
|
||||
--> $DIR/method_list_1.rs:69:5
|
||||
|
|
||||
LL | / pub fn deref(&self) -> &Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name
|
||||
|
||||
error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut`
|
||||
--> $DIR/method_list_1.rs:73:5
|
||||
|
|
||||
LL | / pub fn deref_mut(&mut self) -> &mut Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name
|
||||
|
||||
error: method `div` can be confused for the standard trait method `std::ops::Div::div`
|
||||
--> $DIR/method_list_1.rs:77:5
|
||||
|
|
||||
LL | / pub fn div(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name
|
||||
|
||||
error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop`
|
||||
--> $DIR/method_list_1.rs:81:5
|
||||
|
|
||||
LL | / pub fn drop(&mut self) {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::Drop` or choosing a less ambiguous method name
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
88
tests/ui/should_impl_trait/method_list_2.rs
Normal file
88
tests/ui/should_impl_trait/method_list_2.rs
Normal file
@ -0,0 +1,88 @@
|
||||
// edition:2018
|
||||
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
#![allow(
|
||||
clippy::missing_errors_doc,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::must_use_candidate,
|
||||
clippy::unused_self,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::missing_safety_doc,
|
||||
clippy::wrong_self_convention
|
||||
)]
|
||||
|
||||
use std::ops::Mul;
|
||||
use std::rc::{self, Rc};
|
||||
use std::sync::{self, Arc};
|
||||
|
||||
fn main() {}
|
||||
pub struct T;
|
||||
|
||||
impl T {
|
||||
// *****************************************
|
||||
// trait method list part 2, should lint all
|
||||
// *****************************************
|
||||
|
||||
pub fn eq(&self, other: &Self) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn from_iter<T>(iter: T) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn from_str(s: &str) -> Result<Self, Self> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn hash(&self, state: &mut T) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn index(&self, index: usize) -> &Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn index_mut(&mut self, index: usize) -> &mut Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn into_iter(self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn mul(self, rhs: Self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn neg(self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn next(&mut self) -> Option<Self> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn not(self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn rem(self, rhs: Self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn shl(self, rhs: Self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn shr(self, rhs: Self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn sub(self, rhs: Self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
// **********
|
||||
// part 2 end
|
||||
// **********
|
||||
}
|
153
tests/ui/should_impl_trait/method_list_2.stderr
Normal file
153
tests/ui/should_impl_trait/method_list_2.stderr
Normal file
@ -0,0 +1,153 @@
|
||||
error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq`
|
||||
--> $DIR/method_list_2.rs:26:5
|
||||
|
|
||||
LL | / pub fn eq(&self, other: &Self) -> bool {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= note: `-D clippy::should-implement-trait` implied by `-D warnings`
|
||||
= help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name
|
||||
|
||||
error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter`
|
||||
--> $DIR/method_list_2.rs:30:5
|
||||
|
|
||||
LL | / pub fn from_iter<T>(iter: T) -> Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name
|
||||
|
||||
error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
|
||||
--> $DIR/method_list_2.rs:34:5
|
||||
|
|
||||
LL | / pub fn from_str(s: &str) -> Result<Self, Self> {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
|
||||
|
||||
error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash`
|
||||
--> $DIR/method_list_2.rs:38:5
|
||||
|
|
||||
LL | / pub fn hash(&self, state: &mut T) {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
|
||||
|
||||
error: method `index` can be confused for the standard trait method `std::ops::Index::index`
|
||||
--> $DIR/method_list_2.rs:42:5
|
||||
|
|
||||
LL | / pub fn index(&self, index: usize) -> &Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name
|
||||
|
||||
error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut`
|
||||
--> $DIR/method_list_2.rs:46:5
|
||||
|
|
||||
LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name
|
||||
|
||||
error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`
|
||||
--> $DIR/method_list_2.rs:50:5
|
||||
|
|
||||
LL | / pub fn into_iter(self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name
|
||||
|
||||
error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul`
|
||||
--> $DIR/method_list_2.rs:54:5
|
||||
|
|
||||
LL | / pub fn mul(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name
|
||||
|
||||
error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg`
|
||||
--> $DIR/method_list_2.rs:58:5
|
||||
|
|
||||
LL | / pub fn neg(self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name
|
||||
|
||||
error: method `next` can be confused for the standard trait method `std::iter::Iterator::next`
|
||||
--> $DIR/method_list_2.rs:62:5
|
||||
|
|
||||
LL | / pub fn next(&mut self) -> Option<Self> {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name
|
||||
|
||||
error: method `not` can be confused for the standard trait method `std::ops::Not::not`
|
||||
--> $DIR/method_list_2.rs:66:5
|
||||
|
|
||||
LL | / pub fn not(self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name
|
||||
|
||||
error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem`
|
||||
--> $DIR/method_list_2.rs:70:5
|
||||
|
|
||||
LL | / pub fn rem(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name
|
||||
|
||||
error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl`
|
||||
--> $DIR/method_list_2.rs:74:5
|
||||
|
|
||||
LL | / pub fn shl(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name
|
||||
|
||||
error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr`
|
||||
--> $DIR/method_list_2.rs:78:5
|
||||
|
|
||||
LL | / pub fn shr(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name
|
||||
|
||||
error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub`
|
||||
--> $DIR/method_list_2.rs:82:5
|
||||
|
|
||||
LL | / pub fn sub(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name
|
||||
|
||||
error: aborting due to 15 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user