diff --git a/clippy_lints/src/splitting_strings_at_newlines.rs b/clippy_lints/src/splitting_strings_at_newlines.rs index 7e10bfee2cf1..517edecbdf96 100644 --- a/clippy_lints/src/splitting_strings_at_newlines.rs +++ b/clippy_lints/src/splitting_strings_at_newlines.rs @@ -1,14 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::ty::implements_trait; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; - declare_clippy_lint! { /// ### What it does /// @@ -34,40 +31,25 @@ declare_clippy_lint! { declare_lint_pass!(SplittingStringsAtNewlines => [SPLITTING_STRINGS_AT_NEWLINES]); -// Check if an expr is of a type that implements `Deref` with `Target = str` -fn derefs_into_str(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { - matches!( - cx.tcx.get_diagnostic_item(sym::Deref), - Some(def_id) if ( - implements_trait(cx, cx.typeck_results().expr_ty(expr), def_id, &[]) - && matches!( - cx.get_associated_type(cx.typeck_results().expr_ty_adjusted(expr), def_id, "Target"), - Some(target) if target.is_str() - ) - ) - ) -} - impl LateLintPass<'_> for SplittingStringsAtNewlines { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { - // We're looking for `A.trim().split(B)`, where the type of `A` implements `Deref` with `Target = - // str` (e.g. a `str` literal or an expression returning `String`), and `B` is a `Pattern` - // that hard-codes a newline (either `"\n"` or `"\r\n"`). There are a lot of ways to specify a - // pattern, and this lint only checks the most basic ones: a `'\n'`, `"\n"`, and `"\r\n"`. + // We're looking for `A.trim().split(B)`, where the adjusted type of `A` is `&str` (e.g. a `str` + // literal or an expression returning `String`), and `B` is a `Pattern` that hard-codes a + // newline (either `"\n"` or `"\r\n"`). There are a lot of ways to specify a pattern, and + // this lint only checks the most basic ones: a `'\n'`, `"\n"`, and `"\r\n"`. if expr.span.from_expansion() { // Don't generate lints in code expanded from macros return; } - if let ExprKind::MethodCall(split_method_name, split_receiver, split_args, _) = expr.kind + if let ExprKind::MethodCall(split_method_name, split_receiver, [split_arg], _) = expr.kind && split_method_name.ident.as_str() == "split" - && split_args.len() == 1 && let ExprKind::MethodCall(trim_method_name, trim_receiver, trim_args, _) = split_receiver.kind && trim_method_name.ident.as_str() == "trim" && trim_args.is_empty() - && derefs_into_str(cx, trim_receiver) - && let ExprKind::Lit(split_lit) = split_args[0].kind + && cx.typeck_results().expr_ty_adjusted(trim_receiver).peel_refs().is_str() + && let ExprKind::Lit(split_lit) = split_arg.kind { let char_n = matches!(split_lit.node, LitKind::Char('\n')); let str_n_or_rn =