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