Skip to content

Commit aa74b29

Browse files
committed
refactor
1 parent dfe63da commit aa74b29

File tree

2 files changed

+18
-29
lines changed

2 files changed

+18
-29
lines changed

clippy_lints/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1022,6 +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));
10251026
// add lints here, do not remove this comment, it's used in `new_lint`
10261027
}
10271028

clippy_lints/src/manual_partial_ord_and_ord_impl.rs

+17-29
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
2-
use clippy_utils::{get_trait_def_id, match_qpath, path_res, ty::implements_trait};
2+
use clippy_utils::{match_qpath, path_res, ty::implements_trait};
33
use rustc_errors::Applicability;
44
use rustc_hir::def::Res;
55
use rustc_hir::{Expr, ExprKind, Impl, ImplItemKind, Item, ItemKind, PatKind};
66
use rustc_hir_analysis::hir_ty_to_ty;
77
use rustc_lint::{LateContext, LateLintPass};
88
use rustc_middle::ty::{EarlyBinder, TraitRef};
9-
use rustc_session::{declare_tool_lint, impl_lint_pass};
10-
use rustc_span::def_id::DefId;
9+
use rustc_session::{declare_lint_pass, declare_tool_lint};
1110
use rustc_span::sym;
12-
use std::cell::OnceCell;
1311

1412
declare_clippy_lint! {
1513
/// ### What it does
1614
/// Checks for manual implementations of both `PartialOrd` and `Ord` when only `Ord` is
1715
/// necessary.
1816
///
1917
/// ### Why is this bad?
20-
/// If both `PartialOrd` and `Ord` are implemented, `PartialOrd` will wrap the returned value of
21-
/// `Ord::cmp` in `Some`. Not doing this may silently introduce an error upon refactoring.
18+
/// If both `PartialOrd` and `Ord` are implemented, they must agree. This is commonly done by
19+
/// wrapping the result of `cmp` in `Some` for `partial_cmp`. Not doing this may silently
20+
/// introduce an error upon refactoring.
2221
///
2322
/// ### Example
2423
/// ```rust,ignore
@@ -59,15 +58,7 @@ declare_clippy_lint! {
5958
correctness,
6059
"manual implementation of `PartialOrd` when `Ord` is already implemented"
6160
}
62-
impl_lint_pass!(ManualPartialOrdAndOrdImpl => [MANUAL_PARTIAL_ORD_AND_ORD_IMPL]);
63-
64-
#[derive(Clone)]
65-
pub struct ManualPartialOrdAndOrdImpl {
66-
pub ord_def_id: OnceCell<DefId>,
67-
}
68-
69-
// TODO: The number of if_chain! calls makes this is a bit hard to follow, can that be reduced?
70-
// or more generally, can this be done cleaner?
61+
declare_lint_pass!(ManualPartialOrdAndOrdImpl => [MANUAL_PARTIAL_ORD_AND_ORD_IMPL]);
7162

7263
impl LateLintPass<'_> for ManualPartialOrdAndOrdImpl {
7364
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
@@ -78,28 +69,25 @@ impl LateLintPass<'_> for ManualPartialOrdAndOrdImpl {
7869
if cx.tcx.is_diagnostic_item(sym::PartialOrd, partial_ord_def_id);
7970
if !cx.tcx.is_automatically_derived(item.owner_id.to_def_id());
8071
then {
81-
lint_impl_body(self, cx, imp, item, impl_trait_ref);
72+
lint_impl_body(cx, imp, item, impl_trait_ref);
8273
}
8374
}
8475
}
8576
}
8677

87-
#[allow(clippy::unnecessary_def_path)] // ???
88-
fn lint_impl_body<'tcx>(
89-
conf: &mut ManualPartialOrdAndOrdImpl,
90-
cx: &LateContext<'tcx>,
91-
imp: &Impl<'_>,
92-
item: &Item<'_>,
93-
impl_trait_ref: TraitRef<'tcx>,
94-
) {
78+
fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, imp: &Impl<'_>, item: &Item<'_>, impl_trait_ref: TraitRef<'tcx>) {
9579
for imp_item in imp.items {
9680
if_chain! {
9781
if imp_item.ident.name == sym::partial_cmp;
9882
if let ImplItemKind::Fn(_, id) = cx.tcx.hir().impl_item(imp_item.id).kind;
9983
then {
10084
let body = cx.tcx.hir().body(id);
101-
// TODO: This can't be changed without causing compilation to fail
102-
let ord_def_id = conf.ord_def_id.get_or_init(|| get_trait_def_id(cx, &["core", "cmp", "Ord"]).unwrap());
85+
let ord_def_id = cx
86+
.tcx
87+
.diagnostic_items(impl_trait_ref.def_id.krate)
88+
.name_to_id
89+
.get(&sym::Ord)
90+
.unwrap();
10391
if let ExprKind::Block(block, ..) = body.value.kind && implements_trait(
10492
cx,
10593
hir_ty_to_ty(cx.tcx, imp.self_ty),
@@ -111,11 +99,12 @@ fn lint_impl_body<'tcx>(
11199
if block.stmts.is_empty();
112100
if let Some(expr) = block.expr;
113101
if let ExprKind::Call(Expr { kind: ExprKind::Path(some_path), ..}, [cmp_expr]) = expr.kind;
102+
// TODO: We can likely use the `option_some_variant` lang item instead, but this may be tricky
103+
// due to the fact that `expr` is the constructor, not `option_some_variant` itself.
114104
if match_qpath(some_path, &["Some"]);
115105
if let ExprKind::MethodCall(cmp_path, _, [other_expr], ..) = cmp_expr.kind;
116106
if cmp_path.ident.name == sym::cmp;
117107
if let Res::Local(..) = path_res(cx, other_expr);
118-
// TODO: Self explanatory
119108
then {}
120109
else {
121110
span_lint_and_then(
@@ -134,8 +123,7 @@ fn lint_impl_body<'tcx>(
134123
block.span,
135124
"change this to",
136125
format!("{{ Some(self.cmp({})) }}", param_ident.name),
137-
// TODO: This is always correct afaik.
138-
Applicability::MaybeIncorrect
126+
Applicability::Unspecified,
139127
);
140128
} else {
141129
diag.help("return the value of `self.cmp` wrapped in `Some` instead");

0 commit comments

Comments
 (0)