@@ -1290,8 +1290,8 @@ declare_clippy_lint! {
1290
1290
}
1291
1291
1292
1292
declare_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.
1295
1295
///
1296
1296
/// **Why is this bad?** It's less clear that we are pushing a single character.
1297
1297
///
@@ -1300,16 +1300,18 @@ declare_clippy_lint! {
1300
1300
/// **Example:**
1301
1301
/// ```rust
1302
1302
/// let mut string = String::new();
1303
+ /// string.insert_str(0, "R");
1303
1304
/// string.push_str("R");
1304
1305
/// ```
1305
1306
/// Could be written as
1306
1307
/// ```rust
1307
1308
/// let mut string = String::new();
1309
+ /// string.insert(0, 'R');
1308
1310
/// string.push('R');
1309
1311
/// ```
1310
- pub SINGLE_CHAR_PUSH_STR ,
1312
+ pub SINGLE_CHAR_ADD_STR ,
1311
1313
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"
1313
1315
}
1314
1316
1315
1317
declare_clippy_lint ! {
@@ -1390,7 +1392,7 @@ declare_lint_pass!(Methods => [
1390
1392
INEFFICIENT_TO_STRING ,
1391
1393
NEW_RET_NO_SELF ,
1392
1394
SINGLE_CHAR_PATTERN ,
1393
- SINGLE_CHAR_PUSH_STR ,
1395
+ SINGLE_CHAR_ADD_STR ,
1394
1396
SEARCH_IS_SOME ,
1395
1397
FILTER_NEXT ,
1396
1398
SKIP_WHILE_NEXT ,
@@ -1521,6 +1523,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
1521
1523
if let Some ( fn_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( expr. hir_id ) {
1522
1524
if match_def_path ( cx, fn_def_id, & paths:: PUSH_STR ) {
1523
1525
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) ;
1524
1528
}
1525
1529
}
1526
1530
@@ -3202,7 +3206,7 @@ fn get_hint_if_single_char_arg(
3202
3206
if let hir:: ExprKind :: Lit ( lit) = & arg. kind;
3203
3207
if let ast:: LitKind :: Str ( r, style) = lit. node;
3204
3208
let string = r. as_str( ) ;
3205
- if string. len ( ) == 1 ;
3209
+ if string. chars ( ) . count ( ) == 1 ;
3206
3210
then {
3207
3211
let snip = snippet_with_applicability( cx, arg. span, & string, applicability) ;
3208
3212
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
3241
3245
fn lint_single_char_push_string ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > , args : & [ hir:: Expr < ' _ > ] ) {
3242
3246
let mut applicability = Applicability :: MachineApplicable ;
3243
3247
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) ;
3245
3250
let sugg = format ! ( "{}.push({})" , base_string_snippet, extension_string) ;
3246
3251
span_lint_and_sugg (
3247
3252
cx,
3248
- SINGLE_CHAR_PUSH_STR ,
3253
+ SINGLE_CHAR_ADD_STR ,
3249
3254
expr. span ,
3250
3255
"calling `push_str()` using a single-character string literal" ,
3251
3256
"consider using `push` with a character literal" ,
@@ -3255,6 +3260,26 @@ fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args
3255
3260
}
3256
3261
}
3257
3262
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
+
3258
3283
/// Checks for the `USELESS_ASREF` lint.
3259
3284
fn lint_asref ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > , call_name : & str , as_ref_args : & [ hir:: Expr < ' _ > ] ) {
3260
3285
// when we get here, we've already checked that the call name is "as_ref" or "as_mut"
0 commit comments