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