about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/methods/mod.rs25
-rw-r--r--clippy_lints/src/utils/paths.rs1
-rw-r--r--tests/ui/single_char_insert_str.fixed18
-rw-r--r--tests/ui/single_char_insert_str.rs18
-rw-r--r--tests/ui/single_char_insert_str.stderr40
5 files changed, 100 insertions, 2 deletions
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 3c3093e869c..86e7c57afae 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -1290,8 +1290,8 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Warns when using `push_str` with a single-character string literal,
-    /// and `push` with a `char` would work fine.
+    /// **What it does:** Warns when using `push_str` with a single-character string literal
+    /// where `push` with a `char` would work fine.
     ///
     /// **Why is this bad?** It's less clear that we are pushing a single character.
     ///
@@ -1521,6 +1521,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
                     if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
                         lint_single_char_push_string(cx, expr, args);
+                    } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) {
+                        lint_single_char_insert_string(cx, expr, args);
                     }
                 }
 
@@ -3255,6 +3257,25 @@ fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args
     }
 }
 
+/// lint for length-1 `str`s as argument for `insert_str`
+fn lint_single_char_insert_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+    let mut applicability = Applicability::MachineApplicable;
+    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) {
+        let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
+        let pos_arg = snippet(cx, args[1].span, "..");
+        let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string);
+        span_lint_and_sugg(
+            cx,
+            SINGLE_CHAR_PUSH_STR,
+            expr.span,
+            "calling `insert_str()` using a single-character string literal",
+            "consider using `insert` with a character literal",
+            sugg,
+            applicability,
+        );
+    }
+}
+
 /// Checks for the `USELESS_ASREF` lint.
 fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) {
     // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs
index cd72fdd61fd..34d5c8d2eb7 100644
--- a/clippy_lints/src/utils/paths.rs
+++ b/clippy_lints/src/utils/paths.rs
@@ -52,6 +52,7 @@ pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entr
 pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"];
 pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
 pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
+pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
 pub const INTO: [&str; 3] = ["core", "convert", "Into"];
 pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"];
 pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
diff --git a/tests/ui/single_char_insert_str.fixed b/tests/ui/single_char_insert_str.fixed
new file mode 100644
index 00000000000..c3416720ec3
--- /dev/null
+++ b/tests/ui/single_char_insert_str.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+#![warn(clippy::single_char_push_str)]
+
+fn main() {
+    let mut string = String::new();
+    string.insert(0, 'R');
+    string.insert(1, '\'');
+
+    string.insert(0, 'u');
+    string.insert_str(2, "st");
+    string.insert_str(0, "");
+    string.insert(0, '\x52');
+    string.insert(0, '\u{0052}');
+    let x: usize = 2;
+    string.insert(x, 'a');
+    const Y: usize = 1;
+    string.insert(Y, 'a');
+}
diff --git a/tests/ui/single_char_insert_str.rs b/tests/ui/single_char_insert_str.rs
new file mode 100644
index 00000000000..2295669e81d
--- /dev/null
+++ b/tests/ui/single_char_insert_str.rs
@@ -0,0 +1,18 @@
+// run-rustfix
+#![warn(clippy::single_char_push_str)]
+
+fn main() {
+    let mut string = String::new();
+    string.insert_str(0, "R");
+    string.insert_str(1, "'");
+
+    string.insert(0, 'u');
+    string.insert_str(2, "st");
+    string.insert_str(0, "");
+    string.insert_str(0, "\x52");
+    string.insert_str(0, "\u{0052}");
+    let x: usize = 2;
+    string.insert_str(x, r##"a"##);
+    const Y: usize = 1;
+    string.insert_str(Y, r##"a"##);
+}
diff --git a/tests/ui/single_char_insert_str.stderr b/tests/ui/single_char_insert_str.stderr
new file mode 100644
index 00000000000..65dc8a69d69
--- /dev/null
+++ b/tests/ui/single_char_insert_str.stderr
@@ -0,0 +1,40 @@
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_insert_str.rs:6:5
+   |
+LL |     string.insert_str(0, "R");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')`
+   |
+   = note: `-D clippy::single-char-push-str` implied by `-D warnings`
+
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_insert_str.rs:7:5
+   |
+LL |     string.insert_str(1, "'");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '/'')`
+
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_insert_str.rs:12:5
+   |
+LL |     string.insert_str(0, "/x52");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/x52')`
+
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_insert_str.rs:13:5
+   |
+LL |     string.insert_str(0, "/u{0052}");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/u{0052}')`
+
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_insert_str.rs:15:5
+   |
+LL |     string.insert_str(x, r##"a"##);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')`
+
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_insert_str.rs:17:5
+   |
+LL |     string.insert_str(Y, r##"a"##);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')`
+
+error: aborting due to 6 previous errors
+