Skip to content

Commit 66c5738

Browse files
committed
extract helper functions
too many lines no more!
1 parent 8aae8a4 commit 66c5738

File tree

1 file changed

+113
-101
lines changed

1 file changed

+113
-101
lines changed

clippy_lints/src/non_canonical_impls.rs

Lines changed: 113 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use clippy_utils::{
55
};
66
use rustc_errors::Applicability;
77
use rustc_hir::def_id::LocalDefId;
8-
use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp};
8+
use rustc_hir::{Block, Body, Expr, ExprKind, ImplItem, ImplItemKind, Item, LangItem, Node, UnOp};
99
use rustc_lint::{LateContext, LateLintPass, LintContext};
10-
use rustc_middle::ty::EarlyBinder;
10+
use rustc_middle::ty::{EarlyBinder, TraitRef};
1111
use rustc_session::declare_lint_pass;
1212
use rustc_span::sym;
1313
use rustc_span::symbol::kw;
@@ -112,7 +112,6 @@ declare_clippy_lint! {
112112
declare_lint_pass!(NonCanonicalImpls => [NON_CANONICAL_CLONE_IMPL, NON_CANONICAL_PARTIAL_ORD_IMPL]);
113113

114114
impl LateLintPass<'_> for NonCanonicalImpls {
115-
#[expect(clippy::too_many_lines)]
116115
fn check_impl_item<'tcx>(&mut self, cx: &LateContext<'tcx>, impl_item: &ImplItem<'tcx>) {
117116
if let Node::Item(item) = cx.tcx.parent_hir_node(impl_item.hir_id())
118117
&& let Some(trait_impl) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::skip_binder)
@@ -128,114 +127,127 @@ impl LateLintPass<'_> for NonCanonicalImpls {
128127
&& let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy)
129128
&& implements_trait(cx, trait_impl.self_ty(), copy_def_id, &[])
130129
{
131-
if impl_item.ident.name == sym::clone {
132-
if block.stmts.is_empty()
133-
&& let Some(expr) = block.expr
134-
&& let ExprKind::Unary(UnOp::Deref, deref) = expr.kind
135-
&& let ExprKind::Path(qpath) = deref.kind
136-
&& last_path_segment(&qpath).ident.name == kw::SelfLower
137-
{
138-
} else {
139-
span_lint_and_sugg(
140-
cx,
141-
NON_CANONICAL_CLONE_IMPL,
142-
block.span,
143-
"non-canonical implementation of `clone` on a `Copy` type",
144-
"change this to",
145-
"{ *self }".to_owned(),
146-
Applicability::MaybeIncorrect,
147-
);
148-
149-
return;
150-
}
151-
}
152-
153-
if impl_item.ident.name == sym::clone_from {
154-
span_lint_and_sugg(
155-
cx,
156-
NON_CANONICAL_CLONE_IMPL,
157-
impl_item.span,
158-
"unnecessary implementation of `clone_from` on a `Copy` type",
159-
"remove it",
160-
String::new(),
161-
Applicability::MaybeIncorrect,
162-
);
163-
}
130+
check_clone_on_copy(cx, impl_item, block);
164131
} else if trait_name == Some(sym::PartialOrd)
165132
&& impl_item.ident.name == sym::partial_cmp
166133
&& let Some(ord_def_id) = cx.tcx.get_diagnostic_item(sym::Ord)
167134
&& implements_trait(cx, trait_impl.self_ty(), ord_def_id, &[])
168135
{
169-
// If the `cmp` call likely needs to be fully qualified in the suggestion
170-
// (like `std::cmp::Ord::cmp`). It's unfortunate we must put this here but we can't
171-
// access `cmp_expr` in the suggestion without major changes, as we lint in `else`.
172-
let mut needs_fully_qualified = false;
136+
check_partial_ord_on_ord(cx, impl_item, item, &trait_impl, body, block);
137+
}
138+
}
139+
}
140+
}
173141

174-
if block.stmts.is_empty()
175-
&& let Some(expr) = block.expr
176-
&& expr_is_cmp(cx, expr, impl_item, &mut needs_fully_qualified)
177-
{
178-
return;
179-
}
180-
// Fix #12683, allow [`needless_return`] here
181-
else if block.expr.is_none()
182-
&& let Some(stmt) = block.stmts.first()
183-
&& let rustc_hir::StmtKind::Semi(Expr {
184-
kind: ExprKind::Ret(Some(ret)),
185-
..
186-
}) = stmt.kind
187-
&& expr_is_cmp(cx, ret, impl_item, &mut needs_fully_qualified)
188-
{
189-
return;
190-
}
191-
// If `Self` and `Rhs` are not the same type, bail. This makes creating a valid
192-
// suggestion tons more complex.
193-
else if let [lhs, rhs, ..] = trait_impl.args.as_slice()
194-
&& lhs != rhs
195-
{
196-
return;
197-
}
142+
fn check_clone_on_copy(cx: &LateContext<'_>, impl_item: &ImplItem<'_>, block: &Block<'_>) {
143+
if impl_item.ident.name == sym::clone {
144+
if block.stmts.is_empty()
145+
&& let Some(expr) = block.expr
146+
&& let ExprKind::Unary(UnOp::Deref, deref) = expr.kind
147+
&& let ExprKind::Path(qpath) = deref.kind
148+
&& last_path_segment(&qpath).ident.name == kw::SelfLower
149+
{
150+
} else {
151+
span_lint_and_sugg(
152+
cx,
153+
NON_CANONICAL_CLONE_IMPL,
154+
block.span,
155+
"non-canonical implementation of `clone` on a `Copy` type",
156+
"change this to",
157+
"{ *self }".to_owned(),
158+
Applicability::MaybeIncorrect,
159+
);
160+
}
161+
}
198162

199-
span_lint_and_then(
200-
cx,
201-
NON_CANONICAL_PARTIAL_ORD_IMPL,
202-
item.span,
203-
"non-canonical implementation of `partial_cmp` on an `Ord` type",
204-
|diag| {
205-
let [_, other] = body.params else {
206-
return;
207-
};
208-
let Some(std_or_core) = std_or_core(cx) else {
209-
return;
210-
};
163+
if impl_item.ident.name == sym::clone_from {
164+
span_lint_and_sugg(
165+
cx,
166+
NON_CANONICAL_CLONE_IMPL,
167+
impl_item.span,
168+
"unnecessary implementation of `clone_from` on a `Copy` type",
169+
"remove it",
170+
String::new(),
171+
Applicability::MaybeIncorrect,
172+
);
173+
}
174+
}
211175

212-
let suggs = match (other.pat.simple_ident(), needs_fully_qualified) {
213-
(Some(other_ident), true) => vec![(
214-
block.span,
215-
format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, {})) }}", other_ident.name),
216-
)],
217-
(Some(other_ident), false) => {
218-
vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))]
219-
},
220-
(None, true) => vec![
221-
(
222-
block.span,
223-
format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, other)) }}"),
224-
),
225-
(other.pat.span, "other".to_owned()),
226-
],
227-
(None, false) => vec![
228-
(block.span, "{ Some(self.cmp(other)) }".to_owned()),
229-
(other.pat.span, "other".to_owned()),
230-
],
231-
};
176+
fn check_partial_ord_on_ord<'tcx>(
177+
cx: &LateContext<'tcx>,
178+
impl_item: &ImplItem<'_>,
179+
item: &Item<'_>,
180+
trait_impl: &TraitRef<'_>,
181+
body: &Body<'_>,
182+
block: &Block<'tcx>,
183+
) {
184+
// If the `cmp` call likely needs to be fully qualified in the suggestion
185+
// (like `std::cmp::Ord::cmp`). It's unfortunate we must put this here but we can't
186+
// access `cmp_expr` in the suggestion without major changes, as we lint in `else`.
232187

233-
diag.multipart_suggestion("change this to", suggs, Applicability::Unspecified);
234-
},
235-
);
236-
}
237-
}
188+
let mut needs_fully_qualified = false;
189+
if block.stmts.is_empty()
190+
&& let Some(expr) = block.expr
191+
&& expr_is_cmp(cx, expr, impl_item, &mut needs_fully_qualified)
192+
{
193+
return;
194+
}
195+
// Fix #12683, allow [`needless_return`] here
196+
else if block.expr.is_none()
197+
&& let Some(stmt) = block.stmts.first()
198+
&& let rustc_hir::StmtKind::Semi(Expr {
199+
kind: ExprKind::Ret(Some(ret)),
200+
..
201+
}) = stmt.kind
202+
&& expr_is_cmp(cx, ret, impl_item, &mut needs_fully_qualified)
203+
{
204+
return;
205+
}
206+
// If `Self` and `Rhs` are not the same type, bail. This makes creating a valid
207+
// suggestion tons more complex.
208+
else if let [lhs, rhs, ..] = trait_impl.args.as_slice()
209+
&& lhs != rhs
210+
{
211+
return;
238212
}
213+
214+
span_lint_and_then(
215+
cx,
216+
NON_CANONICAL_PARTIAL_ORD_IMPL,
217+
item.span,
218+
"non-canonical implementation of `partial_cmp` on an `Ord` type",
219+
|diag| {
220+
let [_, other] = body.params else {
221+
return;
222+
};
223+
let Some(std_or_core) = std_or_core(cx) else {
224+
return;
225+
};
226+
227+
let suggs = match (other.pat.simple_ident(), needs_fully_qualified) {
228+
(Some(other_ident), true) => vec![(
229+
block.span,
230+
format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, {})) }}", other_ident.name),
231+
)],
232+
(Some(other_ident), false) => {
233+
vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))]
234+
},
235+
(None, true) => vec![
236+
(
237+
block.span,
238+
format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, other)) }}"),
239+
),
240+
(other.pat.span, "other".to_owned()),
241+
],
242+
(None, false) => vec![
243+
(block.span, "{ Some(self.cmp(other)) }".to_owned()),
244+
(other.pat.span, "other".to_owned()),
245+
],
246+
};
247+
248+
diag.multipart_suggestion("change this to", suggs, Applicability::Unspecified);
249+
},
250+
);
239251
}
240252

241253
/// Return true if `expr_kind` is a `cmp` call.

0 commit comments

Comments
 (0)