Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit ded9354

Browse files
committed
Suggest using Vec::extend() in same_item_push
Using `Vec::extend(std::iter::repeat_n(item, N))` allows to use the more natural number of elements to add `N`, as is probably done in the original loop, instead of computing the difference between the existing number of elements and the wanted one. Before MSRV 1.82, the older suggestion to use `Vec::resize()` is still issued.
1 parent ab55d3f commit ded9354

File tree

6 files changed

+66
-28
lines changed

6 files changed

+66
-28
lines changed

book/src/lint_configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
767767
* [`ptr_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr)
768768
* [`redundant_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names)
769769
* [`redundant_static_lifetimes`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes)
770+
* [`same_item_push`](https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push)
770771
* [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current)
771772
* [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind)
772773
* [`transmute_ptr_to_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref)

clippy_config/src/conf.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,7 @@ define_Conf! {
636636
ptr_as_ptr,
637637
redundant_field_names,
638638
redundant_static_lifetimes,
639+
same_item_push,
639640
seek_from_current,
640641
seek_rewind,
641642
transmute_ptr_to_ref,

clippy_lints/src/loops/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ impl Loops {
830830
for_kv_map::check(cx, pat, arg, body);
831831
mut_range_bound::check(cx, arg, body);
832832
single_element_loop::check(cx, pat, arg, body, expr);
833-
same_item_push::check(cx, pat, arg, body, expr);
833+
same_item_push::check(cx, pat, arg, body, expr, &self.msrv);
834834
manual_flatten::check(cx, pat, arg, body, span);
835835
manual_find::check(cx, pat, arg, body, span, expr);
836836
unused_enumerate_index::check(cx, pat, arg, body);

clippy_lints/src/loops/same_item_push.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use super::SAME_ITEM_PUSH;
2-
use clippy_utils::diagnostics::span_lint_and_help;
3-
use clippy_utils::path_to_local;
2+
use clippy_utils::diagnostics::span_lint_and_then;
3+
use clippy_utils::msrvs::Msrv;
44
use clippy_utils::source::snippet_with_context;
55
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
6+
use clippy_utils::{msrvs, path_to_local, std_or_core};
67
use rustc_data_structures::fx::FxHashSet;
78
use rustc_errors::Applicability;
89
use rustc_hir::def::{DefKind, Res};
@@ -19,19 +20,30 @@ pub(super) fn check<'tcx>(
1920
_: &'tcx Expr<'_>,
2021
body: &'tcx Expr<'_>,
2122
_: &'tcx Expr<'_>,
23+
msrv: &Msrv,
2224
) {
23-
fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>, ctxt: SyntaxContext) {
25+
fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>, ctxt: SyntaxContext, msrv: &Msrv) {
2426
let mut app = Applicability::Unspecified;
2527
let vec_str = snippet_with_context(cx, vec.span, ctxt, "", &mut app).0;
2628
let item_str = snippet_with_context(cx, pushed_item.span, ctxt, "", &mut app).0;
2729

28-
span_lint_and_help(
30+
let secondary_help = if msrv.meets(msrvs::REPEAT_N)
31+
&& let Some(std_or_core) = std_or_core(cx)
32+
{
33+
format!("or `{vec_str}.extend({std_or_core}::iter::repeat_n({item_str}, SIZE))`")
34+
} else {
35+
format!("or `{vec_str}.resize(NEW_SIZE, {item_str})`")
36+
};
37+
38+
span_lint_and_then(
2939
cx,
3040
SAME_ITEM_PUSH,
3141
vec.span,
32-
"it looks like the same item is being pushed into this Vec",
33-
None,
34-
format!("consider using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"),
42+
"it looks like the same item is being pushed into this `Vec`",
43+
|diag| {
44+
diag.help(format!("consider using `vec![{item_str};SIZE]`"))
45+
.help(secondary_help);
46+
},
3547
);
3648
}
3749

@@ -67,23 +79,23 @@ pub(super) fn check<'tcx>(
6779
{
6880
match init.kind {
6981
// immutable bindings that are initialized with literal
70-
ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt),
82+
ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt, msrv),
7183
// immutable bindings that are initialized with constant
7284
ExprKind::Path(ref path) => {
7385
if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) {
74-
emit_lint(cx, vec, pushed_item, ctxt);
86+
emit_lint(cx, vec, pushed_item, ctxt, msrv);
7587
}
7688
},
7789
_ => {},
7890
}
7991
}
8092
},
8193
// constant
82-
Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item, ctxt),
94+
Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item, ctxt, msrv),
8395
_ => {},
8496
}
8597
},
86-
ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt),
98+
ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt, msrv),
8799
_ => {},
88100
}
89101
}

tests/ui/same_item_push.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,43 @@ fn main() {
2121
let item = 2;
2222
for _ in 5..=20 {
2323
vec.push(item);
24-
//~^ ERROR: it looks like the same item is being pushed into this Vec
24+
//~^ ERROR: it looks like the same item is being pushed into this `Vec`
2525
}
2626

2727
let mut vec: Vec<u8> = Vec::new();
2828
for _ in 0..15 {
2929
let item = 2;
3030
vec.push(item);
31-
//~^ ERROR: it looks like the same item is being pushed into this Vec
31+
//~^ ERROR: it looks like the same item is being pushed into this `Vec`
3232
}
3333

3434
let mut vec: Vec<u8> = Vec::new();
3535
for _ in 0..15 {
3636
vec.push(13);
37-
//~^ ERROR: it looks like the same item is being pushed into this Vec
37+
//~^ ERROR: it looks like the same item is being pushed into this `Vec`
3838
}
3939

4040
let mut vec = Vec::new();
4141
for _ in 0..20 {
4242
vec.push(VALUE);
43-
//~^ ERROR: it looks like the same item is being pushed into this Vec
43+
//~^ ERROR: it looks like the same item is being pushed into this `Vec`
4444
}
4545

4646
let mut vec = Vec::new();
4747
let item = VALUE;
4848
for _ in 0..20 {
4949
vec.push(item);
50-
//~^ ERROR: it looks like the same item is being pushed into this Vec
50+
//~^ ERROR: it looks like the same item is being pushed into this `Vec`
51+
}
52+
53+
#[clippy::msrv = "1.81"]
54+
fn older_msrv() {
55+
let mut vec = Vec::new();
56+
let item = VALUE;
57+
for _ in 0..20 {
58+
vec.push(item);
59+
//~^ ERROR: it looks like the same item is being pushed into this `Vec`
60+
}
5161
}
5262

5363
// ** non-linted cases **

tests/ui/same_item_push.stderr

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,58 @@
1-
error: it looks like the same item is being pushed into this Vec
1+
error: it looks like the same item is being pushed into this `Vec`
22
--> tests/ui/same_item_push.rs:23:9
33
|
44
LL | vec.push(item);
55
| ^^^
66
|
7-
= help: consider using vec![item;SIZE] or vec.resize(NEW_SIZE, item)
7+
= help: consider using `vec![item;SIZE]`
8+
= help: or `vec.extend(std::iter::repeat_n(item, SIZE))`
89
= note: `-D clippy::same-item-push` implied by `-D warnings`
910
= help: to override `-D warnings` add `#[allow(clippy::same_item_push)]`
1011

11-
error: it looks like the same item is being pushed into this Vec
12+
error: it looks like the same item is being pushed into this `Vec`
1213
--> tests/ui/same_item_push.rs:30:9
1314
|
1415
LL | vec.push(item);
1516
| ^^^
1617
|
17-
= help: consider using vec![item;SIZE] or vec.resize(NEW_SIZE, item)
18+
= help: consider using `vec![item;SIZE]`
19+
= help: or `vec.extend(std::iter::repeat_n(item, SIZE))`
1820

19-
error: it looks like the same item is being pushed into this Vec
21+
error: it looks like the same item is being pushed into this `Vec`
2022
--> tests/ui/same_item_push.rs:36:9
2123
|
2224
LL | vec.push(13);
2325
| ^^^
2426
|
25-
= help: consider using vec![13;SIZE] or vec.resize(NEW_SIZE, 13)
27+
= help: consider using `vec![13;SIZE]`
28+
= help: or `vec.extend(std::iter::repeat_n(13, SIZE))`
2629

27-
error: it looks like the same item is being pushed into this Vec
30+
error: it looks like the same item is being pushed into this `Vec`
2831
--> tests/ui/same_item_push.rs:42:9
2932
|
3033
LL | vec.push(VALUE);
3134
| ^^^
3235
|
33-
= help: consider using vec![VALUE;SIZE] or vec.resize(NEW_SIZE, VALUE)
36+
= help: consider using `vec![VALUE;SIZE]`
37+
= help: or `vec.extend(std::iter::repeat_n(VALUE, SIZE))`
3438

35-
error: it looks like the same item is being pushed into this Vec
39+
error: it looks like the same item is being pushed into this `Vec`
3640
--> tests/ui/same_item_push.rs:49:9
3741
|
3842
LL | vec.push(item);
3943
| ^^^
4044
|
41-
= help: consider using vec![item;SIZE] or vec.resize(NEW_SIZE, item)
45+
= help: consider using `vec![item;SIZE]`
46+
= help: or `vec.extend(std::iter::repeat_n(item, SIZE))`
4247

43-
error: aborting due to 5 previous errors
48+
error: it looks like the same item is being pushed into this `Vec`
49+
--> tests/ui/same_item_push.rs:58:13
50+
|
51+
LL | vec.push(item);
52+
| ^^^
53+
|
54+
= help: consider using `vec![item;SIZE]`
55+
= help: or `vec.resize(NEW_SIZE, item)`
56+
57+
error: aborting due to 6 previous errors
4458

0 commit comments

Comments
 (0)