Skip to content

Commit 0baf6bf

Browse files
committed
Auto merge of rust-lang#7163 - mgacek8:issue7110_needless_collect_with_type_annotations, r=flip1995
needless_collect: Lint cases with type annotations for indirect usage and recognize `BinaryHeap` fixes rust-lang#7110 changelog: needless_collect: Lint cases with type annotations for indirect usage and recognize `BinaryHeap`.
2 parents 7e538e3 + f79a2a3 commit 0baf6bf

File tree

4 files changed

+112
-12
lines changed

4 files changed

+112
-12
lines changed

clippy_lints/src/loops/needless_collect.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ use clippy_utils::{is_trait_method, path_to_local_id, paths};
77
use if_chain::if_chain;
88
use rustc_errors::Applicability;
99
use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor};
10-
use rustc_hir::{Block, Expr, ExprKind, GenericArg, HirId, Local, Pat, PatKind, QPath, StmtKind};
10+
use rustc_hir::{Block, Expr, ExprKind, GenericArg, GenericArgs, HirId, Local, Pat, PatKind, QPath, StmtKind, Ty};
1111
use rustc_lint::LateContext;
1212
use rustc_middle::hir::map::Map;
13+
1314
use rustc_span::symbol::{sym, Ident};
1415
use rustc_span::{MultiSpan, Span};
1516

@@ -26,7 +27,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
2627
if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
2728
if let Some(generic_args) = chain_method.args;
2829
if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
29-
let ty = cx.typeck_results().node_type(ty.hir_id);
30+
if let Some(ty) = cx.typeck_results().node_type_opt(ty.hir_id);
3031
if is_type_diagnostic_item(cx, ty, sym::vec_type)
3132
|| is_type_diagnostic_item(cx, ty, sym::vecdeque_type)
3233
|| match_type(cx, ty, &paths::BTREEMAP)
@@ -58,20 +59,33 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
5859
}
5960

6061
fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
62+
fn get_hir_id<'tcx>(ty: Option<&Ty<'tcx>>, method_args: Option<&GenericArgs<'tcx>>) -> Option<HirId> {
63+
if let Some(ty) = ty {
64+
return Some(ty.hir_id);
65+
}
66+
67+
if let Some(generic_args) = method_args {
68+
if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0) {
69+
return Some(ty.hir_id);
70+
}
71+
}
72+
73+
None
74+
}
6175
if let ExprKind::Block(block, _) = expr.kind {
6276
for stmt in block.stmts {
6377
if_chain! {
6478
if let StmtKind::Local(
6579
Local { pat: Pat { hir_id: pat_id, kind: PatKind::Binding(_, _, ident, .. ), .. },
66-
init: Some(init_expr), .. }
80+
init: Some(init_expr), ty, .. }
6781
) = stmt.kind;
6882
if let ExprKind::MethodCall(method_name, collect_span, &[ref iter_source], ..) = init_expr.kind;
6983
if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
70-
if let Some(generic_args) = method_name.args;
71-
if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
72-
if let ty = cx.typeck_results().node_type(ty.hir_id);
84+
if let Some(hir_id) = get_hir_id(*ty, method_name.args);
85+
if let Some(ty) = cx.typeck_results().node_type_opt(hir_id);
7386
if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
7487
is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
88+
is_type_diagnostic_item(cx, ty, sym::BinaryHeap) ||
7589
match_type(cx, ty, &paths::LINKED_LIST);
7690
if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident);
7791
if let [iter_call] = &*iter_calls;

tests/ui/copy_iterator.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ impl Iterator for Countdown {
1616

1717
fn main() {
1818
let my_iterator = Countdown(5);
19-
let a: Vec<_> = my_iterator.take(1).collect();
20-
assert_eq!(a.len(), 1);
21-
let b: Vec<_> = my_iterator.collect();
22-
assert_eq!(b.len(), 5);
19+
assert_eq!(my_iterator.take(1).count(), 1);
20+
assert_eq!(my_iterator.count(), 5);
2321
}

tests/ui/needless_collect_indirect.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::{HashMap, VecDeque};
1+
use std::collections::{BinaryHeap, HashMap, LinkedList, VecDeque};
22

33
fn main() {
44
let sample = [1; 5];
@@ -43,3 +43,35 @@ fn main() {
4343
.collect::<Vec<_>>();
4444
}
4545
}
46+
47+
mod issue7110 {
48+
// #7110 - lint for type annotation cases
49+
use super::*;
50+
51+
fn lint_vec(string: &str) -> usize {
52+
let buffer: Vec<&str> = string.split('/').collect();
53+
buffer.len()
54+
}
55+
fn lint_vec_deque() -> usize {
56+
let sample = [1; 5];
57+
let indirect_len: VecDeque<_> = sample.iter().collect();
58+
indirect_len.len()
59+
}
60+
fn lint_linked_list() -> usize {
61+
let sample = [1; 5];
62+
let indirect_len: LinkedList<_> = sample.iter().collect();
63+
indirect_len.len()
64+
}
65+
fn lint_binary_heap() -> usize {
66+
let sample = [1; 5];
67+
let indirect_len: BinaryHeap<_> = sample.iter().collect();
68+
indirect_len.len()
69+
}
70+
fn dont_lint(string: &str) -> usize {
71+
let buffer: Vec<&str> = string.split('/').collect();
72+
for buff in &buffer {
73+
println!("{}", buff);
74+
}
75+
buffer.len()
76+
}
77+
}

tests/ui/needless_collect_indirect.stderr

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,61 @@ LL |
6969
LL | sample.into_iter().any(|x| x == a);
7070
|
7171

72-
error: aborting due to 5 previous errors
72+
error: avoid using `collect()` when not needed
73+
--> $DIR/needless_collect_indirect.rs:52:51
74+
|
75+
LL | let buffer: Vec<&str> = string.split('/').collect();
76+
| ^^^^^^^
77+
LL | buffer.len()
78+
| ------------ the iterator could be used here instead
79+
|
80+
help: take the original Iterator's count instead of collecting it and finding the length
81+
|
82+
LL |
83+
LL | string.split('/').count()
84+
|
85+
86+
error: avoid using `collect()` when not needed
87+
--> $DIR/needless_collect_indirect.rs:57:55
88+
|
89+
LL | let indirect_len: VecDeque<_> = sample.iter().collect();
90+
| ^^^^^^^
91+
LL | indirect_len.len()
92+
| ------------------ the iterator could be used here instead
93+
|
94+
help: take the original Iterator's count instead of collecting it and finding the length
95+
|
96+
LL |
97+
LL | sample.iter().count()
98+
|
99+
100+
error: avoid using `collect()` when not needed
101+
--> $DIR/needless_collect_indirect.rs:62:57
102+
|
103+
LL | let indirect_len: LinkedList<_> = sample.iter().collect();
104+
| ^^^^^^^
105+
LL | indirect_len.len()
106+
| ------------------ the iterator could be used here instead
107+
|
108+
help: take the original Iterator's count instead of collecting it and finding the length
109+
|
110+
LL |
111+
LL | sample.iter().count()
112+
|
113+
114+
error: avoid using `collect()` when not needed
115+
--> $DIR/needless_collect_indirect.rs:67:57
116+
|
117+
LL | let indirect_len: BinaryHeap<_> = sample.iter().collect();
118+
| ^^^^^^^
119+
LL | indirect_len.len()
120+
| ------------------ the iterator could be used here instead
121+
|
122+
help: take the original Iterator's count instead of collecting it and finding the length
123+
|
124+
LL |
125+
LL | sample.iter().count()
126+
|
127+
128+
error: aborting due to 9 previous errors
73129

0 commit comments

Comments
 (0)