Skip to content

Commit ef152d9

Browse files
committed
Better suggestion for array_into_iter in for loop.
1 parent aec2c5b commit ef152d9

File tree

2 files changed

+45
-18
lines changed

2 files changed

+45
-18
lines changed

compiler/rustc_lint/src/array_into_iter.rs

+44-17
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment};
66
use rustc_session::lint::FutureIncompatibilityReason;
77
use rustc_span::edition::Edition;
88
use rustc_span::symbol::sym;
9+
use rustc_span::Span;
910

1011
declare_lint! {
1112
/// The `array_into_iter` lint detects calling `into_iter` on arrays.
@@ -36,13 +37,29 @@ declare_lint! {
3637
};
3738
}
3839

39-
declare_lint_pass!(
40-
/// Checks for instances of calling `into_iter` on arrays.
41-
ArrayIntoIter => [ARRAY_INTO_ITER]
42-
);
40+
#[derive(Copy, Clone, Default)]
41+
pub struct ArrayIntoIter {
42+
for_expr_span: Span,
43+
}
44+
45+
impl_lint_pass!(ArrayIntoIter => [ARRAY_INTO_ITER]);
4346

4447
impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
4548
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
49+
// Save the span of expressions in `for _ in expr` syntax,
50+
// so we can give a better suggestion for those later.
51+
if let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) = &expr.kind {
52+
if let hir::ExprKind::Call(path, [arg]) = &arg.kind {
53+
if let hir::ExprKind::Path(hir::QPath::LangItem(
54+
hir::LangItem::IntoIterIntoIter,
55+
_,
56+
)) = &path.kind
57+
{
58+
self.for_expr_span = arg.span;
59+
}
60+
}
61+
}
62+
4663
// We only care about method call expressions.
4764
if let hir::ExprKind::MethodCall(call, span, args, _) = &expr.kind {
4865
if call.ident.name != sym::into_iter {
@@ -98,27 +115,37 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
98115
_ => bug!("array type coerced to something other than array or slice"),
99116
};
100117
cx.struct_span_lint(ARRAY_INTO_ITER, *span, |lint| {
101-
lint.build(&format!(
118+
let mut diag = lint.build(&format!(
102119
"this method call resolves to `<&{} as IntoIterator>::into_iter` \
103120
(due to backwards compatibility), \
104121
but will resolve to <{} as IntoIterator>::into_iter in Rust 2021.",
105122
target, target,
106-
))
107-
.span_suggestion(
123+
));
124+
diag.span_suggestion(
108125
call.ident.span,
109126
"use `.iter()` instead of `.into_iter()` to avoid ambiguity",
110127
"iter".into(),
111128
Applicability::MachineApplicable,
112-
)
113-
.multipart_suggestion(
114-
"or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
115-
vec![
116-
(expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
117-
(receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), ")".into()),
118-
],
119-
Applicability::MaybeIncorrect,
120-
)
121-
.emit();
129+
);
130+
if self.for_expr_span == expr.span {
131+
let expr_span = expr.span.ctxt().outer_expn_data().call_site;
132+
diag.span_suggestion(
133+
receiver_arg.span.shrink_to_hi().to(expr_span.shrink_to_hi()),
134+
"or remove `.into_iter()` to iterate by value",
135+
String::new(),
136+
Applicability::MaybeIncorrect,
137+
);
138+
} else {
139+
diag.multipart_suggestion(
140+
"or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
141+
vec![
142+
(expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
143+
(receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), ")".into()),
144+
],
145+
Applicability::MaybeIncorrect,
146+
);
147+
}
148+
diag.emit();
122149
})
123150
}
124151
}

compiler/rustc_lint/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ macro_rules! late_lint_passes {
163163
// FIXME: Turn the computation of types which implement Debug into a query
164164
// and change this to a module lint pass
165165
MissingDebugImplementations: MissingDebugImplementations::default(),
166-
ArrayIntoIter: ArrayIntoIter,
166+
ArrayIntoIter: ArrayIntoIter::default(),
167167
ClashingExternDeclarations: ClashingExternDeclarations::new(),
168168
DropTraitConstraints: DropTraitConstraints,
169169
TemporaryCStringAsPtr: TemporaryCStringAsPtr,

0 commit comments

Comments
 (0)