|
| 1 | +use super::utils::clone_or_copy_needed; |
1 | 2 | use clippy_utils::diagnostics::span_lint_and_then; |
2 | 3 | use clippy_utils::higher::ForLoop; |
3 | 4 | use clippy_utils::source::snippet_opt; |
4 | 5 | use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait}; |
5 | | -use clippy_utils::{fn_def_id, get_parent_expr, path_to_local_id, usage}; |
| 6 | +use clippy_utils::{fn_def_id, get_parent_expr}; |
6 | 7 | use rustc_errors::Applicability; |
7 | | -use rustc_hir::intravisit::{walk_expr, Visitor}; |
8 | | -use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, HirId, LangItem, Mutability, Pat}; |
| 8 | +use rustc_hir::{def_id::DefId, Expr, ExprKind, LangItem}; |
9 | 9 | use rustc_lint::LateContext; |
10 | | -use rustc_middle::hir::nested_filter; |
11 | | -use rustc_middle::ty; |
12 | 10 | use rustc_span::{sym, Symbol}; |
13 | 11 |
|
14 | 12 | use super::UNNECESSARY_TO_OWNED; |
@@ -100,89 +98,6 @@ pub fn check_for_loop_iter( |
100 | 98 | false |
101 | 99 | } |
102 | 100 |
|
103 | | -/// The core logic of `check_for_loop_iter` above, this function wraps a use of |
104 | | -/// `CloneOrCopyVisitor`. |
105 | | -fn clone_or_copy_needed<'tcx>( |
106 | | - cx: &LateContext<'tcx>, |
107 | | - pat: &Pat<'tcx>, |
108 | | - body: &'tcx Expr<'tcx>, |
109 | | -) -> (bool, Vec<&'tcx Expr<'tcx>>) { |
110 | | - let mut visitor = CloneOrCopyVisitor { |
111 | | - cx, |
112 | | - binding_hir_ids: pat_bindings(pat), |
113 | | - clone_or_copy_needed: false, |
114 | | - addr_of_exprs: Vec::new(), |
115 | | - }; |
116 | | - visitor.visit_expr(body); |
117 | | - (visitor.clone_or_copy_needed, visitor.addr_of_exprs) |
118 | | -} |
119 | | - |
120 | | -/// Returns a vector of all `HirId`s bound by the pattern. |
121 | | -fn pat_bindings(pat: &Pat<'_>) -> Vec<HirId> { |
122 | | - let mut collector = usage::ParamBindingIdCollector { |
123 | | - binding_hir_ids: Vec::new(), |
124 | | - }; |
125 | | - collector.visit_pat(pat); |
126 | | - collector.binding_hir_ids |
127 | | -} |
128 | | - |
129 | | -/// `clone_or_copy_needed` will be false when `CloneOrCopyVisitor` is done visiting if the only |
130 | | -/// operations performed on `binding_hir_ids` are: |
131 | | -/// * to take non-mutable references to them |
132 | | -/// * to use them as non-mutable `&self` in method calls |
133 | | -/// If any of `binding_hir_ids` is used in any other way, then `clone_or_copy_needed` will be true |
134 | | -/// when `CloneOrCopyVisitor` is done visiting. |
135 | | -struct CloneOrCopyVisitor<'cx, 'tcx> { |
136 | | - cx: &'cx LateContext<'tcx>, |
137 | | - binding_hir_ids: Vec<HirId>, |
138 | | - clone_or_copy_needed: bool, |
139 | | - addr_of_exprs: Vec<&'tcx Expr<'tcx>>, |
140 | | -} |
141 | | - |
142 | | -impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { |
143 | | - type NestedFilter = nested_filter::OnlyBodies; |
144 | | - |
145 | | - fn nested_visit_map(&mut self) -> Self::Map { |
146 | | - self.cx.tcx.hir() |
147 | | - } |
148 | | - |
149 | | - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { |
150 | | - walk_expr(self, expr); |
151 | | - if self.is_binding(expr) { |
152 | | - if let Some(parent) = get_parent_expr(self.cx, expr) { |
153 | | - match parent.kind { |
154 | | - ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) => { |
155 | | - self.addr_of_exprs.push(parent); |
156 | | - return; |
157 | | - }, |
158 | | - ExprKind::MethodCall(_, args, _) => { |
159 | | - if_chain! { |
160 | | - if args.iter().skip(1).all(|arg| !self.is_binding(arg)); |
161 | | - if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id); |
162 | | - let method_ty = self.cx.tcx.type_of(method_def_id); |
163 | | - let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder(); |
164 | | - if matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Not)); |
165 | | - then { |
166 | | - return; |
167 | | - } |
168 | | - } |
169 | | - }, |
170 | | - _ => {}, |
171 | | - } |
172 | | - } |
173 | | - self.clone_or_copy_needed = true; |
174 | | - } |
175 | | - } |
176 | | -} |
177 | | - |
178 | | -impl<'cx, 'tcx> CloneOrCopyVisitor<'cx, 'tcx> { |
179 | | - fn is_binding(&self, expr: &Expr<'tcx>) -> bool { |
180 | | - self.binding_hir_ids |
181 | | - .iter() |
182 | | - .any(|hir_id| path_to_local_id(expr, *hir_id)) |
183 | | - } |
184 | | -} |
185 | | - |
186 | 101 | /// Returns true if the named method is `IntoIterator::into_iter`. |
187 | 102 | pub fn is_into_iter(cx: &LateContext<'_>, callee_def_id: DefId) -> bool { |
188 | 103 | cx.tcx.lang_items().require(LangItem::IntoIterIntoIter) == Ok(callee_def_id) |
|
0 commit comments