Auto merge of #10788 - Centri3:duplicate_manual_partial_ord_impl, r=xFrednet,blyxyas

New lint [`manual_partial_ord_and_ord_impl`]

Lints when both `PartialOrd` and `Ord` are manually implemented yet the body of `PartialOrd::partial_cmp` isn't `Some(self.cmp(<other>))`.

This is in `correctness` currently but I'm ok with elsewhere.

Closes #10744

---

changelog: new lint [`needless_partial_ord_impl`]
[#10788](https://github.com/rust-lang/rust-clippy/pull/10788)
This commit is contained in:
bors 2023-07-08 18:22:54 +00:00
commit e5db198fd3
14 changed files with 455 additions and 59 deletions

View file

@ -4834,6 +4834,7 @@ Released 2018-09-13
[`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
[`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor [`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor
[`incorrect_clone_impl_on_copy_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#incorrect_clone_impl_on_copy_type [`incorrect_clone_impl_on_copy_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#incorrect_clone_impl_on_copy_type
[`incorrect_partial_ord_impl_on_ord_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#incorrect_partial_ord_impl_on_ord_type
[`index_refutable_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice [`index_refutable_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice
[`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing [`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing
[`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask [`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask

View file

@ -207,6 +207,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO, crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO,
crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO, crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO,
crate::incorrect_impls::INCORRECT_CLONE_IMPL_ON_COPY_TYPE_INFO, crate::incorrect_impls::INCORRECT_CLONE_IMPL_ON_COPY_TYPE_INFO,
crate::incorrect_impls::INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE_INFO,
crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO, crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO,
crate::indexing_slicing::INDEXING_SLICING_INFO, crate::indexing_slicing::INDEXING_SLICING_INFO,
crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO, crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO,

View file

@ -1,10 +1,15 @@
use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_node, last_path_segment, ty::implements_trait}; use clippy_utils::{
diagnostics::{span_lint_and_sugg, span_lint_and_then},
get_parent_node, is_res_lang_ctor, last_path_segment, path_res,
ty::implements_trait,
};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{ExprKind, ImplItem, ImplItemKind, Node, UnOp}; use rustc_hir::{def::Res, Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, UnOp};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::EarlyBinder; use rustc_middle::ty::EarlyBinder;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, symbol}; use rustc_span::{sym, symbol::kw};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@ -45,22 +50,80 @@ declare_clippy_lint! {
correctness, correctness,
"manual implementation of `Clone` on a `Copy` type" "manual implementation of `Clone` on a `Copy` type"
} }
declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE]); declare_clippy_lint! {
/// ### What it does
/// Checks for manual implementations of both `PartialOrd` and `Ord` when only `Ord` is
/// necessary.
///
/// ### Why is this bad?
/// If both `PartialOrd` and `Ord` are implemented, they must agree. This is commonly done by
/// wrapping the result of `cmp` in `Some` for `partial_cmp`. Not doing this may silently
/// introduce an error upon refactoring.
///
/// ### Limitations
/// Will not lint if `Self` and `Rhs` do not have the same type.
///
/// ### Example
/// ```rust
/// # use std::cmp::Ordering;
/// #[derive(Eq, PartialEq)]
/// struct A(u32);
///
/// impl Ord for A {
/// fn cmp(&self, other: &Self) -> Ordering {
/// // ...
/// # todo!();
/// }
/// }
///
/// impl PartialOrd for A {
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
/// // ...
/// # todo!();
/// }
/// }
/// ```
/// Use instead:
/// ```rust
/// # use std::cmp::Ordering;
/// #[derive(Eq, PartialEq)]
/// struct A(u32);
///
/// impl Ord for A {
/// fn cmp(&self, other: &Self) -> Ordering {
/// // ...
/// # todo!();
/// }
/// }
///
/// impl PartialOrd for A {
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
/// Some(self.cmp(other))
/// }
/// }
/// ```
#[clippy::version = "1.72.0"]
pub INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE,
correctness,
"manual implementation of `PartialOrd` when `Ord` is already implemented"
}
declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE, INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE]);
impl LateLintPass<'_> for IncorrectImpls { impl LateLintPass<'_> for IncorrectImpls {
#[expect(clippy::needless_return)] #[expect(clippy::too_many_lines)]
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
let node = get_parent_node(cx.tcx, impl_item.hir_id()); let Some(Node::Item(item)) = get_parent_node(cx.tcx, impl_item.hir_id()) else {
let Some(Node::Item(item)) = node else {
return; return;
}; };
let Some(trait_impl) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::skip_binder) else { let Some(trait_impl) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::skip_binder) else {
return; return;
}; };
let trait_impl_def_id = trait_impl.def_id;
if cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) { if cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) {
return; return;
} }
let ItemKind::Impl(imp) = item.kind else {
return;
};
let ImplItemKind::Fn(_, impl_item_id) = cx.tcx.hir().impl_item(impl_item.impl_item_id()).kind else { let ImplItemKind::Fn(_, impl_item_id) = cx.tcx.hir().impl_item(impl_item.impl_item_id()).kind else {
return; return;
}; };
@ -68,11 +131,8 @@ impl LateLintPass<'_> for IncorrectImpls {
let ExprKind::Block(block, ..) = body.value.kind else { let ExprKind::Block(block, ..) = body.value.kind else {
return; return;
}; };
// Above is duplicated from the `duplicate_manual_partial_ord_impl` branch.
// Remove it while solving conflicts once that PR is merged.
// Actual implementation; remove this comment once aforementioned PR is merged if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl.def_id)
if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl_def_id)
&& let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy) && let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy)
&& implements_trait( && implements_trait(
cx, cx,
@ -84,9 +144,9 @@ impl LateLintPass<'_> for IncorrectImpls {
if impl_item.ident.name == sym::clone { if impl_item.ident.name == sym::clone {
if block.stmts.is_empty() if block.stmts.is_empty()
&& let Some(expr) = block.expr && let Some(expr) = block.expr
&& let ExprKind::Unary(UnOp::Deref, inner) = expr.kind && let ExprKind::Unary(UnOp::Deref, deref) = expr.kind
&& let ExprKind::Path(qpath) = inner.kind && let ExprKind::Path(qpath) = deref.kind
&& last_path_segment(&qpath).ident.name == symbol::kw::SelfLower && last_path_segment(&qpath).ident.name == kw::SelfLower
{} else { {} else {
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
@ -108,7 +168,7 @@ impl LateLintPass<'_> for IncorrectImpls {
INCORRECT_CLONE_IMPL_ON_COPY_TYPE, INCORRECT_CLONE_IMPL_ON_COPY_TYPE,
impl_item.span, impl_item.span,
"incorrect implementation of `clone_from` on a `Copy` type", "incorrect implementation of `clone_from` on a `Copy` type",
"remove this", "remove it",
String::new(), String::new(),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
@ -116,5 +176,69 @@ impl LateLintPass<'_> for IncorrectImpls {
return; return;
} }
} }
if cx.tcx.is_diagnostic_item(sym::PartialOrd, trait_impl.def_id)
&& impl_item.ident.name == sym::partial_cmp
&& let Some(ord_def_id) = cx
.tcx
.diagnostic_items(trait_impl.def_id.krate)
.name_to_id
.get(&sym::Ord)
&& implements_trait(
cx,
hir_ty_to_ty(cx.tcx, imp.self_ty),
*ord_def_id,
trait_impl.substs,
)
{
if block.stmts.is_empty()
&& let Some(expr) = block.expr
&& let ExprKind::Call(
Expr {
kind: ExprKind::Path(some_path),
hir_id: some_hir_id,
..
},
[cmp_expr],
) = expr.kind
&& is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome)
&& let ExprKind::MethodCall(cmp_path, _, [other_expr], ..) = cmp_expr.kind
&& cmp_path.ident.name == sym::cmp
&& let Res::Local(..) = path_res(cx, other_expr)
{} else {
// If `Self` and `Rhs` are not the same type, bail. This makes creating a valid
// suggestion tons more complex.
if let [lhs, rhs, ..] = trait_impl.substs.as_slice() && lhs != rhs {
return;
}
span_lint_and_then(
cx,
INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE,
item.span,
"incorrect implementation of `partial_cmp` on an `Ord` type",
|diag| {
let [_, other] = body.params else {
return;
};
let suggs = if let Some(other_ident) = other.pat.simple_ident() {
vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))]
} else {
vec![
(block.span, "{ Some(self.cmp(other)) }".to_owned()),
(other.pat.span, "other".to_owned()),
]
};
diag.multipart_suggestion(
"change this to",
suggs,
Applicability::Unspecified,
);
}
);
}
}
} }
} }

View file

@ -2,6 +2,7 @@
#![allow(clippy::needless_if)] #![allow(clippy::needless_if)]
#![warn(clippy::bool_comparison)] #![warn(clippy::bool_comparison)]
#![allow(clippy::incorrect_partial_ord_impl_on_ord_type)]
fn main() { fn main() {
let x = true; let x = true;

View file

@ -2,6 +2,7 @@
#![allow(clippy::needless_if)] #![allow(clippy::needless_if)]
#![warn(clippy::bool_comparison)] #![warn(clippy::bool_comparison)]
#![allow(clippy::incorrect_partial_ord_impl_on_ord_type)]
fn main() { fn main() {
let x = true; let x = true;

View file

@ -1,5 +1,5 @@
error: equality checks against true are unnecessary error: equality checks against true are unnecessary
--> $DIR/bool_comparison.rs:8:8 --> $DIR/bool_comparison.rs:9:8
| |
LL | if x == true { LL | if x == true {
| ^^^^^^^^^ help: try simplifying it as shown: `x` | ^^^^^^^^^ help: try simplifying it as shown: `x`
@ -7,127 +7,127 @@ LL | if x == true {
= note: `-D clippy::bool-comparison` implied by `-D warnings` = note: `-D clippy::bool-comparison` implied by `-D warnings`
error: equality checks against false can be replaced by a negation error: equality checks against false can be replaced by a negation
--> $DIR/bool_comparison.rs:13:8 --> $DIR/bool_comparison.rs:14:8
| |
LL | if x == false { LL | if x == false {
| ^^^^^^^^^^ help: try simplifying it as shown: `!x` | ^^^^^^^^^^ help: try simplifying it as shown: `!x`
error: equality checks against true are unnecessary error: equality checks against true are unnecessary
--> $DIR/bool_comparison.rs:18:8 --> $DIR/bool_comparison.rs:19:8
| |
LL | if true == x { LL | if true == x {
| ^^^^^^^^^ help: try simplifying it as shown: `x` | ^^^^^^^^^ help: try simplifying it as shown: `x`
error: equality checks against false can be replaced by a negation error: equality checks against false can be replaced by a negation
--> $DIR/bool_comparison.rs:23:8 --> $DIR/bool_comparison.rs:24:8
| |
LL | if false == x { LL | if false == x {
| ^^^^^^^^^^ help: try simplifying it as shown: `!x` | ^^^^^^^^^^ help: try simplifying it as shown: `!x`
error: inequality checks against true can be replaced by a negation error: inequality checks against true can be replaced by a negation
--> $DIR/bool_comparison.rs:28:8 --> $DIR/bool_comparison.rs:29:8
| |
LL | if x != true { LL | if x != true {
| ^^^^^^^^^ help: try simplifying it as shown: `!x` | ^^^^^^^^^ help: try simplifying it as shown: `!x`
error: inequality checks against false are unnecessary error: inequality checks against false are unnecessary
--> $DIR/bool_comparison.rs:33:8 --> $DIR/bool_comparison.rs:34:8
| |
LL | if x != false { LL | if x != false {
| ^^^^^^^^^^ help: try simplifying it as shown: `x` | ^^^^^^^^^^ help: try simplifying it as shown: `x`
error: inequality checks against true can be replaced by a negation error: inequality checks against true can be replaced by a negation
--> $DIR/bool_comparison.rs:38:8 --> $DIR/bool_comparison.rs:39:8
| |
LL | if true != x { LL | if true != x {
| ^^^^^^^^^ help: try simplifying it as shown: `!x` | ^^^^^^^^^ help: try simplifying it as shown: `!x`
error: inequality checks against false are unnecessary error: inequality checks against false are unnecessary
--> $DIR/bool_comparison.rs:43:8 --> $DIR/bool_comparison.rs:44:8
| |
LL | if false != x { LL | if false != x {
| ^^^^^^^^^^ help: try simplifying it as shown: `x` | ^^^^^^^^^^ help: try simplifying it as shown: `x`
error: less than comparison against true can be replaced by a negation error: less than comparison against true can be replaced by a negation
--> $DIR/bool_comparison.rs:48:8 --> $DIR/bool_comparison.rs:49:8
| |
LL | if x < true { LL | if x < true {
| ^^^^^^^^ help: try simplifying it as shown: `!x` | ^^^^^^^^ help: try simplifying it as shown: `!x`
error: greater than checks against false are unnecessary error: greater than checks against false are unnecessary
--> $DIR/bool_comparison.rs:53:8 --> $DIR/bool_comparison.rs:54:8
| |
LL | if false < x { LL | if false < x {
| ^^^^^^^^^ help: try simplifying it as shown: `x` | ^^^^^^^^^ help: try simplifying it as shown: `x`
error: greater than checks against false are unnecessary error: greater than checks against false are unnecessary
--> $DIR/bool_comparison.rs:58:8 --> $DIR/bool_comparison.rs:59:8
| |
LL | if x > false { LL | if x > false {
| ^^^^^^^^^ help: try simplifying it as shown: `x` | ^^^^^^^^^ help: try simplifying it as shown: `x`
error: less than comparison against true can be replaced by a negation error: less than comparison against true can be replaced by a negation
--> $DIR/bool_comparison.rs:63:8 --> $DIR/bool_comparison.rs:64:8
| |
LL | if true > x { LL | if true > x {
| ^^^^^^^^ help: try simplifying it as shown: `!x` | ^^^^^^^^ help: try simplifying it as shown: `!x`
error: order comparisons between booleans can be simplified error: order comparisons between booleans can be simplified
--> $DIR/bool_comparison.rs:69:8 --> $DIR/bool_comparison.rs:70:8
| |
LL | if x < y { LL | if x < y {
| ^^^^^ help: try simplifying it as shown: `!x & y` | ^^^^^ help: try simplifying it as shown: `!x & y`
error: order comparisons between booleans can be simplified error: order comparisons between booleans can be simplified
--> $DIR/bool_comparison.rs:74:8 --> $DIR/bool_comparison.rs:75:8
| |
LL | if x > y { LL | if x > y {
| ^^^^^ help: try simplifying it as shown: `x & !y` | ^^^^^ help: try simplifying it as shown: `x & !y`
error: this comparison might be written more concisely error: this comparison might be written more concisely
--> $DIR/bool_comparison.rs:122:8 --> $DIR/bool_comparison.rs:123:8
| |
LL | if a == !b {}; LL | if a == !b {};
| ^^^^^^^ help: try simplifying it as shown: `a != b` | ^^^^^^^ help: try simplifying it as shown: `a != b`
error: this comparison might be written more concisely error: this comparison might be written more concisely
--> $DIR/bool_comparison.rs:123:8 --> $DIR/bool_comparison.rs:124:8
| |
LL | if !a == b {}; LL | if !a == b {};
| ^^^^^^^ help: try simplifying it as shown: `a != b` | ^^^^^^^ help: try simplifying it as shown: `a != b`
error: this comparison might be written more concisely error: this comparison might be written more concisely
--> $DIR/bool_comparison.rs:127:8 --> $DIR/bool_comparison.rs:128:8
| |
LL | if b == !a {}; LL | if b == !a {};
| ^^^^^^^ help: try simplifying it as shown: `b != a` | ^^^^^^^ help: try simplifying it as shown: `b != a`
error: this comparison might be written more concisely error: this comparison might be written more concisely
--> $DIR/bool_comparison.rs:128:8 --> $DIR/bool_comparison.rs:129:8
| |
LL | if !b == a {}; LL | if !b == a {};
| ^^^^^^^ help: try simplifying it as shown: `b != a` | ^^^^^^^ help: try simplifying it as shown: `b != a`
error: equality checks against false can be replaced by a negation error: equality checks against false can be replaced by a negation
--> $DIR/bool_comparison.rs:152:8 --> $DIR/bool_comparison.rs:153:8
| |
LL | if false == m!(func) {} LL | if false == m!(func) {}
| ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)` | ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)`
error: equality checks against false can be replaced by a negation error: equality checks against false can be replaced by a negation
--> $DIR/bool_comparison.rs:153:8 --> $DIR/bool_comparison.rs:154:8
| |
LL | if m!(func) == false {} LL | if m!(func) == false {}
| ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)` | ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)`
error: equality checks against true are unnecessary error: equality checks against true are unnecessary
--> $DIR/bool_comparison.rs:154:8 --> $DIR/bool_comparison.rs:155:8
| |
LL | if true == m!(func) {} LL | if true == m!(func) {}
| ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)` | ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)`
error: equality checks against true are unnecessary error: equality checks against true are unnecessary
--> $DIR/bool_comparison.rs:155:8 --> $DIR/bool_comparison.rs:156:8
| |
LL | if m!(func) == true {} LL | if m!(func) == true {}
| ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)` | ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)`

View file

@ -1,4 +1,8 @@
#![allow(clippy::incorrect_clone_impl_on_copy_type, dead_code)] #![allow(
clippy::incorrect_clone_impl_on_copy_type,
clippy::incorrect_partial_ord_impl_on_ord_type,
dead_code
)]
#![warn(clippy::expl_impl_clone_on_copy)] #![warn(clippy::expl_impl_clone_on_copy)]
#[derive(Copy)] #[derive(Copy)]

View file

@ -1,5 +1,5 @@
error: you are implementing `Clone` explicitly on a `Copy` type error: you are implementing `Clone` explicitly on a `Copy` type
--> $DIR/derive.rs:7:1 --> $DIR/derive.rs:11:1
| |
LL | / impl Clone for Qux { LL | / impl Clone for Qux {
LL | | fn clone(&self) -> Self { LL | | fn clone(&self) -> Self {
@ -9,7 +9,7 @@ LL | | }
| |_^ | |_^
| |
note: consider deriving `Clone` or removing `Copy` note: consider deriving `Clone` or removing `Copy`
--> $DIR/derive.rs:7:1 --> $DIR/derive.rs:11:1
| |
LL | / impl Clone for Qux { LL | / impl Clone for Qux {
LL | | fn clone(&self) -> Self { LL | | fn clone(&self) -> Self {
@ -20,7 +20,7 @@ LL | | }
= note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings` = note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings`
error: you are implementing `Clone` explicitly on a `Copy` type error: you are implementing `Clone` explicitly on a `Copy` type
--> $DIR/derive.rs:31:1 --> $DIR/derive.rs:35:1
| |
LL | / impl<'a> Clone for Lt<'a> { LL | / impl<'a> Clone for Lt<'a> {
LL | | fn clone(&self) -> Self { LL | | fn clone(&self) -> Self {
@ -30,7 +30,7 @@ LL | | }
| |_^ | |_^
| |
note: consider deriving `Clone` or removing `Copy` note: consider deriving `Clone` or removing `Copy`
--> $DIR/derive.rs:31:1 --> $DIR/derive.rs:35:1
| |
LL | / impl<'a> Clone for Lt<'a> { LL | / impl<'a> Clone for Lt<'a> {
LL | | fn clone(&self) -> Self { LL | | fn clone(&self) -> Self {
@ -40,7 +40,7 @@ LL | | }
| |_^ | |_^
error: you are implementing `Clone` explicitly on a `Copy` type error: you are implementing `Clone` explicitly on a `Copy` type
--> $DIR/derive.rs:42:1 --> $DIR/derive.rs:46:1
| |
LL | / impl Clone for BigArray { LL | / impl Clone for BigArray {
LL | | fn clone(&self) -> Self { LL | | fn clone(&self) -> Self {
@ -50,7 +50,7 @@ LL | | }
| |_^ | |_^
| |
note: consider deriving `Clone` or removing `Copy` note: consider deriving `Clone` or removing `Copy`
--> $DIR/derive.rs:42:1 --> $DIR/derive.rs:46:1
| |
LL | / impl Clone for BigArray { LL | / impl Clone for BigArray {
LL | | fn clone(&self) -> Self { LL | | fn clone(&self) -> Self {
@ -60,7 +60,7 @@ LL | | }
| |_^ | |_^
error: you are implementing `Clone` explicitly on a `Copy` type error: you are implementing `Clone` explicitly on a `Copy` type
--> $DIR/derive.rs:53:1 --> $DIR/derive.rs:57:1
| |
LL | / impl Clone for FnPtr { LL | / impl Clone for FnPtr {
LL | | fn clone(&self) -> Self { LL | | fn clone(&self) -> Self {
@ -70,7 +70,7 @@ LL | | }
| |_^ | |_^
| |
note: consider deriving `Clone` or removing `Copy` note: consider deriving `Clone` or removing `Copy`
--> $DIR/derive.rs:53:1 --> $DIR/derive.rs:57:1
| |
LL | / impl Clone for FnPtr { LL | / impl Clone for FnPtr {
LL | | fn clone(&self) -> Self { LL | | fn clone(&self) -> Self {
@ -80,7 +80,7 @@ LL | | }
| |_^ | |_^
error: you are implementing `Clone` explicitly on a `Copy` type error: you are implementing `Clone` explicitly on a `Copy` type
--> $DIR/derive.rs:73:1 --> $DIR/derive.rs:77:1
| |
LL | / impl<T: Clone> Clone for Generic2<T> { LL | / impl<T: Clone> Clone for Generic2<T> {
LL | | fn clone(&self) -> Self { LL | | fn clone(&self) -> Self {
@ -90,7 +90,7 @@ LL | | }
| |_^ | |_^
| |
note: consider deriving `Clone` or removing `Copy` note: consider deriving `Clone` or removing `Copy`
--> $DIR/derive.rs:73:1 --> $DIR/derive.rs:77:1
| |
LL | / impl<T: Clone> Clone for Generic2<T> { LL | / impl<T: Clone> Clone for Generic2<T> {
LL | | fn clone(&self) -> Self { LL | | fn clone(&self) -> Self {

View file

@ -1,5 +1,6 @@
#![warn(clippy::derive_ord_xor_partial_ord)] #![warn(clippy::derive_ord_xor_partial_ord)]
#![allow(clippy::unnecessary_wraps)] #![allow(clippy::unnecessary_wraps)]
#![allow(clippy::incorrect_partial_ord_impl_on_ord_type)]
use std::cmp::Ordering; use std::cmp::Ordering;

View file

@ -1,11 +1,11 @@
error: you are deriving `Ord` but have implemented `PartialOrd` explicitly error: you are deriving `Ord` but have implemented `PartialOrd` explicitly
--> $DIR/derive_ord_xor_partial_ord.rs:21:10 --> $DIR/derive_ord_xor_partial_ord.rs:22:10
| |
LL | #[derive(Ord, PartialEq, Eq)] LL | #[derive(Ord, PartialEq, Eq)]
| ^^^ | ^^^
| |
note: `PartialOrd` implemented here note: `PartialOrd` implemented here
--> $DIR/derive_ord_xor_partial_ord.rs:24:1 --> $DIR/derive_ord_xor_partial_ord.rs:25:1
| |
LL | impl PartialOrd for DeriveOrd { LL | impl PartialOrd for DeriveOrd {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -13,20 +13,20 @@ LL | impl PartialOrd for DeriveOrd {
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are deriving `Ord` but have implemented `PartialOrd` explicitly error: you are deriving `Ord` but have implemented `PartialOrd` explicitly
--> $DIR/derive_ord_xor_partial_ord.rs:30:10 --> $DIR/derive_ord_xor_partial_ord.rs:31:10
| |
LL | #[derive(Ord, PartialEq, Eq)] LL | #[derive(Ord, PartialEq, Eq)]
| ^^^ | ^^^
| |
note: `PartialOrd` implemented here note: `PartialOrd` implemented here
--> $DIR/derive_ord_xor_partial_ord.rs:33:1 --> $DIR/derive_ord_xor_partial_ord.rs:34:1
| |
LL | impl PartialOrd<DeriveOrdWithExplicitTypeVariable> for DeriveOrdWithExplicitTypeVariable { LL | impl PartialOrd<DeriveOrdWithExplicitTypeVariable> for DeriveOrdWithExplicitTypeVariable {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are implementing `Ord` explicitly but have derived `PartialOrd` error: you are implementing `Ord` explicitly but have derived `PartialOrd`
--> $DIR/derive_ord_xor_partial_ord.rs:42:1 --> $DIR/derive_ord_xor_partial_ord.rs:43:1
| |
LL | / impl std::cmp::Ord for DerivePartialOrd { LL | / impl std::cmp::Ord for DerivePartialOrd {
LL | | fn cmp(&self, other: &Self) -> Ordering { LL | | fn cmp(&self, other: &Self) -> Ordering {
@ -36,14 +36,14 @@ LL | | }
| |_^ | |_^
| |
note: `PartialOrd` implemented here note: `PartialOrd` implemented here
--> $DIR/derive_ord_xor_partial_ord.rs:39:10 --> $DIR/derive_ord_xor_partial_ord.rs:40:10
| |
LL | #[derive(PartialOrd, PartialEq, Eq)] LL | #[derive(PartialOrd, PartialEq, Eq)]
| ^^^^^^^^^^ | ^^^^^^^^^^
= note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are implementing `Ord` explicitly but have derived `PartialOrd` error: you are implementing `Ord` explicitly but have derived `PartialOrd`
--> $DIR/derive_ord_xor_partial_ord.rs:62:5 --> $DIR/derive_ord_xor_partial_ord.rs:63:5
| |
LL | / impl Ord for DerivePartialOrdInUseOrd { LL | / impl Ord for DerivePartialOrdInUseOrd {
LL | | fn cmp(&self, other: &Self) -> Ordering { LL | | fn cmp(&self, other: &Self) -> Ordering {
@ -53,7 +53,7 @@ LL | | }
| |_____^ | |_____^
| |
note: `PartialOrd` implemented here note: `PartialOrd` implemented here
--> $DIR/derive_ord_xor_partial_ord.rs:59:14 --> $DIR/derive_ord_xor_partial_ord.rs:60:14
| |
LL | #[derive(PartialOrd, PartialEq, Eq)] LL | #[derive(PartialOrd, PartialEq, Eq)]
| ^^^^^^^^^^ | ^^^^^^^^^^

View file

@ -16,7 +16,7 @@ LL | / fn clone_from(&mut self, source: &Self) {
LL | | source.clone(); LL | | source.clone();
LL | | *self = source.clone(); LL | | *self = source.clone();
LL | | } LL | | }
| |_____^ help: remove this | |_____^ help: remove it
error: incorrect implementation of `clone` on a `Copy` type error: incorrect implementation of `clone` on a `Copy` type
--> $DIR/incorrect_clone_impl_on_copy_type.rs:81:29 --> $DIR/incorrect_clone_impl_on_copy_type.rs:81:29
@ -34,7 +34,7 @@ LL | / fn clone_from(&mut self, source: &Self) {
LL | | source.clone(); LL | | source.clone();
LL | | *self = source.clone(); LL | | *self = source.clone();
LL | | } LL | | }
| |_____^ help: remove this | |_____^ help: remove it
error: aborting due to 4 previous errors error: aborting due to 4 previous errors

View file

@ -0,0 +1,114 @@
//@run-rustfix
#![allow(unused)]
#![no_main]
use std::cmp::Ordering;
// lint
#[derive(Eq, PartialEq)]
struct A(u32);
impl Ord for A {
fn cmp(&self, other: &Self) -> Ordering {
todo!();
}
}
impl PartialOrd for A {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}
// do not lint
#[derive(Eq, PartialEq)]
struct B(u32);
impl Ord for B {
fn cmp(&self, other: &Self) -> Ordering {
todo!();
}
}
impl PartialOrd for B {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
// lint, and give `_` a name
#[derive(Eq, PartialEq)]
struct C(u32);
impl Ord for C {
fn cmp(&self, other: &Self) -> Ordering {
todo!();
}
}
impl PartialOrd for C {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}
// do not lint derived
#[derive(Eq, Ord, PartialEq, PartialOrd)]
struct D(u32);
// do not lint if ord is not manually implemented
#[derive(Eq, PartialEq)]
struct E(u32);
impl PartialOrd for E {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
todo!();
}
}
// do not lint since ord has more restrictive bounds
#[derive(Eq, PartialEq)]
struct Uwu<A>(A);
impl<A: std::fmt::Debug + Ord + PartialOrd> Ord for Uwu<A> {
fn cmp(&self, other: &Self) -> Ordering {
todo!();
}
}
impl<A: Ord + PartialOrd> PartialOrd for Uwu<A> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
todo!();
}
}
// do not lint since `Rhs` is not `Self`
#[derive(Eq, PartialEq)]
struct F(u32);
impl Ord for F {
fn cmp(&self, other: &Self) -> Ordering {
todo!();
}
}
impl PartialOrd for F {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq<u32> for F {
fn eq(&self, other: &u32) -> bool {
todo!();
}
}
impl PartialOrd<u32> for F {
fn partial_cmp(&self, other: &u32) -> Option<Ordering> {
todo!();
}
}

View file

@ -0,0 +1,118 @@
//@run-rustfix
#![allow(unused)]
#![no_main]
use std::cmp::Ordering;
// lint
#[derive(Eq, PartialEq)]
struct A(u32);
impl Ord for A {
fn cmp(&self, other: &Self) -> Ordering {
todo!();
}
}
impl PartialOrd for A {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
todo!();
}
}
// do not lint
#[derive(Eq, PartialEq)]
struct B(u32);
impl Ord for B {
fn cmp(&self, other: &Self) -> Ordering {
todo!();
}
}
impl PartialOrd for B {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
// lint, and give `_` a name
#[derive(Eq, PartialEq)]
struct C(u32);
impl Ord for C {
fn cmp(&self, other: &Self) -> Ordering {
todo!();
}
}
impl PartialOrd for C {
fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
todo!();
}
}
// do not lint derived
#[derive(Eq, Ord, PartialEq, PartialOrd)]
struct D(u32);
// do not lint if ord is not manually implemented
#[derive(Eq, PartialEq)]
struct E(u32);
impl PartialOrd for E {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
todo!();
}
}
// do not lint since ord has more restrictive bounds
#[derive(Eq, PartialEq)]
struct Uwu<A>(A);
impl<A: std::fmt::Debug + Ord + PartialOrd> Ord for Uwu<A> {
fn cmp(&self, other: &Self) -> Ordering {
todo!();
}
}
impl<A: Ord + PartialOrd> PartialOrd for Uwu<A> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
todo!();
}
}
// do not lint since `Rhs` is not `Self`
#[derive(Eq, PartialEq)]
struct F(u32);
impl Ord for F {
fn cmp(&self, other: &Self) -> Ordering {
todo!();
}
}
impl PartialOrd for F {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq<u32> for F {
fn eq(&self, other: &u32) -> bool {
todo!();
}
}
impl PartialOrd<u32> for F {
fn partial_cmp(&self, other: &u32) -> Option<Ordering> {
todo!();
}
}

View file

@ -0,0 +1,31 @@
error: incorrect implementation of `partial_cmp` on an `Ord` type
--> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:18:1
|
LL | / impl PartialOrd for A {
LL | | fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
| | _____________________________________________________________-
LL | || todo!();
LL | || }
| ||_____- help: change this to: `{ Some(self.cmp(other)) }`
LL | | }
| |__^
|
= note: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default
error: incorrect implementation of `partial_cmp` on an `Ord` type
--> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:52:1
|
LL | / impl PartialOrd for C {
LL | | fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
LL | | todo!();
LL | | }
LL | | }
| |_^
|
help: change this to
|
LL | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
| ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 2 previous errors