|
1 |
| -use clippy_utils::{diagnostics::span_lint, return_ty, ty::implements_trait}; |
2 |
| -use rustc_hir::{ImplItem, ImplItemKind}; |
| 1 | +use clippy_utils::{diagnostics::span_lint, get_parent_node, ty::implements_trait}; |
| 2 | +use rustc_hir::{def_id::LocalDefId, FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; |
3 | 3 | use rustc_lint::{LateContext, LateLintPass};
|
4 | 4 | use rustc_session::{declare_lint_pass, declare_tool_lint};
|
5 |
| -use rustc_span::symbol::kw; |
6 | 5 | use rustc_span::symbol::sym;
|
7 | 6 |
|
8 | 7 | declare_clippy_lint! {
|
@@ -41,25 +40,51 @@ declare_clippy_lint! {
|
41 | 40 | declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]);
|
42 | 41 |
|
43 | 42 | impl LateLintPass<'_> for IterNotReturningIterator {
|
44 |
| - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'tcx>) { |
45 |
| - let name = impl_item.ident.name.as_str(); |
46 |
| - if_chain! { |
47 |
| - if let ImplItemKind::Fn(fn_sig, _) = &impl_item.kind; |
48 |
| - let ret_ty = return_ty(cx, impl_item.hir_id()); |
49 |
| - if matches!(name, "iter" | "iter_mut"); |
50 |
| - if let [param] = cx.tcx.fn_arg_names(impl_item.def_id); |
51 |
| - if param.name == kw::SelfLower; |
52 |
| - if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); |
53 |
| - if !implements_trait(cx, ret_ty, iter_trait_id, &[]); |
| 43 | + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { |
| 44 | + let name = item.ident.name.as_str(); |
| 45 | + if matches!(name, "iter" | "iter_mut") { |
| 46 | + if let TraitItemKind::Fn(fn_sig, _) = &item.kind { |
| 47 | + check_sig(cx, name, fn_sig, item.def_id); |
| 48 | + } |
| 49 | + } |
| 50 | + } |
54 | 51 |
|
55 |
| - then { |
56 |
| - span_lint( |
57 |
| - cx, |
58 |
| - ITER_NOT_RETURNING_ITERATOR, |
59 |
| - fn_sig.span, |
60 |
| - &format!("this method is named `{}` but its return type does not implement `Iterator`", name), |
61 |
| - ); |
| 52 | + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) { |
| 53 | + let name = item.ident.name.as_str(); |
| 54 | + if matches!(name, "iter" | "iter_mut") |
| 55 | + && !matches!( |
| 56 | + get_parent_node(cx.tcx, item.hir_id()), |
| 57 | + Some(Node::Item(Item { kind: ItemKind::Impl(i), .. })) if i.of_trait.is_some() |
| 58 | + ) |
| 59 | + { |
| 60 | + if let ImplItemKind::Fn(fn_sig, _) = &item.kind { |
| 61 | + check_sig(cx, name, fn_sig, item.def_id); |
62 | 62 | }
|
63 | 63 | }
|
64 | 64 | }
|
65 | 65 | }
|
| 66 | + |
| 67 | +fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) { |
| 68 | + if sig.decl.implicit_self.has_implicit_self() { |
| 69 | + let ret_ty = cx.tcx.fn_sig(fn_id).skip_binder().output(); |
| 70 | + let ret_ty = cx |
| 71 | + .tcx |
| 72 | + .try_normalize_erasing_regions(cx.param_env, ret_ty) |
| 73 | + .unwrap_or(ret_ty); |
| 74 | + if cx |
| 75 | + .tcx |
| 76 | + .get_diagnostic_item(sym::Iterator) |
| 77 | + .map_or(false, |iter_id| !implements_trait(cx, ret_ty, iter_id, &[])) |
| 78 | + { |
| 79 | + span_lint( |
| 80 | + cx, |
| 81 | + ITER_NOT_RETURNING_ITERATOR, |
| 82 | + sig.span, |
| 83 | + &format!( |
| 84 | + "this method is named `{}` but its return type does not implement `Iterator`", |
| 85 | + name |
| 86 | + ), |
| 87 | + ); |
| 88 | + } |
| 89 | + } |
| 90 | +} |
0 commit comments