Skip to content

Commit 9991040

Browse files
committed
Auto merge of #7289 - camsteffen:needless-collect-shadow, r=Manishearth
Fix needless_collect with binding shadowing changelog: Fix [`needless_collect`] weird output when a binding is shadowed Fixes #7200
2 parents b1752f6 + 21c829e commit 9991040

File tree

1 file changed

+36
-61
lines changed

1 file changed

+36
-61
lines changed

clippy_lints/src/loops/needless_collect.rs

Lines changed: 36 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ use clippy_utils::{is_trait_method, path_to_local_id};
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, GenericArgs, HirId, Local, Pat, PatKind, QPath, StmtKind, Ty};
10+
use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, StmtKind};
1111
use rustc_lint::LateContext;
1212
use rustc_middle::hir::map::Map;
13-
use rustc_span::symbol::{sym, Ident};
13+
use rustc_span::sym;
1414
use rustc_span::{MultiSpan, Span};
1515

1616
const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";
@@ -24,10 +24,8 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
2424
if let ExprKind::MethodCall(method, _, args, _) = expr.kind;
2525
if let ExprKind::MethodCall(chain_method, method0_span, _, _) = args[0].kind;
2626
if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
27-
if let Some(generic_args) = chain_method.args;
28-
if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
29-
if let Some(ty) = cx.typeck_results().node_type_opt(ty.hir_id);
3027
then {
28+
let ty = cx.typeck_results().expr_ty(&args[0]);
3129
let mut applicability = Applicability::MachineApplicable;
3230
let is_empty_sugg = "next().is_none()".to_string();
3331
let method_name = &*method.ident.name.as_str();
@@ -72,40 +70,25 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
7270
}
7371

7472
fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
75-
fn get_hir_id<'tcx>(ty: Option<&Ty<'tcx>>, method_args: Option<&GenericArgs<'tcx>>) -> Option<HirId> {
76-
if let Some(ty) = ty {
77-
return Some(ty.hir_id);
78-
}
79-
80-
if let Some(generic_args) = method_args {
81-
if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0) {
82-
return Some(ty.hir_id);
83-
}
84-
}
85-
86-
None
87-
}
8873
if let ExprKind::Block(block, _) = expr.kind {
8974
for stmt in block.stmts {
9075
if_chain! {
91-
if let StmtKind::Local(
92-
Local { pat: Pat { hir_id: pat_id, kind: PatKind::Binding(_, _, ident, .. ), .. },
93-
init: Some(init_expr), ty, .. }
94-
) = stmt.kind;
76+
if let StmtKind::Local(local) = stmt.kind;
77+
if let PatKind::Binding(_, id, ..) = local.pat.kind;
78+
if let Some(init_expr) = local.init;
9579
if let ExprKind::MethodCall(method_name, collect_span, &[ref iter_source], ..) = init_expr.kind;
9680
if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
97-
if let Some(hir_id) = get_hir_id(*ty, method_name.args);
98-
if let Some(ty) = cx.typeck_results().node_type_opt(hir_id);
81+
let ty = cx.typeck_results().expr_ty(init_expr);
9982
if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
10083
is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
10184
is_type_diagnostic_item(cx, ty, sym::BinaryHeap) ||
10285
is_type_diagnostic_item(cx, ty, sym::LinkedList);
103-
if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident);
86+
if let Some(iter_calls) = detect_iter_and_into_iters(block, id);
10487
if let [iter_call] = &*iter_calls;
10588
then {
10689
let mut used_count_visitor = UsedCountVisitor {
10790
cx,
108-
id: *pat_id,
91+
id,
10992
count: 0,
11093
};
11194
walk_block(&mut used_count_visitor, block);
@@ -187,48 +170,40 @@ enum IterFunctionKind {
187170
struct IterFunctionVisitor {
188171
uses: Vec<IterFunction>,
189172
seen_other: bool,
190-
target: Ident,
173+
target: HirId,
191174
}
192175
impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
193176
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
194177
// Check function calls on our collection
195-
if_chain! {
196-
if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind;
197-
if let Some(Expr { kind: ExprKind::Path(QPath::Resolved(_, path)), .. }) = args.get(0);
198-
if let &[name] = &path.segments;
199-
if name.ident == self.target;
200-
then {
201-
let len = sym!(len);
202-
let is_empty = sym!(is_empty);
203-
let contains = sym!(contains);
204-
match method_name.ident.name {
205-
sym::into_iter => self.uses.push(
206-
IterFunction { func: IterFunctionKind::IntoIter, span: expr.span }
207-
),
208-
name if name == len => self.uses.push(
209-
IterFunction { func: IterFunctionKind::Len, span: expr.span }
210-
),
211-
name if name == is_empty => self.uses.push(
212-
IterFunction { func: IterFunctionKind::IsEmpty, span: expr.span }
213-
),
214-
name if name == contains => self.uses.push(
215-
IterFunction { func: IterFunctionKind::Contains(args[1].span), span: expr.span }
216-
),
178+
if let ExprKind::MethodCall(method_name, _, [recv, args @ ..], _) = &expr.kind {
179+
if path_to_local_id(recv, self.target) {
180+
match &*method_name.ident.name.as_str() {
181+
"into_iter" => self.uses.push(IterFunction {
182+
func: IterFunctionKind::IntoIter,
183+
span: expr.span,
184+
}),
185+
"len" => self.uses.push(IterFunction {
186+
func: IterFunctionKind::Len,
187+
span: expr.span,
188+
}),
189+
"is_empty" => self.uses.push(IterFunction {
190+
func: IterFunctionKind::IsEmpty,
191+
span: expr.span,
192+
}),
193+
"contains" => self.uses.push(IterFunction {
194+
func: IterFunctionKind::Contains(args[0].span),
195+
span: expr.span,
196+
}),
217197
_ => self.seen_other = true,
218198
}
219-
return
199+
return;
220200
}
221201
}
222202
// Check if the collection is used for anything else
223-
if_chain! {
224-
if let Expr { kind: ExprKind::Path(QPath::Resolved(_, path)), .. } = expr;
225-
if let &[name] = &path.segments;
226-
if name.ident == self.target;
227-
then {
228-
self.seen_other = true;
229-
} else {
230-
walk_expr(self, expr);
231-
}
203+
if path_to_local_id(expr, self.target) {
204+
self.seen_other = true;
205+
} else {
206+
walk_expr(self, expr);
232207
}
233208
}
234209

@@ -262,10 +237,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
262237

263238
/// Detect the occurrences of calls to `iter` or `into_iter` for the
264239
/// given identifier
265-
fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, identifier: Ident) -> Option<Vec<IterFunction>> {
240+
fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, id: HirId) -> Option<Vec<IterFunction>> {
266241
let mut visitor = IterFunctionVisitor {
267242
uses: Vec::new(),
268-
target: identifier,
243+
target: id,
269244
seen_other: false,
270245
};
271246
visitor.visit_block(block);

0 commit comments

Comments
 (0)