about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMara Bos <m-ou.se@m-ou.se>2021-05-25 19:15:27 +0200
committerMara Bos <m-ou.se@m-ou.se>2021-06-26 12:14:22 +0000
commitef152d9b9fe9899a8e0ba14d11fa1d75ef56b1d6 (patch)
tree632fca2d45d6ad3971357ed334ad27e16b5b9719
parentaec2c5b2b61a5c69742e5e408aa5e64477be6eb3 (diff)
downloadrust-ef152d9b9fe9899a8e0ba14d11fa1d75ef56b1d6.tar.gz
rust-ef152d9b9fe9899a8e0ba14d11fa1d75ef56b1d6.zip
Better suggestion for array_into_iter in for loop.
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs61
-rw-r--r--compiler/rustc_lint/src/lib.rs2
2 files changed, 45 insertions, 18 deletions
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index 738c63c3b8b..77741c7240b 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -6,6 +6,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_session::lint::FutureIncompatibilityReason;
 use rustc_span::edition::Edition;
 use rustc_span::symbol::sym;
+use rustc_span::Span;
 
 declare_lint! {
     /// The `array_into_iter` lint detects calling `into_iter` on arrays.
@@ -36,13 +37,29 @@ declare_lint! {
     };
 }
 
-declare_lint_pass!(
-    /// Checks for instances of calling `into_iter` on arrays.
-    ArrayIntoIter => [ARRAY_INTO_ITER]
-);
+#[derive(Copy, Clone, Default)]
+pub struct ArrayIntoIter {
+    for_expr_span: Span,
+}
+
+impl_lint_pass!(ArrayIntoIter => [ARRAY_INTO_ITER]);
 
 impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
+        // Save the span of expressions in `for _ in expr` syntax,
+        // so we can give a better suggestion for those later.
+        if let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) = &expr.kind {
+            if let hir::ExprKind::Call(path, [arg]) = &arg.kind {
+                if let hir::ExprKind::Path(hir::QPath::LangItem(
+                    hir::LangItem::IntoIterIntoIter,
+                    _,
+                )) = &path.kind
+                {
+                    self.for_expr_span = arg.span;
+                }
+            }
+        }
+
         // We only care about method call expressions.
         if let hir::ExprKind::MethodCall(call, span, args, _) = &expr.kind {
             if call.ident.name != sym::into_iter {
@@ -98,27 +115,37 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
                 _ => bug!("array type coerced to something other than array or slice"),
             };
             cx.struct_span_lint(ARRAY_INTO_ITER, *span, |lint| {
-                lint.build(&format!(
+                let mut diag = lint.build(&format!(
                     "this method call resolves to `<&{} as IntoIterator>::into_iter` \
                     (due to backwards compatibility), \
                     but will resolve to <{} as IntoIterator>::into_iter in Rust 2021.",
                     target, target,
-                ))
-                .span_suggestion(
+                ));
+                diag.span_suggestion(
                     call.ident.span,
                     "use `.iter()` instead of `.into_iter()` to avoid ambiguity",
                     "iter".into(),
                     Applicability::MachineApplicable,
-                )
-                .multipart_suggestion(
-                    "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
-                    vec![
-                        (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
-                        (receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), ")".into()),
-                    ],
-                    Applicability::MaybeIncorrect,
-                )
-                .emit();
+                );
+                if self.for_expr_span == expr.span {
+                    let expr_span = expr.span.ctxt().outer_expn_data().call_site;
+                    diag.span_suggestion(
+                        receiver_arg.span.shrink_to_hi().to(expr_span.shrink_to_hi()),
+                        "or remove `.into_iter()` to iterate by value",
+                        String::new(),
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    diag.multipart_suggestion(
+                        "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
+                        vec![
+                            (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
+                            (receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), ")".into()),
+                        ],
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                diag.emit();
             })
         }
     }
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 4f59460aa82..89f9809d643 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -163,7 +163,7 @@ macro_rules! late_lint_passes {
                 // FIXME: Turn the computation of types which implement Debug into a query
                 // and change this to a module lint pass
                 MissingDebugImplementations: MissingDebugImplementations::default(),
-                ArrayIntoIter: ArrayIntoIter,
+                ArrayIntoIter: ArrayIntoIter::default(),
                 ClashingExternDeclarations: ClashingExternDeclarations::new(),
                 DropTraitConstraints: DropTraitConstraints,
                 TemporaryCStringAsPtr: TemporaryCStringAsPtr,