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