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