Extend implicit_clone to handle to_string calls (#14177)

Put another way, merge `string_to_string` into `implicit_clone`, as
suggested here:
https://github.com/rust-lang/rust-clippy/issues/14173#issuecomment-2645846915

Note: [I
wrote](https://github.com/rust-lang/rust-clippy/commit/b8913894a13431bea99400dc9f53a1fd9f41a6c6)
this comment:
https://github.com/rust-lang/rust-clippy/blob/6cdb7f68c39a2458c6b8f6dc63da4123a6a5af89/clippy_lints/src/methods/implicit_clone.rs#L43-L45

Here is the context for why I wrote it:
https://github.com/rust-lang/rust-clippy/pull/7978#discussion_r769128853

Regardless, it's probably time for the comment to go away. Extending
`implicit_clone` to handle `to_string` calls yields many hits within
Clippy's codebase.

changelog: extend `implicit_clone` to handle `to_string` calls
This commit is contained in:
Timo
2025-08-02 11:41:00 +00:00
committed by GitHub
28 changed files with 61 additions and 285 deletions
+3 -3
View File
@@ -47,9 +47,9 @@ unset CARGO_MANIFEST_DIR
# Run a lint and make sure it produces the expected output. It's also expected to exit with code 1
# FIXME: How to match the clippy invocation in compile-test.rs?
./target/debug/clippy-driver -Dwarnings -Aunused -Zui-testing --emit metadata --crate-type bin tests/ui/string_to_string.rs 2>string_to_string.stderr && exit 1
sed -e "/= help: for/d" string_to_string.stderr > normalized.stderr
diff -u normalized.stderr tests/ui/string_to_string.stderr
./target/debug/clippy-driver -Dwarnings -Aunused -Zui-testing --emit metadata --crate-type bin tests/ui/char_lit_as_u8.rs 2>char_lit_as_u8.stderr && exit 1
sed -e "/= help: for/d" char_lit_as_u8.stderr > normalized.stderr
diff -u normalized.stderr tests/ui/char_lit_as_u8.stderr
# make sure "clippy-driver --rustc --arg" and "rustc --arg" behave the same
SYSROOT=$(rustc --print sysroot)
+1 -2
View File
@@ -100,8 +100,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
cond.span,
BRACED_EXPR_MESSAGE,
"try",
snippet_block_with_applicability(cx, ex.span, "..", Some(expr.span), &mut applicability)
.to_string(),
snippet_block_with_applicability(cx, ex.span, "..", Some(expr.span), &mut applicability),
applicability,
);
}
+3 -3
View File
@@ -235,9 +235,9 @@ fn lint_branches_sharing_code<'tcx>(
let cond_snippet = reindent_multiline(&snippet(cx, cond_span, "_"), false, None);
let cond_indent = indent_of(cx, cond_span);
let moved_snippet = reindent_multiline(&snippet(cx, span, "_"), true, None);
let suggestion = moved_snippet.to_string() + "\n" + &cond_snippet + "{";
let suggestion = moved_snippet + "\n" + &cond_snippet + "{";
let suggestion = reindent_multiline(&suggestion, true, cond_indent);
(replace_span, suggestion.to_string())
(replace_span, suggestion)
});
let end_suggestion = res.end_span(last_block, sm).map(|span| {
let moved_snipped = reindent_multiline(&snippet(cx, span, "_"), true, None);
@@ -253,7 +253,7 @@ fn lint_branches_sharing_code<'tcx>(
.then_some(range.start - 4..range.end)
})
.map_or(span, |range| range.with_ctxt(span.ctxt()));
(span, suggestion.to_string())
(span, suggestion.clone())
});
let (span, msg, end_span) = match (&start_suggestion, &end_suggestion) {
-1
View File
@@ -690,7 +690,6 @@
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,
+2
View File
@@ -34,6 +34,8 @@ macro_rules! declare_with_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"]
+1 -1
View File
@@ -81,7 +81,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
e.span,
msg,
"try",
make_sugg(cx, &cond.kind, cond_inner.span, els.span, "..", Some(e.span)).to_string(),
make_sugg(cx, &cond.kind, cond_inner.span, els.span, "..", Some(e.span)),
Applicability::MachineApplicable,
),
_ => span_lint_and_help(cx, IF_NOT_ELSE, e.span, msg, None, help),
-1
View File
@@ -665,7 +665,6 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
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));
+1 -1
View File
@@ -83,7 +83,7 @@ fn check_fn(
format!("{} async {}", vis_snip, &header_snip[vis_snip.len() + 1..ret_pos])
};
let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span)).to_string();
let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span));
diag.multipart_suggestion(
"make the function `async` and return the output of the future directly",
@@ -31,9 +31,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
let match_body = peel_blocks(arms[0].body);
let mut app = Applicability::MaybeIncorrect;
let ctxt = expr.span.ctxt();
let mut snippet_body = snippet_block_with_context(cx, match_body.span, ctxt, "..", Some(expr.span), &mut app)
.0
.to_string();
let mut snippet_body = snippet_block_with_context(cx, match_body.span, ctxt, "..", Some(expr.span), &mut app).0;
// Do we need to add ';' to suggestion ?
if let Node::Stmt(stmt) = cx.tcx.parent_hir_node(expr.hir_id)
+3 -5
View File
@@ -112,9 +112,7 @@ fn report_single_pattern(
let (sugg, help) = if is_unit_expr(arm.body) {
(String::new(), "`match` expression can be removed")
} else {
let mut sugg = snippet_block_with_context(cx, arm.body.span, ctxt, "..", Some(expr.span), &mut app)
.0
.to_string();
let mut sugg = snippet_block_with_context(cx, arm.body.span, ctxt, "..", Some(expr.span), &mut app).0;
if let Node::Stmt(stmt) = cx.tcx.parent_hir_node(expr.hir_id)
&& let StmtKind::Expr(_) = stmt.kind
&& match arm.body.kind {
@@ -127,7 +125,7 @@ fn report_single_pattern(
(sugg, "try")
};
span_lint_and_then(cx, lint, expr.span, msg, |diag| {
diag.span_suggestion(expr.span, help, sugg.to_string(), app);
diag.span_suggestion(expr.span, help, sugg, app);
note(diag);
});
return;
@@ -188,7 +186,7 @@ fn report_single_pattern(
};
span_lint_and_then(cx, lint, expr.span, msg, |diag| {
diag.span_suggestion(expr.span, "try", sugg.to_string(), app);
diag.span_suggestion(expr.span, "try", sugg, app);
note(diag);
});
}
+1 -3
View File
@@ -40,14 +40,12 @@ pub fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &hir::Expr<'_>, re
}
/// Returns true if the named method can be used to clone the receiver.
/// Note that `to_string` is not flagged by `implicit_clone`. So other lints that call
/// `is_clone_like` and that do flag `to_string` must handle it separately. See, e.g.,
/// `is_to_owned_like` in `unnecessary_to_owned.rs`.
pub fn is_clone_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: hir::def_id::DefId) -> bool {
match method_name {
sym::to_os_string => is_diag_item_method(cx, method_def_id, sym::OsStr),
sym::to_owned => is_diag_trait_item(cx, method_def_id, sym::ToOwned),
sym::to_path_buf => is_diag_item_method(cx, method_def_id, sym::Path),
sym::to_string => is_diag_trait_item(cx, method_def_id, sym::ToString),
sym::to_vec => cx
.tcx
.impl_of_method(method_def_id)
+1 -1
View File
@@ -5450,7 +5450,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
implicit_clone::check(cx, name, expr, recv);
}
},
(sym::to_os_string | sym::to_path_buf | sym::to_vec, []) => {
(sym::to_os_string | sym::to_path_buf | sym::to_string | sym::to_vec, []) => {
implicit_clone::check(cx, name, expr, recv);
},
(sym::type_id, []) => {
@@ -216,7 +216,7 @@ pub(super) fn check<'tcx>(
{
format!("{}::cmp::Reverse({})", std_or_core, trigger.closure_body)
} else {
trigger.closure_body.to_string()
trigger.closure_body
},
),
if trigger.reverse {
@@ -621,8 +621,8 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id:
/// Returns true if the named method can be used to convert the receiver to its "owned"
/// representation.
fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool {
is_clone_like(cx, method_name, method_def_id)
|| is_cow_into_owned(cx, method_name, method_def_id)
is_cow_into_owned(cx, method_name, method_def_id)
|| (method_name != sym::to_string && is_clone_like(cx, method_name, method_def_id))
|| is_to_string_on_string_like(cx, call_expr, method_name, method_def_id)
}
+1 -1
View File
@@ -97,7 +97,7 @@ fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) {
els.span.with_lo(then.span.hi()),
"redundant else block",
"remove the `else` block and move the contents out",
make_sugg(cx, els.span, "..", Some(expr.span)).to_string(),
make_sugg(cx, els.span, "..", Some(expr.span)),
app,
);
}
-121
View File
@@ -13,8 +13,6 @@
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
@@ -411,125 +409,6 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
}
}
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)
{
if let Some(parent_span) = is_called_from_map_like(cx, expr) {
suggest_cloned_string_to_string(cx, parent_span);
} else {
#[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
span_lint_and_then(
cx,
STRING_TO_STRING,
expr.span,
"`to_string()` called on a `String`",
|diag| {
diag.help("consider using `.clone()`");
},
);
}
}
},
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`.
+1 -1
View File
@@ -117,7 +117,7 @@ pub fn read_crates(toml_path: &Path) -> (Vec<CrateWithSource>, RecursiveOptions)
crate_sources.push(CrateWithSource {
name: tk.name.clone(),
source: CrateSource::CratesIo {
version: version.to_string(),
version: version.clone(),
},
file_link: tk.file_link(DEFAULT_DOCS_LINK),
options: tk.options.clone(),
+1 -1
View File
@@ -220,7 +220,7 @@ fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, us
let same_in_both_hashmaps = old_stats
.iter()
.filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val))
.map(|(k, v)| (k.to_string(), *v))
.map(|(k, v)| (k.clone(), *v))
.collect::<Vec<(String, usize)>>();
let mut old_stats_deduped = old_stats;
+1
View File
@@ -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`
+12 -6
View File
@@ -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
+6
View File
@@ -135,4 +135,10 @@ fn main() {
}
let no_clone = &NoClone;
let _ = no_clone.to_owned();
let s = String::from("foo");
let _ = s.clone();
//~^ implicit_clone
let _ = s.clone();
//~^ implicit_clone
}
+6
View File
@@ -135,4 +135,10 @@ fn to_owned(&self) -> Self {
}
let no_clone = &NoClone;
let _ = no_clone.to_owned();
let s = String::from("foo");
let _ = s.to_owned();
//~^ implicit_clone
let _ = s.to_string();
//~^ implicit_clone
}
+13 -1
View File
@@ -67,5 +67,17 @@ error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenc
LL | let _ = pathbuf_ref.to_path_buf();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(**pathbuf_ref).clone()`
error: aborting due to 11 previous errors
error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type
--> tests/ui/implicit_clone.rs:140:13
|
LL | let _ = s.to_owned();
| ^^^^^^^^^^^^ help: consider using: `s.clone()`
error: implicitly cloning a `String` by calling `to_string` on its dereferenced type
--> tests/ui/implicit_clone.rs:142:13
|
LL | let _ = s.to_string();
| ^^^^^^^^^^^^^ help: consider using: `s.clone()`
error: aborting due to 13 previous errors
-21
View File
@@ -1,21 +0,0 @@
#![warn(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();
//~^ string_to_string
let variable1 = String::new();
let v = &variable1;
let variable2 = Some(v);
let _ = variable2.map(|x| {
println!();
x.to_string()
});
//~^^ string_to_string
let x = Some(String::new());
let _ = x.unwrap_or_else(|| v.to_string());
//~^ string_to_string
}
-28
View File
@@ -1,28 +0,0 @@
error: `to_string()` called on a `String`
--> tests/ui/string_to_string.rs:6:17
|
LL | let mut v = message.to_string();
| ^^^^^^^^^^^^^^^^^^^
|
= help: consider using `.clone()`
= note: `-D clippy::string-to-string` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::string_to_string)]`
error: `to_string()` called on a `String`
--> tests/ui/string_to_string.rs:14:9
|
LL | x.to_string()
| ^^^^^^^^^^^^^
|
= help: consider using `.clone()`
error: `to_string()` called on a `String`
--> tests/ui/string_to_string.rs:19:33
|
LL | let _ = x.unwrap_or_else(|| v.to_string());
| ^^^^^^^^^^^^^
|
= help: consider using `.clone()`
error: aborting due to 3 previous errors
-20
View File
@@ -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
}
-20
View File
@@ -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
}
-38
View File
@@ -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