Also check code generated by macros

This commit is contained in:
Guillaume Gomez 2023-12-16 18:15:32 +01:00
parent 91fd01c31c
commit 6b444f3092
3 changed files with 104 additions and 110 deletions

View file

@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{get_parent_as_impl, get_trait_def_id, path_res};
use clippy_utils::{get_trait_def_id, path_res};
use rustc_ast::BinOpKind;
use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, Expr, ExprKind, FnDecl};
use rustc_hir::{Body, Expr, ExprKind, FnDecl, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::declare_lint_pass;
@ -66,22 +66,32 @@ impl<'tcx> LateLintPass<'tcx> for UnconditionalRecursion {
method_span: Span,
def_id: LocalDefId,
) {
// We don't check code generated from (proc) macro.
if method_span.from_expansion() {
return;
}
// If the function is a method...
if let FnKind::Method(name, _) = kind
// That has two arguments.
&& let [self_arg, other_arg] = cx
.tcx
.instantiate_bound_regions_with_erased(cx.tcx.fn_sig(def_id).skip_binder())
.inputs()
&& let Some(self_arg) = get_ty_def_id(*self_arg)
&& let Some(other_arg) = get_ty_def_id(*other_arg)
// The two arguments are of the same type.
&& self_arg == other_arg
&& let hir_id = cx.tcx.local_def_id_to_hir_id(def_id)
&& let Some(impl_) = get_parent_as_impl(cx.tcx, hir_id)
&& let Some((
_,
Node::Item(Item {
kind: ItemKind::Impl(impl_),
owner_id,
..
}),
)) = cx.tcx.hir().parent_iter(hir_id).next()
// We exclude `impl` blocks generated from rustc's proc macros.
&& !cx.tcx.has_attr(*owner_id, sym::automatically_derived)
// It is a implementation of a trait.
&& let Some(trait_) = impl_.of_trait
&& let Some(trait_def_id) = trait_.trait_def_id()
// The trait is `PartialEq`.
&& Some(trait_def_id) == get_trait_def_id(cx, &["core", "cmp", "PartialEq"])
{
let to_check_op = if name.name == sym::eq {

View file

@ -1,6 +1,7 @@
//@no-rustfix
#![warn(clippy::unconditional_recursion)]
#![allow(clippy::partialeq_ne_impl)]
enum Foo {
A,
@ -123,6 +124,40 @@ impl PartialEq for S3 {
}
}
// There should be no warning here!
#[derive(PartialEq)]
enum E {
A,
B,
}
#[derive(PartialEq)]
struct Bar<T: PartialEq>(T);
struct S4;
impl PartialEq for S4 {
fn eq(&self, other: &Self) -> bool {
// No warning here.
Bar(self) == Bar(other)
}
}
macro_rules! impl_partial_eq {
($ty:ident) => {
impl PartialEq for $ty {
fn eq(&self, other: &Self) -> bool {
self == other
}
}
};
}
struct S5;
impl_partial_eq!(S5);
//~^ ERROR: function cannot return without recursing
fn main() {
// test code goes here
}

View file

@ -1,5 +1,5 @@
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:41:5
--> $DIR/unconditional_recursion.rs:42:5
|
LL | fn ne(&self, other: &Self) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@ -12,7 +12,7 @@ LL | self.ne(other)
= help: to override `-D warnings` add `#[allow(unconditional_recursion)]`
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:45:5
--> $DIR/unconditional_recursion.rs:46:5
|
LL | fn eq(&self, other: &Self) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@ -22,20 +22,8 @@ LL | self.eq(other)
|
= help: a `loop` may express intention better if this is on purpose
error: re-implementing `PartialEq::ne` is unnecessary
--> $DIR/unconditional_recursion.rs:11:5
|
LL | / fn ne(&self, other: &Self) -> bool {
LL | |
LL | | self != other
LL | | }
| |_____^
|
= note: `-D clippy::partialeq-ne-impl` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::partialeq_ne_impl)]`
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:11:5
--> $DIR/unconditional_recursion.rs:12:5
|
LL | / fn ne(&self, other: &Self) -> bool {
LL | |
@ -44,7 +32,7 @@ LL | | }
| |_____^
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:13:9
--> $DIR/unconditional_recursion.rs:14:9
|
LL | self != other
| ^^^^^^^^^^^^^
@ -52,7 +40,7 @@ LL | self != other
= help: to override `-D warnings` add `#[allow(clippy::unconditional_recursion)]`
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:15:5
--> $DIR/unconditional_recursion.rs:16:5
|
LL | / fn eq(&self, other: &Self) -> bool {
LL | |
@ -61,30 +49,13 @@ LL | | }
| |_____^
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:17:9
--> $DIR/unconditional_recursion.rs:18:9
|
LL | self == other
| ^^^^^^^^^^^^^
error: re-implementing `PartialEq::ne` is unnecessary
--> $DIR/unconditional_recursion.rs:27:5
|
LL | / fn ne(&self, other: &Self) -> bool {
LL | | self != &Foo2::B // no error here
LL | | }
| |_____^
error: re-implementing `PartialEq::ne` is unnecessary
--> $DIR/unconditional_recursion.rs:41:5
|
LL | / fn ne(&self, other: &Self) -> bool {
LL | |
LL | | self.ne(other)
LL | | }
| |_____^
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:41:5
--> $DIR/unconditional_recursion.rs:42:5
|
LL | / fn ne(&self, other: &Self) -> bool {
LL | |
@ -93,19 +64,19 @@ LL | | }
| |_____^
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:43:9
--> $DIR/unconditional_recursion.rs:44:9
|
LL | self.ne(other)
| ^^^^^^^^^^^^^^
error: parameter is only used in recursion
--> $DIR/unconditional_recursion.rs:41:18
--> $DIR/unconditional_recursion.rs:42:18
|
LL | fn ne(&self, other: &Self) -> bool {
| ^^^^^ help: if this is intentional, prefix it with an underscore: `_other`
|
note: parameter used here
--> $DIR/unconditional_recursion.rs:43:17
--> $DIR/unconditional_recursion.rs:44:17
|
LL | self.ne(other)
| ^^^^^
@ -113,7 +84,7 @@ LL | self.ne(other)
= help: to override `-D warnings` add `#[allow(clippy::only_used_in_recursion)]`
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:45:5
--> $DIR/unconditional_recursion.rs:46:5
|
LL | / fn eq(&self, other: &Self) -> bool {
LL | |
@ -122,50 +93,25 @@ LL | | }
| |_____^
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:47:9
--> $DIR/unconditional_recursion.rs:48:9
|
LL | self.eq(other)
| ^^^^^^^^^^^^^^
error: parameter is only used in recursion
--> $DIR/unconditional_recursion.rs:45:18
--> $DIR/unconditional_recursion.rs:46:18
|
LL | fn eq(&self, other: &Self) -> bool {
| ^^^^^ help: if this is intentional, prefix it with an underscore: `_other`
|
note: parameter used here
--> $DIR/unconditional_recursion.rs:47:17
--> $DIR/unconditional_recursion.rs:48:17
|
LL | self.eq(other)
| ^^^^^
error: re-implementing `PartialEq::ne` is unnecessary
--> $DIR/unconditional_recursion.rs:57:5
|
LL | / fn ne(&self, other: &Self) -> bool {
LL | | self.eq(other) // no error
LL | | }
| |_____^
error: re-implementing `PartialEq::ne` is unnecessary
--> $DIR/unconditional_recursion.rs:77:5
|
LL | / fn ne(&self, other: &Self) -> bool {
LL | | self.a() // no error
LL | | }
| |_____^
error: re-implementing `PartialEq::ne` is unnecessary
--> $DIR/unconditional_recursion.rs:89:5
|
LL | / fn ne(&self, other: &Self) -> bool {
LL | |
LL | | other != self
LL | | }
| |_____^
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:89:5
--> $DIR/unconditional_recursion.rs:90:5
|
LL | / fn ne(&self, other: &Self) -> bool {
LL | |
@ -174,13 +120,13 @@ LL | | }
| |_____^
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:91:9
--> $DIR/unconditional_recursion.rs:92:9
|
LL | other != self
| ^^^^^^^^^^^^^
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:93:5
--> $DIR/unconditional_recursion.rs:94:5
|
LL | / fn eq(&self, other: &Self) -> bool {
LL | |
@ -189,22 +135,13 @@ LL | | }
| |_____^
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:95:9
--> $DIR/unconditional_recursion.rs:96:9
|
LL | other == self
| ^^^^^^^^^^^^^
error: re-implementing `PartialEq::ne` is unnecessary
--> $DIR/unconditional_recursion.rs:103:5
|
LL | / fn ne(&self, other: &Self) -> bool {
LL | |
LL | | other != other
LL | | }
| |_____^
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:103:5
--> $DIR/unconditional_recursion.rs:104:5
|
LL | / fn ne(&self, other: &Self) -> bool {
LL | |
@ -213,13 +150,13 @@ LL | | }
| |_____^
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:105:9
--> $DIR/unconditional_recursion.rs:106:9
|
LL | other != other
| ^^^^^^^^^^^^^^
error: equal expressions as operands to `!=`
--> $DIR/unconditional_recursion.rs:105:9
--> $DIR/unconditional_recursion.rs:106:9
|
LL | other != other
| ^^^^^^^^^^^^^^
@ -227,7 +164,7 @@ LL | other != other
= note: `#[deny(clippy::eq_op)]` on by default
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:107:5
--> $DIR/unconditional_recursion.rs:108:5
|
LL | / fn eq(&self, other: &Self) -> bool {
LL | |
@ -236,28 +173,19 @@ LL | | }
| |_____^
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:109:9
--> $DIR/unconditional_recursion.rs:110:9
|
LL | other == other
| ^^^^^^^^^^^^^^
error: equal expressions as operands to `==`
--> $DIR/unconditional_recursion.rs:109:9
--> $DIR/unconditional_recursion.rs:110:9
|
LL | other == other
| ^^^^^^^^^^^^^^
error: re-implementing `PartialEq::ne` is unnecessary
--> $DIR/unconditional_recursion.rs:116:5
|
LL | / fn ne(&self, _other: &Self) -> bool {
LL | |
LL | | self != self
LL | | }
| |_____^
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:116:5
--> $DIR/unconditional_recursion.rs:117:5
|
LL | / fn ne(&self, _other: &Self) -> bool {
LL | |
@ -266,19 +194,19 @@ LL | | }
| |_____^
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:118:9
--> $DIR/unconditional_recursion.rs:119:9
|
LL | self != self
| ^^^^^^^^^^^^
error: equal expressions as operands to `!=`
--> $DIR/unconditional_recursion.rs:118:9
--> $DIR/unconditional_recursion.rs:119:9
|
LL | self != self
| ^^^^^^^^^^^^
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:120:5
--> $DIR/unconditional_recursion.rs:121:5
|
LL | / fn eq(&self, _other: &Self) -> bool {
LL | |
@ -287,16 +215,37 @@ LL | | }
| |_____^
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:122:9
--> $DIR/unconditional_recursion.rs:123:9
|
LL | self == self
| ^^^^^^^^^^^^
error: equal expressions as operands to `==`
--> $DIR/unconditional_recursion.rs:122:9
--> $DIR/unconditional_recursion.rs:123:9
|
LL | self == self
| ^^^^^^^^^^^^
error: aborting due to 26 previous errors
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:149:13
|
LL | / fn eq(&self, other: &Self) -> bool {
LL | | self == other
LL | | }
| |_____________^
...
LL | impl_partial_eq!(S5);
| -------------------- in this macro invocation
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:150:17
|
LL | self == other
| ^^^^^^^^^^^^^
...
LL | impl_partial_eq!(S5);
| -------------------- in this macro invocation
= note: this error originates in the macro `impl_partial_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 19 previous errors