Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions clippy_lints/src/methods/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,6 @@ mod search_is_some;
mod seek_from_current;
mod seek_to_start_instead_of_rewind;
mod single_char_add_str;
mod single_char_insert_string;
mod single_char_push_string;
mod skip_while_next;
mod sliced_string_as_bytes;
mod stable_sort_primitive;
Expand Down
80 changes: 73 additions & 7 deletions clippy_lints/src/methods/single_char_add_str.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,80 @@
use crate::methods::{single_char_insert_string, single_char_push_string};
use rustc_hir as hir;
use super::SINGLE_CHAR_ADD_STR;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{snippet_with_applicability, str_literal_to_char_literal};
use rustc_ast::BorrowKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::sym;

pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
match cx.tcx.get_diagnostic_name(fn_def_id) {
Some(sym::string_push_str) => single_char_push_string::check(cx, expr, receiver, args),
Some(sym::string_insert_str) => single_char_insert_string::check(cx, expr, receiver, args),
_ => {},
let mut applicability = Applicability::MachineApplicable;
let (short_name, arg, extra) = match cx.tcx.get_diagnostic_name(fn_def_id) {
Some(sym::string_insert_str) => (
"insert",
&args[1],
Some(|applicability| {
format!(
"{}, ",
snippet_with_applicability(cx, args[0].span, "..", applicability)
)
}),
),
Some(sym::string_push_str) => ("push", &args[0], None),
_ => return,
};

if let Some(extension_string) = str_literal_to_char_literal(cx, arg, &mut applicability, false) {
let base_string_snippet =
snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability);
span_lint_and_sugg(
cx,
SINGLE_CHAR_ADD_STR,
expr.span,
format!("calling `{short_name}_str()` using a single-character string literal"),
format!("consider using `{short_name}` with a character literal"),
format!(
"{base_string_snippet}.{short_name}({}{extension_string})",
extra.map_or(String::new(), |f| f(&mut applicability))
),
applicability,
);
} else if let ExprKind::AddrOf(BorrowKind::Ref, _, inner) = arg.kind
&& let ExprKind::MethodCall(path_segment, method_arg, [], _) = inner.kind
&& path_segment.ident.name == 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 = match (
snippet_with_applicability(cx, method_arg.span.source_callsite(), "_", &mut applicability),
is_ref_char(cx, method_arg),
) {
(snippet, false) => snippet,
(snippet, true) => format!("*{snippet}").into(),
};
span_lint_and_sugg(
cx,
SINGLE_CHAR_ADD_STR,
expr.span,
format!("calling `{short_name}_str()` using a single-character converted to string"),
format!("consider using `{short_name}` without `to_string()`"),
format!(
"{base_string_snippet}.{short_name}({}{extension_string})",
extra.map_or(String::new(), |f| f(&mut applicability))
),
applicability,
);
}
}
}

fn is_ref_char(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
matches!(cx.typeck_results().expr_ty(expr).kind(), ty::Ref(_, ty, _) if ty.is_char())
}

fn is_char(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
cx.typeck_results().expr_ty(expr).is_char()
}
67 changes: 0 additions & 67 deletions clippy_lints/src/methods/single_char_insert_string.rs

This file was deleted.

65 changes: 0 additions & 65 deletions clippy_lints/src/methods/single_char_push_string.rs

This file was deleted.