]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/methods/suspicious_splitn.rs
Auto merge of #7546 - mgeier:patch-1, r=giraffate
[rust.git] / clippy_lints / src / methods / suspicious_splitn.rs
1 use clippy_utils::consts::{constant, Constant};
2 use clippy_utils::diagnostics::span_lint_and_note;
3 use if_chain::if_chain;
4 use rustc_ast::LitKind;
5 use rustc_hir::{Expr, ExprKind};
6 use rustc_lint::LateContext;
7 use rustc_span::source_map::Spanned;
8
9 use super::SUSPICIOUS_SPLITN;
10
11 pub(super) fn check(
12     cx: &LateContext<'_>,
13     method_name: &str,
14     expr: &Expr<'_>,
15     self_arg: &Expr<'_>,
16     count_arg: &Expr<'_>,
17 ) {
18     if_chain! {
19         if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg);
20         if count <= 1;
21         if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
22         if let Some(impl_id) = cx.tcx.impl_of_method(call_id);
23         let lang_items = cx.tcx.lang_items();
24         if lang_items.slice_impl() == Some(impl_id) || lang_items.str_impl() == Some(impl_id);
25         then {
26             // Ignore empty slice and string literals when used with a literal count.
27             if (matches!(self_arg.kind, ExprKind::Array([]))
28                 || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty())
29             ) && matches!(count_arg.kind, ExprKind::Lit(_))
30             {
31                 return;
32             }
33
34             let (msg, note_msg) = if count == 0 {
35                 (format!("`{}` called with `0` splits", method_name),
36                 "the resulting iterator will always return `None`")
37             } else {
38                 (format!("`{}` called with `1` split", method_name),
39                 if lang_items.slice_impl() == Some(impl_id) {
40                     "the resulting iterator will always return the entire slice followed by `None`"
41                 } else {
42                     "the resulting iterator will always return the entire string followed by `None`"
43                 })
44             };
45
46             span_lint_and_note(
47                 cx,
48                 SUSPICIOUS_SPLITN,
49                 expr.span,
50                 &msg,
51                 None,
52                 note_msg,
53             );
54         }
55     }
56 }