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:
commit
87c895ad83
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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, '?');
|
||||
}
|
||||
|
@ -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, "?");
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user