Skip to content

Commit 295fe28

Browse files
committed
Auto merge of #6313 - giraffate:fix_fp_needless_collect, r=ebroto
Fix FP in indirect `needless_collect` when used multiple times Fix #5991 Fix #6297 changelog: Fix FP in indirect `needless_collect` when used multiple times
2 parents 51b633b + 8f89108 commit 295fe28

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

clippy_lints/src/loops.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -2950,7 +2950,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
29502950
for ref stmt in block.stmts {
29512951
if_chain! {
29522952
if let StmtKind::Local(
2953-
Local { pat: Pat { kind: PatKind::Binding(_, _, ident, .. ), .. },
2953+
Local { pat: Pat { hir_id: pat_id, kind: PatKind::Binding(_, _, ident, .. ), .. },
29542954
init: Some(ref init_expr), .. }
29552955
) = stmt.kind;
29562956
if let ExprKind::MethodCall(ref method_name, _, &[ref iter_source], ..) = init_expr.kind;
@@ -2964,6 +2964,16 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
29642964
if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident);
29652965
if iter_calls.len() == 1;
29662966
then {
2967+
let mut used_count_visitor = UsedCountVisitor {
2968+
cx,
2969+
id: *pat_id,
2970+
count: 0,
2971+
};
2972+
walk_block(&mut used_count_visitor, block);
2973+
if used_count_visitor.count > 1 {
2974+
return;
2975+
}
2976+
29672977
// Suggest replacing iter_call with iter_replacement, and removing stmt
29682978
let iter_call = &iter_calls[0];
29692979
span_lint_and_then(
@@ -3087,6 +3097,28 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
30873097
}
30883098
}
30893099

3100+
struct UsedCountVisitor<'a, 'tcx> {
3101+
cx: &'a LateContext<'tcx>,
3102+
id: HirId,
3103+
count: usize,
3104+
}
3105+
3106+
impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
3107+
type Map = Map<'tcx>;
3108+
3109+
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
3110+
if same_var(self.cx, expr, self.id) {
3111+
self.count += 1;
3112+
} else {
3113+
walk_expr(self, expr);
3114+
}
3115+
}
3116+
3117+
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
3118+
NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
3119+
}
3120+
}
3121+
30903122
/// Detect the occurrences of calls to `iter` or `into_iter` for the
30913123
/// given identifier
30923124
fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, identifier: Ident) -> Option<Vec<IterFunction>> {

tests/ui/needless_collect_indirect.rs

+20
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,24 @@ fn main() {
2222
let sample = vec![a.clone(), "b".to_string(), "c".to_string()];
2323
let non_copy_contains = sample.into_iter().collect::<Vec<_>>();
2424
non_copy_contains.contains(&a);
25+
26+
// Fix #5991
27+
let vec_a = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
28+
let vec_b = vec_a.iter().collect::<Vec<_>>();
29+
if vec_b.len() > 3 {}
30+
let other_vec = vec![1, 3, 12, 4, 16, 2];
31+
let we_got_the_same_numbers = other_vec.iter().filter(|item| vec_b.contains(item)).collect::<Vec<_>>();
32+
33+
// Fix #6297
34+
let sample = [1; 5];
35+
let multiple_indirect = sample.iter().collect::<Vec<_>>();
36+
let sample2 = vec![2, 3];
37+
if multiple_indirect.is_empty() {
38+
// do something
39+
} else {
40+
let found = sample2
41+
.iter()
42+
.filter(|i| multiple_indirect.iter().any(|s| **s % **i == 0))
43+
.collect::<Vec<_>>();
44+
}
2545
}

0 commit comments

Comments
 (0)