about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/declared_lints.rs1
-rw-r--r--clippy_lints/src/deprecated_lints.rs2
-rw-r--r--clippy_lints/src/lib.rs1
-rw-r--r--clippy_lints/src/strings.rs109
-rw-r--r--tests/ui/deprecated.rs1
-rw-r--r--tests/ui/deprecated.stderr18
-rw-r--r--tests/ui/string_to_string.fixed21
-rw-r--r--tests/ui/string_to_string.rs21
-rw-r--r--tests/ui/string_to_string.stderr23
-rw-r--r--tests/ui/string_to_string_in_map.fixed20
-rw-r--r--tests/ui/string_to_string_in_map.rs20
-rw-r--r--tests/ui/string_to_string_in_map.stderr38
12 files changed, 15 insertions, 260 deletions
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 5fcb851dfeb..1b0e87ffa71 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -683,7 +683,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::strings::STRING_FROM_UTF8_AS_BYTES_INFO,
     crate::strings::STRING_LIT_AS_BYTES_INFO,
     crate::strings::STRING_SLICE_INFO,
-    crate::strings::STRING_TO_STRING_INFO,
     crate::strings::STR_TO_STRING_INFO,
     crate::strings::TRIM_SPLIT_WHITESPACE_INFO,
     crate::strlen_on_c_strings::STRLEN_ON_C_STRINGS_INFO,
diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs
index 5204f73ea0a..88aebc3e6a1 100644
--- a/clippy_lints/src/deprecated_lints.rs
+++ b/clippy_lints/src/deprecated_lints.rs
@@ -34,6 +34,8 @@ declare_with_version! { DEPRECATED(DEPRECATED_VERSION) = [
     ("clippy::replace_consts", "`min_value` and `max_value` are now deprecated"),
     #[clippy::version = "pre 1.29.0"]
     ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"),
+    #[clippy::version = "1.90.0"]
+    ("clippy::string_to_string", "`clippy:implicit_clone` covers those cases"),
     #[clippy::version = "pre 1.29.0"]
     ("clippy::unsafe_vector_initialization", "the suggested alternative could be substantially slower"),
     #[clippy::version = "pre 1.29.0"]
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index ca1a0b35710..cd9917e3ac8 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -782,7 +782,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
     store.register_late_pass(|_| Box::new(empty_drop::EmptyDrop));
     store.register_late_pass(|_| Box::new(strings::StrToString));
-    store.register_late_pass(|_| Box::new(strings::StringToString));
     store.register_late_pass(|_| Box::new(zero_sized_map_values::ZeroSizedMapValues));
     store.register_late_pass(|_| Box::<vec_init_then_push::VecInitThenPush>::default());
     store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing));
diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs
index 9fcef84eeb3..d520df95ae8 100644
--- a/clippy_lints/src/strings.rs
+++ b/clippy_lints/src/strings.rs
@@ -13,8 +13,6 @@ use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::source_map::Spanned;
 
-use std::ops::ControlFlow;
-
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for string appends of the form `x = x + y` (without
@@ -413,113 +411,6 @@ impl<'tcx> LateLintPass<'tcx> for StrToString {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// This lint checks for `.to_string()` method calls on values of type `String`.
-    ///
-    /// ### Why restrict this?
-    /// The `to_string` method is also used on other types to convert them to a string.
-    /// When called on a `String` it only clones the `String`, which can be more specifically
-    /// expressed with `.clone()`.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// let msg = String::from("Hello World");
-    /// let _ = msg.to_string();
-    /// ```
-    /// Use instead:
-    /// ```no_run
-    /// let msg = String::from("Hello World");
-    /// let _ = msg.clone();
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub STRING_TO_STRING,
-    restriction,
-    "using `to_string()` on a `String`, which should be `clone()`"
-}
-
-declare_lint_pass!(StringToString => [STRING_TO_STRING]);
-
-fn is_parent_map_like(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<rustc_span::Span> {
-    if let Some(parent_expr) = get_parent_expr(cx, expr)
-        && let ExprKind::MethodCall(name, _, _, parent_span) = parent_expr.kind
-        && name.ident.name == sym::map
-        && let Some(caller_def_id) = cx.typeck_results().type_dependent_def_id(parent_expr.hir_id)
-        && (clippy_utils::is_diag_item_method(cx, caller_def_id, sym::Result)
-            || clippy_utils::is_diag_item_method(cx, caller_def_id, sym::Option)
-            || clippy_utils::is_diag_trait_item(cx, caller_def_id, sym::Iterator))
-    {
-        Some(parent_span)
-    } else {
-        None
-    }
-}
-
-fn is_called_from_map_like(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<rustc_span::Span> {
-    // Look for a closure as parent of `expr`, discarding simple blocks
-    let parent_closure = cx
-        .tcx
-        .hir_parent_iter(expr.hir_id)
-        .try_fold(expr.hir_id, |child_hir_id, (_, node)| match node {
-            // Check that the child expression is the only expression in the block
-            Node::Block(block) if block.stmts.is_empty() && block.expr.map(|e| e.hir_id) == Some(child_hir_id) => {
-                ControlFlow::Continue(block.hir_id)
-            },
-            Node::Expr(expr) if matches!(expr.kind, ExprKind::Block(..)) => ControlFlow::Continue(expr.hir_id),
-            Node::Expr(expr) if matches!(expr.kind, ExprKind::Closure(_)) => ControlFlow::Break(Some(expr)),
-            _ => ControlFlow::Break(None),
-        })
-        .break_value()?;
-    is_parent_map_like(cx, parent_closure?)
-}
-
-fn suggest_cloned_string_to_string(cx: &LateContext<'_>, span: rustc_span::Span) {
-    span_lint_and_sugg(
-        cx,
-        STRING_TO_STRING,
-        span,
-        "`to_string()` called on a `String`",
-        "try",
-        "cloned()".to_string(),
-        Applicability::MachineApplicable,
-    );
-}
-
-impl<'tcx> LateLintPass<'tcx> for StringToString {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
-        if expr.span.from_expansion() {
-            return;
-        }
-
-        match &expr.kind {
-            ExprKind::MethodCall(path, self_arg, [], _) => {
-                if path.ident.name == sym::to_string
-                    && let ty = cx.typeck_results().expr_ty(self_arg)
-                    && is_type_lang_item(cx, ty.peel_refs(), LangItem::String)
-                    && let Some(parent_span) = is_called_from_map_like(cx, expr)
-                {
-                    suggest_cloned_string_to_string(cx, parent_span);
-                }
-            },
-            ExprKind::Path(QPath::TypeRelative(ty, segment)) => {
-                if segment.ident.name == sym::to_string
-                    && let rustc_hir::TyKind::Path(QPath::Resolved(_, path)) = ty.peel_refs().kind
-                    && let rustc_hir::def::Res::Def(_, def_id) = path.res
-                    && cx
-                        .tcx
-                        .lang_items()
-                        .get(LangItem::String)
-                        .is_some_and(|lang_id| lang_id == def_id)
-                    && let Some(parent_span) = is_parent_map_like(cx, expr)
-                {
-                    suggest_cloned_string_to_string(cx, parent_span);
-                }
-            },
-            _ => {},
-        }
-    }
-}
-
-declare_clippy_lint! {
-    /// ### What it does
     /// Warns about calling `str::trim` (or variants) before `str::split_whitespace`.
     ///
     /// ### Why is this bad?
diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs
index 6b69bdd29ce..9743a83fb93 100644
--- a/tests/ui/deprecated.rs
+++ b/tests/ui/deprecated.rs
@@ -12,6 +12,7 @@
 #![warn(clippy::regex_macro)] //~ ERROR: lint `clippy::regex_macro`
 #![warn(clippy::replace_consts)] //~ ERROR: lint `clippy::replace_consts`
 #![warn(clippy::should_assert_eq)] //~ ERROR: lint `clippy::should_assert_eq`
+#![warn(clippy::string_to_string)] //~ ERROR: lint `clippy::string_to_string`
 #![warn(clippy::unsafe_vector_initialization)] //~ ERROR: lint `clippy::unsafe_vector_initialization`
 #![warn(clippy::unstable_as_mut_slice)] //~ ERROR: lint `clippy::unstable_as_mut_slice`
 #![warn(clippy::unstable_as_slice)] //~ ERROR: lint `clippy::unstable_as_slice`
diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr
index 07e59d33d60..cd225da611c 100644
--- a/tests/ui/deprecated.stderr
+++ b/tests/ui/deprecated.stderr
@@ -61,35 +61,41 @@ error: lint `clippy::should_assert_eq` has been removed: `assert!(a == b)` can n
 LL | #![warn(clippy::should_assert_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unsafe_vector_initialization` has been removed: the suggested alternative could be substantially slower
+error: lint `clippy::string_to_string` has been removed: `clippy:implicit_clone` covers those cases
   --> tests/ui/deprecated.rs:15:9
    |
+LL | #![warn(clippy::string_to_string)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lint `clippy::unsafe_vector_initialization` has been removed: the suggested alternative could be substantially slower
+  --> tests/ui/deprecated.rs:16:9
+   |
 LL | #![warn(clippy::unsafe_vector_initialization)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` is now stable
-  --> tests/ui/deprecated.rs:16:9
+  --> tests/ui/deprecated.rs:17:9
    |
 LL | #![warn(clippy::unstable_as_mut_slice)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` is now stable
-  --> tests/ui/deprecated.rs:17:9
+  --> tests/ui/deprecated.rs:18:9
    |
 LL | #![warn(clippy::unstable_as_slice)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::unused_collect` has been removed: `Iterator::collect` is now marked as `#[must_use]`
-  --> tests/ui/deprecated.rs:18:9
+  --> tests/ui/deprecated.rs:19:9
    |
 LL | #![warn(clippy::unused_collect)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::wrong_pub_self_convention` has been removed: `clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config
-  --> tests/ui/deprecated.rs:19:9
+  --> tests/ui/deprecated.rs:20:9
    |
 LL | #![warn(clippy::wrong_pub_self_convention)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 15 previous errors
+error: aborting due to 16 previous errors
 
diff --git a/tests/ui/string_to_string.fixed b/tests/ui/string_to_string.fixed
deleted file mode 100644
index 751f451cb68..00000000000
--- a/tests/ui/string_to_string.fixed
+++ /dev/null
@@ -1,21 +0,0 @@
-#![warn(clippy::implicit_clone, clippy::string_to_string)]
-#![allow(clippy::redundant_clone, clippy::unnecessary_literal_unwrap)]
-
-fn main() {
-    let mut message = String::from("Hello");
-    let mut v = message.clone();
-    //~^ ERROR: implicitly cloning a `String` by calling `to_string` on its dereferenced type
-
-    let variable1 = String::new();
-    let v = &variable1;
-    let variable2 = Some(v);
-    let _ = variable2.map(|x| {
-        println!();
-        x.clone()
-        //~^ ERROR: implicitly cloning a `String` by calling `to_string` on its dereferenced type
-    });
-
-    let x = Some(String::new());
-    let _ = x.unwrap_or_else(|| v.clone());
-    //~^ ERROR: implicitly cloning a `String` by calling `to_string` on its dereferenced type
-}
diff --git a/tests/ui/string_to_string.rs b/tests/ui/string_to_string.rs
deleted file mode 100644
index d519677d59e..00000000000
--- a/tests/ui/string_to_string.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-#![warn(clippy::implicit_clone, clippy::string_to_string)]
-#![allow(clippy::redundant_clone, clippy::unnecessary_literal_unwrap)]
-
-fn main() {
-    let mut message = String::from("Hello");
-    let mut v = message.to_string();
-    //~^ ERROR: implicitly cloning a `String` by calling `to_string` on its dereferenced type
-
-    let variable1 = String::new();
-    let v = &variable1;
-    let variable2 = Some(v);
-    let _ = variable2.map(|x| {
-        println!();
-        x.to_string()
-        //~^ ERROR: implicitly cloning a `String` by calling `to_string` on its dereferenced type
-    });
-
-    let x = Some(String::new());
-    let _ = x.unwrap_or_else(|| v.to_string());
-    //~^ ERROR: implicitly cloning a `String` by calling `to_string` on its dereferenced type
-}
diff --git a/tests/ui/string_to_string.stderr b/tests/ui/string_to_string.stderr
deleted file mode 100644
index 220fe3170c6..00000000000
--- a/tests/ui/string_to_string.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error: implicitly cloning a `String` by calling `to_string` on its dereferenced type
-  --> tests/ui/string_to_string.rs:6:17
-   |
-LL |     let mut v = message.to_string();
-   |                 ^^^^^^^^^^^^^^^^^^^ help: consider using: `message.clone()`
-   |
-   = note: `-D clippy::implicit-clone` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::implicit_clone)]`
-
-error: implicitly cloning a `String` by calling `to_string` on its dereferenced type
-  --> tests/ui/string_to_string.rs:14:9
-   |
-LL |         x.to_string()
-   |         ^^^^^^^^^^^^^ help: consider using: `x.clone()`
-
-error: implicitly cloning a `String` by calling `to_string` on its dereferenced type
-  --> tests/ui/string_to_string.rs:19:33
-   |
-LL |     let _ = x.unwrap_or_else(|| v.to_string());
-   |                                 ^^^^^^^^^^^^^ help: consider using: `v.clone()`
-
-error: aborting due to 3 previous errors
-
diff --git a/tests/ui/string_to_string_in_map.fixed b/tests/ui/string_to_string_in_map.fixed
deleted file mode 100644
index efc085539f1..00000000000
--- a/tests/ui/string_to_string_in_map.fixed
+++ /dev/null
@@ -1,20 +0,0 @@
-#![deny(clippy::string_to_string)]
-#![allow(clippy::unnecessary_literal_unwrap, clippy::useless_vec, clippy::iter_cloned_collect)]
-
-fn main() {
-    let variable1 = String::new();
-    let v = &variable1;
-    let variable2 = Some(v);
-    let _ = variable2.cloned();
-    //~^ string_to_string
-    let _ = variable2.cloned();
-    //~^ string_to_string
-    #[rustfmt::skip]
-    let _ = variable2.cloned();
-    //~^ string_to_string
-
-    let _ = vec![String::new()].iter().cloned().collect::<Vec<_>>();
-    //~^ string_to_string
-    let _ = vec![String::new()].iter().cloned().collect::<Vec<_>>();
-    //~^ string_to_string
-}
diff --git a/tests/ui/string_to_string_in_map.rs b/tests/ui/string_to_string_in_map.rs
deleted file mode 100644
index 5bf1d7ba5a2..00000000000
--- a/tests/ui/string_to_string_in_map.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-#![deny(clippy::string_to_string)]
-#![allow(clippy::unnecessary_literal_unwrap, clippy::useless_vec, clippy::iter_cloned_collect)]
-
-fn main() {
-    let variable1 = String::new();
-    let v = &variable1;
-    let variable2 = Some(v);
-    let _ = variable2.map(String::to_string);
-    //~^ string_to_string
-    let _ = variable2.map(|x| x.to_string());
-    //~^ string_to_string
-    #[rustfmt::skip]
-    let _ = variable2.map(|x| { x.to_string() });
-    //~^ string_to_string
-
-    let _ = vec![String::new()].iter().map(String::to_string).collect::<Vec<_>>();
-    //~^ string_to_string
-    let _ = vec![String::new()].iter().map(|x| x.to_string()).collect::<Vec<_>>();
-    //~^ string_to_string
-}
diff --git a/tests/ui/string_to_string_in_map.stderr b/tests/ui/string_to_string_in_map.stderr
deleted file mode 100644
index 35aeed656ee..00000000000
--- a/tests/ui/string_to_string_in_map.stderr
+++ /dev/null
@@ -1,38 +0,0 @@
-error: `to_string()` called on a `String`
-  --> tests/ui/string_to_string_in_map.rs:8:23
-   |
-LL |     let _ = variable2.map(String::to_string);
-   |                       ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cloned()`
-   |
-note: the lint level is defined here
-  --> tests/ui/string_to_string_in_map.rs:1:9
-   |
-LL | #![deny(clippy::string_to_string)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `to_string()` called on a `String`
-  --> tests/ui/string_to_string_in_map.rs:10:23
-   |
-LL |     let _ = variable2.map(|x| x.to_string());
-   |                       ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cloned()`
-
-error: `to_string()` called on a `String`
-  --> tests/ui/string_to_string_in_map.rs:13:23
-   |
-LL |     let _ = variable2.map(|x| { x.to_string() });
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cloned()`
-
-error: `to_string()` called on a `String`
-  --> tests/ui/string_to_string_in_map.rs:16:40
-   |
-LL |     let _ = vec![String::new()].iter().map(String::to_string).collect::<Vec<_>>();
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cloned()`
-
-error: `to_string()` called on a `String`
-  --> tests/ui/string_to_string_in_map.rs:18:40
-   |
-LL |     let _ = vec![String::new()].iter().map(|x| x.to_string()).collect::<Vec<_>>();
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cloned()`
-
-error: aborting due to 5 previous errors
-