Skip to content

Commit 8e422ea

Browse files
committed
add a lint for repeat().take()
1 parent 0f9cc8d commit 8e422ea

15 files changed

+159
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5725,6 +5725,7 @@ Released 2018-09-13
57255725
[`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
57265726
[`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns
57275727
[`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid
5728+
[`manual_repeat_n`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_repeat_n
57285729
[`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain
57295730
[`manual_rotate`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rotate
57305731
[`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
418418
crate::methods::MANUAL_IS_VARIANT_AND_INFO,
419419
crate::methods::MANUAL_NEXT_BACK_INFO,
420420
crate::methods::MANUAL_OK_OR_INFO,
421+
crate::methods::MANUAL_REPEAT_N_INFO,
421422
crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO,
422423
crate::methods::MANUAL_SPLIT_ONCE_INFO,
423424
crate::methods::MANUAL_STR_REPEAT_INFO,
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::msrvs::{self, Msrv};
3+
use clippy_utils::source::{snippet, snippet_with_context};
4+
use clippy_utils::{fn_def_id, is_trait_method};
5+
use rustc_errors::Applicability;
6+
use rustc_hir::{Expr, ExprKind};
7+
use rustc_lint::LateContext;
8+
use rustc_span::sym;
9+
10+
use super::MANUAL_REPEAT_N;
11+
12+
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, repeat_expr: &Expr<'_>, take_arg: &Expr<'_>, msrv: &Msrv) {
13+
if msrv.meets(msrvs::REPEAT_N)
14+
&& !expr.span.from_expansion()
15+
&& is_trait_method(cx, expr, sym::Iterator)
16+
&& let ExprKind::Call(_, [repeat_arg]) = repeat_expr.kind
17+
&& let Some(def_id) = fn_def_id(cx, repeat_expr)
18+
&& cx.tcx.is_diagnostic_item(sym::iter_repeat, def_id)
19+
{
20+
let mut app = Applicability::MachineApplicable;
21+
span_lint_and_sugg(
22+
cx,
23+
MANUAL_REPEAT_N,
24+
expr.span,
25+
"this `.repeat().take()` can be written more concisely",
26+
"consider using `repeat_n()` instead",
27+
format!(
28+
"std::iter::repeat_n({}, {})",
29+
snippet_with_context(cx, repeat_arg.span, expr.span.ctxt(), "..", &mut app).0,
30+
snippet(cx, take_arg.span, "")
31+
),
32+
Applicability::MachineApplicable,
33+
);
34+
}
35+
}

clippy_lints/src/methods/mod.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ mod manual_inspect;
5757
mod manual_is_variant_and;
5858
mod manual_next_back;
5959
mod manual_ok_or;
60+
mod manual_repeat_n;
6061
mod manual_saturating_arithmetic;
6162
mod manual_str_repeat;
6263
mod manual_try_fold;
@@ -4284,6 +4285,29 @@ declare_clippy_lint! {
42844285
"map of a trivial closure (not dependent on parameter) over a range"
42854286
}
42864287

4288+
declare_clippy_lint! {
4289+
/// ### What it does
4290+
///
4291+
/// Checks for `repeat().take()` that can be replaced with `repeat_n()`.
4292+
///
4293+
/// ### Why is this bad?
4294+
///
4295+
/// Using `repeat_n()` is more concise and clearer.
4296+
///
4297+
/// ### Example
4298+
/// ```no_run
4299+
/// let _ = std::iter::repeat(10).take(3);
4300+
/// ```
4301+
/// Use instead:
4302+
/// ```no_run
4303+
/// let _ = std::iter::repeat_n(10, 3);
4304+
/// ```
4305+
#[clippy::version = "1.85.0"]
4306+
pub MANUAL_REPEAT_N,
4307+
style,
4308+
"detect `repeat().take()` that can be replaced with `repeat_n()`"
4309+
}
4310+
42874311
pub struct Methods {
42884312
avoid_breaking_exported_api: bool,
42894313
msrv: Msrv,
@@ -4449,6 +4473,7 @@ impl_lint_pass!(Methods => [
44494473
MAP_ALL_ANY_IDENTITY,
44504474
MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
44514475
UNNECESSARY_MAP_OR,
4476+
MANUAL_REPEAT_N,
44524477
]);
44534478

44544479
/// Extracts a method call name, args, and `Span` of the method name.
@@ -5117,6 +5142,7 @@ impl Methods {
51175142
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
51185143
("take", [arg]) => {
51195144
iter_out_of_bounds::check_take(cx, expr, recv, arg);
5145+
manual_repeat_n::check(cx, expr, recv, arg, &self.msrv);
51205146
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
51215147
iter_overeager_cloned::check(
51225148
cx,

clippy_utils/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
clippy::missing_errors_doc,
1616
clippy::missing_panics_doc,
1717
clippy::must_use_candidate,
18+
clippy::manual_repeat_n,
1819
rustc::diagnostic_outside_of_impl,
1920
rustc::untranslatable_diagnostic
2021
)]

tests/ui/from_iter_instead_of_collect.fixed

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![warn(clippy::from_iter_instead_of_collect)]
1+
#![warn(clippy::from_iter_instead_of_collect, clippy::manual_repeat_n)]
22
#![allow(unused_imports)]
33
#![allow(clippy::useless_vec)]
44

@@ -19,7 +19,7 @@ impl<'a> FromIterator<&'a bool> for Foo {
1919
}
2020

2121
fn main() {
22-
let iter_expr = std::iter::repeat(5).take(5);
22+
let iter_expr = std::iter::repeat_n(5, 5);
2323
let _ = iter_expr.collect::<Vec<_>>();
2424

2525
let _ = vec![5, 5, 5, 5].iter().enumerate().collect::<HashMap<usize, &i8>>();

tests/ui/from_iter_instead_of_collect.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![warn(clippy::from_iter_instead_of_collect)]
1+
#![warn(clippy::from_iter_instead_of_collect, clippy::manual_repeat_n)]
22
#![allow(unused_imports)]
33
#![allow(clippy::useless_vec)]
44

tests/ui/from_iter_instead_of_collect.stderr

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ LL | <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied())
77
= note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings`
88
= help: to override `-D warnings` add `#[allow(clippy::from_iter_instead_of_collect)]`
99

10+
error: this `.repeat().take()` can be written more concisely
11+
--> tests/ui/from_iter_instead_of_collect.rs:22:21
12+
|
13+
LL | let iter_expr = std::iter::repeat(5).take(5);
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(5, 5)`
15+
|
16+
= note: `-D clippy::manual-repeat-n` implied by `-D warnings`
17+
= help: to override `-D warnings` add `#[allow(clippy::manual_repeat_n)]`
18+
1019
error: usage of `FromIterator::from_iter`
1120
--> tests/ui/from_iter_instead_of_collect.rs:23:13
1221
|
@@ -91,5 +100,5 @@ error: usage of `FromIterator::from_iter`
91100
LL | for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {}
92101
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<&i32>>()`
93102

94-
error: aborting due to 15 previous errors
103+
error: aborting due to 16 previous errors
95104

tests/ui/manual_repeat_n.fixed

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![warn(clippy::manual_repeat_n)]
2+
3+
use std::iter::repeat;
4+
5+
fn main() {
6+
let _ = std::iter::repeat_n(10, 3);
7+
8+
let _ = std::iter::repeat_n(String::from("foo"), 4);
9+
10+
for value in std::iter::repeat_n(5, 3) {}
11+
12+
let _: Vec<_> = std::iter::repeat_n(String::from("bar"), 10).collect();
13+
14+
let _ = std::iter::repeat_n(vec![1, 2], 2);
15+
}

tests/ui/manual_repeat_n.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![warn(clippy::manual_repeat_n)]
2+
3+
use std::iter::repeat;
4+
5+
fn main() {
6+
let _ = repeat(10).take(3);
7+
8+
let _ = repeat(String::from("foo")).take(4);
9+
10+
for value in std::iter::repeat(5).take(3) {}
11+
12+
let _: Vec<_> = std::iter::repeat(String::from("bar")).take(10).collect();
13+
14+
let _ = repeat(vec![1, 2]).take(2);
15+
}

tests/ui/manual_repeat_n.stderr

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error: this `.repeat().take()` can be written more concisely
2+
--> tests/ui/manual_repeat_n.rs:6:13
3+
|
4+
LL | let _ = repeat(10).take(3);
5+
| ^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(10, 3)`
6+
|
7+
= note: `-D clippy::manual-repeat-n` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::manual_repeat_n)]`
9+
10+
error: this `.repeat().take()` can be written more concisely
11+
--> tests/ui/manual_repeat_n.rs:8:13
12+
|
13+
LL | let _ = repeat(String::from("foo")).take(4);
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(String::from("foo"), 4)`
15+
16+
error: this `.repeat().take()` can be written more concisely
17+
--> tests/ui/manual_repeat_n.rs:10:18
18+
|
19+
LL | for value in std::iter::repeat(5).take(3) {}
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(5, 3)`
21+
22+
error: this `.repeat().take()` can be written more concisely
23+
--> tests/ui/manual_repeat_n.rs:12:21
24+
|
25+
LL | let _: Vec<_> = std::iter::repeat(String::from("bar")).take(10).collect();
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(String::from("bar"), 10)`
27+
28+
error: this `.repeat().take()` can be written more concisely
29+
--> tests/ui/manual_repeat_n.rs:14:13
30+
|
31+
LL | let _ = repeat(vec![1, 2]).take(2);
32+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(vec![1, 2], 2)`
33+
34+
error: aborting due to 5 previous errors
35+

tests/ui/manual_str_repeat.fixed

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![allow(non_local_definitions)]
1+
#![allow(non_local_definitions, clippy::manual_repeat_n)]
22
#![warn(clippy::manual_str_repeat)]
33

44
use std::borrow::Cow;

tests/ui/manual_str_repeat.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![allow(non_local_definitions)]
1+
#![allow(non_local_definitions, clippy::manual_repeat_n)]
22
#![warn(clippy::manual_str_repeat)]
33

44
use std::borrow::Cow;

tests/ui/slow_vector_initialization.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![allow(clippy::manual_repeat_n)]
2+
13
//@no-rustfix
24
use std::iter::repeat;
35
fn main() {

tests/ui/slow_vector_initialization.stderr

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: slow zero-filling initialization
2-
--> tests/ui/slow_vector_initialization.rs:14:5
2+
--> tests/ui/slow_vector_initialization.rs:16:5
33
|
44
LL | let mut vec1 = Vec::with_capacity(len);
55
| ----------------------- help: consider replacing this with: `vec![0; len]`
@@ -10,95 +10,95 @@ LL | vec1.extend(repeat(0).take(len));
1010
= help: to override `-D warnings` add `#[allow(clippy::slow_vector_initialization)]`
1111

1212
error: slow zero-filling initialization
13-
--> tests/ui/slow_vector_initialization.rs:20:5
13+
--> tests/ui/slow_vector_initialization.rs:22:5
1414
|
1515
LL | let mut vec2 = Vec::with_capacity(len - 10);
1616
| ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
1717
LL | vec2.extend(repeat(0).take(len - 10));
1818
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1919

2020
error: slow zero-filling initialization
21-
--> tests/ui/slow_vector_initialization.rs:28:5
21+
--> tests/ui/slow_vector_initialization.rs:30:5
2222
|
2323
LL | let mut vec4 = Vec::with_capacity(len);
2424
| ----------------------- help: consider replacing this with: `vec![0; len]`
2525
LL | vec4.extend(repeat(0).take(vec4.capacity()));
2626
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2727

2828
error: slow zero-filling initialization
29-
--> tests/ui/slow_vector_initialization.rs:39:5
29+
--> tests/ui/slow_vector_initialization.rs:41:5
3030
|
3131
LL | let mut resized_vec = Vec::with_capacity(30);
3232
| ---------------------- help: consider replacing this with: `vec![0; 30]`
3333
LL | resized_vec.resize(30, 0);
3434
| ^^^^^^^^^^^^^^^^^^^^^^^^^
3535

3636
error: slow zero-filling initialization
37-
--> tests/ui/slow_vector_initialization.rs:43:5
37+
--> tests/ui/slow_vector_initialization.rs:45:5
3838
|
3939
LL | let mut extend_vec = Vec::with_capacity(30);
4040
| ---------------------- help: consider replacing this with: `vec![0; 30]`
4141
LL | extend_vec.extend(repeat(0).take(30));
4242
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4343

4444
error: slow zero-filling initialization
45-
--> tests/ui/slow_vector_initialization.rs:51:5
45+
--> tests/ui/slow_vector_initialization.rs:53:5
4646
|
4747
LL | let mut vec1 = Vec::with_capacity(len);
4848
| ----------------------- help: consider replacing this with: `vec![0; len]`
4949
LL | vec1.resize(len, 0);
5050
| ^^^^^^^^^^^^^^^^^^^
5151

5252
error: slow zero-filling initialization
53-
--> tests/ui/slow_vector_initialization.rs:60:5
53+
--> tests/ui/slow_vector_initialization.rs:62:5
5454
|
5555
LL | let mut vec3 = Vec::with_capacity(len - 10);
5656
| ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
5757
LL | vec3.resize(len - 10, 0);
5858
| ^^^^^^^^^^^^^^^^^^^^^^^^
5959

6060
error: slow zero-filling initialization
61-
--> tests/ui/slow_vector_initialization.rs:64:5
61+
--> tests/ui/slow_vector_initialization.rs:66:5
6262
|
6363
LL | let mut vec4 = Vec::with_capacity(len);
6464
| ----------------------- help: consider replacing this with: `vec![0; len]`
6565
LL | vec4.resize(vec4.capacity(), 0);
6666
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6767

6868
error: slow zero-filling initialization
69-
--> tests/ui/slow_vector_initialization.rs:69:5
69+
--> tests/ui/slow_vector_initialization.rs:71:5
7070
|
7171
LL | vec1 = Vec::with_capacity(10);
7272
| ---------------------- help: consider replacing this with: `vec![0; 10]`
7373
LL | vec1.resize(10, 0);
7474
| ^^^^^^^^^^^^^^^^^^
7575

7676
error: slow zero-filling initialization
77-
--> tests/ui/slow_vector_initialization.rs:77:5
77+
--> tests/ui/slow_vector_initialization.rs:79:5
7878
|
7979
LL | let mut vec1 = Vec::new();
8080
| ---------- help: consider replacing this with: `vec![0; len]`
8181
LL | vec1.resize(len, 0);
8282
| ^^^^^^^^^^^^^^^^^^^
8383

8484
error: slow zero-filling initialization
85-
--> tests/ui/slow_vector_initialization.rs:82:5
85+
--> tests/ui/slow_vector_initialization.rs:84:5
8686
|
8787
LL | let mut vec3 = Vec::new();
8888
| ---------- help: consider replacing this with: `vec![0; len - 10]`
8989
LL | vec3.resize(len - 10, 0);
9090
| ^^^^^^^^^^^^^^^^^^^^^^^^
9191

9292
error: slow zero-filling initialization
93-
--> tests/ui/slow_vector_initialization.rs:87:5
93+
--> tests/ui/slow_vector_initialization.rs:89:5
9494
|
9595
LL | vec1 = Vec::new();
9696
| ---------- help: consider replacing this with: `vec![0; 10]`
9797
LL | vec1.resize(10, 0);
9898
| ^^^^^^^^^^^^^^^^^^
9999

100100
error: slow zero-filling initialization
101-
--> tests/ui/slow_vector_initialization.rs:91:5
101+
--> tests/ui/slow_vector_initialization.rs:93:5
102102
|
103103
LL | vec1 = vec![];
104104
| ------ help: consider replacing this with: `vec![0; 10]`

0 commit comments

Comments
 (0)