Skip to content

Commit 004e89d

Browse files
committed
rename to manual_partial_ord_and_ord_impl
cargo dev fmt cargo test passes cargo test passes refactor a lil Update bool_comparison.stderr heavily refactor + bump `clippy::version` refactor refactor check bounds to increase accuracy, and add todos
1 parent 2a1fd22 commit 004e89d

14 files changed

+328
-195
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4921,7 +4921,6 @@ Released 2018-09-13
49214921
[`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back
49224922
[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
49234923
[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
4924-
[`manual_partial_ord_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_partial_ord_impl
49254924
[`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
49264925
[`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns
49274926
[`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid
@@ -5021,6 +5020,7 @@ Released 2018-09-13
50215020
[`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref
50225021
[`needless_option_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_take
50235022
[`needless_parens_on_range_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_parens_on_range_literals
5023+
[`needless_partial_ord_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_partial_ord_impl
50245024
[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
50255025
[`needless_pub_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pub_self
50265026
[`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
277277
crate::manual_let_else::MANUAL_LET_ELSE_INFO,
278278
crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
279279
crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO,
280-
crate::manual_partial_ord_impl::MANUAL_PARTIAL_ORD_IMPL_INFO,
281280
crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO,
282281
crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
283282
crate::manual_retain::MANUAL_RETAIN_INFO,
@@ -470,6 +469,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
470469
crate::needless_else::NEEDLESS_ELSE_INFO,
471470
crate::needless_for_each::NEEDLESS_FOR_EACH_INFO,
472471
crate::needless_if::NEEDLESS_IF_INFO,
472+
crate::needless_impls::NEEDLESS_PARTIAL_ORD_IMPL_INFO,
473473
crate::needless_late_init::NEEDLESS_LATE_INIT_INFO,
474474
crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO,
475475
crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO,

clippy_lints/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ mod manual_is_ascii_check;
188188
mod manual_let_else;
189189
mod manual_main_separator_str;
190190
mod manual_non_exhaustive;
191-
mod manual_partial_ord_impl;
192191
mod manual_range_patterns;
193192
mod manual_rem_euclid;
194193
mod manual_retain;
@@ -228,6 +227,7 @@ mod needless_continue;
228227
mod needless_else;
229228
mod needless_for_each;
230229
mod needless_if;
230+
mod needless_impls;
231231
mod needless_late_init;
232232
mod needless_parens_on_range_literals;
233233
mod needless_pass_by_value;

clippy_lints/src/manual_partial_ord_impl.rs

Lines changed: 0 additions & 132 deletions
This file was deleted.

clippy_lints/src/needless_impls.rs

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

tests/ui/bool_comparison.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#![allow(clippy::needless_if)]
44
#![warn(clippy::bool_comparison)]
5+
#![allow(clippy::needless_partial_ord_impl)]
56

67
fn main() {
78
let x = true;

tests/ui/bool_comparison.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#![allow(clippy::needless_if)]
44
#![warn(clippy::bool_comparison)]
5+
#![allow(clippy::needless_partial_ord_impl)]
56

67
fn main() {
78
let x = true;

0 commit comments

Comments
 (0)