Skip to content

Commit 2350ee7

Browse files
matthiaskrgrebroto
authored andcommitted
single_char_push_str lint using insert_str() on single-char literals and suggest insert()
changelog: single_char_push_str: lint using string.insert_str() with single char literals and suggests string.insert() with a char Fixes #6026
1 parent 7387b87 commit 2350ee7

File tree

5 files changed

+100
-2
lines changed

5 files changed

+100
-2
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,8 +1290,8 @@ declare_clippy_lint! {
12901290
}
12911291

12921292
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` with a single-character string literal
1294+
/// where `push` with a `char` would work fine.
12951295
///
12961296
/// **Why is this bad?** It's less clear that we are pushing a single character.
12971297
///
@@ -1521,6 +1521,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
15211521
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
15221522
if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
15231523
lint_single_char_push_string(cx, expr, args);
1524+
} else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) {
1525+
lint_single_char_insert_string(cx, expr, args);
15241526
}
15251527
}
15261528

@@ -3255,6 +3257,25 @@ fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args
32553257
}
32563258
}
32573259

3260+
/// lint for length-1 `str`s as argument for `insert_str`
3261+
fn lint_single_char_insert_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
3262+
let mut applicability = Applicability::MachineApplicable;
3263+
if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) {
3264+
let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
3265+
let pos_arg = snippet(cx, args[1].span, "..");
3266+
let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string);
3267+
span_lint_and_sugg(
3268+
cx,
3269+
SINGLE_CHAR_PUSH_STR,
3270+
expr.span,
3271+
"calling `insert_str()` using a single-character string literal",
3272+
"consider using `insert` with a character literal",
3273+
sugg,
3274+
applicability,
3275+
);
3276+
}
3277+
}
3278+
32583279
/// Checks for the `USELESS_ASREF` lint.
32593280
fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) {
32603281
// when we get here, we've already checked that the call name is "as_ref" or "as_mut"

clippy_lints/src/utils/paths.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entr
5252
pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"];
5353
pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
5454
pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
55+
pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
5556
pub const INTO: [&str; 3] = ["core", "convert", "Into"];
5657
pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"];
5758
pub const IO_READ: [&str; 3] = ["std", "io", "Read"];

tests/ui/single_char_insert_str.fixed

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// run-rustfix
2+
#![warn(clippy::single_char_push_str)]
3+
4+
fn main() {
5+
let mut string = String::new();
6+
string.insert(0, 'R');
7+
string.insert(1, '\'');
8+
9+
string.insert(0, 'u');
10+
string.insert_str(2, "st");
11+
string.insert_str(0, "");
12+
string.insert(0, '\x52');
13+
string.insert(0, '\u{0052}');
14+
let x: usize = 2;
15+
string.insert(x, 'a');
16+
const Y: usize = 1;
17+
string.insert(Y, 'a');
18+
}

tests/ui/single_char_insert_str.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// run-rustfix
2+
#![warn(clippy::single_char_push_str)]
3+
4+
fn main() {
5+
let mut string = String::new();
6+
string.insert_str(0, "R");
7+
string.insert_str(1, "'");
8+
9+
string.insert(0, 'u');
10+
string.insert_str(2, "st");
11+
string.insert_str(0, "");
12+
string.insert_str(0, "\x52");
13+
string.insert_str(0, "\u{0052}");
14+
let x: usize = 2;
15+
string.insert_str(x, r##"a"##);
16+
const Y: usize = 1;
17+
string.insert_str(Y, r##"a"##);
18+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
error: calling `insert_str()` using a single-character string literal
2+
--> $DIR/single_char_insert_str.rs:6:5
3+
|
4+
LL | string.insert_str(0, "R");
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')`
6+
|
7+
= note: `-D clippy::single-char-push-str` implied by `-D warnings`
8+
9+
error: calling `insert_str()` using a single-character string literal
10+
--> $DIR/single_char_insert_str.rs:7:5
11+
|
12+
LL | string.insert_str(1, "'");
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '/'')`
14+
15+
error: calling `insert_str()` using a single-character string literal
16+
--> $DIR/single_char_insert_str.rs:12:5
17+
|
18+
LL | string.insert_str(0, "/x52");
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/x52')`
20+
21+
error: calling `insert_str()` using a single-character string literal
22+
--> $DIR/single_char_insert_str.rs:13:5
23+
|
24+
LL | string.insert_str(0, "/u{0052}");
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/u{0052}')`
26+
27+
error: calling `insert_str()` using a single-character string literal
28+
--> $DIR/single_char_insert_str.rs:15:5
29+
|
30+
LL | string.insert_str(x, r##"a"##);
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')`
32+
33+
error: calling `insert_str()` using a single-character string literal
34+
--> $DIR/single_char_insert_str.rs:17:5
35+
|
36+
LL | string.insert_str(Y, r##"a"##);
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')`
38+
39+
error: aborting due to 6 previous errors
40+

0 commit comments

Comments
 (0)