about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/methods/single_char_insert_string.rs42
-rw-r--r--clippy_lints/src/methods/single_char_push_string.rs41
-rw-r--r--tests/ui/single_char_add_str.fixed10
-rw-r--r--tests/ui/single_char_add_str.rs10
-rw-r--r--tests/ui/single_char_add_str.stderr58
5 files changed, 148 insertions, 13 deletions
diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs
index 20ec2b74d81..ba9ef9c84f9 100644
--- a/clippy_lints/src/methods/single_char_insert_string.rs
+++ b/clippy_lints/src/methods/single_char_insert_string.rs
@@ -1,8 +1,9 @@
 use super::utils::get_hint_if_single_char_arg;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
+use rustc_ast::BorrowKind;
 use rustc_errors::Applicability;
-use rustc_hir as hir;
+use rustc_hir::{self as hir, ExprKind};
 use rustc_lint::LateContext;
 
 use super::SINGLE_CHAR_ADD_STR;
@@ -25,4 +26,43 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::
             applicability,
         );
     }
+
+    if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[1].kind
+        && let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind
+        && path_segment.ident.name == rustc_span::sym::to_string
+        && (is_ref_char(cx, method_arg) || is_char(cx, method_arg))
+    {
+        let base_string_snippet =
+            snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability);
+        let extension_string =
+            snippet_with_applicability(cx, method_arg.span.source_callsite(), "..", &mut applicability);
+        let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
+        let deref_string = if is_ref_char(cx, method_arg) { "*" } else { "" };
+
+        let sugg = format!("{base_string_snippet}.insert({pos_arg}, {deref_string}{extension_string})");
+        span_lint_and_sugg(
+            cx,
+            SINGLE_CHAR_ADD_STR,
+            expr.span,
+            "calling `insert_str()` using a single-character converted to string",
+            "consider using `insert` without `to_string()`",
+            sugg,
+            applicability,
+        );
+    }
+}
+
+fn is_ref_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
+    if cx.typeck_results().expr_ty(expr).is_ref()
+        && let rustc_middle::ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(expr).kind()
+        && ty.is_char()
+    {
+        return true;
+    }
+
+    false
+}
+
+fn is_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
+    cx.typeck_results().expr_ty(expr).is_char()
 }
diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs
index 97c13825bc1..f00a5ab455e 100644
--- a/clippy_lints/src/methods/single_char_push_string.rs
+++ b/clippy_lints/src/methods/single_char_push_string.rs
@@ -1,8 +1,9 @@
 use super::utils::get_hint_if_single_char_arg;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
+use rustc_ast::BorrowKind;
 use rustc_errors::Applicability;
-use rustc_hir as hir;
+use rustc_hir::{self as hir, ExprKind};
 use rustc_lint::LateContext;
 
 use super::SINGLE_CHAR_ADD_STR;
@@ -24,4 +25,42 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::
             applicability,
         );
     }
+
+    if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[0].kind
+        && let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind
+        && path_segment.ident.name == rustc_span::sym::to_string
+        && (is_ref_char(cx, method_arg) || is_char(cx, method_arg))
+    {
+        let base_string_snippet =
+            snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability);
+        let extension_string =
+            snippet_with_applicability(cx, method_arg.span.source_callsite(), "..", &mut applicability);
+        let deref_string = if is_ref_char(cx, method_arg) { "*" } else { "" };
+
+        let sugg = format!("{base_string_snippet}.push({deref_string}{extension_string})");
+        span_lint_and_sugg(
+            cx,
+            SINGLE_CHAR_ADD_STR,
+            expr.span,
+            "calling `push_str()` using a single-character converted to string",
+            "consider using `push` without `to_string()`",
+            sugg,
+            applicability,
+        );
+    }
+}
+
+fn is_ref_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
+    if cx.typeck_results().expr_ty(expr).is_ref()
+        && let rustc_middle::ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(expr).kind()
+        && ty.is_char()
+    {
+        return true;
+    }
+
+    false
+}
+
+fn is_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
+    cx.typeck_results().expr_ty(expr).is_char()
 }
diff --git a/tests/ui/single_char_add_str.fixed b/tests/ui/single_char_add_str.fixed
index eafd17f5387..aef15252b1b 100644
--- a/tests/ui/single_char_add_str.fixed
+++ b/tests/ui/single_char_add_str.fixed
@@ -21,6 +21,12 @@ fn main() {
     string.push('\u{0052}');
     string.push('a');
 
+    let c_ref = &'a';
+    string.push(*c_ref);
+    let c = 'a';
+    string.push(c);
+    string.push('a');
+
     get_string!().push('ö');
 
     // `insert_str` tests
@@ -41,5 +47,9 @@ fn main() {
     string.insert(Y, '"');
     string.insert(Y, '\'');
 
+    string.insert(0, *c_ref);
+    string.insert(0, c);
+    string.insert(0, 'a');
+
     get_string!().insert(1, '?');
 }
diff --git a/tests/ui/single_char_add_str.rs b/tests/ui/single_char_add_str.rs
index 5326c7cf24c..7f97250dacd 100644
--- a/tests/ui/single_char_add_str.rs
+++ b/tests/ui/single_char_add_str.rs
@@ -21,6 +21,12 @@ fn main() {
     string.push_str("\u{0052}");
     string.push_str(r##"a"##);
 
+    let c_ref = &'a';
+    string.push_str(&c_ref.to_string());
+    let c = 'a';
+    string.push_str(&c.to_string());
+    string.push_str(&'a'.to_string());
+
     get_string!().push_str("ö");
 
     // `insert_str` tests
@@ -41,5 +47,9 @@ fn main() {
     string.insert_str(Y, r##"""##);
     string.insert_str(Y, r##"'"##);
 
+    string.insert_str(0, &c_ref.to_string());
+    string.insert_str(0, &c.to_string());
+    string.insert_str(0, &'a'.to_string());
+
     get_string!().insert_str(1, "?");
 }
diff --git a/tests/ui/single_char_add_str.stderr b/tests/ui/single_char_add_str.stderr
index 89d75f20f55..7791c67578a 100644
--- a/tests/ui/single_char_add_str.stderr
+++ b/tests/ui/single_char_add_str.stderr
@@ -31,65 +31,101 @@ error: calling `push_str()` using a single-character string literal
 LL |     string.push_str(r##"a"##);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')`
 
+error: calling `push_str()` using a single-character converted to string
+  --> tests/ui/single_char_add_str.rs:25:5
+   |
+LL |     string.push_str(&c_ref.to_string());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push(*c_ref)`
+
+error: calling `push_str()` using a single-character converted to string
+  --> tests/ui/single_char_add_str.rs:27:5
+   |
+LL |     string.push_str(&c.to_string());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push(c)`
+
+error: calling `push_str()` using a single-character converted to string
+  --> tests/ui/single_char_add_str.rs:28:5
+   |
+LL |     string.push_str(&'a'.to_string());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push('a')`
+
 error: calling `push_str()` using a single-character string literal
-  --> tests/ui/single_char_add_str.rs:24:5
+  --> tests/ui/single_char_add_str.rs:30:5
    |
 LL |     get_string!().push_str("ö");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `get_string!().push('ö')`
 
 error: calling `insert_str()` using a single-character string literal
-  --> tests/ui/single_char_add_str.rs:29:5
+  --> tests/ui/single_char_add_str.rs:35:5
    |
 LL |     string.insert_str(0, "R");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')`
 
 error: calling `insert_str()` using a single-character string literal
-  --> tests/ui/single_char_add_str.rs:30:5
+  --> tests/ui/single_char_add_str.rs:36: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
-  --> tests/ui/single_char_add_str.rs:35:5
+  --> tests/ui/single_char_add_str.rs:41: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
-  --> tests/ui/single_char_add_str.rs:36:5
+  --> tests/ui/single_char_add_str.rs:42: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
-  --> tests/ui/single_char_add_str.rs:38:5
+  --> tests/ui/single_char_add_str.rs:44: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
-  --> tests/ui/single_char_add_str.rs:40:5
+  --> tests/ui/single_char_add_str.rs:46:5
    |
 LL |     string.insert_str(Y, r##"a"##);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')`
 
 error: calling `insert_str()` using a single-character string literal
-  --> tests/ui/single_char_add_str.rs:41:5
+  --> tests/ui/single_char_add_str.rs:47:5
    |
 LL |     string.insert_str(Y, r##"""##);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '"')`
 
 error: calling `insert_str()` using a single-character string literal
-  --> tests/ui/single_char_add_str.rs:42:5
+  --> tests/ui/single_char_add_str.rs:48:5
    |
 LL |     string.insert_str(Y, r##"'"##);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '\'')`
 
+error: calling `insert_str()` using a single-character converted to string
+  --> tests/ui/single_char_add_str.rs:50:5
+   |
+LL |     string.insert_str(0, &c_ref.to_string());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, *c_ref)`
+
+error: calling `insert_str()` using a single-character converted to string
+  --> tests/ui/single_char_add_str.rs:51:5
+   |
+LL |     string.insert_str(0, &c.to_string());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, c)`
+
+error: calling `insert_str()` using a single-character converted to string
+  --> tests/ui/single_char_add_str.rs:52:5
+   |
+LL |     string.insert_str(0, &'a'.to_string());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, 'a')`
+
 error: calling `insert_str()` using a single-character string literal
-  --> tests/ui/single_char_add_str.rs:44:5
+  --> tests/ui/single_char_add_str.rs:54:5
    |
 LL |     get_string!().insert_str(1, "?");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `get_string!().insert(1, '?')`
 
-error: aborting due to 15 previous errors
+error: aborting due to 21 previous errors