about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMaybe Waffle <waffle.lapkin@gmail.com>2022-07-24 21:07:23 +0400
committerMaybe Waffle <waffle.lapkin@gmail.com>2022-10-09 13:05:52 +0000
commit21ec99b6fa77088b35dc747c42dfdbec3d341545 (patch)
tree4d9d96b5d6a733090080db9227ce22eedc0e6bf5
parentd030ba52e20da70ddca073bd6795d0c27aff2ddb (diff)
downloadrust-21ec99b6fa77088b35dc747c42dfdbec3d341545.tar.gz
rust-21ec99b6fa77088b35dc747c42dfdbec3d341545.zip
`for_loop_over_fallibles`: Suggest removing `.next()`
-rw-r--r--compiler/rustc_lint/src/for_loop_over_fallibles.rs49
1 files changed, 38 insertions, 11 deletions
diff --git a/compiler/rustc_lint/src/for_loop_over_fallibles.rs b/compiler/rustc_lint/src/for_loop_over_fallibles.rs
index d765131442f..78b6ca6a653 100644
--- a/compiler/rustc_lint/src/for_loop_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loop_over_fallibles.rs
@@ -73,17 +73,30 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopOverFallibles {
         );
 
         cx.struct_span_lint(FOR_LOOP_OVER_FALLIBLES, arg.span, |diag| {
-            diag.build(msg)
-                .multipart_suggestion_verbose(
-                    "consider using `if let` to clear intent",
-                    vec![
-                        // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
-                        (expr.span.with_hi(pat.span.lo()), format!("if let {var}(")),
-                        (pat.span.between(arg.span), format!(") = ")),
-                    ],
-                    Applicability::MachineApplicable,
-                )
-                .emit()
+            let mut warn = diag.build(msg);
+
+            if let Some(recv) = extract_iterator_next_call(cx, arg)
+            && let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span)
+            {
+                warn.span_suggestion(
+                    recv.span.between(arg.span.shrink_to_hi()),
+                    format!("to iterate over `{recv_snip}` remove the call to `next`"),
+                    "",
+                    Applicability::MaybeIncorrect
+                );
+            }
+
+            warn.multipart_suggestion_verbose(
+                "consider using `if let` to clear intent",
+                vec![
+                    // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
+                    (expr.span.with_hi(pat.span.lo()), format!("if let {var}(")),
+                    (pat.span.between(arg.span), format!(") = ")),
+                ],
+                Applicability::MachineApplicable,
+            );
+
+            warn.emit()
         })
     }
 }
@@ -103,3 +116,17 @@ fn extract_for_loop<'tcx>(expr: &Expr<'tcx>) -> Option<(&'tcx Pat<'tcx>, &'tcx E
         None
     }
 }
+
+fn extract_iterator_next_call<'tcx>(
+    cx: &LateContext<'_>,
+    expr: &Expr<'tcx>,
+) -> Option<&'tcx Expr<'tcx>> {
+    // This won't work for `Iterator::next(iter)`, is this an issue?
+    if let hir::ExprKind::MethodCall(_, [recv], _) = expr.kind
+    && cx.typeck_results().type_dependent_def_id(expr.hir_id) == cx.tcx.lang_items().next_fn()
+    {
+        Some(recv)
+    } else {
+        return None
+    }
+}