Merge remote-tracking branch 'upstream/master' into rustup

This commit is contained in:
Philipp Krones
2026-02-19 15:38:57 +01:00
26 changed files with 604 additions and 267 deletions
+14 -27
View File
@@ -1,13 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::numeric_literal::NumericLiteral;
use clippy_utils::res::MaybeResPath;
use clippy_utils::res::MaybeResPath as _;
use clippy_utils::source::{SpanRangeExt, snippet_opt};
use clippy_utils::visitors::{Visitable, for_each_expr_without_closures};
use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias};
use rustc_ast::{LitFloatType, LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp};
use rustc_hir::{Expr, ExprKind, FnRetTy, Lit, Node, Path, QPath, TyKind, UnOp};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::{self, FloatTy, InferTy, Ty};
@@ -97,7 +97,7 @@ pub(super) fn check<'tcx>(
// skip cast of fn call that returns type alias
if let ExprKind::Cast(inner, ..) = expr.kind
&& is_cast_from_ty_alias(cx, inner, cast_from)
&& is_cast_from_ty_alias(cx, inner)
{
return false;
}
@@ -270,34 +270,25 @@ fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
/// Finds whether an `Expr` returns a type alias.
///
/// TODO: Maybe we should move this to `clippy_utils` so others won't need to go down this dark,
/// dark path reimplementing this (or something similar).
fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx>, cast_from: Ty<'tcx>) -> bool {
/// When in doubt, for example because it calls a non-local function that we don't have the
/// declaration for, assume if might be a type alias.
fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx>) -> bool {
for_each_expr_without_closures(expr, |expr| {
// Calls are a `Path`, and usage of locals are a `Path`. So, this checks
// - call() as i32
// - local as i32
if let ExprKind::Path(qpath) = expr.kind {
let res = cx.qpath_res(&qpath, expr.hir_id);
// Function call
if let Res::Def(DefKind::Fn, def_id) = res {
let Some(snippet) = cx.tcx.def_span(def_id).get_source_text(cx) else {
return ControlFlow::Continue(());
let Some(def_id) = def_id.as_local() else {
// External function, we can't know, better be safe
return ControlFlow::Break(());
};
// This is the worst part of this entire function. This is the only way I know of to
// check whether a function returns a type alias. Sure, you can get the return type
// from a function in the current crate as an hir ty, but how do you get it for
// external functions?? Simple: It's impossible. So, we check whether a part of the
// function's declaration snippet is exactly equal to the `Ty`. That way, we can
// see whether it's a type alias.
//
// FIXME: This won't work if the type is given an alias through `use`, should we
// consider this a type alias as well?
if !snippet
.split("->")
.skip(1)
.any(|s| snippet_eq_ty(s, cast_from) || s.split("where").any(|ty| snippet_eq_ty(ty, cast_from)))
if let Some(FnRetTy::Return(ty)) = cx.tcx.hir_get_fn_output(def_id)
&& let TyKind::Path(qpath) = ty.kind
&& is_ty_alias(&qpath)
{
// Function call to a local function returning a type alias
return ControlFlow::Break(());
}
// Local usage
@@ -305,7 +296,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
&& let Node::LetStmt(l) = cx.tcx.parent_hir_node(hir_id)
{
if let Some(e) = l.init
&& is_cast_from_ty_alias(cx, e, cast_from)
&& is_cast_from_ty_alias(cx, e)
{
return ControlFlow::Break::<()>(());
}
@@ -323,7 +314,3 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
})
.is_some()
}
fn snippet_eq_ty(snippet: &str, ty: Ty<'_>) -> bool {
snippet.trim() == ty.to_string() || snippet.trim().contains(&format!("::{ty}"))
}
+2 -2
View File
@@ -245,8 +245,8 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
// We want to lint unsafe blocks #0 and #1
let bad_unsafe_blocks = self
.metavar_expns
.iter()
.filter_map(|(_, state)| match state {
.values()
.filter_map(|state| match state {
MetavarState::ReferencedInUnsafe { unsafe_blocks } => Some(unsafe_blocks.as_slice()),
MetavarState::ReferencedInSafe => None,
})
+2 -1
View File
@@ -21,6 +21,7 @@ pub(super) fn check<'tcx>(
recv: &'tcx Expr<'tcx>, // hashmap
m_arg: &'tcx Expr<'tcx>, // |(_, v)| v
msrv: Msrv,
method_name: Symbol,
) {
if map_type == sym::into_iter && !msrv.meets(cx, msrvs::INTO_KEYS) {
return;
@@ -67,7 +68,7 @@ pub(super) fn check<'tcx>(
format!("iterating on a map's {replacement_kind}s"),
"try",
format!(
"{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {body_snippet})",
"{recv_snippet}.{into_prefix}{replacement_kind}s().{method_name}(|{}{bound_ident}| {body_snippet})",
annotation.prefix_str(),
),
applicability,
@@ -1,13 +1,15 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{implements_trait, is_copy};
use clippy_utils::visitors::for_each_expr_without_closures;
use core::ops::ControlFlow;
use rustc_ast::BindingMode;
use rustc_errors::Applicability;
use rustc_hir::{Body, Expr, ExprKind, HirId, HirIdSet, PatKind};
use rustc_hir::{Body, CaptureBy, Closure, Expr, ExprKind, HirId, HirIdSet, Param, PatKind};
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_lint::LateContext;
use rustc_middle::mir::{FakeReadCause, Mutability};
use rustc_middle::ty::{self, BorrowKind};
use rustc_middle::ty::{self, BorrowKind, UpvarCapture};
use rustc_span::{Symbol, sym};
use super::{ITER_OVEREAGER_CLONED, REDUNDANT_ITER_CLONED};
@@ -64,6 +66,11 @@ pub(super) fn check<'tcx>(
let body @ Body { params: [p], .. } = cx.tcx.hir_body(closure.body) else {
return;
};
if param_captured_by_move_block(cx, body.value, p) {
return;
}
let mut delegate = MoveDelegate {
used_move: HirIdSet::default(),
};
@@ -140,6 +147,34 @@ struct MoveDelegate {
used_move: HirIdSet,
}
/// Checks if the expression contains a closure or coroutine with `move` capture semantics that
/// captures the given parameter.
fn param_captured_by_move_block(cx: &LateContext<'_>, expr: &Expr<'_>, param: &Param<'_>) -> bool {
let mut param_hir_ids = HirIdSet::default();
param.pat.walk(|pat| {
param_hir_ids.insert(pat.hir_id);
true
});
for_each_expr_without_closures(expr, |e| {
if let ExprKind::Closure(Closure {
capture_clause: CaptureBy::Value { .. },
def_id,
..
}) = e.kind
&& cx.tcx.closure_captures(*def_id).iter().any(|capture| {
matches!(capture.info.capture_kind, UpvarCapture::ByValue)
&& matches!(capture.place.base, PlaceBase::Upvar(upvar) if param_hir_ids.contains(&upvar.var_path.hir_id))
})
{
return ControlFlow::Break(());
}
ControlFlow::Continue(())
})
.is_some()
}
impl<'tcx> Delegate<'tcx> for MoveDelegate {
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, _: HirId) {
if let PlaceBase::Local(l) = place_with_id.place.base {
+7 -1
View File
@@ -5275,6 +5275,9 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
call_span,
self.msrv,
);
if let Some((map_name @ (sym::iter | sym::into_iter), recv2, _, _, _)) = method_call(recv) {
iter_kv_map::check(cx, map_name, expr, recv2, arg, self.msrv, sym::filter_map);
}
},
(sym::find_map, [arg]) => {
unnecessary_filter_map::check(cx, expr, arg, call_span, unnecessary_filter_map::Kind::FindMap);
@@ -5285,6 +5288,9 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
lines_filter_map_ok::check_filter_or_flat_map(
cx, expr, recv, "flat_map", arg, call_span, self.msrv,
);
if let Some((map_name @ (sym::iter | sym::into_iter), recv2, _, _, _)) = method_call(recv) {
iter_kv_map::check(cx, map_name, expr, recv2, arg, self.msrv, sym::flat_map);
}
},
(sym::flatten, []) => {
match method_call(recv) {
@@ -5383,7 +5389,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
manual_is_variant_and::check_map(cx, expr);
match method_call(recv) {
Some((map_name @ (sym::iter | sym::into_iter), recv2, _, _, _)) => {
iter_kv_map::check(cx, map_name, expr, recv2, m_arg, self.msrv);
iter_kv_map::check(cx, map_name, expr, recv2, m_arg, self.msrv, sym::map);
},
Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
cx,
@@ -99,10 +99,6 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
self.found = true;
return;
},
ExprKind::If(..) => {
self.found = true;
return;
},
ExprKind::Path(_) => {
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id)
&& adj
+3 -1
View File
@@ -417,6 +417,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
&& args.iter().any(|a| a.hir_id == expr.hir_id)
&& let Res::Def(DefKind::AssocFn, def_id) = expr.res(cx)
&& cx.tcx.is_diagnostic_item(sym::to_string_method, def_id)
&& let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id)
&& args.type_at(0).is_str()
{
// Detected `ToString::to_string` passed as an argument (generic: any call or method call)
span_lint_and_sugg(
@@ -425,7 +427,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
expr.span,
"`ToString::to_string` used as `&str` to `String` converter",
"try",
"ToOwned::to_owned".to_string(),
"str::to_owned".to_string(),
Applicability::MachineApplicable,
);
}
+2 -2
View File
@@ -820,8 +820,8 @@ pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
matches!(
(l, r),
(Defaultness::Implicit, Defaultness::Implicit)
| (Defaultness::Default(_), Defaultness::Default(_))
| (Defaultness::Final(_), Defaultness::Final(_))
| (Defaultness::Default(_), Defaultness::Default(_))
| (Defaultness::Final(_), Defaultness::Final(_))
)
}
+4 -5
View File
@@ -2340,12 +2340,11 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl FnOnce(&
&& let item = tcx.hir_item(id)
&& let ItemKind::Const(ident, _generics, ty, _body) = item.kind
&& let TyKind::Path(QPath::Resolved(_, path)) = ty.kind
// We could also check for the type name `test::TestDescAndFn`
&& let Res::Def(DefKind::Struct, _) = path.res
// We could also check for the type name `test::TestDescAndFn`
&& let Res::Def(DefKind::Struct, _) = path.res
&& find_attr!(tcx.hir_attrs(item.hir_id()), AttributeKind::RustcTestMarker(..))
{
if find_attr!(tcx.hir_attrs(item.hir_id()), AttributeKind::RustcTestMarker(..)) {
names.push(ident.name);
}
names.push(ident.name);
}
}
names.sort_unstable();
+1
View File
@@ -126,6 +126,7 @@ fn config(&mut self, config: &mut interface::Config) {
config.psess_created = Some(Box::new(move |psess| {
track_clippy_args(psess, clippy_args_var.as_deref());
}));
config.extra_symbols = sym::EXTRA_SYMBOLS.into();
}
}
+2 -5
View File
@@ -197,10 +197,6 @@ fn base_config(&self, test_dir: &str, mandatory_annotations: bool) -> Config {
defaults.set_custom("diagnostic-collector", collector);
}
config.with_args(&self.args);
let current_exe_path = env::current_exe().unwrap();
let deps_path = current_exe_path.parent().unwrap();
let profile_path = deps_path.parent().unwrap();
config.program.args.extend(
[
"--emit=metadata",
@@ -224,6 +220,7 @@ fn base_config(&self, test_dir: &str, mandatory_annotations: bool) -> Config {
config.program.args.push(format!("--sysroot={sysroot}").into());
}
let profile_path = target_dir.join(env!("PROFILE"));
config.program.program = profile_path.join(if cfg!(windows) {
"clippy-driver.exe"
} else {
@@ -469,7 +466,7 @@ enum DiagnosticOrMessage {
}
/// Collects applicabilities from the diagnostics produced for each UI test, producing the
/// `util/gh-pages/lints.json` file used by <https://rust-lang.github.io/rust-clippy/>
/// `util/gh-pages/index.html` file used by <https://rust-lang.github.io/rust-clippy/>
#[derive(Debug, Clone)]
struct DiagnosticCollector {
sender: Sender<Vec<u8>>,
+8 -2
View File
@@ -114,6 +114,12 @@ fn issue16322(item: String) {
}
fn issue16458() {
macro_rules! m {
() => {
""
};
}
macro_rules! partly_comes_from_macro {
($i:ident: $ty:ty, $def:expr) => {
let _ = {
@@ -125,7 +131,7 @@ fn issue16458() {
}
partly_comes_from_macro! {
required_version: String, env!("HOME").to_string()
required_version: String, m!().to_string()
}
macro_rules! all_comes_from_macro {
@@ -141,6 +147,6 @@ fn issue16458() {
};
}
all_comes_from_macro! {
required_version: String, env!("HOME").to_string();
required_version: String, m!().to_string();
}
}
+8 -2
View File
@@ -114,6 +114,12 @@ fn issue16322(item: String) {
}
fn issue16458() {
macro_rules! m {
() => {
""
};
}
macro_rules! partly_comes_from_macro {
($i:ident: $ty:ty, $def:expr) => {
let _ = {
@@ -125,7 +131,7 @@ macro_rules! partly_comes_from_macro {
}
partly_comes_from_macro! {
required_version: String, env!("HOME").to_string()
required_version: String, m!().to_string()
}
macro_rules! all_comes_from_macro {
@@ -141,6 +147,6 @@ macro_rules! all_comes_from_macro {
};
}
all_comes_from_macro! {
required_version: String, env!("HOME").to_string();
required_version: String, m!().to_string();
}
}
+2 -2
View File
@@ -56,13 +56,13 @@ LL | if item == t!(frohes_neu_Jahr).to_string() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(frohes_neu_Jahr)`
error: this creates an owned instance just for comparison
--> tests/ui/cmp_owned/with_suggestion.rs:135:51
--> tests/ui/cmp_owned/with_suggestion.rs:141:51
|
LL | let res = <$ty>::default() == "$def".to_string();
| ^^^^^^^^^^^^^^^^^^ help: try: `"$def"`
...
LL | / all_comes_from_macro! {
LL | | required_version: String, env!("HOME").to_string();
LL | | required_version: String, m!().to_string();
LL | | }
| |_____- in this macro invocation
|
+37 -1
View File
@@ -1,5 +1,11 @@
#![warn(clippy::iter_kv_map)]
#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)]
#![allow(
unused_mut,
clippy::redundant_clone,
clippy::redundant_closure,
clippy::suspicious_map,
clippy::map_identity
)]
use std::collections::{BTreeMap, HashMap};
@@ -195,3 +201,33 @@ fn issue16340() {
let _ = hm.keys().map(|key| vec![key]);
//~^ iter_kv_map
}
fn issue16515() {
let hash_map: HashMap<u32, u32> = HashMap::new();
hash_map.keys().flat_map(|k| Some(*k));
//~^ iter_kv_map
hash_map.values().flat_map(|v| Some(*v));
//~^ iter_kv_map
hash_map.keys().filter_map(|k| (k > &0).then_some(1));
//~^ iter_kv_map
hash_map.values().filter_map(|v| (v > &0).then_some(1));
//~^ iter_kv_map
hash_map.into_keys().flat_map(|k| Some(k));
//~^ iter_kv_map
let hash_map: HashMap<u32, u32> = HashMap::new();
hash_map.into_values().flat_map(|v| Some(v));
//~^ iter_kv_map
let hash_map: HashMap<u32, u32> = HashMap::new();
hash_map.into_keys().filter_map(|k| (k > 0).then_some(1));
//~^ iter_kv_map
let hash_map: HashMap<u32, u32> = HashMap::new();
hash_map.into_values().filter_map(|v| (v > 0).then_some(1));
//~^ iter_kv_map
}
+37 -1
View File
@@ -1,5 +1,11 @@
#![warn(clippy::iter_kv_map)]
#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)]
#![allow(
unused_mut,
clippy::redundant_clone,
clippy::redundant_closure,
clippy::suspicious_map,
clippy::map_identity
)]
use std::collections::{BTreeMap, HashMap};
@@ -199,3 +205,33 @@ fn issue16340() {
let _ = hm.iter().map(|(key, _)| vec![key]);
//~^ iter_kv_map
}
fn issue16515() {
let hash_map: HashMap<u32, u32> = HashMap::new();
hash_map.iter().flat_map(|(k, _)| Some(*k));
//~^ iter_kv_map
hash_map.iter().flat_map(|(_, v)| Some(*v));
//~^ iter_kv_map
hash_map.iter().filter_map(|(k, _)| (k > &0).then_some(1));
//~^ iter_kv_map
hash_map.iter().filter_map(|(_, v)| (v > &0).then_some(1));
//~^ iter_kv_map
hash_map.into_iter().flat_map(|(k, _)| Some(k));
//~^ iter_kv_map
let hash_map: HashMap<u32, u32> = HashMap::new();
hash_map.into_iter().flat_map(|(_, v)| Some(v));
//~^ iter_kv_map
let hash_map: HashMap<u32, u32> = HashMap::new();
hash_map.into_iter().filter_map(|(k, _)| (k > 0).then_some(1));
//~^ iter_kv_map
let hash_map: HashMap<u32, u32> = HashMap::new();
hash_map.into_iter().filter_map(|(_, v)| (v > 0).then_some(1));
//~^ iter_kv_map
}
+174 -126
View File
@@ -1,5 +1,5 @@
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:14:13
--> tests/ui/iter_kv_map.rs:20:13
|
LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
@@ -8,174 +8,73 @@ LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
= help: to override `-D warnings` add `#[allow(clippy::iter_kv_map)]`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:16:13
--> tests/ui/iter_kv_map.rs:22:13
|
LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:18:13
--> tests/ui/iter_kv_map.rs:24:13
|
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:21:13
--> tests/ui/iter_kv_map.rs:27:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:23:13
--> tests/ui/iter_kv_map.rs:29:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:26:13
--> tests/ui/iter_kv_map.rs:32:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:28:13
--> tests/ui/iter_kv_map.rs:34:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:31:13
--> tests/ui/iter_kv_map.rs:37:13
|
LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:33:13
--> tests/ui/iter_kv_map.rs:39:13
|
LL | let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:48:13
|
LL | let _ = map.iter().map(|(key, _value)| key * 9).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:50:13
|
LL | let _ = map.iter().map(|(_key, value)| value * 17).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:54:13
|
LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:58:13
|
LL | let _ = map
| _____________^
LL | |
LL | | .clone()
LL | | .into_iter()
... |
LL | | val
LL | | })
| |__________^
|
help: try
|
LL ~ let _ = map
LL +
LL + .clone().into_values().map(|mut val| {
LL + val += 2;
LL + val
LL + })
|
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:69:13
|
LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:74:13
|
LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:76:13
|
LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:78:13
|
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:81:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:83:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:86:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:88:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:91:13
|
LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:93:13
|
LL | let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:108:13
|
LL | let _ = map.iter().map(|(key, _value)| key * 9).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:110:13
--> tests/ui/iter_kv_map.rs:56:13
|
LL | let _ = map.iter().map(|(_key, value)| value * 17).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:114:13
--> tests/ui/iter_kv_map.rs:60:13
|
LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:118:13
--> tests/ui/iter_kv_map.rs:64:13
|
LL | let _ = map
| _____________^
@@ -198,82 +97,231 @@ LL + })
|
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:129:13
--> tests/ui/iter_kv_map.rs:75:13
|
LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:145:13
--> tests/ui/iter_kv_map.rs:80:13
|
LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:148:13
--> tests/ui/iter_kv_map.rs:82:13
|
LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:151:13
--> tests/ui/iter_kv_map.rs:84:13
|
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:160:13
--> tests/ui/iter_kv_map.rs:87:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:163:13
--> tests/ui/iter_kv_map.rs:89:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:166:13
--> tests/ui/iter_kv_map.rs:92:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:169:13
--> tests/ui/iter_kv_map.rs:94:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:97:13
|
LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:172:13
--> tests/ui/iter_kv_map.rs:99:13
|
LL | let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:114:13
|
LL | let _ = map.iter().map(|(key, _value)| key * 9).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:116:13
|
LL | let _ = map.iter().map(|(_key, value)| value * 17).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:120:13
|
LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:124:13
|
LL | let _ = map
| _____________^
LL | |
LL | | .clone()
LL | | .into_iter()
... |
LL | | val
LL | | })
| |__________^
|
help: try
|
LL ~ let _ = map
LL +
LL + .clone().into_values().map(|mut val| {
LL + val += 2;
LL + val
LL + })
|
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:135:13
|
LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:151:13
|
LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:154:13
|
LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:157:13
|
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:166:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:169:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:172:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:175:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:178:13
|
LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:181:13
|
LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:178:13
--> tests/ui/iter_kv_map.rs:184:13
|
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:193:13
--> tests/ui/iter_kv_map.rs:199:13
|
LL | let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.as_ref().values()`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:199:13
--> tests/ui/iter_kv_map.rs:205:13
|
LL | let _ = hm.iter().map(|(key, _)| vec![key]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hm.keys().map(|key| vec![key])`
error: aborting due to 40 previous errors
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:211:5
|
LL | hash_map.iter().flat_map(|(k, _)| Some(*k));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.keys().flat_map(|k| Some(*k))`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:214:5
|
LL | hash_map.iter().flat_map(|(_, v)| Some(*v));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.values().flat_map(|v| Some(*v))`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:217:5
|
LL | hash_map.iter().filter_map(|(k, _)| (k > &0).then_some(1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.keys().filter_map(|k| (k > &0).then_some(1))`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:220:5
|
LL | hash_map.iter().filter_map(|(_, v)| (v > &0).then_some(1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.values().filter_map(|v| (v > &0).then_some(1))`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:223:5
|
LL | hash_map.into_iter().flat_map(|(k, _)| Some(k));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.into_keys().flat_map(|k| Some(k))`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:227:5
|
LL | hash_map.into_iter().flat_map(|(_, v)| Some(v));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.into_values().flat_map(|v| Some(v))`
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:231:5
|
LL | hash_map.into_iter().filter_map(|(k, _)| (k > 0).then_some(1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.into_keys().filter_map(|k| (k > 0).then_some(1))`
error: iterating on a map's values
--> tests/ui/iter_kv_map.rs:235:5
|
LL | hash_map.into_iter().filter_map(|(_, v)| (v > 0).then_some(1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.into_values().filter_map(|v| (v > 0).then_some(1))`
error: aborting due to 48 previous errors
+60
View File
@@ -102,3 +102,63 @@ fn main() {
fn cloned_flatten(x: Option<&Option<String>>) -> Option<String> {
x.cloned().flatten()
}
mod issue_16428 {
#[derive(Clone)]
struct Foo;
impl Foo {
async fn do_async(&self) {}
}
fn async_move_map() -> Vec<impl std::future::Future<Output = ()>> {
let map: std::collections::HashMap<(), Foo> = std::collections::HashMap::new();
// Should NOT lint: async move block captures `item` by value
map.values()
.cloned()
.map(|item| async move { item.do_async().await })
.collect::<Vec<_>>()
}
fn async_move_for_each() {
let map: std::collections::HashMap<(), Foo> = std::collections::HashMap::new();
// Should NOT lint: async move block captures `item` by value
map.values()
.cloned()
.for_each(|item| drop(async move { item.do_async().await }));
}
fn move_closure() {
let vec = vec!["1".to_string(), "2".to_string()];
// Should NOT lint: move closure captures `x` by value
let _: Vec<_> = vec.iter().cloned().map(|x| move || x.len()).collect();
}
fn async_move_not_capturing_param() {
let vec = vec!["1".to_string(), "2".to_string()];
// Should lint: async move captures `y`, not `x`
let _ = vec.iter().map(|x| {
//~^ redundant_iter_cloned
let y = x.len();
async move { y }
});
}
fn move_closure_not_capturing_param() {
let vec = vec!["1".to_string(), "2".to_string()];
// Should lint: move closure captures `y`, not `x`
let _: Vec<_> = vec
//~^ redundant_iter_cloned
.iter()
.map(|x| {
let y = x.len();
move || y
})
.collect();
}
}
+61
View File
@@ -103,3 +103,64 @@ fn bar<'a>(iter: impl Iterator<Item = &'a S<'a>> + 'a, target: String) -> impl I
fn cloned_flatten(x: Option<&Option<String>>) -> Option<String> {
x.cloned().flatten()
}
mod issue_16428 {
#[derive(Clone)]
struct Foo;
impl Foo {
async fn do_async(&self) {}
}
fn async_move_map() -> Vec<impl std::future::Future<Output = ()>> {
let map: std::collections::HashMap<(), Foo> = std::collections::HashMap::new();
// Should NOT lint: async move block captures `item` by value
map.values()
.cloned()
.map(|item| async move { item.do_async().await })
.collect::<Vec<_>>()
}
fn async_move_for_each() {
let map: std::collections::HashMap<(), Foo> = std::collections::HashMap::new();
// Should NOT lint: async move block captures `item` by value
map.values()
.cloned()
.for_each(|item| drop(async move { item.do_async().await }));
}
fn move_closure() {
let vec = vec!["1".to_string(), "2".to_string()];
// Should NOT lint: move closure captures `x` by value
let _: Vec<_> = vec.iter().cloned().map(|x| move || x.len()).collect();
}
fn async_move_not_capturing_param() {
let vec = vec!["1".to_string(), "2".to_string()];
// Should lint: async move captures `y`, not `x`
let _ = vec.iter().cloned().map(|x| {
//~^ redundant_iter_cloned
let y = x.len();
async move { y }
});
}
fn move_closure_not_capturing_param() {
let vec = vec!["1".to_string(), "2".to_string()];
// Should lint: move closure captures `y`, not `x`
let _: Vec<_> = vec
//~^ redundant_iter_cloned
.iter()
.cloned()
.map(|x| {
let y = x.len();
move || y
})
.collect();
}
}
+43 -1
View File
@@ -165,5 +165,47 @@ LL | let _ = vec.iter().cloned().any(|x| x.len() == 1);
| |
| help: try: `.any(|x| x.len() == 1)`
error: aborting due to 19 previous errors
error: unneeded cloning of iterator items
--> tests/ui/iter_overeager_cloned.rs:145:17
|
LL | let _ = vec.iter().cloned().map(|x| {
| _________________^
LL | |
LL | | let y = x.len();
LL | | async move { y }
LL | | });
| |__________^
|
help: try
|
LL ~ let _ = vec.iter().map(|x| {
LL +
LL + let y = x.len();
LL + async move { y }
LL ~ });
|
error: unneeded cloning of iterator items
--> tests/ui/iter_overeager_cloned.rs:156:25
|
LL | let _: Vec<_> = vec
| _________________________^
LL | |
LL | | .iter()
LL | | .cloned()
... |
LL | | move || y
LL | | })
| |______________^
|
help: try
|
LL ~ .iter()
LL + .map(|x| {
LL + let y = x.len();
LL + move || y
LL + })
|
error: aborting due to 21 previous errors
+15 -10
View File
@@ -1,10 +1,10 @@
#![warn(clippy::str_to_string)]
fn main() {
let hello = "hello world".to_owned();
let hello: String = "hello world".to_owned();
//~^ str_to_string
let msg = &hello[..];
let msg: &str = &hello[..];
msg.to_owned();
//~^ str_to_string
}
@@ -19,7 +19,7 @@ fn issue16271(key: &[u8]) {
};
}
let _value = t!(str::from_utf8(key)).to_owned();
let _value: String = t!(str::from_utf8(key)).to_owned();
//~^ str_to_string
}
@@ -32,22 +32,27 @@ impl<T> GenericWrapper<T> {
}
fn issue16511(x: Option<&str>) {
let _ = x.map(ToOwned::to_owned);
let _: Option<String> = x.map(str::to_owned);
//~^ str_to_string
let _ = x.map(ToOwned::to_owned);
let _: Option<String> = x.map(str::to_owned);
//~^ str_to_string
let _ = ["a", "b"].iter().map(ToOwned::to_owned);
//~^ str_to_string
// This should not trigger the lint because ToOwned::to_owned would produce &str, not String.
let _: Vec<String> = ["a", "b"].iter().map(ToString::to_string).collect();
fn mapper<F: Fn(&str) -> String>(f: F) -> String {
f("hello")
}
let _ = mapper(ToOwned::to_owned);
let _: String = mapper(str::to_owned);
//~^ str_to_string
let w = GenericWrapper("hello");
let _ = w.mapper(ToOwned::to_owned);
let w: GenericWrapper<&str> = GenericWrapper("hello");
let _: String = w.mapper(str::to_owned);
//~^ str_to_string
}
// No lint: non-str types should not trigger str_to_string. See #16569
fn no_lint_non_str() {
let _: Vec<String> = [1, 2].iter().map(i32::to_string).collect();
}
+15 -10
View File
@@ -1,10 +1,10 @@
#![warn(clippy::str_to_string)]
fn main() {
let hello = "hello world".to_string();
let hello: String = "hello world".to_string();
//~^ str_to_string
let msg = &hello[..];
let msg: &str = &hello[..];
msg.to_string();
//~^ str_to_string
}
@@ -19,7 +19,7 @@ macro_rules! t {
};
}
let _value = t!(str::from_utf8(key)).to_string();
let _value: String = t!(str::from_utf8(key)).to_string();
//~^ str_to_string
}
@@ -32,22 +32,27 @@ fn mapper<U, F: FnOnce(T) -> U>(self, f: F) -> U {
}
fn issue16511(x: Option<&str>) {
let _ = x.map(ToString::to_string);
let _: Option<String> = x.map(ToString::to_string);
//~^ str_to_string
let _ = x.map(str::to_string);
let _: Option<String> = x.map(str::to_string);
//~^ str_to_string
let _ = ["a", "b"].iter().map(ToString::to_string);
//~^ str_to_string
// This should not trigger the lint because ToOwned::to_owned would produce &str, not String.
let _: Vec<String> = ["a", "b"].iter().map(ToString::to_string).collect();
fn mapper<F: Fn(&str) -> String>(f: F) -> String {
f("hello")
}
let _ = mapper(ToString::to_string);
let _: String = mapper(ToString::to_string);
//~^ str_to_string
let w = GenericWrapper("hello");
let _ = w.mapper(ToString::to_string);
let w: GenericWrapper<&str> = GenericWrapper("hello");
let _: String = w.mapper(ToString::to_string);
//~^ str_to_string
}
// No lint: non-str types should not trigger str_to_string. See #16569
fn no_lint_non_str() {
let _: Vec<String> = [1, 2].iter().map(i32::to_string).collect();
}
+19 -25
View File
@@ -1,8 +1,8 @@
error: `to_string()` called on a `&str`
--> tests/ui/str_to_string.rs:4:17
--> tests/ui/str_to_string.rs:4:25
|
LL | let hello = "hello world".to_string();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"hello world".to_owned()`
LL | let hello: String = "hello world".to_string();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"hello world".to_owned()`
|
= note: `-D clippy::str-to-string` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::str_to_string)]`
@@ -14,40 +14,34 @@ LL | msg.to_string();
| ^^^^^^^^^^^^^^^ help: try: `msg.to_owned()`
error: `to_string()` called on a `&str`
--> tests/ui/str_to_string.rs:22:18
--> tests/ui/str_to_string.rs:22:26
|
LL | let _value = t!(str::from_utf8(key)).to_string();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(str::from_utf8(key)).to_owned()`
LL | let _value: String = t!(str::from_utf8(key)).to_string();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(str::from_utf8(key)).to_owned()`
error: `ToString::to_string` used as `&str` to `String` converter
--> tests/ui/str_to_string.rs:35:19
--> tests/ui/str_to_string.rs:35:35
|
LL | let _ = x.map(ToString::to_string);
| ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`
LL | let _: Option<String> = x.map(ToString::to_string);
| ^^^^^^^^^^^^^^^^^^^ help: try: `str::to_owned`
error: `ToString::to_string` used as `&str` to `String` converter
--> tests/ui/str_to_string.rs:38:19
--> tests/ui/str_to_string.rs:38:35
|
LL | let _ = x.map(str::to_string);
| ^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`
LL | let _: Option<String> = x.map(str::to_string);
| ^^^^^^^^^^^^^^ help: try: `str::to_owned`
error: `ToString::to_string` used as `&str` to `String` converter
--> tests/ui/str_to_string.rs:41:35
--> tests/ui/str_to_string.rs:47:28
|
LL | let _ = ["a", "b"].iter().map(ToString::to_string);
| ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`
LL | let _: String = mapper(ToString::to_string);
| ^^^^^^^^^^^^^^^^^^^ help: try: `str::to_owned`
error: `ToString::to_string` used as `&str` to `String` converter
--> tests/ui/str_to_string.rs:47:20
--> tests/ui/str_to_string.rs:51:30
|
LL | let _ = mapper(ToString::to_string);
| ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`
LL | let _: String = w.mapper(ToString::to_string);
| ^^^^^^^^^^^^^^^^^^^ help: try: `str::to_owned`
error: `ToString::to_string` used as `&str` to `String` converter
--> tests/ui/str_to_string.rs:51:22
|
LL | let _ = w.mapper(ToString::to_string);
| ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned`
error: aborting due to 8 previous errors
error: aborting due to 7 previous errors
+5 -4
View File
@@ -133,12 +133,13 @@ fn main() {
aaa();
//~^ unnecessary_cast
let x = aaa();
aaa();
x;
//~^ unnecessary_cast
bbb();
//~^ unnecessary_cast
// Will not lint currently.
bbb() as u32;
let x = bbb();
bbb() as u32;
x;
//~^ unnecessary_cast
let i8_ptr: *const i8 = &1;
let u8_ptr: *const u8 = &1;
+4 -3
View File
@@ -133,12 +133,13 @@ pub fn $a() -> $b {
aaa() as u32;
//~^ unnecessary_cast
let x = aaa();
aaa() as u32;
x as u32;
//~^ unnecessary_cast
// Will not lint currently.
bbb() as u32;
//~^ unnecessary_cast
let x = bbb();
bbb() as u32;
x as u32;
//~^ unnecessary_cast
let i8_ptr: *const i8 = &1;
let u8_ptr: *const u8 = &1;
+42 -30
View File
@@ -100,170 +100,182 @@ LL | aaa() as u32;
error: casting to the same type is unnecessary (`u32` -> `u32`)
--> tests/ui/unnecessary_cast.rs:136:5
|
LL | aaa() as u32;
| ^^^^^^^^^^^^ help: try: `aaa()`
LL | x as u32;
| ^^^^^^^^ help: try: `x`
error: casting to the same type is unnecessary (`u32` -> `u32`)
--> tests/ui/unnecessary_cast.rs:138:5
|
LL | bbb() as u32;
| ^^^^^^^^^^^^ help: try: `bbb()`
error: casting to the same type is unnecessary (`u32` -> `u32`)
--> tests/ui/unnecessary_cast.rs:141:5
|
LL | x as u32;
| ^^^^^^^^ help: try: `x`
error: casting integer literal to `f32` is unnecessary
--> tests/ui/unnecessary_cast.rs:173:9
--> tests/ui/unnecessary_cast.rs:174:9
|
LL | 100 as f32;
| ^^^^^^^^^^ help: try: `100_f32`
error: casting integer literal to `f64` is unnecessary
--> tests/ui/unnecessary_cast.rs:175:9
--> tests/ui/unnecessary_cast.rs:176:9
|
LL | 100 as f64;
| ^^^^^^^^^^ help: try: `100_f64`
error: casting integer literal to `f64` is unnecessary
--> tests/ui/unnecessary_cast.rs:177:9
--> tests/ui/unnecessary_cast.rs:178:9
|
LL | 100_i32 as f64;
| ^^^^^^^^^^^^^^ help: try: `100_f64`
error: casting integer literal to `f32` is unnecessary
--> tests/ui/unnecessary_cast.rs:179:17
--> tests/ui/unnecessary_cast.rs:180:17
|
LL | let _ = -100 as f32;
| ^^^^^^^^^^^ help: try: `-100_f32`
error: casting integer literal to `f64` is unnecessary
--> tests/ui/unnecessary_cast.rs:181:17
--> tests/ui/unnecessary_cast.rs:182:17
|
LL | let _ = -100 as f64;
| ^^^^^^^^^^^ help: try: `-100_f64`
error: casting integer literal to `f64` is unnecessary
--> tests/ui/unnecessary_cast.rs:183:17
--> tests/ui/unnecessary_cast.rs:184:17
|
LL | let _ = -100_i32 as f64;
| ^^^^^^^^^^^^^^^ help: try: `-100_f64`
error: casting float literal to `f32` is unnecessary
--> tests/ui/unnecessary_cast.rs:185:9
--> tests/ui/unnecessary_cast.rs:186:9
|
LL | 100. as f32;
| ^^^^^^^^^^^ help: try: `100_f32`
error: casting float literal to `f64` is unnecessary
--> tests/ui/unnecessary_cast.rs:187:9
--> tests/ui/unnecessary_cast.rs:188:9
|
LL | 100. as f64;
| ^^^^^^^^^^^ help: try: `100_f64`
error: casting integer literal to `u32` is unnecessary
--> tests/ui/unnecessary_cast.rs:200:9
--> tests/ui/unnecessary_cast.rs:201:9
|
LL | 1 as u32;
| ^^^^^^^^ help: try: `1_u32`
error: casting integer literal to `i32` is unnecessary
--> tests/ui/unnecessary_cast.rs:202:9
--> tests/ui/unnecessary_cast.rs:203:9
|
LL | 0x10 as i32;
| ^^^^^^^^^^^ help: try: `0x10_i32`
error: casting integer literal to `usize` is unnecessary
--> tests/ui/unnecessary_cast.rs:204:9
--> tests/ui/unnecessary_cast.rs:205:9
|
LL | 0b10 as usize;
| ^^^^^^^^^^^^^ help: try: `0b10_usize`
error: casting integer literal to `u16` is unnecessary
--> tests/ui/unnecessary_cast.rs:206:9
--> tests/ui/unnecessary_cast.rs:207:9
|
LL | 0o73 as u16;
| ^^^^^^^^^^^ help: try: `0o73_u16`
error: casting integer literal to `u32` is unnecessary
--> tests/ui/unnecessary_cast.rs:208:9
--> tests/ui/unnecessary_cast.rs:209:9
|
LL | 1_000_000_000 as u32;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32`
error: casting float literal to `f64` is unnecessary
--> tests/ui/unnecessary_cast.rs:211:9
--> tests/ui/unnecessary_cast.rs:212:9
|
LL | 1.0 as f64;
| ^^^^^^^^^^ help: try: `1.0_f64`
error: casting float literal to `f32` is unnecessary
--> tests/ui/unnecessary_cast.rs:213:9
--> tests/ui/unnecessary_cast.rs:214:9
|
LL | 0.5 as f32;
| ^^^^^^^^^^ help: try: `0.5_f32`
error: casting integer literal to `i32` is unnecessary
--> tests/ui/unnecessary_cast.rs:218:17
--> tests/ui/unnecessary_cast.rs:219:17
|
LL | let _ = -1 as i32;
| ^^^^^^^^^ help: try: `-1_i32`
error: casting float literal to `f32` is unnecessary
--> tests/ui/unnecessary_cast.rs:220:17
--> tests/ui/unnecessary_cast.rs:221:17
|
LL | let _ = -1.0 as f32;
| ^^^^^^^^^^^ help: try: `-1.0_f32`
error: casting to the same type is unnecessary (`i32` -> `i32`)
--> tests/ui/unnecessary_cast.rs:227:18
--> tests/ui/unnecessary_cast.rs:228:18
|
LL | let _ = &(x as i32);
| ^^^^^^^^^^ help: try: `{ x }`
error: casting integer literal to `i32` is unnecessary
--> tests/ui/unnecessary_cast.rs:234:22
--> tests/ui/unnecessary_cast.rs:235:22
|
LL | let _: i32 = -(1) as i32;
| ^^^^^^^^^^^ help: try: `-1_i32`
error: casting integer literal to `i64` is unnecessary
--> tests/ui/unnecessary_cast.rs:237:22
--> tests/ui/unnecessary_cast.rs:238:22
|
LL | let _: i64 = -(1) as i64;
| ^^^^^^^^^^^ help: try: `-1_i64`
error: casting float literal to `f64` is unnecessary
--> tests/ui/unnecessary_cast.rs:245:22
--> tests/ui/unnecessary_cast.rs:246:22
|
LL | let _: f64 = (-8.0 as f64).exp();
| ^^^^^^^^^^^^^ help: try: `(-8.0_f64)`
error: casting float literal to `f64` is unnecessary
--> tests/ui/unnecessary_cast.rs:248:23
--> tests/ui/unnecessary_cast.rs:249:23
|
LL | let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior
| ^^^^^^^^^^^^ help: try: `8.0_f64`
error: casting to the same type is unnecessary (`f32` -> `f32`)
--> tests/ui/unnecessary_cast.rs:258:20
--> tests/ui/unnecessary_cast.rs:259:20
|
LL | let _num = foo() as f32;
| ^^^^^^^^^^^^ help: try: `foo()`
error: casting to the same type is unnecessary (`usize` -> `usize`)
--> tests/ui/unnecessary_cast.rs:269:9
--> tests/ui/unnecessary_cast.rs:270:9
|
LL | (*x as usize).pow(2)
| ^^^^^^^^^^^^^ help: try: `(*x)`
error: casting to the same type is unnecessary (`usize` -> `usize`)
--> tests/ui/unnecessary_cast.rs:277:31
--> tests/ui/unnecessary_cast.rs:278:31
|
LL | assert_eq!(vec.len(), x as usize);
| ^^^^^^^^^^ help: try: `x`
error: casting to the same type is unnecessary (`i64` -> `i64`)
--> tests/ui/unnecessary_cast.rs:280:17
--> tests/ui/unnecessary_cast.rs:281:17
|
LL | let _ = (5i32 as i64 as i64).abs();
| ^^^^^^^^^^^^^^^^^^^^ help: try: `(5i32 as i64)`
error: casting to the same type is unnecessary (`i64` -> `i64`)
--> tests/ui/unnecessary_cast.rs:283:17
--> tests/ui/unnecessary_cast.rs:284:17
|
LL | let _ = 5i32 as i64 as i64;
| ^^^^^^^^^^^^^^^^^^ help: try: `5i32 as i64`
error: aborting due to 44 previous errors
error: aborting due to 46 previous errors