|
1 | 1 | use clippy_utils::diagnostics::span_lint_and_then;
|
2 |
| -use clippy_utils::{get_parent_as_impl, get_trait_def_id, path_res}; |
| 2 | +use clippy_utils::{get_trait_def_id, path_res}; |
3 | 3 | use rustc_ast::BinOpKind;
|
4 | 4 | use rustc_hir::def::Res;
|
5 | 5 | use rustc_hir::def_id::{DefId, LocalDefId};
|
6 | 6 | use rustc_hir::intravisit::FnKind;
|
7 |
| -use rustc_hir::{Body, Expr, ExprKind, FnDecl}; |
| 7 | +use rustc_hir::{Body, Expr, ExprKind, FnDecl, Item, ItemKind, Node}; |
8 | 8 | use rustc_lint::{LateContext, LateLintPass};
|
9 | 9 | use rustc_middle::ty::{self, Ty};
|
10 | 10 | use rustc_session::declare_lint_pass;
|
@@ -66,22 +66,32 @@ impl<'tcx> LateLintPass<'tcx> for UnconditionalRecursion {
|
66 | 66 | method_span: Span,
|
67 | 67 | def_id: LocalDefId,
|
68 | 68 | ) {
|
69 |
| - // We don't check code generated from (proc) macro. |
70 |
| - if method_span.from_expansion() { |
71 |
| - return; |
72 |
| - } |
| 69 | + // If the function is a method... |
73 | 70 | if let FnKind::Method(name, _) = kind
|
| 71 | + // That has two arguments. |
74 | 72 | && let [self_arg, other_arg] = cx
|
75 | 73 | .tcx
|
76 | 74 | .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(def_id).skip_binder())
|
77 | 75 | .inputs()
|
78 | 76 | && let Some(self_arg) = get_ty_def_id(*self_arg)
|
79 | 77 | && let Some(other_arg) = get_ty_def_id(*other_arg)
|
| 78 | + // The two arguments are of the same type. |
80 | 79 | && self_arg == other_arg
|
81 | 80 | && let hir_id = cx.tcx.local_def_id_to_hir_id(def_id)
|
82 |
| - && let Some(impl_) = get_parent_as_impl(cx.tcx, hir_id) |
| 81 | + && let Some(( |
| 82 | + _, |
| 83 | + Node::Item(Item { |
| 84 | + kind: ItemKind::Impl(impl_), |
| 85 | + owner_id, |
| 86 | + .. |
| 87 | + }), |
| 88 | + )) = cx.tcx.hir().parent_iter(hir_id).next() |
| 89 | + // We exclude `impl` blocks generated from rustc's proc macros. |
| 90 | + && !cx.tcx.has_attr(*owner_id, sym::automatically_derived) |
| 91 | + // It is a implementation of a trait. |
83 | 92 | && let Some(trait_) = impl_.of_trait
|
84 | 93 | && let Some(trait_def_id) = trait_.trait_def_id()
|
| 94 | + // The trait is `PartialEq`. |
85 | 95 | && Some(trait_def_id) == get_trait_def_id(cx, &["core", "cmp", "PartialEq"])
|
86 | 96 | {
|
87 | 97 | let to_check_op = if name.name == sym::eq {
|
|
0 commit comments