From 73cd95465e85f878fc5c30a79ce76a9fb59d690c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Sat, 16 Jul 2022 10:22:43 +0200 Subject: [PATCH 1/6] Add iter_once and iter_empty lints --- CHANGELOG.md | 2 + clippy_lints/src/iter_once_empty.rs | 164 ++++++++++++++++++++++ clippy_lints/src/lib.register_lints.rs | 2 + clippy_lints/src/lib.register_nursery.rs | 2 + clippy_lints/src/lib.register_pedantic.rs | 2 + clippy_lints/src/lib.rs | 2 + clippy_utils/src/lib.rs | 1 + tests/ui/iter_empty.fixed | 32 +++++ tests/ui/iter_empty.rs | 32 +++++ tests/ui/iter_empty.stderr | 40 ++++++ tests/ui/iter_once.fixed | 32 +++++ tests/ui/iter_once.rs | 32 +++++ tests/ui/iter_once.stderr | 40 ++++++ 13 files changed, 383 insertions(+) create mode 100644 clippy_lints/src/iter_once_empty.rs create mode 100644 tests/ui/iter_empty.fixed create mode 100644 tests/ui/iter_empty.rs create mode 100644 tests/ui/iter_empty.stderr create mode 100644 tests/ui/iter_once.fixed create mode 100644 tests/ui/iter_once.rs create mode 100644 tests/ui/iter_once.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ea7e76ee108..94f71eba0a29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3651,11 +3651,13 @@ Released 2018-09-13 [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count +[`iter_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_empty [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop [`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice [`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero +[`iter_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_once [`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain diff --git a/clippy_lints/src/iter_once_empty.rs b/clippy_lints/src/iter_once_empty.rs new file mode 100644 index 000000000000..098960011123 --- /dev/null +++ b/clippy_lints/src/iter_once_empty.rs @@ -0,0 +1,164 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use rustc_ast::ast::{Expr, ExprKind}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usage of: + /// + /// - `[foo].iter()` + /// - `[foo].iter_mut()` + /// - `[foo].into_iter()` + /// - `Some(foo).iter()` + /// - `Some(foo).iter_mut()` + /// - `Some(foo).into_iter()` + /// + /// ### Why is this bad? + /// + /// It is simpler to use the once function from the standard library: + /// + /// ### Example + /// + /// ```rust + /// let a = [123].iter(); + /// let b = Some(123).into_iter(); + /// ``` + /// Use instead: + /// ```rust + /// use std::iter; + /// let a = iter::once(&123); + /// let b = iter::once(123); + /// ``` + /// + /// ### Known problems + /// + /// The type of the resulting iterator might become incompatible with its usage + #[clippy::version = "1.64.0"] + pub ITER_ONCE, + nursery, + "Iterator for array of length 1" +} + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usage of: + /// + /// - `[].iter()` + /// - `[].iter_mut()` + /// - `[].into_iter()` + /// - `None.iter()` + /// - `None.iter_mut()` + /// - `None.into_iter()` + /// + /// ### Why is this bad? + /// + /// It is simpler to use the empty function from the standard library: + /// + /// ### Example + /// + /// ```rust + /// use std::{slice, option}; + /// let a: slice::Iter = [].iter(); + /// let f: option::IntoIter = None.into_iter(); + /// ``` + /// Use instead: + /// ```rust + /// use std::iter; + /// let a: iter::Empty = iter::empty(); + /// let b: iter::Empty = iter::empty(); + /// ``` + /// + /// ### Known problems + /// + /// The type of the resulting iterator might become incompatible with its usage + #[clippy::version = "1.64.0"] + pub ITER_EMPTY, + nursery, + "Iterator for empty array" +} + +declare_lint_pass!(IterOnceEmpty => [ITER_ONCE, ITER_EMPTY]); + +impl EarlyLintPass for IterOnceEmpty { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if expr.span.from_expansion() { + // Don't lint match expressions present in + // macro_rules! block + return; + } + + let (method_name, args) = if let ExprKind::MethodCall(seg, args, _) = &expr.kind { + (seg.ident.as_str(), args) + } else { + return; + }; + let arg = if args.len() == 1 { + &args[0] + } else { + return; + }; + + let item = match &arg.kind { + ExprKind::Array(v) if v.len() <= 1 => v.first(), + ExprKind::Path(None, p) => { + if p.segments.len() == 1 && p.segments[0].ident.name == rustc_span::sym::None { + None + } else { + return; + } + }, + ExprKind::Call(f, some_args) if some_args.len() == 1 => { + if let ExprKind::Path(None, p) = &f.kind { + if p.segments.len() == 1 && p.segments[0].ident.name == rustc_span::sym::Some { + Some(&some_args[0]) + } else { + return; + } + } else { + return; + } + }, + _ => return, + }; + + if let Some(i) = item { + let (sugg, msg) = match method_name { + "iter" => ( + format!("std::iter::once(&{})", snippet(cx, i.span, "...")), + "this `iter` call can be replaced with std::iter::once", + ), + "iter_mut" => ( + format!("std::iter::once(&mut {})", snippet(cx, i.span, "...")), + "this `iter_mut` call can be replaced with std::iter::once", + ), + "into_iter" => ( + format!("std::iter::once({})", snippet(cx, i.span, "...")), + "this `into_iter` call can be replaced with std::iter::once", + ), + _ => return, + }; + span_lint_and_sugg(cx, ITER_ONCE, expr.span, msg, "try", sugg, Applicability::Unspecified); + } else { + let msg = match method_name { + "iter" => "this `iter call` can be replaced with std::iter::empty", + "iter_mut" => "this `iter_mut` call can be replaced with std::iter::empty", + "into_iter" => "this `into_iter` call can be replaced with std::iter::empty", + _ => return, + }; + span_lint_and_sugg( + cx, + ITER_EMPTY, + expr.span, + msg, + "try", + "std::iter::empty()".to_string(), + Applicability::Unspecified, + ); + } + } +} diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index d83508a2d6ca..49fc3a895274 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -200,6 +200,8 @@ store.register_lints(&[ invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED, items_after_statements::ITEMS_AFTER_STATEMENTS, iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR, + iter_once_empty::ITER_EMPTY, + iter_once_empty::ITER_ONCE, large_const_arrays::LARGE_CONST_ARRAYS, large_enum_variant::LARGE_ENUM_VARIANT, large_include_file::LARGE_INCLUDE_FILE, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 7d731d52dbbd..9953aca43ee2 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -14,6 +14,8 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE), LintId::of(let_if_seq::USELESS_LET_IF_SEQ), LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), + LintId::of(methods::ITER_EMPTY), + LintId::of(methods::ITER_ONCE), LintId::of(methods::ITER_WITH_DRAIN), LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 4250ee055e6c..6063fb00a7b6 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -41,6 +41,8 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS), LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS), LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR), + LintId::of(iter_once_empty::ITER_EMPTY), + LintId::of(iter_once_empty::ITER_ONCE), LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS), LintId::of(let_underscore::LET_UNDERSCORE_DROP), LintId::of(literal_representation::LARGE_DIGIT_GROUPS), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 88c1a727f8dc..78279db9ad54 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -258,6 +258,7 @@ mod invalid_upcast_comparisons; mod invalid_utf8_in_unchecked; mod items_after_statements; mod iter_not_returning_iterator; +mod iter_once_empty; mod large_const_arrays; mod large_enum_variant; mod large_include_file; @@ -931,6 +932,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default())); store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); + store.register_early_pass(|| Box::new(iter_once_empty::IterOnceEmpty)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index dcfc03475b42..9c58978a0703 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -484,6 +484,7 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { } fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator + 'tcx { let single = |ty| tcx.incoherent_impls(ty).iter().copied(); + #[allow(clippy::iter_empty)] let empty = || [].iter().copied(); match name { "bool" => single(BoolSimplifiedType), diff --git a/tests/ui/iter_empty.fixed b/tests/ui/iter_empty.fixed new file mode 100644 index 000000000000..fb7118f0d4a0 --- /dev/null +++ b/tests/ui/iter_empty.fixed @@ -0,0 +1,32 @@ +// run-rustfix +#![warn(clippy::iter_empty)] +#![allow(clippy::iter_next_slice, clippy::redundant_clone)] + +fn array() { + assert_eq!(std::iter::empty().next(), Option::::None); + assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None); + assert_eq!(std::iter::empty().next(), Option::<&i32>::None); + assert_eq!(std::iter::empty().next(), Option::::None); + assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None); + assert_eq!(std::iter::empty().next(), Option::<&i32>::None); + + // Don't trigger on non-iter methods + let _: Option = None.clone(); + let _: [String; 0] = [].clone(); +} + +macro_rules! in_macros { + () => { + assert_eq!([].into_iter().next(), Option::::None); + assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); + assert_eq!([].iter().next(), Option::<&i32>::None); + assert_eq!(None.into_iter().next(), Option::::None); + assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); + assert_eq!(None.iter().next(), Option::<&i32>::None); + }; +} + +fn main() { + array(); + in_macros!(); +} diff --git a/tests/ui/iter_empty.rs b/tests/ui/iter_empty.rs new file mode 100644 index 000000000000..bb192fe16d1f --- /dev/null +++ b/tests/ui/iter_empty.rs @@ -0,0 +1,32 @@ +// run-rustfix +#![warn(clippy::iter_empty)] +#![allow(clippy::iter_next_slice, clippy::redundant_clone)] + +fn array() { + assert_eq!([].into_iter().next(), Option::::None); + assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); + assert_eq!([].iter().next(), Option::<&i32>::None); + assert_eq!(None.into_iter().next(), Option::::None); + assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); + assert_eq!(None.iter().next(), Option::<&i32>::None); + + // Don't trigger on non-iter methods + let _: Option = None.clone(); + let _: [String; 0] = [].clone(); +} + +macro_rules! in_macros { + () => { + assert_eq!([].into_iter().next(), Option::::None); + assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); + assert_eq!([].iter().next(), Option::<&i32>::None); + assert_eq!(None.into_iter().next(), Option::::None); + assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); + assert_eq!(None.iter().next(), Option::<&i32>::None); + }; +} + +fn main() { + array(); + in_macros!(); +} diff --git a/tests/ui/iter_empty.stderr b/tests/ui/iter_empty.stderr new file mode 100644 index 000000000000..f4f06e93b237 --- /dev/null +++ b/tests/ui/iter_empty.stderr @@ -0,0 +1,40 @@ +error: this `into_iter` call can be replaced with std::iter::empty + --> $DIR/iter_empty.rs:6:16 + | +LL | assert_eq!([].into_iter().next(), Option::::None); + | ^^^^^^^^^^^^^^ help: try: `std::iter::empty()` + | + = note: `-D clippy::iter-empty` implied by `-D warnings` + +error: this `iter_mut` call can be replaced with std::iter::empty + --> $DIR/iter_empty.rs:7:16 + | +LL | assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); + | ^^^^^^^^^^^^^ help: try: `std::iter::empty()` + +error: this `iter call` can be replaced with std::iter::empty + --> $DIR/iter_empty.rs:8:16 + | +LL | assert_eq!([].iter().next(), Option::<&i32>::None); + | ^^^^^^^^^ help: try: `std::iter::empty()` + +error: this `into_iter` call can be replaced with std::iter::empty + --> $DIR/iter_empty.rs:9:16 + | +LL | assert_eq!(None.into_iter().next(), Option::::None); + | ^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` + +error: this `iter_mut` call can be replaced with std::iter::empty + --> $DIR/iter_empty.rs:10:16 + | +LL | assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); + | ^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` + +error: this `iter call` can be replaced with std::iter::empty + --> $DIR/iter_empty.rs:11:16 + | +LL | assert_eq!(None.iter().next(), Option::<&i32>::None); + | ^^^^^^^^^^^ help: try: `std::iter::empty()` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/iter_once.fixed b/tests/ui/iter_once.fixed new file mode 100644 index 000000000000..7247e34d7e86 --- /dev/null +++ b/tests/ui/iter_once.fixed @@ -0,0 +1,32 @@ +// run-rustfix +#![warn(clippy::iter_once)] +#![allow(clippy::iter_next_slice, clippy::redundant_clone)] + +fn array() { + assert_eq!(std::iter::once(123).next(), Some(123)); + assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123)); + assert_eq!(std::iter::once(&123).next(), Some(&123)); + assert_eq!(std::iter::once(123).next(), Some(123)); + assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123)); + assert_eq!(std::iter::once(&123).next(), Some(&123)); + + // Don't trigger on non-iter methods + let _: Option = Some("test".to_string()).clone(); + let _: [String; 1] = ["test".to_string()].clone(); +} + +macro_rules! in_macros { + () => { + assert_eq!([123].into_iter().next(), Some(123)); + assert_eq!([123].iter_mut().next(), Some(&mut 123)); + assert_eq!([123].iter().next(), Some(&123)); + assert_eq!(Some(123).into_iter().next(), Some(123)); + assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); + assert_eq!(Some(123).iter().next(), Some(&123)); + }; +} + +fn main() { + array(); + in_macros!(); +} diff --git a/tests/ui/iter_once.rs b/tests/ui/iter_once.rs new file mode 100644 index 000000000000..3a2b9c95cc53 --- /dev/null +++ b/tests/ui/iter_once.rs @@ -0,0 +1,32 @@ +// run-rustfix +#![warn(clippy::iter_once)] +#![allow(clippy::iter_next_slice, clippy::redundant_clone)] + +fn array() { + assert_eq!([123].into_iter().next(), Some(123)); + assert_eq!([123].iter_mut().next(), Some(&mut 123)); + assert_eq!([123].iter().next(), Some(&123)); + assert_eq!(Some(123).into_iter().next(), Some(123)); + assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); + assert_eq!(Some(123).iter().next(), Some(&123)); + + // Don't trigger on non-iter methods + let _: Option = Some("test".to_string()).clone(); + let _: [String; 1] = ["test".to_string()].clone(); +} + +macro_rules! in_macros { + () => { + assert_eq!([123].into_iter().next(), Some(123)); + assert_eq!([123].iter_mut().next(), Some(&mut 123)); + assert_eq!([123].iter().next(), Some(&123)); + assert_eq!(Some(123).into_iter().next(), Some(123)); + assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); + assert_eq!(Some(123).iter().next(), Some(&123)); + }; +} + +fn main() { + array(); + in_macros!(); +} diff --git a/tests/ui/iter_once.stderr b/tests/ui/iter_once.stderr new file mode 100644 index 000000000000..d9e8f96f7639 --- /dev/null +++ b/tests/ui/iter_once.stderr @@ -0,0 +1,40 @@ +error: this `into_iter` call can be replaced with std::iter::once + --> $DIR/iter_once.rs:6:16 + | +LL | assert_eq!([123].into_iter().next(), Some(123)); + | ^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` + | + = note: `-D clippy::iter-once` implied by `-D warnings` + +error: this `iter_mut` call can be replaced with std::iter::once + --> $DIR/iter_once.rs:7:16 + | +LL | assert_eq!([123].iter_mut().next(), Some(&mut 123)); + | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` + +error: this `iter` call can be replaced with std::iter::once + --> $DIR/iter_once.rs:8:16 + | +LL | assert_eq!([123].iter().next(), Some(&123)); + | ^^^^^^^^^^^^ help: try: `std::iter::once(&123)` + +error: this `into_iter` call can be replaced with std::iter::once + --> $DIR/iter_once.rs:9:16 + | +LL | assert_eq!(Some(123).into_iter().next(), Some(123)); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` + +error: this `iter_mut` call can be replaced with std::iter::once + --> $DIR/iter_once.rs:10:16 + | +LL | assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` + +error: this `iter` call can be replaced with std::iter::once + --> $DIR/iter_once.rs:11:16 + | +LL | assert_eq!(Some(123).iter().next(), Some(&123)); + | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&123)` + +error: aborting due to 6 previous errors + From 332e03146e456ccedc1ab960fcdd739dd45080b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Sat, 16 Jul 2022 12:44:33 +0200 Subject: [PATCH 2/6] Fix the lint in clippy itself --- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/derive.rs | 5 ++++- clippy_lints/src/redundant_slicing.rs | 4 +++- clippy_lints/src/types/mod.rs | 1 + clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/utils/internal_lints/metadata_collector.rs | 2 +- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 5d41c63928df..e0b94f7190af 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -760,7 +760,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .and_then(|subs| subs.get(1..)) { Some(subs) => cx.tcx.mk_substs(subs.iter().copied()), - None => cx.tcx.mk_substs([].iter()), + None => cx.tcx.mk_substs(std::iter::empty::>()), } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() { // Trait methods taking `&self` sub_ty diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index a982990e4186..9ca443b7dff6 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -516,7 +516,10 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain( params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| { tcx.mk_predicate(Binder::dummy(PredicateKind::Trait(TraitPredicate { - trait_ref: TraitRef::new(eq_trait_id, tcx.mk_substs([tcx.mk_param_from_def(param)].into_iter())), + trait_ref: TraitRef::new( + eq_trait_id, + tcx.mk_substs(std::iter::once(tcx.mk_param_from_def(param))), + ), constness: BoundConstness::NotConst, polarity: ImplPolarity::Positive, }))) diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index db6c97f3739c..8693ca9af830 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -11,6 +11,8 @@ use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::subst::GenericArg; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use std::iter; + declare_clippy_lint! { /// ### What it does /// Checks for redundant slicing expressions which use the full range, and @@ -134,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { } else if let Some(target_id) = cx.tcx.lang_items().deref_target() { if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions( cx.param_env, - cx.tcx.mk_projection(target_id, cx.tcx.mk_substs([GenericArg::from(indexed_ty)].into_iter())), + cx.tcx.mk_projection(target_id, cx.tcx.mk_substs(iter::once(GenericArg::from(indexed_ty)))), ) { if deref_ty == expr_ty { let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 353a6f6b899e..f3ba096237f5 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -490,6 +490,7 @@ impl Types { } } } + #[allow(clippy::iter_empty)] match *qpath { QPath::Resolved(Some(ty), p) => { context.is_nested_call = true; diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 3faae9ac0d2b..47b72f4783e3 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -350,7 +350,7 @@ define_Conf! { /// Lint: DISALLOWED_SCRIPT_IDENTS. /// /// The list of unicode scripts allowed to be used in the scope. - (allowed_scripts: Vec = ["Latin"].iter().map(ToString::to_string).collect()), + (allowed_scripts: Vec = vec!["Latin".to_string()]), /// Lint: NON_SEND_FIELDS_IN_SEND_TY. /// /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 92cf42c7ad43..b1148bccc2a2 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -797,7 +797,7 @@ fn get_lint_group_and_level_or_lint( let result = cx.lint_store.check_lint_name( lint_name, Some(sym::clippy), - &[Ident::with_dummy_span(sym::clippy)].into_iter().collect(), + &std::iter::once(Ident::with_dummy_span(sym::clippy)).collect(), ); if let CheckLintNameResult::Tool(Ok(lint_lst)) = result { if let Some(group) = get_lint_group(cx, lint_lst[0]) { From f3f86d8fd96dfa5986ffe10d0837169e473b9b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Sat, 16 Jul 2022 23:07:06 +0200 Subject: [PATCH 3/6] Move iter_once and iter_empty to methods as a late pass This enables more thorough checking of types to avoid triggering on custom Some and None enum variants --- clippy_lints/src/iter_once_empty.rs | 164 -------------------- clippy_lints/src/lib.register_lints.rs | 4 +- clippy_lints/src/lib.register_pedantic.rs | 2 - clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/iter_once_empty.rs | 70 +++++++++ clippy_lints/src/methods/mod.rs | 81 ++++++++++ tests/ui/iter_empty.fixed | 23 +++ tests/ui/iter_empty.rs | 23 +++ tests/ui/iter_once.fixed | 23 +++ tests/ui/iter_once.rs | 23 +++ 10 files changed, 245 insertions(+), 170 deletions(-) delete mode 100644 clippy_lints/src/iter_once_empty.rs create mode 100644 clippy_lints/src/methods/iter_once_empty.rs diff --git a/clippy_lints/src/iter_once_empty.rs b/clippy_lints/src/iter_once_empty.rs deleted file mode 100644 index 098960011123..000000000000 --- a/clippy_lints/src/iter_once_empty.rs +++ /dev/null @@ -1,164 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use rustc_ast::ast::{Expr, ExprKind}; -use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// - /// Checks for usage of: - /// - /// - `[foo].iter()` - /// - `[foo].iter_mut()` - /// - `[foo].into_iter()` - /// - `Some(foo).iter()` - /// - `Some(foo).iter_mut()` - /// - `Some(foo).into_iter()` - /// - /// ### Why is this bad? - /// - /// It is simpler to use the once function from the standard library: - /// - /// ### Example - /// - /// ```rust - /// let a = [123].iter(); - /// let b = Some(123).into_iter(); - /// ``` - /// Use instead: - /// ```rust - /// use std::iter; - /// let a = iter::once(&123); - /// let b = iter::once(123); - /// ``` - /// - /// ### Known problems - /// - /// The type of the resulting iterator might become incompatible with its usage - #[clippy::version = "1.64.0"] - pub ITER_ONCE, - nursery, - "Iterator for array of length 1" -} - -declare_clippy_lint! { - /// ### What it does - /// - /// Checks for usage of: - /// - /// - `[].iter()` - /// - `[].iter_mut()` - /// - `[].into_iter()` - /// - `None.iter()` - /// - `None.iter_mut()` - /// - `None.into_iter()` - /// - /// ### Why is this bad? - /// - /// It is simpler to use the empty function from the standard library: - /// - /// ### Example - /// - /// ```rust - /// use std::{slice, option}; - /// let a: slice::Iter = [].iter(); - /// let f: option::IntoIter = None.into_iter(); - /// ``` - /// Use instead: - /// ```rust - /// use std::iter; - /// let a: iter::Empty = iter::empty(); - /// let b: iter::Empty = iter::empty(); - /// ``` - /// - /// ### Known problems - /// - /// The type of the resulting iterator might become incompatible with its usage - #[clippy::version = "1.64.0"] - pub ITER_EMPTY, - nursery, - "Iterator for empty array" -} - -declare_lint_pass!(IterOnceEmpty => [ITER_ONCE, ITER_EMPTY]); - -impl EarlyLintPass for IterOnceEmpty { - fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if expr.span.from_expansion() { - // Don't lint match expressions present in - // macro_rules! block - return; - } - - let (method_name, args) = if let ExprKind::MethodCall(seg, args, _) = &expr.kind { - (seg.ident.as_str(), args) - } else { - return; - }; - let arg = if args.len() == 1 { - &args[0] - } else { - return; - }; - - let item = match &arg.kind { - ExprKind::Array(v) if v.len() <= 1 => v.first(), - ExprKind::Path(None, p) => { - if p.segments.len() == 1 && p.segments[0].ident.name == rustc_span::sym::None { - None - } else { - return; - } - }, - ExprKind::Call(f, some_args) if some_args.len() == 1 => { - if let ExprKind::Path(None, p) = &f.kind { - if p.segments.len() == 1 && p.segments[0].ident.name == rustc_span::sym::Some { - Some(&some_args[0]) - } else { - return; - } - } else { - return; - } - }, - _ => return, - }; - - if let Some(i) = item { - let (sugg, msg) = match method_name { - "iter" => ( - format!("std::iter::once(&{})", snippet(cx, i.span, "...")), - "this `iter` call can be replaced with std::iter::once", - ), - "iter_mut" => ( - format!("std::iter::once(&mut {})", snippet(cx, i.span, "...")), - "this `iter_mut` call can be replaced with std::iter::once", - ), - "into_iter" => ( - format!("std::iter::once({})", snippet(cx, i.span, "...")), - "this `into_iter` call can be replaced with std::iter::once", - ), - _ => return, - }; - span_lint_and_sugg(cx, ITER_ONCE, expr.span, msg, "try", sugg, Applicability::Unspecified); - } else { - let msg = match method_name { - "iter" => "this `iter call` can be replaced with std::iter::empty", - "iter_mut" => "this `iter_mut` call can be replaced with std::iter::empty", - "into_iter" => "this `into_iter` call can be replaced with std::iter::empty", - _ => return, - }; - span_lint_and_sugg( - cx, - ITER_EMPTY, - expr.span, - msg, - "try", - "std::iter::empty()".to_string(), - Applicability::Unspecified, - ); - } - } -} diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 49fc3a895274..e49321d83fa5 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -200,8 +200,6 @@ store.register_lints(&[ invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED, items_after_statements::ITEMS_AFTER_STATEMENTS, iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR, - iter_once_empty::ITER_EMPTY, - iter_once_empty::ITER_ONCE, large_const_arrays::LARGE_CONST_ARRAYS, large_enum_variant::LARGE_ENUM_VARIANT, large_include_file::LARGE_INCLUDE_FILE, @@ -314,9 +312,11 @@ store.register_lints(&[ methods::ITERATOR_STEP_BY_ZERO, methods::ITER_CLONED_COLLECT, methods::ITER_COUNT, + methods::ITER_EMPTY, methods::ITER_NEXT_SLICE, methods::ITER_NTH, methods::ITER_NTH_ZERO, + methods::ITER_ONCE, methods::ITER_OVEREAGER_CLONED, methods::ITER_SKIP_NEXT, methods::ITER_WITH_DRAIN, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 6063fb00a7b6..4250ee055e6c 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -41,8 +41,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS), LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS), LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR), - LintId::of(iter_once_empty::ITER_EMPTY), - LintId::of(iter_once_empty::ITER_ONCE), LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS), LintId::of(let_underscore::LET_UNDERSCORE_DROP), LintId::of(literal_representation::LARGE_DIGIT_GROUPS), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 78279db9ad54..88c1a727f8dc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -258,7 +258,6 @@ mod invalid_upcast_comparisons; mod invalid_utf8_in_unchecked; mod items_after_statements; mod iter_not_returning_iterator; -mod iter_once_empty; mod large_const_arrays; mod large_enum_variant; mod large_include_file; @@ -932,7 +931,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default())); store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); - store.register_early_pass(|| Box::new(iter_once_empty::IterOnceEmpty)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/methods/iter_once_empty.rs b/clippy_lints/src/methods/iter_once_empty.rs new file mode 100644 index 000000000000..d45dfc67880e --- /dev/null +++ b/clippy_lints/src/methods/iter_once_empty.rs @@ -0,0 +1,70 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_lang_ctor; +use clippy_utils::source::snippet; + +use rustc_errors::Applicability; +use rustc_hir::LangItem::{OptionNone, OptionSome}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; + +use super::{ITER_EMPTY, ITER_ONCE}; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { + let item = match &recv.kind { + ExprKind::Array(v) if v.len() <= 1 => v.first(), + ExprKind::Path(p) => { + if is_lang_ctor(cx, p, OptionNone) { + None + } else { + return; + } + }, + ExprKind::Call(f, some_args) if some_args.len() == 1 => { + if let ExprKind::Path(p) = &f.kind { + if is_lang_ctor(cx, p, OptionSome) { + Some(&some_args[0]) + } else { + return; + } + } else { + return; + } + }, + _ => return, + }; + + if let Some(i) = item { + let (sugg, msg) = match method_name { + "iter" => ( + format!("std::iter::once(&{})", snippet(cx, i.span, "...")), + "this `iter` call can be replaced with std::iter::once", + ), + "iter_mut" => ( + format!("std::iter::once(&mut {})", snippet(cx, i.span, "...")), + "this `iter_mut` call can be replaced with std::iter::once", + ), + "into_iter" => ( + format!("std::iter::once({})", snippet(cx, i.span, "...")), + "this `into_iter` call can be replaced with std::iter::once", + ), + _ => return, + }; + span_lint_and_sugg(cx, ITER_ONCE, expr.span, msg, "try", sugg, Applicability::Unspecified); + } else { + let msg = match method_name { + "iter" => "this `iter call` can be replaced with std::iter::empty", + "iter_mut" => "this `iter_mut` call can be replaced with std::iter::empty", + "into_iter" => "this `into_iter` call can be replaced with std::iter::empty", + _ => return, + }; + span_lint_and_sugg( + cx, + ITER_EMPTY, + expr.span, + msg, + "try", + "std::iter::empty()".to_string(), + Applicability::Unspecified, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5ac6b09f0aa2..e449ae0e4247 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -33,6 +33,7 @@ mod iter_count; mod iter_next_slice; mod iter_nth; mod iter_nth_zero; +mod iter_once_empty; mod iter_overeager_cloned; mod iter_skip_next; mod iter_with_drain; @@ -2304,6 +2305,83 @@ declare_clippy_lint! { more clearly with `if .. else ..`" } +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usage of: + /// + /// - `[foo].iter()` + /// - `[foo].iter_mut()` + /// - `[foo].into_iter()` + /// - `Some(foo).iter()` + /// - `Some(foo).iter_mut()` + /// - `Some(foo).into_iter()` + /// + /// ### Why is this bad? + /// + /// It is simpler to use the once function from the standard library: + /// + /// ### Example + /// + /// ```rust + /// let a = [123].iter(); + /// let b = Some(123).into_iter(); + /// ``` + /// Use instead: + /// ```rust + /// use std::iter; + /// let a = iter::once(&123); + /// let b = iter::once(123); + /// ``` + /// + /// ### Known problems + /// + /// The type of the resulting iterator might become incompatible with its usage + #[clippy::version = "1.64.0"] + pub ITER_ONCE, + nursery, + "Iterator for array of length 1" +} + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usage of: + /// + /// - `[].iter()` + /// - `[].iter_mut()` + /// - `[].into_iter()` + /// - `None.iter()` + /// - `None.iter_mut()` + /// - `None.into_iter()` + /// + /// ### Why is this bad? + /// + /// It is simpler to use the empty function from the standard library: + /// + /// ### Example + /// + /// ```rust + /// use std::{slice, option}; + /// let a: slice::Iter = [].iter(); + /// let f: option::IntoIter = None.into_iter(); + /// ``` + /// Use instead: + /// ```rust + /// use std::iter; + /// let a: iter::Empty = iter::empty(); + /// let b: iter::Empty = iter::empty(); + /// ``` + /// + /// ### Known problems + /// + /// The type of the resulting iterator might become incompatible with its usage + #[clippy::version = "1.64.0"] + pub ITER_EMPTY, + nursery, + "Iterator for empty array" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2406,6 +2484,8 @@ impl_lint_pass!(Methods => [ NEEDLESS_OPTION_TAKE, NO_EFFECT_REPLACE, OBFUSCATED_IF_ELSE, + ITER_ONCE, + ITER_EMPTY ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2708,6 +2788,7 @@ impl Methods { ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), ("is_none", []) => check_is_some_is_none(cx, expr, recv, false), ("is_some", []) => check_is_some_is_none(cx, expr, recv, true), + ("iter" | "iter_mut" | "into_iter", []) => iter_once_empty::check(cx, expr, name, recv), ("join", [join_arg]) => { if let Some(("collect", _, span)) = method_call(recv) { unnecessary_join::check(cx, expr, recv, join_arg, span); diff --git a/tests/ui/iter_empty.fixed b/tests/ui/iter_empty.fixed index fb7118f0d4a0..690da5a87615 100644 --- a/tests/ui/iter_empty.fixed +++ b/tests/ui/iter_empty.fixed @@ -26,7 +26,30 @@ macro_rules! in_macros { }; } +// Don't trigger on a `None` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + None.iter(); + None.iter_mut(); + None.into_iter(); + } +} + fn main() { array(); + custom_option::custom_option(); in_macros!(); } diff --git a/tests/ui/iter_empty.rs b/tests/ui/iter_empty.rs index bb192fe16d1f..f8b56898f2d5 100644 --- a/tests/ui/iter_empty.rs +++ b/tests/ui/iter_empty.rs @@ -26,7 +26,30 @@ macro_rules! in_macros { }; } +// Don't trigger on a `None` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + None.iter(); + None.iter_mut(); + None.into_iter(); + } +} + fn main() { array(); + custom_option::custom_option(); in_macros!(); } diff --git a/tests/ui/iter_once.fixed b/tests/ui/iter_once.fixed index 7247e34d7e86..0c82ab20be1c 100644 --- a/tests/ui/iter_once.fixed +++ b/tests/ui/iter_once.fixed @@ -26,7 +26,30 @@ macro_rules! in_macros { }; } +// Don't trigger on a `Some` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + Some(3).iter(); + Some(3).iter_mut(); + Some(3).into_iter(); + } +} + fn main() { array(); + custom_option::custom_option(); in_macros!(); } diff --git a/tests/ui/iter_once.rs b/tests/ui/iter_once.rs index 3a2b9c95cc53..d561bf27c1df 100644 --- a/tests/ui/iter_once.rs +++ b/tests/ui/iter_once.rs @@ -26,7 +26,30 @@ macro_rules! in_macros { }; } +// Don't trigger on a `Some` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + Some(3).iter(); + Some(3).iter_mut(); + Some(3).into_iter(); + } +} + fn main() { array(); + custom_option::custom_option(); in_macros!(); } From f30d7c2495b3188bfa0cf8bd6dbbf76494c9845e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 19 Jul 2022 22:08:03 +0200 Subject: [PATCH 4/6] Improve suggestions --- clippy_lints/src/methods/iter_once_empty.rs | 70 +++++++++++++-------- clippy_lints/src/methods/mod.rs | 18 +----- tests/ui/iter_empty.stderr | 12 ++-- tests/ui/iter_once.stderr | 12 ++-- 4 files changed, 59 insertions(+), 53 deletions(-) diff --git a/clippy_lints/src/methods/iter_once_empty.rs b/clippy_lints/src/methods/iter_once_empty.rs index d45dfc67880e..82fafb8a45ee 100644 --- a/clippy_lints/src/methods/iter_once_empty.rs +++ b/clippy_lints/src/methods/iter_once_empty.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_lang_ctor; +use clippy_utils::is_no_std_crate; use clippy_utils::source::snippet; use rustc_errors::Applicability; @@ -9,6 +10,22 @@ use rustc_lint::LateContext; use super::{ITER_EMPTY, ITER_ONCE}; +enum IterType { + Iter, + IterMut, + IntoIter, +} + +impl IterType { + fn ref_prefix(&self) -> &'static str { + match self { + Self::Iter => "&", + Self::IterMut => "&mut ", + Self::IntoIter => "", + } + } +} + pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { let item = match &recv.kind { ExprKind::Array(v) if v.len() <= 1 => v.first(), @@ -32,39 +49,42 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: }, _ => return, }; + let iter_type = match method_name { + "iter" => IterType::Iter, + "iter_mut" => IterType::IterMut, + "into_iter" => IterType::IntoIter, + _ => return, + }; if let Some(i) = item { - let (sugg, msg) = match method_name { - "iter" => ( - format!("std::iter::once(&{})", snippet(cx, i.span, "...")), - "this `iter` call can be replaced with std::iter::once", - ), - "iter_mut" => ( - format!("std::iter::once(&mut {})", snippet(cx, i.span, "...")), - "this `iter_mut` call can be replaced with std::iter::once", - ), - "into_iter" => ( - format!("std::iter::once({})", snippet(cx, i.span, "...")), - "this `into_iter` call can be replaced with std::iter::once", - ), - _ => return, - }; - span_lint_and_sugg(cx, ITER_ONCE, expr.span, msg, "try", sugg, Applicability::Unspecified); + let sugg = format!( + "{}::iter::once({}{})", + if is_no_std_crate(cx) { "core" } else { "std" }, + iter_type.ref_prefix(), + snippet(cx, i.span, "...") + ); + span_lint_and_sugg( + cx, + ITER_ONCE, + expr.span, + &format!("`{method_name}` call on a collection with only one item"), + "try", + sugg, + Applicability::MaybeIncorrect, + ); } else { - let msg = match method_name { - "iter" => "this `iter call` can be replaced with std::iter::empty", - "iter_mut" => "this `iter_mut` call can be replaced with std::iter::empty", - "into_iter" => "this `into_iter` call can be replaced with std::iter::empty", - _ => return, - }; span_lint_and_sugg( cx, ITER_EMPTY, expr.span, - msg, + &format!("`{method_name}` call on an empty collection"), "try", - "std::iter::empty()".to_string(), - Applicability::Unspecified, + if is_no_std_crate(cx) { + "core::iter::empty()".to_string() + } else { + "std::iter::empty()".to_string() + }, + Applicability::MaybeIncorrect, ); } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e449ae0e4247..015cd094a9e0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2308,14 +2308,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// - /// Checks for usage of: - /// - /// - `[foo].iter()` - /// - `[foo].iter_mut()` - /// - `[foo].into_iter()` - /// - `Some(foo).iter()` - /// - `Some(foo).iter_mut()` - /// - `Some(foo).into_iter()` + /// Checks for calls to `iter`, `iter_mut` or `into_iter` on collections containing a single item /// /// ### Why is this bad? /// @@ -2346,14 +2339,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// - /// Checks for usage of: - /// - /// - `[].iter()` - /// - `[].iter_mut()` - /// - `[].into_iter()` - /// - `None.iter()` - /// - `None.iter_mut()` - /// - `None.into_iter()` + /// Checks for calls to `iter`, `iter_mut` or `into_iter` on empty collections /// /// ### Why is this bad? /// diff --git a/tests/ui/iter_empty.stderr b/tests/ui/iter_empty.stderr index f4f06e93b237..40c08e6f82bd 100644 --- a/tests/ui/iter_empty.stderr +++ b/tests/ui/iter_empty.stderr @@ -1,4 +1,4 @@ -error: this `into_iter` call can be replaced with std::iter::empty +error: `into_iter` call on an empty collection --> $DIR/iter_empty.rs:6:16 | LL | assert_eq!([].into_iter().next(), Option::::None); @@ -6,31 +6,31 @@ LL | assert_eq!([].into_iter().next(), Option::::None); | = note: `-D clippy::iter-empty` implied by `-D warnings` -error: this `iter_mut` call can be replaced with std::iter::empty +error: `iter_mut` call on an empty collection --> $DIR/iter_empty.rs:7:16 | LL | assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); | ^^^^^^^^^^^^^ help: try: `std::iter::empty()` -error: this `iter call` can be replaced with std::iter::empty +error: `iter` call on an empty collection --> $DIR/iter_empty.rs:8:16 | LL | assert_eq!([].iter().next(), Option::<&i32>::None); | ^^^^^^^^^ help: try: `std::iter::empty()` -error: this `into_iter` call can be replaced with std::iter::empty +error: `into_iter` call on an empty collection --> $DIR/iter_empty.rs:9:16 | LL | assert_eq!(None.into_iter().next(), Option::::None); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` -error: this `iter_mut` call can be replaced with std::iter::empty +error: `iter_mut` call on an empty collection --> $DIR/iter_empty.rs:10:16 | LL | assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); | ^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` -error: this `iter call` can be replaced with std::iter::empty +error: `iter` call on an empty collection --> $DIR/iter_empty.rs:11:16 | LL | assert_eq!(None.iter().next(), Option::<&i32>::None); diff --git a/tests/ui/iter_once.stderr b/tests/ui/iter_once.stderr index d9e8f96f7639..b22c8a99f10b 100644 --- a/tests/ui/iter_once.stderr +++ b/tests/ui/iter_once.stderr @@ -1,4 +1,4 @@ -error: this `into_iter` call can be replaced with std::iter::once +error: `into_iter` call on a collection with only one item --> $DIR/iter_once.rs:6:16 | LL | assert_eq!([123].into_iter().next(), Some(123)); @@ -6,31 +6,31 @@ LL | assert_eq!([123].into_iter().next(), Some(123)); | = note: `-D clippy::iter-once` implied by `-D warnings` -error: this `iter_mut` call can be replaced with std::iter::once +error: `iter_mut` call on a collection with only one item --> $DIR/iter_once.rs:7:16 | LL | assert_eq!([123].iter_mut().next(), Some(&mut 123)); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` -error: this `iter` call can be replaced with std::iter::once +error: `iter` call on a collection with only one item --> $DIR/iter_once.rs:8:16 | LL | assert_eq!([123].iter().next(), Some(&123)); | ^^^^^^^^^^^^ help: try: `std::iter::once(&123)` -error: this `into_iter` call can be replaced with std::iter::once +error: `into_iter` call on a collection with only one item --> $DIR/iter_once.rs:9:16 | LL | assert_eq!(Some(123).into_iter().next(), Some(123)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` -error: this `iter_mut` call can be replaced with std::iter::once +error: `iter_mut` call on a collection with only one item --> $DIR/iter_once.rs:10:16 | LL | assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); | ^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` -error: this `iter` call can be replaced with std::iter::once +error: `iter` call on a collection with only one item --> $DIR/iter_once.rs:11:16 | LL | assert_eq!(Some(123).iter().next(), Some(&123)); From b247594a39cb8e2c3d8d193860eac0eb1c63e1ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 28 Jul 2022 22:54:23 +0200 Subject: [PATCH 5/6] Prevent some false positives --- clippy_lints/src/methods/iter_once_empty.rs | 23 ++++++++++++++++++--- clippy_lints/src/types/mod.rs | 1 - clippy_utils/src/lib.rs | 1 - tests/ui/iter_empty.fixed | 8 +++++++ tests/ui/iter_empty.rs | 8 +++++++ tests/ui/iter_once.fixed | 8 +++++++ tests/ui/iter_once.rs | 8 +++++++ 7 files changed, 52 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/methods/iter_once_empty.rs b/clippy_lints/src/methods/iter_once_empty.rs index 82fafb8a45ee..96b1484528c7 100644 --- a/clippy_lints/src/methods/iter_once_empty.rs +++ b/clippy_lints/src/methods/iter_once_empty.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_lang_ctor; -use clippy_utils::is_no_std_crate; use clippy_utils::source::snippet; +use clippy_utils::{get_expr_use_or_unification_node, is_lang_ctor, is_no_std_crate}; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; use super::{ITER_EMPTY, ITER_ONCE}; @@ -56,6 +55,24 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: _ => return, }; + let is_unified = match get_expr_use_or_unification_node(cx.tcx, expr) { + Some((Node::Expr(parent), child_id)) => match parent.kind { + ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id == child_id => false, + ExprKind::If(_, _, _) + | ExprKind::Match(_, _, _) + | ExprKind::Closure(_) + | ExprKind::Ret(_) + | ExprKind::Break(_, _) => true, + _ => false, + }, + Some((Node::Stmt(_) | Node::Local(_), _)) => false, + _ => true, + }; + + if is_unified { + return; + } + if let Some(i) = item { let sugg = format!( "{}::iter::once({}{})", diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index f3ba096237f5..353a6f6b899e 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -490,7 +490,6 @@ impl Types { } } } - #[allow(clippy::iter_empty)] match *qpath { QPath::Resolved(Some(ty), p) => { context.is_nested_call = true; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 9c58978a0703..dcfc03475b42 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -484,7 +484,6 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { } fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator + 'tcx { let single = |ty| tcx.incoherent_impls(ty).iter().copied(); - #[allow(clippy::iter_empty)] let empty = || [].iter().copied(); match name { "bool" => single(BoolSimplifiedType), diff --git a/tests/ui/iter_empty.fixed b/tests/ui/iter_empty.fixed index 690da5a87615..ad1e106d2b1c 100644 --- a/tests/ui/iter_empty.fixed +++ b/tests/ui/iter_empty.fixed @@ -13,6 +13,14 @@ fn array() { // Don't trigger on non-iter methods let _: Option = None.clone(); let _: [String; 0] = [].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; } macro_rules! in_macros { diff --git a/tests/ui/iter_empty.rs b/tests/ui/iter_empty.rs index f8b56898f2d5..625149b5da51 100644 --- a/tests/ui/iter_empty.rs +++ b/tests/ui/iter_empty.rs @@ -13,6 +13,14 @@ fn array() { // Don't trigger on non-iter methods let _: Option = None.clone(); let _: [String; 0] = [].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; } macro_rules! in_macros { diff --git a/tests/ui/iter_once.fixed b/tests/ui/iter_once.fixed index 0c82ab20be1c..0495bc47e4b2 100644 --- a/tests/ui/iter_once.fixed +++ b/tests/ui/iter_once.fixed @@ -13,6 +13,14 @@ fn array() { // Don't trigger on non-iter methods let _: Option = Some("test".to_string()).clone(); let _: [String; 1] = ["test".to_string()].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; } macro_rules! in_macros { diff --git a/tests/ui/iter_once.rs b/tests/ui/iter_once.rs index d561bf27c1df..96641109bb98 100644 --- a/tests/ui/iter_once.rs +++ b/tests/ui/iter_once.rs @@ -13,6 +13,14 @@ fn array() { // Don't trigger on non-iter methods let _: Option = Some("test".to_string()).clone(); let _: [String; 1] = ["test".to_string()].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; } macro_rules! in_macros { From af4885c0cde76bf1faace76dc8fb53d3d4791422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Sat, 30 Jul 2022 13:39:55 +0200 Subject: [PATCH 6/6] Rename new lints to iter_on_empty_collections and iter_on_single_items --- CHANGELOG.md | 4 ++-- clippy_lints/src/lib.register_lints.rs | 4 ++-- clippy_lints/src/lib.register_nursery.rs | 4 ++-- ...y.rs => iter_on_single_or_empty_collections.rs} | 6 +++--- clippy_lints/src/methods/mod.rs | 14 ++++++++------ ...empty.fixed => iter_on_empty_collections.fixed} | 2 +- ...{iter_empty.rs => iter_on_empty_collections.rs} | 2 +- ...pty.stderr => iter_on_empty_collections.stderr} | 14 +++++++------- ...{iter_once.fixed => iter_on_single_items.fixed} | 2 +- tests/ui/{iter_once.rs => iter_on_single_items.rs} | 2 +- ...ter_once.stderr => iter_on_single_items.stderr} | 14 +++++++------- 11 files changed, 35 insertions(+), 33 deletions(-) rename clippy_lints/src/methods/{iter_once_empty.rs => iter_on_single_or_empty_collections.rs} (95%) rename tests/ui/{iter_empty.fixed => iter_on_empty_collections.fixed} (97%) rename tests/ui/{iter_empty.rs => iter_on_empty_collections.rs} (97%) rename tests/ui/{iter_empty.stderr => iter_on_empty_collections.stderr} (76%) rename tests/ui/{iter_once.fixed => iter_on_single_items.fixed} (97%) rename tests/ui/{iter_once.rs => iter_on_single_items.rs} (97%) rename tests/ui/{iter_once.stderr => iter_on_single_items.stderr} (79%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94f71eba0a29..03a76ccf6071 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3651,13 +3651,13 @@ Released 2018-09-13 [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count -[`iter_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_empty [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop [`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice [`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero -[`iter_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_once +[`iter_on_empty_collections`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_empty_collections +[`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items [`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index e49321d83fa5..b697eb76290d 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -312,11 +312,11 @@ store.register_lints(&[ methods::ITERATOR_STEP_BY_ZERO, methods::ITER_CLONED_COLLECT, methods::ITER_COUNT, - methods::ITER_EMPTY, methods::ITER_NEXT_SLICE, methods::ITER_NTH, methods::ITER_NTH_ZERO, - methods::ITER_ONCE, + methods::ITER_ON_EMPTY_COLLECTIONS, + methods::ITER_ON_SINGLE_ITEMS, methods::ITER_OVEREAGER_CLONED, methods::ITER_SKIP_NEXT, methods::ITER_WITH_DRAIN, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 9953aca43ee2..d65901926553 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -14,8 +14,8 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE), LintId::of(let_if_seq::USELESS_LET_IF_SEQ), LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), - LintId::of(methods::ITER_EMPTY), - LintId::of(methods::ITER_ONCE), + LintId::of(methods::ITER_ON_EMPTY_COLLECTIONS), + LintId::of(methods::ITER_ON_SINGLE_ITEMS), LintId::of(methods::ITER_WITH_DRAIN), LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/clippy_lints/src/methods/iter_once_empty.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs similarity index 95% rename from clippy_lints/src/methods/iter_once_empty.rs rename to clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 96b1484528c7..cea7b0d82ff3 100644 --- a/clippy_lints/src/methods/iter_once_empty.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -7,7 +7,7 @@ use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; -use super::{ITER_EMPTY, ITER_ONCE}; +use super::{ITER_ON_EMPTY_COLLECTIONS, ITER_ON_SINGLE_ITEMS}; enum IterType { Iter, @@ -82,7 +82,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: ); span_lint_and_sugg( cx, - ITER_ONCE, + ITER_ON_SINGLE_ITEMS, expr.span, &format!("`{method_name}` call on a collection with only one item"), "try", @@ -92,7 +92,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: } else { span_lint_and_sugg( cx, - ITER_EMPTY, + ITER_ON_EMPTY_COLLECTIONS, expr.span, &format!("`{method_name}` call on an empty collection"), "try", diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 015cd094a9e0..0936a3f48ca2 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -33,7 +33,7 @@ mod iter_count; mod iter_next_slice; mod iter_nth; mod iter_nth_zero; -mod iter_once_empty; +mod iter_on_single_or_empty_collections; mod iter_overeager_cloned; mod iter_skip_next; mod iter_with_drain; @@ -2331,7 +2331,7 @@ declare_clippy_lint! { /// /// The type of the resulting iterator might become incompatible with its usage #[clippy::version = "1.64.0"] - pub ITER_ONCE, + pub ITER_ON_SINGLE_ITEMS, nursery, "Iterator for array of length 1" } @@ -2363,7 +2363,7 @@ declare_clippy_lint! { /// /// The type of the resulting iterator might become incompatible with its usage #[clippy::version = "1.64.0"] - pub ITER_EMPTY, + pub ITER_ON_EMPTY_COLLECTIONS, nursery, "Iterator for empty array" } @@ -2470,8 +2470,8 @@ impl_lint_pass!(Methods => [ NEEDLESS_OPTION_TAKE, NO_EFFECT_REPLACE, OBFUSCATED_IF_ELSE, - ITER_ONCE, - ITER_EMPTY + ITER_ON_SINGLE_ITEMS, + ITER_ON_EMPTY_COLLECTIONS ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2774,7 +2774,9 @@ impl Methods { ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), ("is_none", []) => check_is_some_is_none(cx, expr, recv, false), ("is_some", []) => check_is_some_is_none(cx, expr, recv, true), - ("iter" | "iter_mut" | "into_iter", []) => iter_once_empty::check(cx, expr, name, recv), + ("iter" | "iter_mut" | "into_iter", []) => { + iter_on_single_or_empty_collections::check(cx, expr, name, recv); + }, ("join", [join_arg]) => { if let Some(("collect", _, span)) = method_call(recv) { unnecessary_join::check(cx, expr, recv, join_arg, span); diff --git a/tests/ui/iter_empty.fixed b/tests/ui/iter_on_empty_collections.fixed similarity index 97% rename from tests/ui/iter_empty.fixed rename to tests/ui/iter_on_empty_collections.fixed index ad1e106d2b1c..bd9b07aefbfb 100644 --- a/tests/ui/iter_empty.fixed +++ b/tests/ui/iter_on_empty_collections.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::iter_empty)] +#![warn(clippy::iter_on_empty_collections)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] fn array() { diff --git a/tests/ui/iter_empty.rs b/tests/ui/iter_on_empty_collections.rs similarity index 97% rename from tests/ui/iter_empty.rs rename to tests/ui/iter_on_empty_collections.rs index 625149b5da51..e15ba94bd465 100644 --- a/tests/ui/iter_empty.rs +++ b/tests/ui/iter_on_empty_collections.rs @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::iter_empty)] +#![warn(clippy::iter_on_empty_collections)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] fn array() { diff --git a/tests/ui/iter_empty.stderr b/tests/ui/iter_on_empty_collections.stderr similarity index 76% rename from tests/ui/iter_empty.stderr rename to tests/ui/iter_on_empty_collections.stderr index 40c08e6f82bd..cbd611769569 100644 --- a/tests/ui/iter_empty.stderr +++ b/tests/ui/iter_on_empty_collections.stderr @@ -1,37 +1,37 @@ error: `into_iter` call on an empty collection - --> $DIR/iter_empty.rs:6:16 + --> $DIR/iter_on_empty_collections.rs:6:16 | LL | assert_eq!([].into_iter().next(), Option::::None); | ^^^^^^^^^^^^^^ help: try: `std::iter::empty()` | - = note: `-D clippy::iter-empty` implied by `-D warnings` + = note: `-D clippy::iter-on-empty-collections` implied by `-D warnings` error: `iter_mut` call on an empty collection - --> $DIR/iter_empty.rs:7:16 + --> $DIR/iter_on_empty_collections.rs:7:16 | LL | assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); | ^^^^^^^^^^^^^ help: try: `std::iter::empty()` error: `iter` call on an empty collection - --> $DIR/iter_empty.rs:8:16 + --> $DIR/iter_on_empty_collections.rs:8:16 | LL | assert_eq!([].iter().next(), Option::<&i32>::None); | ^^^^^^^^^ help: try: `std::iter::empty()` error: `into_iter` call on an empty collection - --> $DIR/iter_empty.rs:9:16 + --> $DIR/iter_on_empty_collections.rs:9:16 | LL | assert_eq!(None.into_iter().next(), Option::::None); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` error: `iter_mut` call on an empty collection - --> $DIR/iter_empty.rs:10:16 + --> $DIR/iter_on_empty_collections.rs:10:16 | LL | assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); | ^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` error: `iter` call on an empty collection - --> $DIR/iter_empty.rs:11:16 + --> $DIR/iter_on_empty_collections.rs:11:16 | LL | assert_eq!(None.iter().next(), Option::<&i32>::None); | ^^^^^^^^^^^ help: try: `std::iter::empty()` diff --git a/tests/ui/iter_once.fixed b/tests/ui/iter_on_single_items.fixed similarity index 97% rename from tests/ui/iter_once.fixed rename to tests/ui/iter_on_single_items.fixed index 0495bc47e4b2..1fa4b03641bc 100644 --- a/tests/ui/iter_once.fixed +++ b/tests/ui/iter_on_single_items.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::iter_once)] +#![warn(clippy::iter_on_single_items)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] fn array() { diff --git a/tests/ui/iter_once.rs b/tests/ui/iter_on_single_items.rs similarity index 97% rename from tests/ui/iter_once.rs rename to tests/ui/iter_on_single_items.rs index 96641109bb98..ea96d8066c56 100644 --- a/tests/ui/iter_once.rs +++ b/tests/ui/iter_on_single_items.rs @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::iter_once)] +#![warn(clippy::iter_on_single_items)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] fn array() { diff --git a/tests/ui/iter_once.stderr b/tests/ui/iter_on_single_items.stderr similarity index 79% rename from tests/ui/iter_once.stderr rename to tests/ui/iter_on_single_items.stderr index b22c8a99f10b..d6c547116363 100644 --- a/tests/ui/iter_once.stderr +++ b/tests/ui/iter_on_single_items.stderr @@ -1,37 +1,37 @@ error: `into_iter` call on a collection with only one item - --> $DIR/iter_once.rs:6:16 + --> $DIR/iter_on_single_items.rs:6:16 | LL | assert_eq!([123].into_iter().next(), Some(123)); | ^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` | - = note: `-D clippy::iter-once` implied by `-D warnings` + = note: `-D clippy::iter-on-single-items` implied by `-D warnings` error: `iter_mut` call on a collection with only one item - --> $DIR/iter_once.rs:7:16 + --> $DIR/iter_on_single_items.rs:7:16 | LL | assert_eq!([123].iter_mut().next(), Some(&mut 123)); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` error: `iter` call on a collection with only one item - --> $DIR/iter_once.rs:8:16 + --> $DIR/iter_on_single_items.rs:8:16 | LL | assert_eq!([123].iter().next(), Some(&123)); | ^^^^^^^^^^^^ help: try: `std::iter::once(&123)` error: `into_iter` call on a collection with only one item - --> $DIR/iter_once.rs:9:16 + --> $DIR/iter_on_single_items.rs:9:16 | LL | assert_eq!(Some(123).into_iter().next(), Some(123)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` error: `iter_mut` call on a collection with only one item - --> $DIR/iter_once.rs:10:16 + --> $DIR/iter_on_single_items.rs:10:16 | LL | assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); | ^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` error: `iter` call on a collection with only one item - --> $DIR/iter_once.rs:11:16 + --> $DIR/iter_on_single_items.rs:11:16 | LL | assert_eq!(Some(123).iter().next(), Some(&123)); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&123)`