Auto merge of #12915 - belyakov-am:lint/single_char_add_str, r=xFrednet

Handle single chars with `to_string()` for `single_char_add_str`

Add support for single chars / literals with `to_string()` call for `push_str()` and `insert_str()`.

changelog: [`single_char_add_str`]: handle single chars with `to_string()` call

Closes #12775
This commit is contained in:
bors 2024-06-11 11:08:45 +00:00
commit 87c895ad83
5 changed files with 148 additions and 13 deletions

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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, '?');
}

View File

@ -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, "?");
}

View File

@ -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