|
1 | 1 | use clippy_utils::diagnostics::span_lint_and_then;
|
2 | 2 | use clippy_utils::source::snippet_opt;
|
3 | 3 | use clippy_utils::ty::{implements_trait, is_copy};
|
| 4 | +use rustc_ast::BindingAnnotation; |
4 | 5 | use rustc_errors::Applicability;
|
5 |
| -use rustc_hir::{Expr, ExprKind}; |
| 6 | +use rustc_hir::{Body, Expr, ExprKind, HirId, HirIdSet, PatKind}; |
| 7 | +use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; |
6 | 8 | use rustc_lint::LateContext;
|
7 |
| -use rustc_middle::ty; |
| 9 | +use rustc_middle::mir::{FakeReadCause, Mutability}; |
| 10 | +use rustc_middle::ty::{self, BorrowKind}; |
8 | 11 | use rustc_span::sym;
|
9 | 12 |
|
10 | 13 | use super::ITER_OVEREAGER_CLONED;
|
11 | 14 | use crate::redundant_clone::REDUNDANT_CLONE;
|
| 15 | +use crate::rustc_trait_selection::infer::TyCtxtInferExt; |
12 | 16 |
|
13 | 17 | #[derive(Clone, Copy)]
|
14 | 18 | pub(super) enum Op<'a> {
|
15 | 19 | // rm `.cloned()`
|
16 | 20 | // e.g. `count`
|
17 | 21 | RmCloned,
|
18 | 22 |
|
| 23 | + // rm `.cloned()` |
| 24 | + // e.g. `map` `for_each` |
| 25 | + NeedlessMove(&'a str, &'a Expr<'a>), |
| 26 | + |
19 | 27 | // later `.cloned()`
|
20 | 28 | // and add `&` to the parameter of closure parameter
|
21 | 29 | // e.g. `find` `filter`
|
@@ -51,8 +59,46 @@ pub(super) fn check<'tcx>(
|
51 | 59 | return;
|
52 | 60 | }
|
53 | 61 |
|
| 62 | + if let Op::NeedlessMove(_, expr) = op { |
| 63 | + let rustc_hir::ExprKind::Closure(closure) = expr.kind else { return } ; |
| 64 | + let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else { return }; |
| 65 | + let mut delegate = MoveDelegate {used_move : HirIdSet::default()}; |
| 66 | + let infcx = cx.tcx.infer_ctxt().build(); |
| 67 | + |
| 68 | + ExprUseVisitor::new( |
| 69 | + &mut delegate, |
| 70 | + &infcx, |
| 71 | + closure.body.hir_id.owner.def_id, |
| 72 | + cx.param_env, |
| 73 | + cx.typeck_results(), |
| 74 | + ) |
| 75 | + .consume_body(body); |
| 76 | + |
| 77 | + let mut to_be_discarded = false; |
| 78 | + |
| 79 | + p.pat.walk(|it| { |
| 80 | + if delegate.used_move.contains(&it.hir_id){ |
| 81 | + to_be_discarded = true; |
| 82 | + return false; |
| 83 | + } |
| 84 | + |
| 85 | + match it.kind { |
| 86 | + PatKind::Binding(BindingAnnotation(_, Mutability::Mut), _, _, _) |
| 87 | + | PatKind::Ref(_, Mutability::Mut) => { |
| 88 | + to_be_discarded = true; |
| 89 | + false |
| 90 | + } |
| 91 | + _ => { true } |
| 92 | + } |
| 93 | + }); |
| 94 | + |
| 95 | + if to_be_discarded { |
| 96 | + return; |
| 97 | + } |
| 98 | + } |
| 99 | + |
54 | 100 | let (lint, msg, trailing_clone) = match op {
|
55 |
| - Op::RmCloned => (REDUNDANT_CLONE, "unneeded cloning of iterator items", ""), |
| 101 | + Op::RmCloned | Op::NeedlessMove(_, _) => (REDUNDANT_CLONE, "unneeded cloning of iterator items", ""), |
56 | 102 | Op::LaterCloned | Op::FixClosure(_, _) => (ITER_OVEREAGER_CLONED, "unnecessarily eager cloning of iterator items", ".cloned()"),
|
57 | 103 | };
|
58 | 104 |
|
@@ -83,8 +129,33 @@ pub(super) fn check<'tcx>(
|
83 | 129 | diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable);
|
84 | 130 | }
|
85 | 131 | }
|
| 132 | + Op::NeedlessMove(_, _) => { |
| 133 | + let method_span = expr.span.with_lo(cloned_call.span.hi()); |
| 134 | + if let Some(snip) = snippet_opt(cx, method_span) { |
| 135 | + let replace_span = expr.span.with_lo(cloned_recv.span.hi()); |
| 136 | + diag.span_suggestion(replace_span, "try", snip, Applicability::MaybeIncorrect); |
| 137 | + } |
| 138 | + } |
86 | 139 | }
|
87 | 140 | }
|
88 | 141 | );
|
89 | 142 | }
|
90 | 143 | }
|
| 144 | + |
| 145 | +struct MoveDelegate { |
| 146 | + used_move: HirIdSet, |
| 147 | +} |
| 148 | + |
| 149 | +impl<'tcx> Delegate<'tcx> for MoveDelegate { |
| 150 | + fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, _: HirId) { |
| 151 | + if let PlaceBase::Local(l) = place_with_id.place.base { |
| 152 | + self.used_move.insert(l); |
| 153 | + } |
| 154 | + } |
| 155 | + |
| 156 | + fn borrow(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: BorrowKind) {} |
| 157 | + |
| 158 | + fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} |
| 159 | + |
| 160 | + fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} |
| 161 | +} |
0 commit comments