|
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