Skip to content

Commit 4f07fe2

Browse files
authored
Cleanup: group code for single_char_add_str lint in one file (#15750)
A lot of code was duplicated instead of being shared. changelog: none
2 parents af0bc98 + ace2e27 commit 4f07fe2

File tree

4 files changed

+73
-141
lines changed

4 files changed

+73
-141
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,6 @@ mod search_is_some;
103103
mod seek_from_current;
104104
mod seek_to_start_instead_of_rewind;
105105
mod single_char_add_str;
106-
mod single_char_insert_string;
107-
mod single_char_push_string;
108106
mod skip_while_next;
109107
mod sliced_string_as_bytes;
110108
mod stable_sort_primitive;
Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,80 @@
1-
use crate::methods::{single_char_insert_string, single_char_push_string};
2-
use rustc_hir as hir;
1+
use super::SINGLE_CHAR_ADD_STR;
2+
use clippy_utils::diagnostics::span_lint_and_sugg;
3+
use clippy_utils::source::{snippet_with_applicability, str_literal_to_char_literal};
4+
use rustc_ast::BorrowKind;
5+
use rustc_errors::Applicability;
6+
use rustc_hir::{Expr, ExprKind};
37
use rustc_lint::LateContext;
8+
use rustc_middle::ty;
49
use rustc_span::sym;
510

6-
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
11+
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
712
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
8-
match cx.tcx.get_diagnostic_name(fn_def_id) {
9-
Some(sym::string_push_str) => single_char_push_string::check(cx, expr, receiver, args),
10-
Some(sym::string_insert_str) => single_char_insert_string::check(cx, expr, receiver, args),
11-
_ => {},
13+
let mut applicability = Applicability::MachineApplicable;
14+
let (short_name, arg, extra) = match cx.tcx.get_diagnostic_name(fn_def_id) {
15+
Some(sym::string_insert_str) => (
16+
"insert",
17+
&args[1],
18+
Some(|applicability| {
19+
format!(
20+
"{}, ",
21+
snippet_with_applicability(cx, args[0].span, "..", applicability)
22+
)
23+
}),
24+
),
25+
Some(sym::string_push_str) => ("push", &args[0], None),
26+
_ => return,
27+
};
28+
29+
if let Some(extension_string) = str_literal_to_char_literal(cx, arg, &mut applicability, false) {
30+
let base_string_snippet =
31+
snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability);
32+
span_lint_and_sugg(
33+
cx,
34+
SINGLE_CHAR_ADD_STR,
35+
expr.span,
36+
format!("calling `{short_name}_str()` using a single-character string literal"),
37+
format!("consider using `{short_name}` with a character literal"),
38+
format!(
39+
"{base_string_snippet}.{short_name}({}{extension_string})",
40+
extra.map_or(String::new(), |f| f(&mut applicability))
41+
),
42+
applicability,
43+
);
44+
} else if let ExprKind::AddrOf(BorrowKind::Ref, _, inner) = arg.kind
45+
&& let ExprKind::MethodCall(path_segment, method_arg, [], _) = inner.kind
46+
&& path_segment.ident.name == sym::to_string
47+
&& (is_ref_char(cx, method_arg) || is_char(cx, method_arg))
48+
{
49+
let base_string_snippet =
50+
snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability);
51+
let extension_string = match (
52+
snippet_with_applicability(cx, method_arg.span.source_callsite(), "_", &mut applicability),
53+
is_ref_char(cx, method_arg),
54+
) {
55+
(snippet, false) => snippet,
56+
(snippet, true) => format!("*{snippet}").into(),
57+
};
58+
span_lint_and_sugg(
59+
cx,
60+
SINGLE_CHAR_ADD_STR,
61+
expr.span,
62+
format!("calling `{short_name}_str()` using a single-character converted to string"),
63+
format!("consider using `{short_name}` without `to_string()`"),
64+
format!(
65+
"{base_string_snippet}.{short_name}({}{extension_string})",
66+
extra.map_or(String::new(), |f| f(&mut applicability))
67+
),
68+
applicability,
69+
);
1270
}
1371
}
1472
}
73+
74+
fn is_ref_char(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
75+
matches!(cx.typeck_results().expr_ty(expr).kind(), ty::Ref(_, ty, _) if ty.is_char())
76+
}
77+
78+
fn is_char(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
79+
cx.typeck_results().expr_ty(expr).is_char()
80+
}

clippy_lints/src/methods/single_char_insert_string.rs

Lines changed: 0 additions & 67 deletions
This file was deleted.

clippy_lints/src/methods/single_char_push_string.rs

Lines changed: 0 additions & 65 deletions
This file was deleted.

0 commit comments

Comments
 (0)