@@ -1290,8 +1290,8 @@ declare_clippy_lint! {
12901290}
12911291
12921292declare_clippy_lint ! {
1293- /// **What it does:** Warns when using `push_str` with a single-character string literal,
1294- /// and `push` with a `char` would work fine.
1293+ /// **What it does:** Warns when using `push_str`/`insert_str` with a single-character string literal
1294+ /// where `push`/`insert ` with a `char` would work fine.
12951295 ///
12961296 /// **Why is this bad?** It's less clear that we are pushing a single character.
12971297 ///
@@ -1300,16 +1300,18 @@ declare_clippy_lint! {
13001300 /// **Example:**
13011301 /// ```rust
13021302 /// let mut string = String::new();
1303+ /// string.insert_str(0, "R");
13031304 /// string.push_str("R");
13041305 /// ```
13051306 /// Could be written as
13061307 /// ```rust
13071308 /// let mut string = String::new();
1309+ /// string.insert(0, 'R');
13081310 /// string.push('R');
13091311 /// ```
1310- pub SINGLE_CHAR_PUSH_STR ,
1312+ pub SINGLE_CHAR_ADD_STR ,
13111313 style,
1312- "`push_str()` used with a single-character string literal as parameter"
1314+ "`push_str()` or `insert_str()` used with a single-character string literal as parameter"
13131315}
13141316
13151317declare_clippy_lint ! {
@@ -1390,7 +1392,7 @@ declare_lint_pass!(Methods => [
13901392 INEFFICIENT_TO_STRING ,
13911393 NEW_RET_NO_SELF ,
13921394 SINGLE_CHAR_PATTERN ,
1393- SINGLE_CHAR_PUSH_STR ,
1395+ SINGLE_CHAR_ADD_STR ,
13941396 SEARCH_IS_SOME ,
13951397 FILTER_NEXT ,
13961398 SKIP_WHILE_NEXT ,
@@ -1521,6 +1523,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
15211523 if let Some ( fn_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( expr. hir_id ) {
15221524 if match_def_path ( cx, fn_def_id, & paths:: PUSH_STR ) {
15231525 lint_single_char_push_string ( cx, expr, args) ;
1526+ } else if match_def_path ( cx, fn_def_id, & paths:: INSERT_STR ) {
1527+ lint_single_char_insert_string ( cx, expr, args) ;
15241528 }
15251529 }
15261530
@@ -3202,7 +3206,7 @@ fn get_hint_if_single_char_arg(
32023206 if let hir:: ExprKind :: Lit ( lit) = & arg. kind;
32033207 if let ast:: LitKind :: Str ( r, style) = lit. node;
32043208 let string = r. as_str( ) ;
3205- if string. len ( ) == 1 ;
3209+ if string. chars ( ) . count ( ) == 1 ;
32063210 then {
32073211 let snip = snippet_with_applicability( cx, arg. span, & string, applicability) ;
32083212 let ch = if let ast:: StrStyle :: Raw ( nhash) = style {
@@ -3241,11 +3245,12 @@ fn lint_single_char_pattern(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &h
32413245fn lint_single_char_push_string ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > , args : & [ hir:: Expr < ' _ > ] ) {
32423246 let mut applicability = Applicability :: MachineApplicable ;
32433247 if let Some ( extension_string) = get_hint_if_single_char_arg ( cx, & args[ 1 ] , & mut applicability) {
3244- let base_string_snippet = snippet_with_applicability ( cx, args[ 0 ] . span , ".." , & mut applicability) ;
3248+ let base_string_snippet =
3249+ snippet_with_applicability ( cx, args[ 0 ] . span . source_callsite ( ) , ".." , & mut applicability) ;
32453250 let sugg = format ! ( "{}.push({})" , base_string_snippet, extension_string) ;
32463251 span_lint_and_sugg (
32473252 cx,
3248- SINGLE_CHAR_PUSH_STR ,
3253+ SINGLE_CHAR_ADD_STR ,
32493254 expr. span ,
32503255 "calling `push_str()` using a single-character string literal" ,
32513256 "consider using `push` with a character literal" ,
@@ -3255,6 +3260,26 @@ fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args
32553260 }
32563261}
32573262
3263+ /// lint for length-1 `str`s as argument for `insert_str`
3264+ fn lint_single_char_insert_string ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > , args : & [ hir:: Expr < ' _ > ] ) {
3265+ let mut applicability = Applicability :: MachineApplicable ;
3266+ if let Some ( extension_string) = get_hint_if_single_char_arg ( cx, & args[ 2 ] , & mut applicability) {
3267+ let base_string_snippet =
3268+ snippet_with_applicability ( cx, args[ 0 ] . span . source_callsite ( ) , "_" , & mut applicability) ;
3269+ let pos_arg = snippet_with_applicability ( cx, args[ 1 ] . span , ".." , & mut applicability) ;
3270+ let sugg = format ! ( "{}.insert({}, {})" , base_string_snippet, pos_arg, extension_string) ;
3271+ span_lint_and_sugg (
3272+ cx,
3273+ SINGLE_CHAR_ADD_STR ,
3274+ expr. span ,
3275+ "calling `insert_str()` using a single-character string literal" ,
3276+ "consider using `insert` with a character literal" ,
3277+ sugg,
3278+ applicability,
3279+ ) ;
3280+ }
3281+ }
3282+
32583283/// Checks for the `USELESS_ASREF` lint.
32593284fn lint_asref ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > , call_name : & str , as_ref_args : & [ hir:: Expr < ' _ > ] ) {
32603285 // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
0 commit comments