Skip to content

Commit cfcf04b

Browse files
committed
heavily refactor + bump clippy::version
1 parent aa74b29 commit cfcf04b

13 files changed

+261
-177
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -4918,7 +4918,6 @@ Released 2018-09-13
49184918
[`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back
49194919
[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
49204920
[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
4921-
[`manual_partial_ord_and_ord_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_partial_ord_and_ord_impl
49224921
[`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
49234922
[`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid
49244923
[`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain
@@ -5014,6 +5013,7 @@ Released 2018-09-13
50145013
[`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref
50155014
[`needless_option_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_take
50165015
[`needless_parens_on_range_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_parens_on_range_literals
5016+
[`needless_partial_ord_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_partial_ord_impl
50175017
[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
50185018
[`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark
50195019
[`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop

clippy_lints/src/declared_lints.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
274274
crate::manual_let_else::MANUAL_LET_ELSE_INFO,
275275
crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
276276
crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO,
277-
crate::manual_partial_ord_and_ord_impl::MANUAL_PARTIAL_ORD_AND_ORD_IMPL_INFO,
278277
crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
279278
crate::manual_retain::MANUAL_RETAIN_INFO,
280279
crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO,
@@ -459,6 +458,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
459458
crate::needless_continue::NEEDLESS_CONTINUE_INFO,
460459
crate::needless_else::NEEDLESS_ELSE_INFO,
461460
crate::needless_for_each::NEEDLESS_FOR_EACH_INFO,
461+
crate::needless_impls::NEEDLESS_PARTIAL_ORD_IMPL_INFO,
462462
crate::needless_late_init::NEEDLESS_LATE_INIT_INFO,
463463
crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO,
464464
crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO,

clippy_lints/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ mod manual_is_ascii_check;
185185
mod manual_let_else;
186186
mod manual_main_separator_str;
187187
mod manual_non_exhaustive;
188-
mod manual_partial_ord_and_ord_impl;
189188
mod manual_rem_euclid;
190189
mod manual_retain;
191190
mod manual_slice_size_calculation;
@@ -223,6 +222,7 @@ mod needless_borrowed_ref;
223222
mod needless_continue;
224223
mod needless_else;
225224
mod needless_for_each;
225+
mod needless_impls;
226226
mod needless_late_init;
227227
mod needless_parens_on_range_literals;
228228
mod needless_pass_by_value;
@@ -1022,7 +1022,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10221022
store.register_late_pass(|_| Box::new(endian_bytes::EndianBytes));
10231023
store.register_late_pass(|_| Box::new(redundant_type_annotations::RedundantTypeAnnotations));
10241024
store.register_late_pass(|_| Box::new(arc_with_non_send_sync::ArcWithNonSendSync));
1025-
store.register_late_pass(|_| Box::new(manual_partial_ord_and_ord_impl::ManualPartialOrdAndOrdImpl));
1025+
store.register_late_pass(|_| Box::new(needless_impls::NeedlessImpls));
10261026
// add lints here, do not remove this comment, it's used in `new_lint`
10271027
}
10281028

clippy_lints/src/manual_partial_ord_and_ord_impl.rs

-139
This file was deleted.

clippy_lints/src/needless_impls.rs

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
use clippy_utils::{diagnostics::span_lint_and_then, get_parent_node, match_qpath, path_res, ty::implements_trait};
2+
use rustc_errors::Applicability;
3+
use rustc_hir::{def::Res, Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, Node, PatKind};
4+
use rustc_hir_analysis::hir_ty_to_ty;
5+
use rustc_lint::{LateContext, LateLintPass};
6+
use rustc_middle::ty::EarlyBinder;
7+
use rustc_session::{declare_lint_pass, declare_tool_lint};
8+
use rustc_span::sym;
9+
use std::borrow::Cow;
10+
11+
declare_clippy_lint! {
12+
/// ### What it does
13+
/// Checks for manual implementations of both `PartialOrd` and `Ord` when only `Ord` is
14+
/// necessary.
15+
///
16+
/// ### Why is this bad?
17+
/// If both `PartialOrd` and `Ord` are implemented, they must agree. This is commonly done by
18+
/// wrapping the result of `cmp` in `Some` for `partial_cmp`. Not doing this may silently
19+
/// introduce an error upon refactoring.
20+
///
21+
/// ### Example
22+
/// ```rust,ignore
23+
/// #[derive(Eq, PartialEq)]
24+
/// struct A(u32);
25+
///
26+
/// impl Ord for A {
27+
/// fn cmp(&self, other: &Self) -> Ordering {
28+
/// todo!();
29+
/// }
30+
/// }
31+
///
32+
/// impl PartialOrd for A {
33+
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
34+
/// todo!();
35+
/// }
36+
/// }
37+
/// ```
38+
/// Use instead:
39+
/// ```rust,ignore
40+
/// #[derive(Eq, PartialEq)]
41+
/// struct A(u32);
42+
///
43+
/// impl Ord for A {
44+
/// fn cmp(&self, other: &Self) -> Ordering {
45+
/// todo!();
46+
/// }
47+
/// }
48+
///
49+
/// impl PartialOrd for A {
50+
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
51+
/// Some(self.cmp(other))
52+
/// }
53+
/// }
54+
/// ```
55+
#[clippy::version = "1.72.0"]
56+
pub NEEDLESS_PARTIAL_ORD_IMPL,
57+
correctness,
58+
"manual implementation of `PartialOrd` when `Ord` is already implemented"
59+
}
60+
declare_lint_pass!(NeedlessImpls => [NEEDLESS_PARTIAL_ORD_IMPL]);
61+
62+
impl LateLintPass<'_> for NeedlessImpls {
63+
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
64+
let node = get_parent_node(cx.tcx, impl_item.hir_id());
65+
let Some(Node::Item(item)) = node else {
66+
return;
67+
};
68+
let ItemKind::Impl(imp) = item.kind else {
69+
return;
70+
};
71+
let Some(trait_impl) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::skip_binder) else {
72+
return;
73+
};
74+
let trait_impl_def_id = trait_impl.def_id;
75+
if cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) {
76+
return;
77+
}
78+
let ImplItemKind::Fn(_, impl_item_id) = cx.tcx.hir().impl_item(impl_item.impl_item_id()).kind else {
79+
return;
80+
};
81+
let body = cx.tcx.hir().body(impl_item_id);
82+
let ExprKind::Block(block, ..) = body.value.kind else {
83+
return;
84+
};
85+
86+
if cx.tcx.is_diagnostic_item(sym::PartialOrd, trait_impl_def_id)
87+
&& impl_item.ident.name == sym::partial_cmp
88+
&& let Some(ord_def_id) = cx
89+
.tcx
90+
.diagnostic_items(trait_impl.def_id.krate)
91+
.name_to_id
92+
.get(&sym::Ord)
93+
&& implements_trait(
94+
cx,
95+
hir_ty_to_ty(cx.tcx, imp.self_ty),
96+
*ord_def_id,
97+
trait_impl.substs,
98+
)
99+
{
100+
if block.stmts.is_empty()
101+
&& let Some(expr) = block.expr
102+
&& let ExprKind::Call(Expr { kind: ExprKind::Path(some_path), .. }, [cmp_expr]) = expr.kind
103+
// TODO: We can likely use the `option_some_variant` lang item instead, but this may be tricky
104+
// due to the fact that `expr` is the constructor, not `option_some_variant` itself.
105+
&& match_qpath(some_path, &["Some"])
106+
&& let ExprKind::MethodCall(cmp_path, _, [other_expr], ..) = cmp_expr.kind
107+
&& cmp_path.ident.name == sym::cmp
108+
&& let Res::Local(..) = path_res(cx, other_expr)
109+
{} else {
110+
span_lint_and_then(
111+
cx,
112+
NEEDLESS_PARTIAL_ORD_IMPL,
113+
item.span,
114+
"manual implementation of `PartialOrd` when `Ord` is already implemented",
115+
|diag| {
116+
let (help, app) = if let Some(other) = body.params.get(0)
117+
&& let PatKind::Binding(_, _, other_ident, ..) = other.pat.kind
118+
{
119+
(
120+
Cow::Owned(format!("{{ Some(self.cmp({})) }}", other_ident.name)),
121+
Applicability::Unspecified,
122+
)
123+
} else {
124+
(Cow::Borrowed("{ Some(self.cmp(...)) }"), Applicability::HasPlaceholders)
125+
};
126+
127+
diag.span_suggestion(
128+
block.span,
129+
"change this to",
130+
help,
131+
app,
132+
);
133+
}
134+
);
135+
}
136+
}
137+
}
138+
}

tests/ui/bool_comparison.fixed

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//@run-rustfix
22

33
#![warn(clippy::bool_comparison)]
4-
#![allow(clippy::manual_partial_ord_and_ord_impl)]
4+
#![allow(clippy::needless_partial_ord_impl)]
55

66
fn main() {
77
let x = true;

tests/ui/bool_comparison.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//@run-rustfix
22

33
#![warn(clippy::bool_comparison)]
4-
#![allow(clippy::manual_partial_ord_and_ord_impl)]
4+
#![allow(clippy::needless_partial_ord_impl)]
55

66
fn main() {
77
let x = true;

tests/ui/derive.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![allow(dead_code)]
1+
#![allow(clippy::needless_partial_ord_impl, dead_code)]
22
#![warn(clippy::expl_impl_clone_on_copy)]
33

44
#[derive(Copy)]

tests/ui/derive_ord_xor_partial_ord.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![warn(clippy::derive_ord_xor_partial_ord)]
22
#![allow(clippy::unnecessary_wraps)]
3-
#![allow(clippy::manual_partial_ord_and_ord_impl)]
3+
#![allow(clippy::needless_partial_ord_impl)]
44

55
use std::cmp::Ordering;
66

tests/ui/manual_partial_ord_and_ord_impl.stderr

-28
This file was deleted.

0 commit comments

Comments
 (0)