]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
Auto merge of #81156 - DrMeepster:read_buf, r=joshtriplett
[rust.git] / src / tools / clippy / clippy_lints / src / iter_not_returning_iterator.rs
1 use clippy_utils::{diagnostics::span_lint, return_ty, ty::implements_trait};
2 use rustc_hir::{ImplItem, ImplItemKind};
3 use rustc_lint::{LateContext, LateLintPass};
4 use rustc_session::{declare_lint_pass, declare_tool_lint};
5 use rustc_span::symbol::kw;
6 use rustc_span::symbol::sym;
7
8 declare_clippy_lint! {
9     /// ### What it does
10     /// Detects methods named `iter` or `iter_mut` that do not have a return type that implements `Iterator`.
11     ///
12     /// ### Why is this bad?
13     /// Methods named `iter` or `iter_mut` conventionally return an `Iterator`.
14     ///
15     /// ### Example
16     /// ```rust
17     /// // `String` does not implement `Iterator`
18     /// struct Data {}
19     /// impl Data {
20     ///     fn iter(&self) -> String {
21     ///         todo!()
22     ///     }
23     /// }
24     /// ```
25     /// Use instead:
26     /// ```rust
27     /// use std::str::Chars;
28     /// struct Data {}
29     /// impl Data {
30     ///    fn iter(&self) -> Chars<'static> {
31     ///        todo!()
32     ///    }
33     /// }
34     /// ```
35     #[clippy::version = "1.57.0"]
36     pub ITER_NOT_RETURNING_ITERATOR,
37     pedantic,
38     "methods named `iter` or `iter_mut` that do not return an `Iterator`"
39 }
40
41 declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]);
42
43 impl LateLintPass<'_> for IterNotReturningIterator {
44     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'tcx>) {
45         let name: &str = &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, &[]);
54
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                 );
62             }
63         }
64     }
65 }