From c8cd09a8e60ce2aae86963d3c8e7d63f33203f55 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 12 Jan 2024 15:37:43 +0100 Subject: [PATCH 1/2] Fix false positive in `PartialEq` check in `unconditional_recursion` lint --- clippy_lints/src/unconditional_recursion.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/unconditional_recursion.rs b/clippy_lints/src/unconditional_recursion.rs index e90306ded61c4..2c2830020872a 100644 --- a/clippy_lints/src/unconditional_recursion.rs +++ b/clippy_lints/src/unconditional_recursion.rs @@ -167,7 +167,15 @@ fn check_partial_eq(cx: &LateContext<'_>, method_span: Span, method_def_id: Loca false } }, - ExprKind::MethodCall(segment, _receiver, &[_arg], _) if segment.ident.name == name.name => { + ExprKind::MethodCall(segment, receiver, &[_arg], _) if segment.ident.name == name.name => { + if let Some(ty) = cx.typeck_results().expr_ty_opt(receiver) + && let Some(ty_id) = get_ty_def_id(ty) + && self_arg != ty_id + { + // Since this called on a different type, the lint should not be + // triggered here. + return; + } if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) && trait_id == trait_def_id From 132667288a6b9de113b03ffb82962c9ee8ab576d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 12 Jan 2024 15:38:07 +0100 Subject: [PATCH 2/2] Add regression ui test for `unconditional_recursion` lint on `PartialEq` --- tests/ui/unconditional_recursion.rs | 26 +++++++++++++++++++++++-- tests/ui/unconditional_recursion.stderr | 19 +++++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/tests/ui/unconditional_recursion.rs b/tests/ui/unconditional_recursion.rs index e1a2d6a90b896..7b898a6e0e784 100644 --- a/tests/ui/unconditional_recursion.rs +++ b/tests/ui/unconditional_recursion.rs @@ -264,6 +264,28 @@ impl S13 { } } -fn main() { - // test code goes here +struct S14 { + field: String, +} + +impl PartialEq for S14 { + fn eq(&self, other: &Self) -> bool { + // Should not warn! + self.field.eq(&other.field) + } +} + +struct S15<'a> { + field: &'a S15<'a>, } + +impl PartialEq for S15<'_> { + fn eq(&self, other: &Self) -> bool { + //~^ ERROR: function cannot return without recursing + let mine = &self.field; + let theirs = &other.field; + mine.eq(theirs) + } +} + +fn main() {} diff --git a/tests/ui/unconditional_recursion.stderr b/tests/ui/unconditional_recursion.stderr index 5d82e2a9f3194..094b80d4586c8 100644 --- a/tests/ui/unconditional_recursion.stderr +++ b/tests/ui/unconditional_recursion.stderr @@ -340,5 +340,22 @@ note: recursive call site LL | Self::default() | ^^^^^^^^^^^^^^^ -error: aborting due to 26 previous errors +error: function cannot return without recursing + --> $DIR/unconditional_recursion.rs:283:5 + | +LL | / fn eq(&self, other: &Self) -> bool { +LL | | +LL | | let mine = &self.field; +LL | | let theirs = &other.field; +LL | | mine.eq(theirs) +LL | | } + | |_____^ + | +note: recursive call site + --> $DIR/unconditional_recursion.rs:287:9 + | +LL | mine.eq(theirs) + | ^^^^^^^^^^^^^^^ + +error: aborting due to 27 previous errors