Skip to content

Commit 448c448

Browse files
committed
new lint truncate_with_drain
1 parent ee0b9b9 commit 448c448

File tree

4 files changed

+144
-71
lines changed

4 files changed

+144
-71
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4247,37 +4247,61 @@ declare_clippy_lint! {
42474247
}
42484248

42494249
declare_clippy_lint! {
4250-
/// ### What it does
4251-
///
4252-
/// Checks for `Iterator::map` over ranges without using the parameter which
4253-
/// could be more clearly expressed using `std::iter::repeat(...).take(...)`
4254-
/// or `std::iter::repeat_n`.
4250+
/// ### What it does
4251+
///
4252+
/// Checks for `Iterator::map` over ranges without using the parameter which
4253+
/// could be more clearly expressed using `std::iter::repeat(...).take(...)`
4254+
/// or `std::iter::repeat_n`.
4255+
///
4256+
/// ### Why is this bad?
4257+
///
4258+
/// It expresses the intent more clearly to `take` the correct number of times
4259+
/// from a generating function than to apply a closure to each number in a
4260+
/// range only to discard them.
4261+
///
4262+
/// ### Example
4263+
///
4264+
/// ```no_run
4265+
/// let random_numbers : Vec<_> = (0..10).map(|_| { 3 + 1 }).collect();
4266+
/// ```
4267+
/// Use instead:
4268+
/// ```no_run
4269+
/// let f : Vec<_> = std::iter::repeat( 3 + 1 ).take(10).collect();
4270+
/// ```
4271+
///
4272+
/// ### Known Issues
4273+
///
4274+
/// This lint may suggest replacing a `Map<Range>` with a `Take<RepeatWith>`.
4275+
/// The former implements some traits that the latter does not, such as
4276+
/// `DoubleEndedIterator`.
4277+
#[clippy::version = "1.84.0"]
4278+
pub MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
4279+
restriction,
4280+
"map of a trivial closure (not dependent on parameter) over a range"
4281+
}
4282+
declare_clippy_lint! {
4283+
/// ### What it does
4284+
/// Checks for usage of `.drain(x..)` for the sole purpose of truncate a container.
42554285
///
42564286
/// ### Why is this bad?
4287+
/// This creates an unnecessary iterator that is dropped immediately.
42574288
///
4258-
/// It expresses the intent more clearly to `take` the correct number of times
4259-
/// from a generating function than to apply a closure to each number in a
4260-
/// range only to discard them.
4289+
/// Calling `.truncate(x)` also makes the intent clearer.
42614290
///
42624291
/// ### Example
4263-
///
42644292
/// ```no_run
4265-
/// let random_numbers : Vec<_> = (0..10).map(|_| { 3 + 1 }).collect();
4293+
/// let mut v = vec![1, 2, 3];
4294+
/// v.drain(1..);
42664295
/// ```
42674296
/// Use instead:
42684297
/// ```no_run
4269-
/// let f : Vec<_> = std::iter::repeat( 3 + 1 ).take(10).collect();
4298+
/// let mut v = vec![1, 2, 3];
4299+
/// v.truncate(1);
42704300
/// ```
4271-
///
4272-
/// ### Known Issues
4273-
///
4274-
/// This lint may suggest replacing a `Map<Range>` with a `Take<RepeatWith>`.
4275-
/// The former implements some traits that the latter does not, such as
4276-
/// `DoubleEndedIterator`.
42774301
#[clippy::version = "1.84.0"]
4278-
pub MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
4279-
restriction,
4280-
"map of a trivial closure (not dependent on parameter) over a range"
4302+
pub TRUNCATE_WITH_DRAIN,
4303+
nursery,
4304+
"calling `drain` in order to `truncate` a `Vec`"
42814305
}
42824306

42834307
pub struct Methods {
@@ -4445,6 +4469,7 @@ impl_lint_pass!(Methods => [
44454469
NEEDLESS_AS_BYTES,
44464470
MAP_ALL_ANY_IDENTITY,
44474471
MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
4472+
TRUNCATE_WITH_DRAIN,
44484473
]);
44494474

44504475
/// Extracts a method call name, args, and `Span` of the method name.

tests/ui/truncate_with_drain.fixed

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ fn vec_range() {
1010

1111
// Do not lint because iterator is used
1212
let mut v = vec![1, 2, 3];
13-
v.drain(1..v.len()).next();
13+
let n = v.drain(1..v.len()).count();
14+
15+
// Do not lint because iterator is assigned and used
16+
let mut v = vec![1, 2, 3];
17+
let iter = v.drain(1..v.len());
18+
let n = iter.count();
1419

1520
// Do lint
1621
let mut v = vec![1, 2, 3];
@@ -27,9 +32,14 @@ fn vec_range_from() {
2732
let mut v = vec![1, 2, 3];
2833
let iter = v.drain(1..);
2934

35+
// Do not lint because iterator is assigned and used
36+
let mut v = vec![1, 2, 3];
37+
let mut iter = v.drain(1..);
38+
let next = iter.next();
39+
3040
// Do not lint because iterator is used
3141
let mut v = vec![1, 2, 3];
32-
v.drain(1..).next();
42+
let next = v.drain(1..).next();
3343

3444
// Do lint
3545
let mut v = vec![1, 2, 3];
@@ -92,7 +102,12 @@ fn vec_deque_range() {
92102

93103
// Do not lint because iterator is used
94104
let mut deque = VecDeque::from([1, 2, 3]);
95-
deque.drain(1..deque.len()).next();
105+
let n = deque.drain(1..deque.len()).count();
106+
107+
// Do not lint because iterator is assigned and used
108+
let mut deque = VecDeque::from([1, 2, 3]);
109+
let iter = deque.drain(1..deque.len());
110+
let n = iter.count();
96111

97112
// Do lint
98113
let mut v = VecDeque::from([1, 2, 3]);
@@ -109,9 +124,14 @@ fn vec_deque_range_from() {
109124
let mut deque = VecDeque::from([1, 2, 3]);
110125
let iter = deque.drain(1..);
111126

127+
// Do not lint because iterator is assigned and used
128+
let mut deque = VecDeque::from([1, 2, 3]);
129+
let mut iter = deque.drain(1..);
130+
let next = iter.next();
131+
112132
// Do not lint because iterator is used
113133
let mut deque = VecDeque::from([1, 2, 3]);
114-
deque.drain(1..).next();
134+
let next = deque.drain(1..).next();
115135

116136
// Do lint
117137
let mut deque = VecDeque::from([1, 2, 3]);
@@ -174,7 +194,12 @@ fn string_range() {
174194

175195
// Do not lint because iterator is used
176196
let mut s = String::from("Hello, world!");
177-
s.drain(1..s.len()).next();
197+
let n = s.drain(1..s.len()).count();
198+
199+
// Do not lint because iterator is assigned and used
200+
let mut s = String::from("Hello, world!");
201+
let iter = s.drain(1..s.len());
202+
let n = iter.count();
178203

179204
// Do lint
180205
let mut s = String::from("Hello, world!");
@@ -191,18 +216,23 @@ fn string_range_from() {
191216
let mut s = String::from("Hello, world!");
192217
let iter = s.drain(1..);
193218

219+
// Do not lint because iterator is assigned and used
220+
let mut s = String::from("Hello, world!");
221+
let mut iter = s.drain(1..);
222+
let next = iter.next();
223+
194224
// Do not lint because iterator is used
195225
let mut s = String::from("Hello, world!");
196-
s.drain(1..).next();
226+
let next = s.drain(1..).next();
197227

198228
// Do lint
199229
let mut s = String::from("Hello, world!");
200230
s.truncate(1);
201231

202232
// Do lint
203233
let x = 1;
204-
let mut s = String::from("Hello, world!");
205-
s.truncate(x);
234+
let mut v = String::from("Hello, world!");
235+
v.truncate(x);
206236
}
207237

208238
fn string_partial_drains() {

tests/ui/truncate_with_drain.rs

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,39 +10,45 @@ fn vec_range() {
1010

1111
// Do not lint because iterator is used
1212
let mut v = vec![1, 2, 3];
13-
v.drain(1..v.len()).next();
13+
let n = v.drain(1..v.len()).count();
14+
15+
// Do not lint because iterator is assigned and used
16+
let mut v = vec![1, 2, 3];
17+
let iter = v.drain(1..v.len());
18+
let n = iter.count();
1419

1520
// Do lint
1621
let mut v = vec![1, 2, 3];
1722
v.drain(1..v.len());
18-
//~^ ERROR: `drain` used to truncate a `Vec`
1923

2024
// Do lint
2125
let x = 1;
2226
let mut v = vec![1, 2, 3];
2327
v.drain(x..v.len());
24-
//~^ ERROR: `drain` used to truncate a `Vec`
2528
}
2629

2730
fn vec_range_from() {
2831
// Do not lint because iterator is assigned
2932
let mut v = vec![1, 2, 3];
3033
let iter = v.drain(1..);
3134

35+
// Do not lint because iterator is assigned and used
36+
let mut v = vec![1, 2, 3];
37+
let mut iter = v.drain(1..);
38+
let next = iter.next();
39+
3240
// Do not lint because iterator is used
3341
let mut v = vec![1, 2, 3];
34-
v.drain(1..).next();
42+
let next = v.drain(1..).next();
3543

3644
// Do lint
3745
let mut v = vec![1, 2, 3];
3846
v.drain(1..);
39-
//~^ ERROR: `drain` used to truncate a `Vec`
4047

4148
// Do lint
4249
let x = 1;
4350
let mut v = vec![1, 2, 3];
4451
v.drain(x..);
45-
//~^ ERROR: `drain` used to truncate a `Vec`
4652
}
4753

4854
fn vec_partial_drains() {
@@ -96,39 +102,45 @@ fn vec_deque_range() {
96102

97103
// Do not lint because iterator is used
98104
let mut deque = VecDeque::from([1, 2, 3]);
99-
deque.drain(1..deque.len()).next();
105+
let n = deque.drain(1..deque.len()).count();
106+
107+
// Do not lint because iterator is assigned and used
108+
let mut deque = VecDeque::from([1, 2, 3]);
109+
let iter = deque.drain(1..deque.len());
110+
let n = iter.count();
100111

101112
// Do lint
102113
let mut v = VecDeque::from([1, 2, 3]);
103114
v.drain(1..v.len());
104-
//~^ ERROR: `drain` used to truncate a `VecDeque`
105115

106116
// Do lint
107117
let x = 1;
108118
let mut v = VecDeque::from([1, 2, 3]);
109119
v.drain(x..v.len());
110-
//~^ ERROR: `drain` used to truncate a `VecDeque`
111120
}
112121

113122
fn vec_deque_range_from() {
114123
// Do not lint because iterator is assigned
115124
let mut deque = VecDeque::from([1, 2, 3]);
116125
let iter = deque.drain(1..);
117126

127+
// Do not lint because iterator is assigned and used
128+
let mut deque = VecDeque::from([1, 2, 3]);
129+
let mut iter = deque.drain(1..);
130+
let next = iter.next();
131+
118132
// Do not lint because iterator is used
119133
let mut deque = VecDeque::from([1, 2, 3]);
120-
deque.drain(1..).next();
134+
let next = deque.drain(1..).next();
121135

122136
// Do lint
123137
let mut deque = VecDeque::from([1, 2, 3]);
124138
deque.drain(1..);
125-
//~^ ERROR: `drain` used to truncate a `VecDeque`
126139

127140
// Do lint
128141
let x = 1;
129142
let mut v = VecDeque::from([1, 2, 3]);
130143
v.drain(x..);
131-
//~^ ERROR: `drain` used to truncate a `VecDeque`
132144
}
133145

134146
fn vec_deque_partial_drains() {
@@ -182,39 +194,45 @@ fn string_range() {
182194

183195
// Do not lint because iterator is used
184196
let mut s = String::from("Hello, world!");
185-
s.drain(1..s.len()).next();
197+
let n = s.drain(1..s.len()).count();
198+
199+
// Do not lint because iterator is assigned and used
200+
let mut s = String::from("Hello, world!");
201+
let iter = s.drain(1..s.len());
202+
let n = iter.count();
186203

187204
// Do lint
188205
let mut s = String::from("Hello, world!");
189206
s.drain(1..s.len());
190-
//~^ ERROR: `drain` used to truncate a `String`
191207

192208
// Do lint
193209
let x = 1;
194210
let mut v = String::from("Hello, world!");
195211
v.drain(x..s.len());
196-
//~^ ERROR: `drain` used to truncate a `String`
197212
}
198213

199214
fn string_range_from() {
200215
// Do not lint because iterator is assigned
201216
let mut s = String::from("Hello, world!");
202217
let iter = s.drain(1..);
203218

219+
// Do not lint because iterator is assigned and used
220+
let mut s = String::from("Hello, world!");
221+
let mut iter = s.drain(1..);
222+
let next = iter.next();
223+
204224
// Do not lint because iterator is used
205225
let mut s = String::from("Hello, world!");
206-
s.drain(1..).next();
226+
let next = s.drain(1..).next();
207227

208228
// Do lint
209229
let mut s = String::from("Hello, world!");
210230
s.drain(1..);
211-
//~^ ERROR: `drain` used to truncate a `String`
212231

213232
// Do lint
214233
let x = 1;
215-
let mut s = String::from("Hello, world!");
216-
s.drain(x..);
217-
//~^ ERROR: `drain` used to truncate a `String`
234+
let mut v = String::from("Hello, world!");
235+
v.drain(x..);
218236
}
219237

220238
fn string_partial_drains() {

0 commit comments

Comments
 (0)