summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/clippy/clippy_lints/src/loops/needless_collect.rs')
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_collect.rs48
1 files changed, 40 insertions, 8 deletions
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
index ddaffc751..6e6faa79a 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
@@ -1,5 +1,6 @@
use super::NEEDLESS_COLLECT;
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
+use clippy_utils::higher;
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
@@ -24,11 +25,11 @@ pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
}
fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
if_chain! {
- if let ExprKind::MethodCall(method, args, _) = expr.kind;
- if let ExprKind::MethodCall(chain_method, _, _) = args[0].kind;
- if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
+ if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind;
+ if let ExprKind::MethodCall(chain_method, ..) = receiver.kind;
+ if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator);
then {
- let ty = cx.typeck_results().expr_ty(&args[0]);
+ let ty = cx.typeck_results().expr_ty(receiver);
let mut applicability = Applicability::MaybeIncorrect;
let is_empty_sugg = "next().is_none()".to_string();
let method_name = method.ident.name.as_str();
@@ -40,7 +41,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
"len" => "count()".to_string(),
"is_empty" => is_empty_sugg,
"contains" => {
- let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability);
+ let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability);
let (arg, pred) = contains_arg
.strip_prefix('&')
.map_or(("&x", &*contains_arg), |s| ("x", s));
@@ -79,7 +80,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
if let StmtKind::Local(local) = stmt.kind;
if let PatKind::Binding(_, id, ..) = local.pat.kind;
if let Some(init_expr) = local.init;
- if let ExprKind::MethodCall(method_name, &[ref iter_source], ..) = init_expr.kind;
+ if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind;
if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
let ty = cx.typeck_results().expr_ty(init_expr);
if is_type_diagnostic_item(cx, ty, sym::Vec) ||
@@ -184,16 +185,25 @@ struct IterFunctionVisitor<'a, 'tcx> {
impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
fn visit_block(&mut self, block: &'tcx Block<'tcx>) {
for (expr, hir_id) in block.stmts.iter().filter_map(get_expr_and_hir_id_from_stmt) {
+ if check_loop_kind(expr).is_some() {
+ continue;
+ }
self.visit_block_expr(expr, hir_id);
}
if let Some(expr) = block.expr {
- self.visit_block_expr(expr, None);
+ if let Some(loop_kind) = check_loop_kind(expr) {
+ if let LoopKind::Conditional(block_expr) = loop_kind {
+ self.visit_block_expr(block_expr, None);
+ }
+ } else {
+ self.visit_block_expr(expr, None);
+ }
}
}
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
// Check function calls on our collection
- if let ExprKind::MethodCall(method_name, [recv, args @ ..], _) = &expr.kind {
+ if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind {
if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) {
self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
self.visit_expr(recv);
@@ -264,6 +274,28 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
}
}
+enum LoopKind<'tcx> {
+ Conditional(&'tcx Expr<'tcx>),
+ Loop,
+}
+
+fn check_loop_kind<'tcx>(expr: &Expr<'tcx>) -> Option<LoopKind<'tcx>> {
+ if let Some(higher::WhileLet { let_expr, .. }) = higher::WhileLet::hir(expr) {
+ return Some(LoopKind::Conditional(let_expr));
+ }
+ if let Some(higher::While { condition, .. }) = higher::While::hir(expr) {
+ return Some(LoopKind::Conditional(condition));
+ }
+ if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr) {
+ return Some(LoopKind::Conditional(arg));
+ }
+ if let ExprKind::Loop { .. } = expr.kind {
+ return Some(LoopKind::Loop);
+ }
+
+ None
+}
+
impl<'tcx> IterFunctionVisitor<'_, 'tcx> {
fn visit_block_expr(&mut self, expr: &'tcx Expr<'tcx>, hir_id: Option<HirId>) {
self.current_statement_hir_id = hir_id;