]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/repeat_once.rs
Move some utils to ty_utils
[rust.git] / clippy_lints / src / repeat_once.rs
1 use crate::consts::{constant_context, Constant};
2 use crate::utils::{in_macro, snippet, span_lint_and_sugg};
3 use clippy_utils::ty::is_type_diagnostic_item;
4 use if_chain::if_chain;
5 use rustc_errors::Applicability;
6 use rustc_hir::{Expr, ExprKind};
7 use rustc_lint::{LateContext, LateLintPass};
8 use rustc_session::{declare_lint_pass, declare_tool_lint};
9 use rustc_span::sym;
10
11 declare_clippy_lint! {
12     /// **What it does:** Checks for usage of `.repeat(1)` and suggest the following method for each types.
13     /// - `.to_string()` for `str`
14     /// - `.clone()` for `String`
15     /// - `.to_vec()` for `slice`
16     ///
17     /// **Why is this bad?** For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning the string is the intention behind this, `clone()` should be used.
18     ///
19     /// **Known problems:** None.
20     ///
21     /// **Example:**
22     ///
23     /// ```rust
24     /// fn main() {
25     ///     let x = String::from("hello world").repeat(1);
26     /// }
27     /// ```
28     /// Use instead:
29     /// ```rust
30     /// fn main() {
31     ///     let x = String::from("hello world").clone();
32     /// }
33     /// ```
34     pub REPEAT_ONCE,
35     complexity,
36     "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
37 }
38
39 declare_lint_pass!(RepeatOnce => [REPEAT_ONCE]);
40
41 impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
42     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
43         if_chain! {
44             if let ExprKind::MethodCall(path, _, [receiver, count], _) = &expr.kind;
45             if path.ident.name == sym!(repeat);
46             if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&count);
47             if !in_macro(receiver.span);
48             then {
49                 let ty = cx.typeck_results().expr_ty(&receiver).peel_refs();
50                 if ty.is_str() {
51                     span_lint_and_sugg(
52                         cx,
53                         REPEAT_ONCE,
54                         expr.span,
55                         "calling `repeat(1)` on str",
56                         "consider using `.to_string()` instead",
57                         format!("{}.to_string()", snippet(cx, receiver.span, r#""...""#)),
58                         Applicability::MachineApplicable,
59                     );
60                 } else if ty.builtin_index().is_some() {
61                     span_lint_and_sugg(
62                         cx,
63                         REPEAT_ONCE,
64                         expr.span,
65                         "calling `repeat(1)` on slice",
66                         "consider using `.to_vec()` instead",
67                         format!("{}.to_vec()", snippet(cx, receiver.span, r#""...""#)),
68                         Applicability::MachineApplicable,
69                     );
70                 } else if is_type_diagnostic_item(cx, ty, sym::string_type) {
71                     span_lint_and_sugg(
72                         cx,
73                         REPEAT_ONCE,
74                         expr.span,
75                         "calling `repeat(1)` on a string literal",
76                         "consider using `.clone()` instead",
77                         format!("{}.clone()", snippet(cx, receiver.span, r#""...""#)),
78                         Applicability::MachineApplicable,
79                     );
80                 }
81             }
82         }
83     }
84 }