Skip to content

Commit 87c895a

Browse files
committed
Auto merge of rust-lang#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 rust-lang#12775
2 parents dbdc437 + f7723ca commit 87c895a

File tree

5 files changed

+148
-13
lines changed

5 files changed

+148
-13
lines changed

clippy_lints/src/methods/single_char_insert_string.rs

+41-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use super::utils::get_hint_if_single_char_arg;
22
use clippy_utils::diagnostics::span_lint_and_sugg;
33
use clippy_utils::source::snippet_with_applicability;
4+
use rustc_ast::BorrowKind;
45
use rustc_errors::Applicability;
5-
use rustc_hir as hir;
6+
use rustc_hir::{self as hir, ExprKind};
67
use rustc_lint::LateContext;
78

89
use super::SINGLE_CHAR_ADD_STR;
@@ -25,4 +26,43 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::
2526
applicability,
2627
);
2728
}
29+
30+
if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[1].kind
31+
&& let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind
32+
&& path_segment.ident.name == rustc_span::sym::to_string
33+
&& (is_ref_char(cx, method_arg) || is_char(cx, method_arg))
34+
{
35+
let base_string_snippet =
36+
snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability);
37+
let extension_string =
38+
snippet_with_applicability(cx, method_arg.span.source_callsite(), "..", &mut applicability);
39+
let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
40+
let deref_string = if is_ref_char(cx, method_arg) { "*" } else { "" };
41+
42+
let sugg = format!("{base_string_snippet}.insert({pos_arg}, {deref_string}{extension_string})");
43+
span_lint_and_sugg(
44+
cx,
45+
SINGLE_CHAR_ADD_STR,
46+
expr.span,
47+
"calling `insert_str()` using a single-character converted to string",
48+
"consider using `insert` without `to_string()`",
49+
sugg,
50+
applicability,
51+
);
52+
}
53+
}
54+
55+
fn is_ref_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
56+
if cx.typeck_results().expr_ty(expr).is_ref()
57+
&& let rustc_middle::ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(expr).kind()
58+
&& ty.is_char()
59+
{
60+
return true;
61+
}
62+
63+
false
64+
}
65+
66+
fn is_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
67+
cx.typeck_results().expr_ty(expr).is_char()
2868
}

clippy_lints/src/methods/single_char_push_string.rs

+40-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use super::utils::get_hint_if_single_char_arg;
22
use clippy_utils::diagnostics::span_lint_and_sugg;
33
use clippy_utils::source::snippet_with_applicability;
4+
use rustc_ast::BorrowKind;
45
use rustc_errors::Applicability;
5-
use rustc_hir as hir;
6+
use rustc_hir::{self as hir, ExprKind};
67
use rustc_lint::LateContext;
78

89
use super::SINGLE_CHAR_ADD_STR;
@@ -24,4 +25,42 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::
2425
applicability,
2526
);
2627
}
28+
29+
if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[0].kind
30+
&& let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind
31+
&& path_segment.ident.name == rustc_span::sym::to_string
32+
&& (is_ref_char(cx, method_arg) || is_char(cx, method_arg))
33+
{
34+
let base_string_snippet =
35+
snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability);
36+
let extension_string =
37+
snippet_with_applicability(cx, method_arg.span.source_callsite(), "..", &mut applicability);
38+
let deref_string = if is_ref_char(cx, method_arg) { "*" } else { "" };
39+
40+
let sugg = format!("{base_string_snippet}.push({deref_string}{extension_string})");
41+
span_lint_and_sugg(
42+
cx,
43+
SINGLE_CHAR_ADD_STR,
44+
expr.span,
45+
"calling `push_str()` using a single-character converted to string",
46+
"consider using `push` without `to_string()`",
47+
sugg,
48+
applicability,
49+
);
50+
}
51+
}
52+
53+
fn is_ref_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
54+
if cx.typeck_results().expr_ty(expr).is_ref()
55+
&& let rustc_middle::ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(expr).kind()
56+
&& ty.is_char()
57+
{
58+
return true;
59+
}
60+
61+
false
62+
}
63+
64+
fn is_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
65+
cx.typeck_results().expr_ty(expr).is_char()
2766
}

tests/ui/single_char_add_str.fixed

+10
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ fn main() {
2121
string.push('\u{0052}');
2222
string.push('a');
2323

24+
let c_ref = &'a';
25+
string.push(*c_ref);
26+
let c = 'a';
27+
string.push(c);
28+
string.push('a');
29+
2430
get_string!().push('ö');
2531

2632
// `insert_str` tests
@@ -41,5 +47,9 @@ fn main() {
4147
string.insert(Y, '"');
4248
string.insert(Y, '\'');
4349

50+
string.insert(0, *c_ref);
51+
string.insert(0, c);
52+
string.insert(0, 'a');
53+
4454
get_string!().insert(1, '?');
4555
}

tests/ui/single_char_add_str.rs

+10
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ fn main() {
2121
string.push_str("\u{0052}");
2222
string.push_str(r##"a"##);
2323

24+
let c_ref = &'a';
25+
string.push_str(&c_ref.to_string());
26+
let c = 'a';
27+
string.push_str(&c.to_string());
28+
string.push_str(&'a'.to_string());
29+
2430
get_string!().push_str("ö");
2531

2632
// `insert_str` tests
@@ -41,5 +47,9 @@ fn main() {
4147
string.insert_str(Y, r##"""##);
4248
string.insert_str(Y, r##"'"##);
4349

50+
string.insert_str(0, &c_ref.to_string());
51+
string.insert_str(0, &c.to_string());
52+
string.insert_str(0, &'a'.to_string());
53+
4454
get_string!().insert_str(1, "?");
4555
}

tests/ui/single_char_add_str.stderr

+47-11
Original file line numberDiff line numberDiff line change
@@ -31,65 +31,101 @@ error: calling `push_str()` using a single-character string literal
3131
LL | string.push_str(r##"a"##);
3232
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')`
3333

34+
error: calling `push_str()` using a single-character converted to string
35+
--> tests/ui/single_char_add_str.rs:25:5
36+
|
37+
LL | string.push_str(&c_ref.to_string());
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push(*c_ref)`
39+
40+
error: calling `push_str()` using a single-character converted to string
41+
--> tests/ui/single_char_add_str.rs:27:5
42+
|
43+
LL | string.push_str(&c.to_string());
44+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push(c)`
45+
46+
error: calling `push_str()` using a single-character converted to string
47+
--> tests/ui/single_char_add_str.rs:28:5
48+
|
49+
LL | string.push_str(&'a'.to_string());
50+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push('a')`
51+
3452
error: calling `push_str()` using a single-character string literal
35-
--> tests/ui/single_char_add_str.rs:24:5
53+
--> tests/ui/single_char_add_str.rs:30:5
3654
|
3755
LL | get_string!().push_str("ö");
3856
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `get_string!().push('ö')`
3957

4058
error: calling `insert_str()` using a single-character string literal
41-
--> tests/ui/single_char_add_str.rs:29:5
59+
--> tests/ui/single_char_add_str.rs:35:5
4260
|
4361
LL | string.insert_str(0, "R");
4462
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')`
4563

4664
error: calling `insert_str()` using a single-character string literal
47-
--> tests/ui/single_char_add_str.rs:30:5
65+
--> tests/ui/single_char_add_str.rs:36:5
4866
|
4967
LL | string.insert_str(1, "'");
5068
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '\'')`
5169

5270
error: calling `insert_str()` using a single-character string literal
53-
--> tests/ui/single_char_add_str.rs:35:5
71+
--> tests/ui/single_char_add_str.rs:41:5
5472
|
5573
LL | string.insert_str(0, "\x52");
5674
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '\x52')`
5775

5876
error: calling `insert_str()` using a single-character string literal
59-
--> tests/ui/single_char_add_str.rs:36:5
77+
--> tests/ui/single_char_add_str.rs:42:5
6078
|
6179
LL | string.insert_str(0, "\u{0052}");
6280
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '\u{0052}')`
6381

6482
error: calling `insert_str()` using a single-character string literal
65-
--> tests/ui/single_char_add_str.rs:38:5
83+
--> tests/ui/single_char_add_str.rs:44:5
6684
|
6785
LL | string.insert_str(x, r##"a"##);
6886
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')`
6987

7088
error: calling `insert_str()` using a single-character string literal
71-
--> tests/ui/single_char_add_str.rs:40:5
89+
--> tests/ui/single_char_add_str.rs:46:5
7290
|
7391
LL | string.insert_str(Y, r##"a"##);
7492
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')`
7593

7694
error: calling `insert_str()` using a single-character string literal
77-
--> tests/ui/single_char_add_str.rs:41:5
95+
--> tests/ui/single_char_add_str.rs:47:5
7896
|
7997
LL | string.insert_str(Y, r##"""##);
8098
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '"')`
8199

82100
error: calling `insert_str()` using a single-character string literal
83-
--> tests/ui/single_char_add_str.rs:42:5
101+
--> tests/ui/single_char_add_str.rs:48:5
84102
|
85103
LL | string.insert_str(Y, r##"'"##);
86104
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '\'')`
87105

106+
error: calling `insert_str()` using a single-character converted to string
107+
--> tests/ui/single_char_add_str.rs:50:5
108+
|
109+
LL | string.insert_str(0, &c_ref.to_string());
110+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, *c_ref)`
111+
112+
error: calling `insert_str()` using a single-character converted to string
113+
--> tests/ui/single_char_add_str.rs:51:5
114+
|
115+
LL | string.insert_str(0, &c.to_string());
116+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, c)`
117+
118+
error: calling `insert_str()` using a single-character converted to string
119+
--> tests/ui/single_char_add_str.rs:52:5
120+
|
121+
LL | string.insert_str(0, &'a'.to_string());
122+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, 'a')`
123+
88124
error: calling `insert_str()` using a single-character string literal
89-
--> tests/ui/single_char_add_str.rs:44:5
125+
--> tests/ui/single_char_add_str.rs:54:5
90126
|
91127
LL | get_string!().insert_str(1, "?");
92128
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `get_string!().insert(1, '?')`
93129

94-
error: aborting due to 15 previous errors
130+
error: aborting due to 21 previous errors
95131

0 commit comments

Comments
 (0)