Skip to content

Commit a36a7c8

Browse files
committed
Auto merge of #7270 - Valentine-Mario:vec_extend_to_append, r=flip1995
Vec extend to append This PR adds a check to suggest changes of vector from ``` vec.extend(other_vec.drain(..)) ``` could be written as ``` vec![].append(&mut vec![]); ``` changelog: Add vec_extend_to_append lint issue: #7209
2 parents 6379d26 + 44608b1 commit a36a7c8

7 files changed

+208
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2295,6 +2295,7 @@ Released 2018-09-13
22952295
<!-- begin autogenerated links to lint list -->
22962296
[`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
22972297
[`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
2298+
[`append_instead_of_extend`]: https://rust-lang.github.io/rust-clippy/master/index.html#append_instead_of_extend
22982299
[`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
22992300
[`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
23002301
[`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants

clippy_lints/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
730730
mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
731731
mem_replace::MEM_REPLACE_WITH_DEFAULT,
732732
mem_replace::MEM_REPLACE_WITH_UNINIT,
733+
methods::APPEND_INSTEAD_OF_EXTEND,
733734
methods::BIND_INSTEAD_OF_MAP,
734735
methods::BYTES_NTH,
735736
methods::CHARS_LAST_CMP,
@@ -1276,6 +1277,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12761277
LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
12771278
LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
12781279
LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
1280+
LintId::of(methods::APPEND_INSTEAD_OF_EXTEND),
12791281
LintId::of(methods::BIND_INSTEAD_OF_MAP),
12801282
LintId::of(methods::BYTES_NTH),
12811283
LintId::of(methods::CHARS_LAST_CMP),
@@ -1736,6 +1738,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
17361738
LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
17371739
LintId::of(loops::MANUAL_MEMCPY),
17381740
LintId::of(loops::NEEDLESS_COLLECT),
1741+
LintId::of(methods::APPEND_INSTEAD_OF_EXTEND),
17391742
LintId::of(methods::EXPECT_FUN_CALL),
17401743
LintId::of(methods::ITER_NTH),
17411744
LintId::of(methods::MANUAL_STR_REPEAT),
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::source::snippet_with_applicability;
3+
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
4+
use if_chain::if_chain;
5+
use rustc_errors::Applicability;
6+
use rustc_hir::{Expr, ExprKind, LangItem};
7+
use rustc_lint::LateContext;
8+
use rustc_span::symbol::sym;
9+
10+
use super::APPEND_INSTEAD_OF_EXTEND;
11+
12+
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
13+
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
14+
if_chain! {
15+
if is_type_diagnostic_item(cx, ty, sym::vec_type);
16+
//check source object
17+
if let ExprKind::MethodCall(src_method, _, [drain_vec, drain_arg], _) = &arg.kind;
18+
if src_method.ident.as_str() == "drain";
19+
if let src_ty = cx.typeck_results().expr_ty(drain_vec).peel_refs();
20+
if is_type_diagnostic_item(cx, src_ty, sym::vec_type);
21+
//check drain range
22+
if let src_ty_range = cx.typeck_results().expr_ty(drain_arg).peel_refs();
23+
if is_type_lang_item(cx, src_ty_range, LangItem::RangeFull);
24+
then {
25+
let mut applicability = Applicability::MachineApplicable;
26+
span_lint_and_sugg(
27+
cx,
28+
APPEND_INSTEAD_OF_EXTEND,
29+
expr.span,
30+
"use of `extend` instead of `append` for adding the full range of a second vector",
31+
"try this",
32+
format!(
33+
"{}.append(&mut {})",
34+
snippet_with_applicability(cx, recv.span, "..", &mut applicability),
35+
snippet_with_applicability(cx, drain_vec.span, "..", &mut applicability)
36+
),
37+
applicability,
38+
);
39+
}
40+
}
41+
}

clippy_lints/src/methods/mod.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod append_instead_of_extend;
12
mod bind_instead_of_map;
23
mod bytes_nth;
34
mod chars_cmp;
@@ -1032,6 +1033,30 @@ declare_clippy_lint! {
10321033
"using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead"
10331034
}
10341035

1036+
declare_clippy_lint! {
1037+
/// **What it does:** Checks for occurrences where one vector gets extended instead of append
1038+
///
1039+
/// **Why is this bad?** Using `append` instead of `extend` is more concise and faster
1040+
///
1041+
/// **Known problems:** None.
1042+
///
1043+
/// **Example:**
1044+
///
1045+
/// ```rust
1046+
/// let mut a = vec![1, 2, 3];
1047+
/// let mut b = vec![4, 5, 6];
1048+
///
1049+
/// // Bad
1050+
/// a.extend(b.drain(..));
1051+
///
1052+
/// // Good
1053+
/// a.append(&mut b);
1054+
/// ```
1055+
pub APPEND_INSTEAD_OF_EXTEND,
1056+
perf,
1057+
"using vec.append(&mut vec) to move the full range of a vecor to another"
1058+
}
1059+
10351060
declare_clippy_lint! {
10361061
/// **What it does:** Checks for the use of `.extend(s.chars())` where s is a
10371062
/// `&str` or `String`.
@@ -1785,7 +1810,8 @@ impl_lint_pass!(Methods => [
17851810
INSPECT_FOR_EACH,
17861811
IMPLICIT_CLONE,
17871812
SUSPICIOUS_SPLITN,
1788-
MANUAL_STR_REPEAT
1813+
MANUAL_STR_REPEAT,
1814+
APPEND_INSTEAD_OF_EXTEND
17891815
]);
17901816

17911817
/// Extracts a method call name, args, and `Span` of the method name.
@@ -2047,7 +2073,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
20472073
Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
20482074
_ => expect_used::check(cx, expr, recv),
20492075
},
2050-
("extend", [arg]) => string_extend_chars::check(cx, expr, recv, arg),
2076+
("extend", [arg]) => {
2077+
string_extend_chars::check(cx, expr, recv, arg);
2078+
append_instead_of_extend::check(cx, expr, recv, arg);
2079+
},
20512080
("filter_map", [arg]) => {
20522081
unnecessary_filter_map::check(cx, expr, arg);
20532082
filter_map_identity::check(cx, expr, arg, span);
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// run-rustfix
2+
#![warn(clippy::append_instead_of_extend)]
3+
use std::collections::BinaryHeap;
4+
fn main() {
5+
//gets linted
6+
let mut vec1 = vec![0u8; 1024];
7+
let mut vec2: std::vec::Vec<u8> = Vec::new();
8+
9+
vec2.append(&mut vec1);
10+
11+
let mut vec3 = vec![0u8; 1024];
12+
let mut vec4: std::vec::Vec<u8> = Vec::new();
13+
14+
vec4.append(&mut vec3);
15+
16+
let mut vec11: std::vec::Vec<u8> = Vec::new();
17+
18+
vec11.append(&mut return_vector());
19+
20+
//won't get linted it dosen't move the entire content of a vec into another
21+
let mut test1 = vec![0u8, 10];
22+
let mut test2: std::vec::Vec<u8> = Vec::new();
23+
24+
test2.extend(test1.drain(4..10));
25+
26+
let mut vec3 = vec![0u8; 104];
27+
let mut vec7: std::vec::Vec<u8> = Vec::new();
28+
29+
vec3.append(&mut vec7);
30+
31+
let mut vec5 = vec![0u8; 1024];
32+
let mut vec6: std::vec::Vec<u8> = Vec::new();
33+
34+
vec5.extend(vec6.drain(..4));
35+
36+
let mut vec9: std::vec::Vec<u8> = Vec::new();
37+
38+
return_vector().append(&mut vec9);
39+
40+
//won't get linted because it is not a vec
41+
42+
let mut heap = BinaryHeap::from(vec![1, 3]);
43+
let mut heap2 = BinaryHeap::from(vec![]);
44+
heap2.extend(heap.drain())
45+
}
46+
47+
fn return_vector() -> Vec<u8> {
48+
let mut new_vector = vec![];
49+
50+
for i in 1..10 {
51+
new_vector.push(i)
52+
}
53+
54+
new_vector
55+
}

tests/ui/append_instead_of_extend.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// run-rustfix
2+
#![warn(clippy::append_instead_of_extend)]
3+
use std::collections::BinaryHeap;
4+
fn main() {
5+
//gets linted
6+
let mut vec1 = vec![0u8; 1024];
7+
let mut vec2: std::vec::Vec<u8> = Vec::new();
8+
9+
vec2.extend(vec1.drain(..));
10+
11+
let mut vec3 = vec![0u8; 1024];
12+
let mut vec4: std::vec::Vec<u8> = Vec::new();
13+
14+
vec4.extend(vec3.drain(..));
15+
16+
let mut vec11: std::vec::Vec<u8> = Vec::new();
17+
18+
vec11.extend(return_vector().drain(..));
19+
20+
//won't get linted it dosen't move the entire content of a vec into another
21+
let mut test1 = vec![0u8, 10];
22+
let mut test2: std::vec::Vec<u8> = Vec::new();
23+
24+
test2.extend(test1.drain(4..10));
25+
26+
let mut vec3 = vec![0u8; 104];
27+
let mut vec7: std::vec::Vec<u8> = Vec::new();
28+
29+
vec3.append(&mut vec7);
30+
31+
let mut vec5 = vec![0u8; 1024];
32+
let mut vec6: std::vec::Vec<u8> = Vec::new();
33+
34+
vec5.extend(vec6.drain(..4));
35+
36+
let mut vec9: std::vec::Vec<u8> = Vec::new();
37+
38+
return_vector().append(&mut vec9);
39+
40+
//won't get linted because it is not a vec
41+
42+
let mut heap = BinaryHeap::from(vec![1, 3]);
43+
let mut heap2 = BinaryHeap::from(vec![]);
44+
heap2.extend(heap.drain())
45+
}
46+
47+
fn return_vector() -> Vec<u8> {
48+
let mut new_vector = vec![];
49+
50+
for i in 1..10 {
51+
new_vector.push(i)
52+
}
53+
54+
new_vector
55+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: use of `extend` instead of `append` for adding the full range of a second vector
2+
--> $DIR/append_instead_of_extend.rs:9:5
3+
|
4+
LL | vec2.extend(vec1.drain(..));
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec2.append(&mut vec1)`
6+
|
7+
= note: `-D clippy::append-instead-of-extend` implied by `-D warnings`
8+
9+
error: use of `extend` instead of `append` for adding the full range of a second vector
10+
--> $DIR/append_instead_of_extend.rs:14:5
11+
|
12+
LL | vec4.extend(vec3.drain(..));
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec4.append(&mut vec3)`
14+
15+
error: use of `extend` instead of `append` for adding the full range of a second vector
16+
--> $DIR/append_instead_of_extend.rs:18:5
17+
|
18+
LL | vec11.extend(return_vector().drain(..));
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec11.append(&mut return_vector())`
20+
21+
error: aborting due to 3 previous errors
22+

0 commit comments

Comments
 (0)