about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--book/src/lint_configuration.md1
-rw-r--r--clippy_config/src/conf.rs1
-rw-r--r--clippy_config/src/msrvs.rs4
-rw-r--r--clippy_lints/src/declared_lints.rs1
-rw-r--r--clippy_lints/src/matches/single_match.rs5
-rw-r--r--clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs134
-rw-r--r--clippy_lints/src/methods/mod.rs37
-rw-r--r--tests/ui/map_with_unused_argument_over_ranges.fixed73
-rw-r--r--tests/ui/map_with_unused_argument_over_ranges.rs73
-rw-r--r--tests/ui/map_with_unused_argument_over_ranges.stderr223
-rw-r--r--tests/ui/repeat_vec_with_capacity.fixed1
-rw-r--r--tests/ui/repeat_vec_with_capacity.rs1
-rw-r--r--tests/ui/repeat_vec_with_capacity.stderr6
-rw-r--r--tests/ui/suspicious_map.rs1
-rw-r--r--tests/ui/suspicious_map.stderr4
16 files changed, 558 insertions, 8 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6225e7a0186..f3a42083aa4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5697,6 +5697,7 @@ Released 2018-09-13
 [`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten
 [`map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_identity
 [`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
+[`map_with_unused_argument_over_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_with_unused_argument_over_ranges
 [`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref
 [`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool
 [`match_like_matches_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro
diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md
index 9ea4c8418fd..c1ede651fc5 100644
--- a/book/src/lint_configuration.md
+++ b/book/src/lint_configuration.md
@@ -710,6 +710,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 * [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold)
 * [`map_clone`](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone)
 * [`map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or)
+* [`map_with_unused_argument_over_ranges`](https://rust-lang.github.io/rust-clippy/master/index.html#map_with_unused_argument_over_ranges)
 * [`match_like_matches_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro)
 * [`mem_replace_with_default`](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default)
 * [`missing_const_for_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn)
diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs
index b0faac6d2a8..26f156a0bbc 100644
--- a/clippy_config/src/conf.rs
+++ b/clippy_config/src/conf.rs
@@ -573,6 +573,7 @@ define_Conf! {
         manual_try_fold,
         map_clone,
         map_unwrap_or,
+        map_with_unused_argument_over_ranges,
         match_like_matches_macro,
         mem_replace_with_default,
         missing_const_for_fn,
diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs
index b809d8d0487..764ca8fb50a 100644
--- a/clippy_config/src/msrvs.rs
+++ b/clippy_config/src/msrvs.rs
@@ -19,7 +19,7 @@ macro_rules! msrv_aliases {
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
     1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY }
-    1,82,0 { IS_NONE_OR }
+    1,82,0 { IS_NONE_OR, REPEAT_N }
     1,81,0 { LINT_REASONS_STABILIZATION }
     1,80,0 { BOX_INTO_ITER}
     1,77,0 { C_STR_LITERALS }
@@ -55,7 +55,7 @@ msrv_aliases! {
     1,33,0 { UNDERSCORE_IMPORTS }
     1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
     1,29,0 { ITER_FLATTEN }
-    1,28,0 { FROM_BOOL }
+    1,28,0 { FROM_BOOL, REPEAT_WITH }
     1,27,0 { ITERATOR_TRY_FOLD }
     1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN }
     1,24,0 { IS_ASCII_DIGIT }
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 5d57cf5173e..f065f6115dc 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -423,6 +423,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::methods::MAP_FLATTEN_INFO,
     crate::methods::MAP_IDENTITY_INFO,
     crate::methods::MAP_UNWRAP_OR_INFO,
+    crate::methods::MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES_INFO,
     crate::methods::MUT_MUTEX_LOCK_INFO,
     crate::methods::NAIVE_BYTECOUNT_INFO,
     crate::methods::NEEDLESS_AS_BYTES_INFO,
diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs
index 2eda238ae8c..337622873a1 100644
--- a/clippy_lints/src/matches/single_match.rs
+++ b/clippy_lints/src/matches/single_match.rs
@@ -249,7 +249,10 @@ impl<'a> PatState<'a> {
         let states = match self {
             Self::Wild => return None,
             Self::Other => {
-                *self = Self::StdEnum(cx.arena.alloc_from_iter((0..adt.variants().len()).map(|_| Self::Other)));
+                *self = Self::StdEnum(
+                    cx.arena
+                        .alloc_from_iter(std::iter::repeat_with(|| Self::Other).take(adt.variants().len())),
+                );
                 let Self::StdEnum(x) = self else {
                     unreachable!();
                 };
diff --git a/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs b/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs
new file mode 100644
index 00000000000..fc656fd78ba
--- /dev/null
+++ b/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs
@@ -0,0 +1,134 @@
+use crate::methods::MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES;
+use clippy_config::msrvs::{self, Msrv};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sugg::Sugg;
+use clippy_utils::{eager_or_lazy, higher, usage};
+use rustc_ast::LitKind;
+use rustc_ast::ast::RangeLimits;
+use rustc_data_structures::packed::Pu128;
+use rustc_errors::Applicability;
+use rustc_hir::{Body, Closure, Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+
+fn extract_count_with_applicability(
+    cx: &LateContext<'_>,
+    range: higher::Range<'_>,
+    applicability: &mut Applicability,
+) -> Option<String> {
+    let start = range.start?;
+    let end = range.end?;
+    // TODO: This doens't handle if either the start or end are negative literals, or if the start is
+    // not a literal. In the first case, we need to be careful about how we handle computing the
+    // count to avoid overflows. In the second, we may need to add parenthesis to make the
+    // suggestion correct.
+    if let ExprKind::Lit(lit) = start.kind
+        && let LitKind::Int(Pu128(lower_bound), _) = lit.node
+    {
+        if let ExprKind::Lit(lit) = end.kind
+            && let LitKind::Int(Pu128(upper_bound), _) = lit.node
+        {
+            // Here we can explicitly calculate the number of iterations
+            let count = if upper_bound >= lower_bound {
+                match range.limits {
+                    RangeLimits::HalfOpen => upper_bound - lower_bound,
+                    RangeLimits::Closed => (upper_bound - lower_bound).checked_add(1)?,
+                }
+            } else {
+                0
+            };
+            return Some(format!("{count}"));
+        }
+        let end_snippet = Sugg::hir_with_applicability(cx, end, "...", applicability)
+            .maybe_par()
+            .into_string();
+        if lower_bound == 0 {
+            if range.limits == RangeLimits::Closed {
+                return Some(format!("{end_snippet} + 1"));
+            }
+            return Some(end_snippet);
+        }
+        if range.limits == RangeLimits::Closed {
+            return Some(format!("{end_snippet} - {}", lower_bound - 1));
+        }
+        return Some(format!("{end_snippet} - {lower_bound}"));
+    }
+    None
+}
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    ex: &Expr<'_>,
+    receiver: &Expr<'_>,
+    arg: &Expr<'_>,
+    msrv: &Msrv,
+    method_call_span: Span,
+) {
+    let mut applicability = Applicability::MaybeIncorrect;
+    if let Some(range) = higher::Range::hir(receiver)
+        && let ExprKind::Closure(Closure { body, .. }) = arg.kind
+        && let body_hir = cx.tcx.hir().body(*body)
+        && let Body {
+            params: [param],
+            value: body_expr,
+        } = body_hir
+        && !usage::BindingUsageFinder::are_params_used(cx, body_hir)
+        && let Some(count) = extract_count_with_applicability(cx, range, &mut applicability)
+    {
+        let method_to_use_name;
+        let new_span;
+        let use_take;
+
+        if eager_or_lazy::switch_to_eager_eval(cx, body_expr) {
+            if msrv.meets(msrvs::REPEAT_N) {
+                method_to_use_name = "repeat_n";
+                let body_snippet = snippet_with_applicability(cx, body_expr.span, "..", &mut applicability);
+                new_span = (arg.span, format!("{body_snippet}, {count}"));
+                use_take = false;
+            } else {
+                method_to_use_name = "repeat";
+                let body_snippet = snippet_with_applicability(cx, body_expr.span, "..", &mut applicability);
+                new_span = (arg.span, body_snippet.to_string());
+                use_take = true;
+            }
+        } else if msrv.meets(msrvs::REPEAT_WITH) {
+            method_to_use_name = "repeat_with";
+            new_span = (param.span, String::new());
+            use_take = true;
+        } else {
+            return;
+        }
+
+        // We need to provide nonempty parts to diag.multipart_suggestion so we
+        // collate all our parts here and then remove those that are empty.
+        let mut parts = vec![
+            (
+                receiver.span.to(method_call_span),
+                format!("std::iter::{method_to_use_name}"),
+            ),
+            new_span,
+        ];
+        if use_take {
+            parts.push((ex.span.shrink_to_hi(), format!(".take({count})")));
+        }
+
+        span_lint_and_then(
+            cx,
+            MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
+            ex.span,
+            "map of a closure that does not depend on its parameter over a range",
+            |diag| {
+                diag.multipart_suggestion(
+                    if use_take {
+                        format!("remove the explicit range and use `{method_to_use_name}` and `take`")
+                    } else {
+                        format!("remove the explicit range and use `{method_to_use_name}`")
+                    },
+                    parts,
+                    applicability,
+                );
+            },
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 0ebb46fa526..f8578ecaf9a 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -67,6 +67,7 @@ mod map_err_ignore;
 mod map_flatten;
 mod map_identity;
 mod map_unwrap_or;
+mod map_with_unused_argument_over_ranges;
 mod mut_mutex_lock;
 mod needless_as_bytes;
 mod needless_character_iteration;
@@ -4218,6 +4219,40 @@ declare_clippy_lint! {
     "combine `.map(_)` followed by `.all(identity)`/`.any(identity)` into a single call"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for `Iterator::map` over ranges without using the parameter which
+    /// could be more clearly expressed using `std::iter::repeat(...).take(...)`
+    /// or `std::iter::repeat_n`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// It expresses the intent more clearly to `take` the correct number of times
+    /// from a generating function than to apply a closure to each number in a
+    /// range only to discard them.
+    ///
+    /// ### Example
+    ///
+    /// ```no_run
+    /// let random_numbers : Vec<_> = (0..10).map(|_| { 3 + 1 }).collect();
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let f : Vec<_> = std::iter::repeat( 3 + 1 ).take(10).collect();
+    /// ```
+    ///
+    /// ### Known Issues
+    ///
+    /// This lint may suggest replacing a `Map<Range>` with a `Take<RepeatWith>`.
+    /// The former implements some traits that the latter does not, such as
+    /// `DoubleEndedIterator`.
+    #[clippy::version = "1.84.0"]
+    pub MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
+    restriction,
+    "map of a trivial closure (not dependent on parameter) over a range"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -4381,6 +4416,7 @@ impl_lint_pass!(Methods => [
     UNNECESSARY_MIN_OR_MAX,
     NEEDLESS_AS_BYTES,
     MAP_ALL_ANY_IDENTITY,
+    MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4876,6 +4912,7 @@ impl Methods {
                     if name == "map" {
                         unused_enumerate_index::check(cx, expr, recv, m_arg);
                         map_clone::check(cx, expr, recv, m_arg, &self.msrv);
+                        map_with_unused_argument_over_ranges::check(cx, expr, recv, m_arg, &self.msrv, span);
                         match method_call(recv) {
                             Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => {
                                 iter_kv_map::check(cx, map_name, expr, recv2, m_arg, &self.msrv);
diff --git a/tests/ui/map_with_unused_argument_over_ranges.fixed b/tests/ui/map_with_unused_argument_over_ranges.fixed
new file mode 100644
index 00000000000..cf520e71a64
--- /dev/null
+++ b/tests/ui/map_with_unused_argument_over_ranges.fixed
@@ -0,0 +1,73 @@
+#![allow(
+    unused,
+    clippy::redundant_closure,
+    clippy::reversed_empty_ranges,
+    clippy::identity_op
+)]
+#![warn(clippy::map_with_unused_argument_over_ranges)]
+
+fn do_something() -> usize {
+    todo!()
+}
+
+fn do_something_interesting(x: usize, y: usize) -> usize {
+    todo!()
+}
+
+macro_rules! gen {
+    () => {
+        (0..10).map(|_| do_something());
+    };
+}
+
+fn main() {
+    // These should be raised
+    std::iter::repeat_with(|| do_something()).take(10);
+    std::iter::repeat_with(|| do_something()).take(10);
+    std::iter::repeat_with(|| do_something()).take(11);
+    std::iter::repeat_with(|| do_something()).take(7);
+    std::iter::repeat_with(|| do_something()).take(8);
+    std::iter::repeat_n(3, 10);
+    std::iter::repeat_with(|| {
+        let x = 3;
+        x + 2
+    }).take(10);
+    std::iter::repeat_with(|| do_something()).take(10).collect::<Vec<_>>();
+    let upper = 4;
+    std::iter::repeat_with(|| do_something()).take(upper);
+    let upper_fn = || 4;
+    std::iter::repeat_with(|| do_something()).take(upper_fn());
+    std::iter::repeat_with(|| do_something()).take(upper_fn() + 1);
+    std::iter::repeat_with(|| do_something()).take(upper_fn() - 2);
+    std::iter::repeat_with(|| do_something()).take(upper_fn() - 1);
+    (-3..9).map(|_| do_something());
+    std::iter::repeat_with(|| do_something()).take(0);
+    std::iter::repeat_with(|| do_something()).take(1);
+    std::iter::repeat_with(|| do_something()).take((1 << 4) - 0);
+    // These should not be raised
+    gen!();
+    let lower = 2;
+    let lower_fn = || 2;
+    (lower..upper_fn()).map(|_| do_something()); // Ranges not starting at zero not yet handled
+    (lower_fn()..upper_fn()).map(|_| do_something()); // Ranges not starting at zero not yet handled
+    (lower_fn()..=upper_fn()).map(|_| do_something()); // Ranges not starting at zero not yet handled
+    (0..10).map(|x| do_something_interesting(x, 4)); // Actual map over range
+    "Foobar".chars().map(|_| do_something()); // Not a map over range
+    // i128::MAX == 340282366920938463463374607431768211455
+    (0..=340282366920938463463374607431768211455).map(|_: u128| do_something()); // Can't be replaced due to overflow
+}
+
+#[clippy::msrv = "1.27"]
+fn msrv_1_27() {
+    (0..10).map(|_| do_something());
+}
+
+#[clippy::msrv = "1.28"]
+fn msrv_1_28() {
+    std::iter::repeat_with(|| do_something()).take(10);
+}
+
+#[clippy::msrv = "1.81"]
+fn msrv_1_82() {
+    std::iter::repeat(3).take(10);
+}
diff --git a/tests/ui/map_with_unused_argument_over_ranges.rs b/tests/ui/map_with_unused_argument_over_ranges.rs
new file mode 100644
index 00000000000..298eee9ca3f
--- /dev/null
+++ b/tests/ui/map_with_unused_argument_over_ranges.rs
@@ -0,0 +1,73 @@
+#![allow(
+    unused,
+    clippy::redundant_closure,
+    clippy::reversed_empty_ranges,
+    clippy::identity_op
+)]
+#![warn(clippy::map_with_unused_argument_over_ranges)]
+
+fn do_something() -> usize {
+    todo!()
+}
+
+fn do_something_interesting(x: usize, y: usize) -> usize {
+    todo!()
+}
+
+macro_rules! gen {
+    () => {
+        (0..10).map(|_| do_something());
+    };
+}
+
+fn main() {
+    // These should be raised
+    (0..10).map(|_| do_something());
+    (0..10).map(|_foo| do_something());
+    (0..=10).map(|_| do_something());
+    (3..10).map(|_| do_something());
+    (3..=10).map(|_| do_something());
+    (0..10).map(|_| 3);
+    (0..10).map(|_| {
+        let x = 3;
+        x + 2
+    });
+    (0..10).map(|_| do_something()).collect::<Vec<_>>();
+    let upper = 4;
+    (0..upper).map(|_| do_something());
+    let upper_fn = || 4;
+    (0..upper_fn()).map(|_| do_something());
+    (0..=upper_fn()).map(|_| do_something());
+    (2..upper_fn()).map(|_| do_something());
+    (2..=upper_fn()).map(|_| do_something());
+    (-3..9).map(|_| do_something());
+    (9..3).map(|_| do_something());
+    (9..=9).map(|_| do_something());
+    (1..=1 << 4).map(|_| do_something());
+    // These should not be raised
+    gen!();
+    let lower = 2;
+    let lower_fn = || 2;
+    (lower..upper_fn()).map(|_| do_something()); // Ranges not starting at zero not yet handled
+    (lower_fn()..upper_fn()).map(|_| do_something()); // Ranges not starting at zero not yet handled
+    (lower_fn()..=upper_fn()).map(|_| do_something()); // Ranges not starting at zero not yet handled
+    (0..10).map(|x| do_something_interesting(x, 4)); // Actual map over range
+    "Foobar".chars().map(|_| do_something()); // Not a map over range
+    // i128::MAX == 340282366920938463463374607431768211455
+    (0..=340282366920938463463374607431768211455).map(|_: u128| do_something()); // Can't be replaced due to overflow
+}
+
+#[clippy::msrv = "1.27"]
+fn msrv_1_27() {
+    (0..10).map(|_| do_something());
+}
+
+#[clippy::msrv = "1.28"]
+fn msrv_1_28() {
+    (0..10).map(|_| do_something());
+}
+
+#[clippy::msrv = "1.81"]
+fn msrv_1_82() {
+    (0..10).map(|_| 3);
+}
diff --git a/tests/ui/map_with_unused_argument_over_ranges.stderr b/tests/ui/map_with_unused_argument_over_ranges.stderr
new file mode 100644
index 00000000000..0b56c6d9521
--- /dev/null
+++ b/tests/ui/map_with_unused_argument_over_ranges.stderr
@@ -0,0 +1,223 @@
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:25:5
+   |
+LL |     (0..10).map(|_| do_something());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::map-with-unused-argument-over-ranges` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::map_with_unused_argument_over_ranges)]`
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (0..10).map(|_| do_something());
+LL +     std::iter::repeat_with(|| do_something()).take(10);
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:26:5
+   |
+LL |     (0..10).map(|_foo| do_something());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (0..10).map(|_foo| do_something());
+LL +     std::iter::repeat_with(|| do_something()).take(10);
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:27:5
+   |
+LL |     (0..=10).map(|_| do_something());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (0..=10).map(|_| do_something());
+LL +     std::iter::repeat_with(|| do_something()).take(11);
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:28:5
+   |
+LL |     (3..10).map(|_| do_something());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (3..10).map(|_| do_something());
+LL +     std::iter::repeat_with(|| do_something()).take(7);
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:29:5
+   |
+LL |     (3..=10).map(|_| do_something());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (3..=10).map(|_| do_something());
+LL +     std::iter::repeat_with(|| do_something()).take(8);
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:30:5
+   |
+LL |     (0..10).map(|_| 3);
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_n`
+   |
+LL |     std::iter::repeat_n(3, 10);
+   |     ~~~~~~~~~~~~~~~~~~~ ~~~~~
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:31:5
+   |
+LL | /     (0..10).map(|_| {
+LL | |         let x = 3;
+LL | |         x + 2
+LL | |     });
+   | |______^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL ~     std::iter::repeat_with(|| {
+LL |         let x = 3;
+LL |         x + 2
+LL ~     }).take(10);
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:35:5
+   |
+LL |     (0..10).map(|_| do_something()).collect::<Vec<_>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (0..10).map(|_| do_something()).collect::<Vec<_>>();
+LL +     std::iter::repeat_with(|| do_something()).take(10).collect::<Vec<_>>();
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:37:5
+   |
+LL |     (0..upper).map(|_| do_something());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (0..upper).map(|_| do_something());
+LL +     std::iter::repeat_with(|| do_something()).take(upper);
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:39:5
+   |
+LL |     (0..upper_fn()).map(|_| do_something());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (0..upper_fn()).map(|_| do_something());
+LL +     std::iter::repeat_with(|| do_something()).take(upper_fn());
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:40:5
+   |
+LL |     (0..=upper_fn()).map(|_| do_something());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (0..=upper_fn()).map(|_| do_something());
+LL +     std::iter::repeat_with(|| do_something()).take(upper_fn() + 1);
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:41:5
+   |
+LL |     (2..upper_fn()).map(|_| do_something());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (2..upper_fn()).map(|_| do_something());
+LL +     std::iter::repeat_with(|| do_something()).take(upper_fn() - 2);
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:42:5
+   |
+LL |     (2..=upper_fn()).map(|_| do_something());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (2..=upper_fn()).map(|_| do_something());
+LL +     std::iter::repeat_with(|| do_something()).take(upper_fn() - 1);
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:44:5
+   |
+LL |     (9..3).map(|_| do_something());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (9..3).map(|_| do_something());
+LL +     std::iter::repeat_with(|| do_something()).take(0);
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:45:5
+   |
+LL |     (9..=9).map(|_| do_something());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (9..=9).map(|_| do_something());
+LL +     std::iter::repeat_with(|| do_something()).take(1);
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:46:5
+   |
+LL |     (1..=1 << 4).map(|_| do_something());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (1..=1 << 4).map(|_| do_something());
+LL +     std::iter::repeat_with(|| do_something()).take((1 << 4) - 0);
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:67:5
+   |
+LL |     (0..10).map(|_| do_something());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat_with` and `take`
+   |
+LL -     (0..10).map(|_| do_something());
+LL +     std::iter::repeat_with(|| do_something()).take(10);
+   |
+
+error: map of a closure that does not depend on its parameter over a range
+  --> tests/ui/map_with_unused_argument_over_ranges.rs:72:5
+   |
+LL |     (0..10).map(|_| 3);
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+help: remove the explicit range and use `repeat` and `take`
+   |
+LL |     std::iter::repeat(3).take(10);
+   |     ~~~~~~~~~~~~~~~~~ ~ +++++++++
+
+error: aborting due to 18 previous errors
+
diff --git a/tests/ui/repeat_vec_with_capacity.fixed b/tests/ui/repeat_vec_with_capacity.fixed
index 2afe2f43325..f72b61b5f6c 100644
--- a/tests/ui/repeat_vec_with_capacity.fixed
+++ b/tests/ui/repeat_vec_with_capacity.fixed
@@ -1,3 +1,4 @@
+#![allow(clippy::map_with_unused_argument_over_ranges)]
 #![warn(clippy::repeat_vec_with_capacity)]
 
 fn main() {
diff --git a/tests/ui/repeat_vec_with_capacity.rs b/tests/ui/repeat_vec_with_capacity.rs
index 659f2a3953d..c0cc81f7843 100644
--- a/tests/ui/repeat_vec_with_capacity.rs
+++ b/tests/ui/repeat_vec_with_capacity.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::map_with_unused_argument_over_ranges)]
 #![warn(clippy::repeat_vec_with_capacity)]
 
 fn main() {
diff --git a/tests/ui/repeat_vec_with_capacity.stderr b/tests/ui/repeat_vec_with_capacity.stderr
index cec9c6ea84a..43027c9cb89 100644
--- a/tests/ui/repeat_vec_with_capacity.stderr
+++ b/tests/ui/repeat_vec_with_capacity.stderr
@@ -1,5 +1,5 @@
 error: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity
-  --> tests/ui/repeat_vec_with_capacity.rs:5:9
+  --> tests/ui/repeat_vec_with_capacity.rs:6:9
    |
 LL |         vec![Vec::<()>::with_capacity(42); 123];
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL |         (0..123).map(|_| Vec::<()>::with_capacity(42)).collect::<Vec<_>>();
    |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity
-  --> tests/ui/repeat_vec_with_capacity.rs:11:9
+  --> tests/ui/repeat_vec_with_capacity.rs:12:9
    |
 LL |         vec![Vec::<()>::with_capacity(42); n];
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL |         (0..n).map(|_| Vec::<()>::with_capacity(42)).collect::<Vec<_>>();
    |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: repeating `Vec::with_capacity` using `iter::repeat`, which does not retain capacity
-  --> tests/ui/repeat_vec_with_capacity.rs:26:9
+  --> tests/ui/repeat_vec_with_capacity.rs:27:9
    |
 LL |         std::iter::repeat(Vec::<()>::with_capacity(42));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/suspicious_map.rs b/tests/ui/suspicious_map.rs
index d4247fcd926..d4a52cb110f 100644
--- a/tests/ui/suspicious_map.rs
+++ b/tests/ui/suspicious_map.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::map_with_unused_argument_over_ranges)]
 #![warn(clippy::suspicious_map)]
 
 fn main() {
diff --git a/tests/ui/suspicious_map.stderr b/tests/ui/suspicious_map.stderr
index 2a5e2bf2a34..769adebaede 100644
--- a/tests/ui/suspicious_map.stderr
+++ b/tests/ui/suspicious_map.stderr
@@ -1,5 +1,5 @@
 error: this call to `map()` won't have an effect on the call to `count()`
-  --> tests/ui/suspicious_map.rs:4:13
+  --> tests/ui/suspicious_map.rs:5:13
    |
 LL |     let _ = (0..3).map(|x| x + 2).count();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL |     let _ = (0..3).map(|x| x + 2).count();
    = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]`
 
 error: this call to `map()` won't have an effect on the call to `count()`
-  --> tests/ui/suspicious_map.rs:8:13
+  --> tests/ui/suspicious_map.rs:9:13
    |
 LL |     let _ = (0..3).map(f).count();
    |             ^^^^^^^^^^^^^^^^^^^^^