2021-06-03 01:41:37 -05:00
use clippy_utils ::consts ::{ constant_context , Constant } ;
2021-03-25 13:29:11 -05:00
use clippy_utils ::diagnostics ::span_lint_and_sugg ;
use clippy_utils ::in_macro ;
use clippy_utils ::source ::snippet ;
use clippy_utils ::ty ::is_type_diagnostic_item ;
2020-07-14 07:59:59 -05:00
use if_chain ::if_chain ;
use rustc_errors ::Applicability ;
use rustc_hir ::{ Expr , ExprKind } ;
use rustc_lint ::{ LateContext , LateLintPass } ;
use rustc_session ::{ declare_lint_pass , declare_tool_lint } ;
2020-11-05 07:29:48 -06:00
use rustc_span ::sym ;
2020-07-14 07:59:59 -05:00
declare_clippy_lint! {
/// **What it does:** Checks for usage of `.repeat(1)` and suggest the following method for each types.
/// - `.to_string()` for `str`
/// - `.clone()` for `String`
/// - `.to_vec()` for `slice`
///
/// **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.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// fn main() {
/// let x = String::from("hello world").repeat(1);
/// }
/// ```
/// Use instead:
/// ```rust
/// fn main() {
/// let x = String::from("hello world").clone();
/// }
/// ```
pub REPEAT_ONCE ,
complexity ,
" using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
}
declare_lint_pass! ( RepeatOnce = > [ REPEAT_ONCE ] ) ;
impl < ' tcx > LateLintPass < ' tcx > for RepeatOnce {
fn check_expr ( & mut self , cx : & LateContext < '_ > , expr : & ' tcx Expr < '_ > ) {
if_chain! {
2020-08-28 09:10:16 -05:00
if let ExprKind ::MethodCall ( path , _ , [ receiver , count ] , _ ) = & expr . kind ;
2020-07-14 07:59:59 -05:00
if path . ident . name = = sym! ( repeat ) ;
2021-04-08 10:50:13 -05:00
if let Some ( Constant ::Int ( 1 ) ) = constant_context ( cx , cx . typeck_results ( ) ) . expr ( count ) ;
2020-08-28 09:10:16 -05:00
if ! in_macro ( receiver . span ) ;
2020-07-14 07:59:59 -05:00
then {
2021-04-08 10:50:13 -05:00
let ty = cx . typeck_results ( ) . expr_ty ( receiver ) . peel_refs ( ) ;
2020-07-14 07:59:59 -05:00
if ty . is_str ( ) {
span_lint_and_sugg (
cx ,
REPEAT_ONCE ,
expr . span ,
" calling `repeat(1)` on str " ,
" consider using `.to_string()` instead " ,
2020-08-28 09:10:16 -05:00
format! ( " {} .to_string() " , snippet ( cx , receiver . span , r # ""...""# ) ) ,
2020-07-14 07:59:59 -05:00
Applicability ::MachineApplicable ,
) ;
} else if ty . builtin_index ( ) . is_some ( ) {
span_lint_and_sugg (
cx ,
REPEAT_ONCE ,
expr . span ,
" calling `repeat(1)` on slice " ,
" consider using `.to_vec()` instead " ,
2020-08-28 09:10:16 -05:00
format! ( " {} .to_vec() " , snippet ( cx , receiver . span , r # ""...""# ) ) ,
2020-07-14 07:59:59 -05:00
Applicability ::MachineApplicable ,
) ;
2020-11-05 07:29:48 -06:00
} else if is_type_diagnostic_item ( cx , ty , sym ::string_type ) {
2020-07-14 07:59:59 -05:00
span_lint_and_sugg (
cx ,
REPEAT_ONCE ,
expr . span ,
" calling `repeat(1)` on a string literal " ,
" consider using `.clone()` instead " ,
2020-08-28 09:10:16 -05:00
format! ( " {} .clone() " , snippet ( cx , receiver . span , r # ""...""# ) ) ,
2020-07-14 07:59:59 -05:00
Applicability ::MachineApplicable ,
) ;
}
}
}
}
}