Skip to content

Commit b1faaae

Browse files
committed
needless_collect: Lint cases with type annotations
1 parent 5e3160c commit b1faaae

File tree

3 files changed

+89
-7
lines changed

3 files changed

+89
-7
lines changed

clippy_lints/src/loops/needless_collect.rs

Lines changed: 18 additions & 5 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

@@ -58,18 +59,30 @@ 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 ty = cx.typeck_results().node_type(hir_id);
7386
if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
7487
is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
7588
match_type(cx, ty, &paths::LINKED_LIST);

tests/ui/needless_collect_indirect.rs

Lines changed: 28 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::{HashMap, LinkedList, VecDeque};
22

33
fn main() {
44
let sample = [1; 5];
@@ -43,3 +43,30 @@ 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 dont_lint(string: &str) -> usize {
66+
let buffer: Vec<&str> = string.split('/').collect();
67+
for buff in &buffer {
68+
println!("{}", buff);
69+
}
70+
buffer.len()
71+
}
72+
}

tests/ui/needless_collect_indirect.stderr

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,47 @@ 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: aborting due to 8 previous errors
73115

0 commit comments

Comments
 (0)